Sort the output of --help mostly alphabetical, make it align better, make
[PostgreSQL.git] / src / bin / pg_dump / pg_dump.c
blobc39c68da36f0a4a008ca1e8564704ca1d064eaa2
1 /*-------------------------------------------------------------------------
3 * pg_dump.c
4 * pg_dump is a utility for dumping out a postgres database
5 * into a script file.
7 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
10 * pg_dump will read the system catalogs in a database and dump out a
11 * script that reproduces the schema in terms of SQL that is understood
12 * by PostgreSQL
14 * IDENTIFICATION
15 * $PostgreSQL$
17 *-------------------------------------------------------------------------
20 #include "postgres_fe.h"
22 #include <unistd.h>
23 #include <ctype.h>
24 #ifdef ENABLE_NLS
25 #include <locale.h>
26 #endif
27 #ifdef HAVE_TERMIOS_H
28 #include <termios.h>
29 #endif
31 #include "getopt_long.h"
33 #ifndef HAVE_INT_OPTRESET
34 int optreset;
35 #endif
37 #include "access/attnum.h"
38 #include "access/sysattr.h"
39 #include "catalog/pg_cast.h"
40 #include "catalog/pg_class.h"
41 #include "catalog/pg_proc.h"
42 #include "catalog/pg_trigger.h"
43 #include "catalog/pg_type.h"
44 #include "libpq/libpq-fs.h"
46 #include "pg_backup_archiver.h"
47 #include "dumputils.h"
49 extern char *optarg;
50 extern int optind,
51 opterr;
54 typedef struct
56 const char *descr; /* comment for an object */
57 Oid classoid; /* object class (catalog OID) */
58 Oid objoid; /* object OID */
59 int objsubid; /* subobject (table column #) */
60 } CommentItem;
63 /* global decls */
64 bool g_verbose; /* User wants verbose narration of our
65 * activities. */
66 Archive *g_fout; /* the script file */
67 PGconn *g_conn; /* the database connection */
69 /* various user-settable parameters */
70 bool dumpInserts; /* dump data using proper insert strings */
71 bool attrNames; /* put attr names into insert strings */
72 bool schemaOnly;
73 bool dataOnly;
74 bool aclsSkip;
75 const char *lockWaitTimeout;
77 /* subquery used to convert user ID (eg, datdba) to user name */
78 static const char *username_subquery;
80 /* obsolete as of 7.3: */
81 static Oid g_last_builtin_oid; /* value of the last builtin oid */
84 * Object inclusion/exclusion lists
86 * The string lists record the patterns given by command-line switches,
87 * which we then convert to lists of OIDs of matching objects.
89 static SimpleStringList schema_include_patterns = {NULL, NULL};
90 static SimpleOidList schema_include_oids = {NULL, NULL};
91 static SimpleStringList schema_exclude_patterns = {NULL, NULL};
92 static SimpleOidList schema_exclude_oids = {NULL, NULL};
94 static SimpleStringList table_include_patterns = {NULL, NULL};
95 static SimpleOidList table_include_oids = {NULL, NULL};
96 static SimpleStringList table_exclude_patterns = {NULL, NULL};
97 static SimpleOidList table_exclude_oids = {NULL, NULL};
99 /* default, if no "inclusion" switches appear, is to dump everything */
100 static bool include_everything = true;
102 static int binary_upgrade = 0;
104 char g_opaque_type[10]; /* name for the opaque type */
106 /* placeholders for the delimiters for comments */
107 char g_comment_start[10];
108 char g_comment_end[10];
110 static const CatalogId nilCatalogId = {0, 0};
112 /* these are to avoid passing around info for findNamespace() */
113 static NamespaceInfo *g_namespaces;
114 static int g_numNamespaces;
116 /* flag to turn on/off dollar quoting */
117 static int disable_dollar_quoting = 0;
120 static void help(const char *progname);
121 static void expand_schema_name_patterns(SimpleStringList *patterns,
122 SimpleOidList *oids);
123 static void expand_table_name_patterns(SimpleStringList *patterns,
124 SimpleOidList *oids);
125 static NamespaceInfo *findNamespace(Oid nsoid, Oid objoid);
126 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
127 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
128 static void dumpComment(Archive *fout, const char *target,
129 const char *namespace, const char *owner,
130 CatalogId catalogId, int subid, DumpId dumpId);
131 static int findComments(Archive *fout, Oid classoid, Oid objoid,
132 CommentItem **items);
133 static int collectComments(Archive *fout, CommentItem **items);
134 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
135 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
136 static void dumpType(Archive *fout, TypeInfo *tinfo);
137 static void dumpBaseType(Archive *fout, TypeInfo *tinfo);
138 static void dumpEnumType(Archive *fout, TypeInfo *tinfo);
139 static void dumpDomain(Archive *fout, TypeInfo *tinfo);
140 static void dumpCompositeType(Archive *fout, TypeInfo *tinfo);
141 static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
142 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
143 static void dumpFunc(Archive *fout, FuncInfo *finfo);
144 static void dumpCast(Archive *fout, CastInfo *cast);
145 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
146 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
147 static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
148 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
149 static void dumpRule(Archive *fout, RuleInfo *rinfo);
150 static void dumpAgg(Archive *fout, AggInfo *agginfo);
151 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
152 static void dumpTable(Archive *fout, TableInfo *tbinfo);
153 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
154 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
155 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
156 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
157 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
158 static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
159 static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
160 static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
161 static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
162 static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
163 static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
164 static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
165 static void dumpUserMappings(Archive *fout, const char *target,
166 const char *servername, const char *namespace,
167 const char *owner, CatalogId catalogId, DumpId dumpId);
169 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
170 const char *type, const char *name, const char *subname,
171 const char *tag, const char *nspname, const char *owner,
172 const char *acls);
174 static void getDependencies(void);
175 static void getDomainConstraints(TypeInfo *tinfo);
176 static void getTableData(TableInfo *tblinfo, int numTables, bool oids);
177 static void getTableDataFKConstraints(void);
178 static char *format_function_arguments(FuncInfo *finfo, char *funcargs);
179 static char *format_function_arguments_old(FuncInfo *finfo, int nallargs,
180 char **allargtypes,
181 char **argmodes,
182 char **argnames);
183 static char *format_function_signature(FuncInfo *finfo, bool honor_quotes);
184 static const char *convertRegProcReference(const char *proc);
185 static const char *convertOperatorReference(const char *opr);
186 static const char *convertTSFunction(Oid funcOid);
187 static Oid findLastBuiltinOid_V71(const char *);
188 static Oid findLastBuiltinOid_V70(void);
189 static void selectSourceSchema(const char *schemaName);
190 static char *getFormattedTypeName(Oid oid, OidOptions opts);
191 static char *myFormatType(const char *typname, int32 typmod);
192 static const char *fmtQualifiedId(const char *schema, const char *id);
193 static bool hasBlobs(Archive *AH);
194 static int dumpBlobs(Archive *AH, void *arg);
195 static int dumpBlobComments(Archive *AH, void *arg);
196 static void dumpDatabase(Archive *AH);
197 static void dumpEncoding(Archive *AH);
198 static void dumpStdStrings(Archive *AH);
199 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
200 static const char *fmtCopyColumnList(const TableInfo *ti);
201 static void do_sql_command(PGconn *conn, const char *query);
202 static void check_sql_result(PGresult *res, PGconn *conn, const char *query,
203 ExecStatusType expected);
207 main(int argc, char **argv)
209 int c;
210 const char *filename = NULL;
211 const char *format = "p";
212 const char *dbname = NULL;
213 const char *pghost = NULL;
214 const char *pgport = NULL;
215 const char *username = NULL;
216 const char *dumpencoding = NULL;
217 const char *std_strings;
218 bool oids = false;
219 TableInfo *tblinfo;
220 int numTables;
221 DumpableObject **dobjs;
222 int numObjs;
223 int i;
224 bool force_password = false;
225 int compressLevel = -1;
226 int plainText = 0;
227 int outputClean = 0;
228 int outputCreate = 0;
229 bool outputBlobs = false;
230 int outputNoOwner = 0;
231 char *outputSuperuser = NULL;
232 char *use_role = NULL;
233 int my_version;
234 int optindex;
235 RestoreOptions *ropt;
237 static int disable_triggers = 0;
238 static int outputNoTablespaces = 0;
239 static int use_setsessauth = 0;
241 struct option long_options[] = {
242 {"binary-upgrade", no_argument, &binary_upgrade, 1}, /* not documented */
243 {"data-only", no_argument, NULL, 'a'},
244 {"blobs", no_argument, NULL, 'b'},
245 {"clean", no_argument, NULL, 'c'},
246 {"create", no_argument, NULL, 'C'},
247 {"file", required_argument, NULL, 'f'},
248 {"format", required_argument, NULL, 'F'},
249 {"inserts", no_argument, NULL, 'd'},
250 {"attribute-inserts", no_argument, NULL, 'D'},
251 {"column-inserts", no_argument, NULL, 'D'},
252 {"host", required_argument, NULL, 'h'},
253 {"ignore-version", no_argument, NULL, 'i'},
254 {"no-reconnect", no_argument, NULL, 'R'},
255 {"oids", no_argument, NULL, 'o'},
256 {"no-owner", no_argument, NULL, 'O'},
257 {"port", required_argument, NULL, 'p'},
258 {"schema", required_argument, NULL, 'n'},
259 {"exclude-schema", required_argument, NULL, 'N'},
260 {"schema-only", no_argument, NULL, 's'},
261 {"superuser", required_argument, NULL, 'S'},
262 {"table", required_argument, NULL, 't'},
263 {"exclude-table", required_argument, NULL, 'T'},
264 {"password", no_argument, NULL, 'W'},
265 {"username", required_argument, NULL, 'U'},
266 {"verbose", no_argument, NULL, 'v'},
267 {"no-privileges", no_argument, NULL, 'x'},
268 {"no-acl", no_argument, NULL, 'x'},
269 {"compress", required_argument, NULL, 'Z'},
270 {"encoding", required_argument, NULL, 'E'},
271 {"help", no_argument, NULL, '?'},
272 {"version", no_argument, NULL, 'V'},
275 * the following options don't have an equivalent short option letter
277 {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
278 {"disable-triggers", no_argument, &disable_triggers, 1},
279 {"lock-wait-timeout", required_argument, NULL, 2},
280 {"no-tablespaces", no_argument, &outputNoTablespaces, 1},
281 {"role", required_argument, NULL, 3},
282 {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
284 {NULL, 0, NULL, 0}
287 set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
289 g_verbose = false;
291 strcpy(g_comment_start, "-- ");
292 g_comment_end[0] = '\0';
293 strcpy(g_opaque_type, "opaque");
295 dataOnly = schemaOnly = dumpInserts = attrNames = false;
296 lockWaitTimeout = NULL;
298 progname = get_progname(argv[0]);
300 /* Set default options based on progname */
301 if (strcmp(progname, "pg_backup") == 0)
302 format = "c";
304 if (argc > 1)
306 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
308 help(progname);
309 exit(0);
311 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
313 puts("pg_dump (PostgreSQL) " PG_VERSION);
314 exit(0);
318 while ((c = getopt_long(argc, argv, "abcCdDE:f:F:h:in:N:oOp:RsS:t:T:U:vWxX:Z:",
319 long_options, &optindex)) != -1)
321 switch (c)
323 case 'a': /* Dump data only */
324 dataOnly = true;
325 break;
327 case 'b': /* Dump blobs */
328 outputBlobs = true;
329 break;
331 case 'c': /* clean (i.e., drop) schema prior to create */
332 outputClean = 1;
333 break;
335 case 'C': /* Create DB */
336 outputCreate = 1;
337 break;
339 case 'd': /* dump data as proper insert strings */
340 dumpInserts = true;
341 break;
343 case 'D': /* dump data as proper insert strings with
344 * attr names */
345 dumpInserts = true;
346 attrNames = true;
347 break;
349 case 'E': /* Dump encoding */
350 dumpencoding = optarg;
351 break;
353 case 'f':
354 filename = optarg;
355 break;
357 case 'F':
358 format = optarg;
359 break;
361 case 'h': /* server host */
362 pghost = optarg;
363 break;
365 case 'i':
366 /* ignored, deprecated option */
367 break;
369 case 'n': /* include schema(s) */
370 simple_string_list_append(&schema_include_patterns, optarg);
371 include_everything = false;
372 break;
374 case 'N': /* exclude schema(s) */
375 simple_string_list_append(&schema_exclude_patterns, optarg);
376 break;
378 case 'o': /* Dump oids */
379 oids = true;
380 break;
382 case 'O': /* Don't reconnect to match owner */
383 outputNoOwner = 1;
384 break;
386 case 'p': /* server port */
387 pgport = optarg;
388 break;
390 case 'R':
391 /* no-op, still accepted for backwards compatibility */
392 break;
394 case 's': /* dump schema only */
395 schemaOnly = true;
396 break;
398 case 'S': /* Username for superuser in plain text output */
399 outputSuperuser = strdup(optarg);
400 break;
402 case 't': /* include table(s) */
403 simple_string_list_append(&table_include_patterns, optarg);
404 include_everything = false;
405 break;
407 case 'T': /* exclude table(s) */
408 simple_string_list_append(&table_exclude_patterns, optarg);
409 break;
411 case 'U':
412 username = optarg;
413 break;
415 case 'v': /* verbose */
416 g_verbose = true;
417 break;
419 case 'W':
420 force_password = true;
421 break;
423 case 'x': /* skip ACL dump */
424 aclsSkip = true;
425 break;
427 case 'X':
428 /* -X is a deprecated alternative to long options */
429 if (strcmp(optarg, "disable-dollar-quoting") == 0)
430 disable_dollar_quoting = 1;
431 else if (strcmp(optarg, "disable-triggers") == 0)
432 disable_triggers = 1;
433 else if (strcmp(optarg, "no-tablespaces") == 0)
434 outputNoTablespaces = 1;
435 else if (strcmp(optarg, "use-set-session-authorization") == 0)
436 use_setsessauth = 1;
437 else
439 fprintf(stderr,
440 _("%s: invalid -X option -- %s\n"),
441 progname, optarg);
442 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
443 exit(1);
445 break;
447 case 'Z': /* Compression Level */
448 compressLevel = atoi(optarg);
449 break;
451 case 0:
452 /* This covers the long options equivalent to -X xxx. */
453 break;
455 case 2: /* lock-wait-timeout */
456 lockWaitTimeout = optarg;
457 break;
459 case 3: /* SET ROLE */
460 use_role = optarg;
461 break;
463 default:
464 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
465 exit(1);
469 if (optind < (argc - 1))
471 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
472 progname, argv[optind + 1]);
473 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
474 progname);
475 exit(1);
478 /* Get database name from command line */
479 if (optind < argc)
480 dbname = argv[optind];
482 if (dataOnly && schemaOnly)
484 write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
485 exit(1);
488 if (dataOnly && outputClean)
490 write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
491 exit(1);
494 if (dumpInserts == true && oids == true)
496 write_msg(NULL, "options -d/-D/--inserts/--column-inserts and -o/--oids cannot be used together\n");
497 write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
498 exit(1);
501 /* open the output file */
502 if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
504 /* This is used by pg_dumpall, and is not documented */
505 plainText = 1;
506 g_fout = CreateArchive(filename, archNull, 0, archModeAppend);
508 else if (pg_strcasecmp(format, "c") == 0 || pg_strcasecmp(format, "custom") == 0)
509 g_fout = CreateArchive(filename, archCustom, compressLevel, archModeWrite);
510 else if (pg_strcasecmp(format, "f") == 0 || pg_strcasecmp(format, "file") == 0)
513 * Dump files into the current directory; for demonstration only, not
514 * documented.
516 g_fout = CreateArchive(filename, archFiles, compressLevel, archModeWrite);
518 else if (pg_strcasecmp(format, "p") == 0 || pg_strcasecmp(format, "plain") == 0)
520 plainText = 1;
521 g_fout = CreateArchive(filename, archNull, 0, archModeWrite);
523 else if (pg_strcasecmp(format, "t") == 0 || pg_strcasecmp(format, "tar") == 0)
524 g_fout = CreateArchive(filename, archTar, compressLevel, archModeWrite);
525 else
527 write_msg(NULL, "invalid output format \"%s\" specified\n", format);
528 exit(1);
531 if (g_fout == NULL)
533 write_msg(NULL, "could not open output file \"%s\" for writing\n", filename);
534 exit(1);
537 /* Let the archiver know how noisy to be */
538 g_fout->verbose = g_verbose;
540 my_version = parse_version(PG_VERSION);
541 if (my_version < 0)
543 write_msg(NULL, "could not parse version string \"%s\"\n", PG_VERSION);
544 exit(1);
548 * We allow the server to be back to 7.0, and up to any minor release
549 * of our own major version. (See also version check in pg_dumpall.c.)
551 g_fout->minRemoteVersion = 70000;
552 g_fout->maxRemoteVersion = (my_version / 100) * 100 + 99;
555 * Open the database using the Archiver, so it knows about it. Errors mean
556 * death.
558 g_conn = ConnectDatabase(g_fout, dbname, pghost, pgport,
559 username, force_password);
561 /* Set the client encoding if requested */
562 if (dumpencoding)
564 if (PQsetClientEncoding(g_conn, dumpencoding) < 0)
566 write_msg(NULL, "invalid client encoding \"%s\" specified\n",
567 dumpencoding);
568 exit(1);
573 * Get the active encoding and the standard_conforming_strings setting, so
574 * we know how to escape strings.
576 g_fout->encoding = PQclientEncoding(g_conn);
578 std_strings = PQparameterStatus(g_conn, "standard_conforming_strings");
579 g_fout->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
581 /* Set the role if requested */
582 if (use_role && g_fout->remoteVersion >= 80100)
584 PQExpBuffer query = createPQExpBuffer();
586 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
587 do_sql_command(g_conn, query->data);
588 destroyPQExpBuffer(query);
591 /* Set the datestyle to ISO to ensure the dump's portability */
592 do_sql_command(g_conn, "SET DATESTYLE = ISO");
594 /* Likewise, avoid using sql_standard intervalstyle */
595 if (g_fout->remoteVersion >= 80400)
596 do_sql_command(g_conn, "SET INTERVALSTYLE = POSTGRES");
599 * If supported, set extra_float_digits so that we can dump float data
600 * exactly (given correctly implemented float I/O code, anyway)
602 if (g_fout->remoteVersion >= 70400)
603 do_sql_command(g_conn, "SET extra_float_digits TO 2");
606 * If synchronized scanning is supported, disable it, to prevent
607 * unpredictable changes in row ordering across a dump and reload.
609 if (g_fout->remoteVersion >= 80300)
610 do_sql_command(g_conn, "SET synchronize_seqscans TO off");
613 * Disable timeouts if supported.
615 if (g_fout->remoteVersion >= 70300)
616 do_sql_command(g_conn, "SET statement_timeout = 0");
619 * Start serializable transaction to dump consistent data.
621 do_sql_command(g_conn, "BEGIN");
623 do_sql_command(g_conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
625 /* Select the appropriate subquery to convert user IDs to names */
626 if (g_fout->remoteVersion >= 80100)
627 username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
628 else if (g_fout->remoteVersion >= 70300)
629 username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
630 else
631 username_subquery = "SELECT usename FROM pg_user WHERE usesysid =";
633 /* Find the last built-in OID, if needed */
634 if (g_fout->remoteVersion < 70300)
636 if (g_fout->remoteVersion >= 70100)
637 g_last_builtin_oid = findLastBuiltinOid_V71(PQdb(g_conn));
638 else
639 g_last_builtin_oid = findLastBuiltinOid_V70();
640 if (g_verbose)
641 write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
644 /* Expand schema selection patterns into OID lists */
645 if (schema_include_patterns.head != NULL)
647 expand_schema_name_patterns(&schema_include_patterns,
648 &schema_include_oids);
649 if (schema_include_oids.head == NULL)
651 write_msg(NULL, "No matching schemas were found\n");
652 exit_nicely();
655 expand_schema_name_patterns(&schema_exclude_patterns,
656 &schema_exclude_oids);
657 /* non-matching exclusion patterns aren't an error */
659 /* Expand table selection patterns into OID lists */
660 if (table_include_patterns.head != NULL)
662 expand_table_name_patterns(&table_include_patterns,
663 &table_include_oids);
664 if (table_include_oids.head == NULL)
666 write_msg(NULL, "No matching tables were found\n");
667 exit_nicely();
670 expand_table_name_patterns(&table_exclude_patterns,
671 &table_exclude_oids);
672 /* non-matching exclusion patterns aren't an error */
675 * Dumping blobs is now default unless we saw an inclusion switch or -s
676 * ... but even if we did see one of these, -b turns it back on.
678 if (include_everything && !schemaOnly)
679 outputBlobs = true;
682 * Now scan the database and create DumpableObject structs for all the
683 * objects we intend to dump.
685 tblinfo = getSchemaData(&numTables);
687 if (g_fout->remoteVersion < 80400)
688 guessConstraintInheritance(tblinfo, numTables);
690 if (!schemaOnly)
692 getTableData(tblinfo, numTables, oids);
693 if (dataOnly)
694 getTableDataFKConstraints();
697 if (outputBlobs && hasBlobs(g_fout))
699 /* Add placeholders to allow correct sorting of blobs */
700 DumpableObject *blobobj;
701 DumpableObject *blobcobj;
703 blobobj = (DumpableObject *) malloc(sizeof(DumpableObject));
704 blobobj->objType = DO_BLOBS;
705 blobobj->catId = nilCatalogId;
706 AssignDumpId(blobobj);
707 blobobj->name = strdup("BLOBS");
709 blobcobj = (DumpableObject *) malloc(sizeof(DumpableObject));
710 blobcobj->objType = DO_BLOB_COMMENTS;
711 blobcobj->catId = nilCatalogId;
712 AssignDumpId(blobcobj);
713 blobcobj->name = strdup("BLOB COMMENTS");
714 addObjectDependency(blobcobj, blobobj->dumpId);
718 * Collect dependency data to assist in ordering the objects.
720 getDependencies();
723 * Sort the objects into a safe dump order (no forward references).
725 * In 7.3 or later, we can rely on dependency information to help us
726 * determine a safe order, so the initial sort is mostly for cosmetic
727 * purposes: we sort by name to ensure that logically identical schemas
728 * will dump identically. Before 7.3 we don't have dependencies and we
729 * use OID ordering as an (unreliable) guide to creation order.
731 getDumpableObjects(&dobjs, &numObjs);
733 if (g_fout->remoteVersion >= 70300)
734 sortDumpableObjectsByTypeName(dobjs, numObjs);
735 else
736 sortDumpableObjectsByTypeOid(dobjs, numObjs);
738 sortDumpableObjects(dobjs, numObjs);
741 * Create archive TOC entries for all the objects to be dumped, in a safe
742 * order.
745 /* First the special ENCODING and STDSTRINGS entries. */
746 dumpEncoding(g_fout);
747 dumpStdStrings(g_fout);
749 /* The database item is always next, unless we don't want it at all */
750 if (include_everything && !dataOnly)
751 dumpDatabase(g_fout);
753 /* Now the rearrangeable objects. */
754 for (i = 0; i < numObjs; i++)
755 dumpDumpableObject(g_fout, dobjs[i]);
758 * And finally we can do the actual output.
760 if (plainText)
762 ropt = NewRestoreOptions();
763 ropt->filename = (char *) filename;
764 ropt->dropSchema = outputClean;
765 ropt->aclsSkip = aclsSkip;
766 ropt->superuser = outputSuperuser;
767 ropt->create = outputCreate;
768 ropt->noOwner = outputNoOwner;
769 ropt->noTablespace = outputNoTablespaces;
770 ropt->disable_triggers = disable_triggers;
771 ropt->use_setsessauth = use_setsessauth;
772 ropt->dataOnly = dataOnly;
774 if (compressLevel == -1)
775 ropt->compression = 0;
776 else
777 ropt->compression = compressLevel;
779 ropt->suppressDumpWarnings = true; /* We've already shown them */
781 RestoreArchive(g_fout, ropt);
784 CloseArchive(g_fout);
786 PQfinish(g_conn);
788 exit(0);
792 static void
793 help(const char *progname)
795 printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
796 printf(_("Usage:\n"));
797 printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
799 printf(_("\nGeneral options:\n"));
800 printf(_(" -f, --file=FILENAME output file name\n"));
801 printf(_(" -F, --format=c|t|p output file format (custom, tar, plain text)\n"));
802 printf(_(" -v, --verbose verbose mode\n"));
803 printf(_(" -Z, --compress=0-9 compression level for compressed formats\n"));
804 printf(_(" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
805 printf(_(" --help show this help, then exit\n"));
806 printf(_(" --version output version information, then exit\n"));
808 printf(_("\nOptions controlling the output content:\n"));
809 printf(_(" -a, --data-only dump only the data, not the schema\n"));
810 printf(_(" -b, --blobs include large objects in dump\n"));
811 printf(_(" -c, --clean clean (drop) database objects before recreating\n"));
812 printf(_(" -C, --create include commands to create database in dump\n"));
813 printf(_(" -d, --inserts dump data as INSERT commands, rather than COPY\n"));
814 printf(_(" -D, --column-inserts dump data as INSERT commands with column names\n"));
815 printf(_(" -E, --encoding=ENCODING dump the data in encoding ENCODING\n"));
816 printf(_(" -n, --schema=SCHEMA dump the named schema(s) only\n"));
817 printf(_(" -N, --exclude-schema=SCHEMA do NOT dump the named schema(s)\n"));
818 printf(_(" -o, --oids include OIDs in dump\n"));
819 printf(_(" -O, --no-owner skip restoration of object ownership in\n"
820 " plain-text format\n"));
821 printf(_(" -s, --schema-only dump only the schema, no data\n"));
822 printf(_(" -S, --superuser=NAME superuser user name to use in plain-text format\n"));
823 printf(_(" -t, --table=TABLE dump the named table(s) only\n"));
824 printf(_(" -T, --exclude-table=TABLE do NOT dump the named table(s)\n"));
825 printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
826 printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n"));
827 printf(_(" --disable-triggers disable triggers during data-only restore\n"));
828 printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
829 printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
830 printf(_(" --use-set-session-authorization\n"
831 " use SET SESSION AUTHORIZATION commands instead of\n"
832 " ALTER OWNER commands to set ownership\n"));
834 printf(_("\nConnection options:\n"));
835 printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
836 printf(_(" -p, --port=PORT database server port number\n"));
837 printf(_(" -U, --username=NAME connect as specified database user\n"));
838 printf(_(" -W, --password force password prompt (should happen automatically)\n"));
840 printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
841 "variable value is used.\n\n"));
842 printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
845 void
846 exit_nicely(void)
848 PQfinish(g_conn);
849 if (g_verbose)
850 write_msg(NULL, "*** aborted because of error\n");
851 exit(1);
855 * Find the OIDs of all schemas matching the given list of patterns,
856 * and append them to the given OID list.
858 static void
859 expand_schema_name_patterns(SimpleStringList *patterns, SimpleOidList *oids)
861 PQExpBuffer query;
862 PGresult *res;
863 SimpleStringListCell *cell;
864 int i;
866 if (patterns->head == NULL)
867 return; /* nothing to do */
869 if (g_fout->remoteVersion < 70300)
871 write_msg(NULL, "server version must be at least 7.3 to use schema selection switches\n");
872 exit_nicely();
875 query = createPQExpBuffer();
878 * We use UNION ALL rather than UNION; this might sometimes result in
879 * duplicate entries in the OID list, but we don't care.
882 for (cell = patterns->head; cell; cell = cell->next)
884 if (cell != patterns->head)
885 appendPQExpBuffer(query, "UNION ALL\n");
886 appendPQExpBuffer(query,
887 "SELECT oid FROM pg_catalog.pg_namespace n\n");
888 processSQLNamePattern(g_conn, query, cell->val, false, false,
889 NULL, "n.nspname", NULL,
890 NULL);
893 res = PQexec(g_conn, query->data);
894 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
896 for (i = 0; i < PQntuples(res); i++)
898 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
901 PQclear(res);
902 destroyPQExpBuffer(query);
906 * Find the OIDs of all tables matching the given list of patterns,
907 * and append them to the given OID list.
909 static void
910 expand_table_name_patterns(SimpleStringList *patterns, SimpleOidList *oids)
912 PQExpBuffer query;
913 PGresult *res;
914 SimpleStringListCell *cell;
915 int i;
917 if (patterns->head == NULL)
918 return; /* nothing to do */
920 query = createPQExpBuffer();
923 * We use UNION ALL rather than UNION; this might sometimes result in
924 * duplicate entries in the OID list, but we don't care.
927 for (cell = patterns->head; cell; cell = cell->next)
929 if (cell != patterns->head)
930 appendPQExpBuffer(query, "UNION ALL\n");
931 appendPQExpBuffer(query,
932 "SELECT c.oid"
933 "\nFROM pg_catalog.pg_class c"
934 "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
935 "\nWHERE c.relkind in ('%c', '%c', '%c')\n",
936 RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
937 processSQLNamePattern(g_conn, query, cell->val, true, false,
938 "n.nspname", "c.relname", NULL,
939 "pg_catalog.pg_table_is_visible(c.oid)");
942 res = PQexec(g_conn, query->data);
943 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
945 for (i = 0; i < PQntuples(res); i++)
947 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
950 PQclear(res);
951 destroyPQExpBuffer(query);
955 * selectDumpableNamespace: policy-setting subroutine
956 * Mark a namespace as to be dumped or not
958 static void
959 selectDumpableNamespace(NamespaceInfo *nsinfo)
962 * If specific tables are being dumped, do not dump any complete
963 * namespaces. If specific namespaces are being dumped, dump just those
964 * namespaces. Otherwise, dump all non-system namespaces.
966 if (table_include_oids.head != NULL)
967 nsinfo->dobj.dump = false;
968 else if (schema_include_oids.head != NULL)
969 nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
970 nsinfo->dobj.catId.oid);
971 else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
972 strcmp(nsinfo->dobj.name, "information_schema") == 0)
973 nsinfo->dobj.dump = false;
974 else
975 nsinfo->dobj.dump = true;
978 * In any case, a namespace can be excluded by an exclusion switch
980 if (nsinfo->dobj.dump &&
981 simple_oid_list_member(&schema_exclude_oids,
982 nsinfo->dobj.catId.oid))
983 nsinfo->dobj.dump = false;
987 * selectDumpableTable: policy-setting subroutine
988 * Mark a table as to be dumped or not
990 static void
991 selectDumpableTable(TableInfo *tbinfo)
994 * If specific tables are being dumped, dump just those tables; else, dump
995 * according to the parent namespace's dump flag.
997 if (table_include_oids.head != NULL)
998 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
999 tbinfo->dobj.catId.oid);
1000 else
1001 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
1004 * In any case, a table can be excluded by an exclusion switch
1006 if (tbinfo->dobj.dump &&
1007 simple_oid_list_member(&table_exclude_oids,
1008 tbinfo->dobj.catId.oid))
1009 tbinfo->dobj.dump = false;
1013 * selectDumpableType: policy-setting subroutine
1014 * Mark a type as to be dumped or not
1016 * If it's a table's rowtype or an autogenerated array type, we also apply a
1017 * special type code to facilitate sorting into the desired order. (We don't
1018 * want to consider those to be ordinary types because that would bring tables
1019 * up into the datatype part of the dump order.) Those tests should be made
1020 * first to ensure the objType change is applied regardless of namespace etc.
1022 static void
1023 selectDumpableType(TypeInfo *tinfo)
1025 /* skip complex types, except for standalone composite types */
1026 if (OidIsValid(tinfo->typrelid) &&
1027 tinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1029 tinfo->dobj.dump = false;
1030 tinfo->dobj.objType = DO_DUMMY_TYPE;
1033 /* skip auto-generated array types */
1034 else if (tinfo->isArray)
1036 tinfo->dobj.dump = false;
1037 tinfo->dobj.objType = DO_DUMMY_TYPE;
1040 /* dump only types in dumpable namespaces */
1041 else if (!tinfo->dobj.namespace->dobj.dump)
1042 tinfo->dobj.dump = false;
1044 /* skip undefined placeholder types */
1045 else if (!tinfo->isDefined)
1046 tinfo->dobj.dump = false;
1048 else
1049 tinfo->dobj.dump = true;
1053 * selectDumpableObject: policy-setting subroutine
1054 * Mark a generic dumpable object as to be dumped or not
1056 * Use this only for object types without a special-case routine above.
1058 static void
1059 selectDumpableObject(DumpableObject *dobj)
1062 * Default policy is to dump if parent namespace is dumpable, or always
1063 * for non-namespace-associated items.
1065 if (dobj->namespace)
1066 dobj->dump = dobj->namespace->dobj.dump;
1067 else
1068 dobj->dump = true;
1072 * Dump a table's contents for loading using the COPY command
1073 * - this routine is called by the Archiver when it wants the table
1074 * to be dumped.
1077 static int
1078 dumpTableData_copy(Archive *fout, void *dcontext)
1080 TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1081 TableInfo *tbinfo = tdinfo->tdtable;
1082 const char *classname = tbinfo->dobj.name;
1083 const bool hasoids = tbinfo->hasoids;
1084 const bool oids = tdinfo->oids;
1085 PQExpBuffer q = createPQExpBuffer();
1086 PGresult *res;
1087 int ret;
1088 char *copybuf;
1089 const char *column_list;
1091 if (g_verbose)
1092 write_msg(NULL, "dumping contents of table %s\n", classname);
1095 * Make sure we are in proper schema. We will qualify the table name
1096 * below anyway (in case its name conflicts with a pg_catalog table); but
1097 * this ensures reproducible results in case the table contains regproc,
1098 * regclass, etc columns.
1100 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
1103 * If possible, specify the column list explicitly so that we have no
1104 * possibility of retrieving data in the wrong column order. (The default
1105 * column ordering of COPY will not be what we want in certain corner
1106 * cases involving ADD COLUMN and inheritance.)
1108 if (g_fout->remoteVersion >= 70300)
1109 column_list = fmtCopyColumnList(tbinfo);
1110 else
1111 column_list = ""; /* can't select columns in COPY */
1113 if (oids && hasoids)
1115 appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
1116 fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1117 classname),
1118 column_list);
1120 else
1122 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1123 fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1124 classname),
1125 column_list);
1127 res = PQexec(g_conn, q->data);
1128 check_sql_result(res, g_conn, q->data, PGRES_COPY_OUT);
1129 PQclear(res);
1131 for (;;)
1133 ret = PQgetCopyData(g_conn, &copybuf, 0);
1135 if (ret < 0)
1136 break; /* done or error */
1138 if (copybuf)
1140 WriteData(fout, copybuf, ret);
1141 PQfreemem(copybuf);
1144 /* ----------
1145 * THROTTLE:
1147 * There was considerable discussion in late July, 2000 regarding
1148 * slowing down pg_dump when backing up large tables. Users with both
1149 * slow & fast (multi-processor) machines experienced performance
1150 * degradation when doing a backup.
1152 * Initial attempts based on sleeping for a number of ms for each ms
1153 * of work were deemed too complex, then a simple 'sleep in each loop'
1154 * implementation was suggested. The latter failed because the loop
1155 * was too tight. Finally, the following was implemented:
1157 * If throttle is non-zero, then
1158 * See how long since the last sleep.
1159 * Work out how long to sleep (based on ratio).
1160 * If sleep is more than 100ms, then
1161 * sleep
1162 * reset timer
1163 * EndIf
1164 * EndIf
1166 * where the throttle value was the number of ms to sleep per ms of
1167 * work. The calculation was done in each loop.
1169 * Most of the hard work is done in the backend, and this solution
1170 * still did not work particularly well: on slow machines, the ratio
1171 * was 50:1, and on medium paced machines, 1:1, and on fast
1172 * multi-processor machines, it had little or no effect, for reasons
1173 * that were unclear.
1175 * Further discussion ensued, and the proposal was dropped.
1177 * For those people who want this feature, it can be implemented using
1178 * gettimeofday in each loop, calculating the time since last sleep,
1179 * multiplying that by the sleep ratio, then if the result is more
1180 * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1181 * function to sleep for a subsecond period ie.
1183 * select(0, NULL, NULL, NULL, &tvi);
1185 * This will return after the interval specified in the structure tvi.
1186 * Finally, call gettimeofday again to save the 'last sleep time'.
1187 * ----------
1190 archprintf(fout, "\\.\n\n\n");
1192 if (ret == -2)
1194 /* copy data transfer failed */
1195 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
1196 write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
1197 write_msg(NULL, "The command was: %s\n", q->data);
1198 exit_nicely();
1201 /* Check command status and return to normal libpq state */
1202 res = PQgetResult(g_conn);
1203 check_sql_result(res, g_conn, q->data, PGRES_COMMAND_OK);
1204 PQclear(res);
1206 destroyPQExpBuffer(q);
1207 return 1;
1210 static int
1211 dumpTableData_insert(Archive *fout, void *dcontext)
1213 TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1214 TableInfo *tbinfo = tdinfo->tdtable;
1215 const char *classname = tbinfo->dobj.name;
1216 PQExpBuffer q = createPQExpBuffer();
1217 PGresult *res;
1218 int tuple;
1219 int nfields;
1220 int field;
1223 * Make sure we are in proper schema. We will qualify the table name
1224 * below anyway (in case its name conflicts with a pg_catalog table); but
1225 * this ensures reproducible results in case the table contains regproc,
1226 * regclass, etc columns.
1228 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
1230 if (fout->remoteVersion >= 70100)
1232 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1233 "SELECT * FROM ONLY %s",
1234 fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1235 classname));
1237 else
1239 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1240 "SELECT * FROM %s",
1241 fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1242 classname));
1245 res = PQexec(g_conn, q->data);
1246 check_sql_result(res, g_conn, q->data, PGRES_COMMAND_OK);
1250 PQclear(res);
1252 res = PQexec(g_conn, "FETCH 100 FROM _pg_dump_cursor");
1253 check_sql_result(res, g_conn, "FETCH 100 FROM _pg_dump_cursor",
1254 PGRES_TUPLES_OK);
1255 nfields = PQnfields(res);
1256 for (tuple = 0; tuple < PQntuples(res); tuple++)
1258 archprintf(fout, "INSERT INTO %s ", fmtId(classname));
1259 if (nfields == 0)
1261 /* corner case for zero-column table */
1262 archprintf(fout, "DEFAULT VALUES;\n");
1263 continue;
1265 if (attrNames == true)
1267 resetPQExpBuffer(q);
1268 appendPQExpBuffer(q, "(");
1269 for (field = 0; field < nfields; field++)
1271 if (field > 0)
1272 appendPQExpBuffer(q, ", ");
1273 appendPQExpBufferStr(q, fmtId(PQfname(res, field)));
1275 appendPQExpBuffer(q, ") ");
1276 archputs(q->data, fout);
1278 archprintf(fout, "VALUES (");
1279 for (field = 0; field < nfields; field++)
1281 if (field > 0)
1282 archprintf(fout, ", ");
1283 if (PQgetisnull(res, tuple, field))
1285 archprintf(fout, "NULL");
1286 continue;
1289 /* XXX This code is partially duplicated in ruleutils.c */
1290 switch (PQftype(res, field))
1292 case INT2OID:
1293 case INT4OID:
1294 case INT8OID:
1295 case OIDOID:
1296 case FLOAT4OID:
1297 case FLOAT8OID:
1298 case NUMERICOID:
1301 * These types are printed without quotes unless
1302 * they contain values that aren't accepted by the
1303 * scanner unquoted (e.g., 'NaN'). Note that
1304 * strtod() and friends might accept NaN, so we
1305 * can't use that to test.
1307 * In reality we only need to defend against
1308 * infinity and NaN, so we need not get too crazy
1309 * about pattern matching here.
1311 const char *s = PQgetvalue(res, tuple, field);
1313 if (strspn(s, "0123456789 +-eE.") == strlen(s))
1314 archprintf(fout, "%s", s);
1315 else
1316 archprintf(fout, "'%s'", s);
1318 break;
1320 case BITOID:
1321 case VARBITOID:
1322 archprintf(fout, "B'%s'",
1323 PQgetvalue(res, tuple, field));
1324 break;
1326 case BOOLOID:
1327 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
1328 archprintf(fout, "true");
1329 else
1330 archprintf(fout, "false");
1331 break;
1333 default:
1334 /* All other types are printed as string literals. */
1335 resetPQExpBuffer(q);
1336 appendStringLiteralAH(q,
1337 PQgetvalue(res, tuple, field),
1338 fout);
1339 archputs(q->data, fout);
1340 break;
1343 archprintf(fout, ");\n");
1345 } while (PQntuples(res) > 0);
1347 PQclear(res);
1349 archprintf(fout, "\n\n");
1351 do_sql_command(g_conn, "CLOSE _pg_dump_cursor");
1353 destroyPQExpBuffer(q);
1354 return 1;
1359 * dumpTableData -
1360 * dump the contents of a single table
1362 * Actually, this just makes an ArchiveEntry for the table contents.
1364 static void
1365 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
1367 TableInfo *tbinfo = tdinfo->tdtable;
1368 PQExpBuffer copyBuf = createPQExpBuffer();
1369 DataDumperPtr dumpFn;
1370 char *copyStmt;
1372 if (!dumpInserts)
1374 /* Dump/restore using COPY */
1375 dumpFn = dumpTableData_copy;
1376 /* must use 2 steps here 'cause fmtId is nonreentrant */
1377 appendPQExpBuffer(copyBuf, "COPY %s ",
1378 fmtId(tbinfo->dobj.name));
1379 appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
1380 fmtCopyColumnList(tbinfo),
1381 (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
1382 copyStmt = copyBuf->data;
1384 else
1386 /* Restore using INSERT */
1387 dumpFn = dumpTableData_insert;
1388 copyStmt = NULL;
1391 ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
1392 tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
1393 NULL, tbinfo->rolname,
1394 false, "TABLE DATA", SECTION_DATA,
1395 "", "", copyStmt,
1396 tdinfo->dobj.dependencies, tdinfo->dobj.nDeps,
1397 dumpFn, tdinfo);
1399 destroyPQExpBuffer(copyBuf);
1403 * getTableData -
1404 * set up dumpable objects representing the contents of tables
1406 static void
1407 getTableData(TableInfo *tblinfo, int numTables, bool oids)
1409 int i;
1411 for (i = 0; i < numTables; i++)
1413 /* Skip VIEWs (no data to dump) */
1414 if (tblinfo[i].relkind == RELKIND_VIEW)
1415 continue;
1416 /* Skip SEQUENCEs (handled elsewhere) */
1417 if (tblinfo[i].relkind == RELKIND_SEQUENCE)
1418 continue;
1420 if (tblinfo[i].dobj.dump)
1422 TableDataInfo *tdinfo;
1424 tdinfo = (TableDataInfo *) malloc(sizeof(TableDataInfo));
1426 tdinfo->dobj.objType = DO_TABLE_DATA;
1429 * Note: use tableoid 0 so that this object won't be mistaken for
1430 * something that pg_depend entries apply to.
1432 tdinfo->dobj.catId.tableoid = 0;
1433 tdinfo->dobj.catId.oid = tblinfo[i].dobj.catId.oid;
1434 AssignDumpId(&tdinfo->dobj);
1435 tdinfo->dobj.name = tblinfo[i].dobj.name;
1436 tdinfo->dobj.namespace = tblinfo[i].dobj.namespace;
1437 tdinfo->tdtable = &(tblinfo[i]);
1438 tdinfo->oids = oids;
1439 addObjectDependency(&tdinfo->dobj, tblinfo[i].dobj.dumpId);
1441 tblinfo[i].dataObj = tdinfo;
1447 * getTableDataFKConstraints -
1448 * add dump-order dependencies reflecting foreign key constraints
1450 * This code is executed only in a data-only dump --- in schema+data dumps
1451 * we handle foreign key issues by not creating the FK constraints until
1452 * after the data is loaded. In a data-only dump, however, we want to
1453 * order the table data objects in such a way that a table's referenced
1454 * tables are restored first. (In the presence of circular references or
1455 * self-references this may be impossible; we'll detect and complain about
1456 * that during the dependency sorting step.)
1458 static void
1459 getTableDataFKConstraints(void)
1461 DumpableObject **dobjs;
1462 int numObjs;
1463 int i;
1465 /* Search through all the dumpable objects for FK constraints */
1466 getDumpableObjects(&dobjs, &numObjs);
1467 for (i = 0; i < numObjs; i++)
1469 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
1471 ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
1472 TableInfo *ftable;
1474 /* Not interesting unless both tables are to be dumped */
1475 if (cinfo->contable == NULL ||
1476 cinfo->contable->dataObj == NULL)
1477 continue;
1478 ftable = findTableByOid(cinfo->confrelid);
1479 if (ftable == NULL ||
1480 ftable->dataObj == NULL)
1481 continue;
1483 * Okay, make referencing table's TABLE_DATA object depend on
1484 * the referenced table's TABLE_DATA object.
1486 addObjectDependency(&cinfo->contable->dataObj->dobj,
1487 ftable->dataObj->dobj.dumpId);
1490 free(dobjs);
1495 * guessConstraintInheritance:
1496 * In pre-8.4 databases, we can't tell for certain which constraints
1497 * are inherited. We assume a CHECK constraint is inherited if its name
1498 * matches the name of any constraint in the parent. Originally this code
1499 * tried to compare the expression texts, but that can fail for various
1500 * reasons --- for example, if the parent and child tables are in different
1501 * schemas, reverse-listing of function calls may produce different text
1502 * (schema-qualified or not) depending on search path.
1504 * In 8.4 and up we can rely on the conislocal field to decide which
1505 * constraints must be dumped; much safer.
1507 * This function assumes all conislocal flags were initialized to TRUE.
1508 * It clears the flag on anything that seems to be inherited.
1510 static void
1511 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
1513 int i,
1517 for (i = 0; i < numTables; i++)
1519 TableInfo *tbinfo = &(tblinfo[i]);
1520 int numParents;
1521 TableInfo **parents;
1522 TableInfo *parent;
1524 /* Sequences and views never have parents */
1525 if (tbinfo->relkind == RELKIND_SEQUENCE ||
1526 tbinfo->relkind == RELKIND_VIEW)
1527 continue;
1529 /* Don't bother computing anything for non-target tables, either */
1530 if (!tbinfo->dobj.dump)
1531 continue;
1533 numParents = tbinfo->numParents;
1534 parents = tbinfo->parents;
1536 if (numParents == 0)
1537 continue; /* nothing to see here, move along */
1539 /* scan for inherited CHECK constraints */
1540 for (j = 0; j < tbinfo->ncheck; j++)
1542 ConstraintInfo *constr;
1544 constr = &(tbinfo->checkexprs[j]);
1546 for (k = 0; k < numParents; k++)
1548 int l;
1550 parent = parents[k];
1551 for (l = 0; l < parent->ncheck; l++)
1553 ConstraintInfo *pconstr = &(parent->checkexprs[l]);
1555 if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
1557 constr->conislocal = false;
1558 break;
1561 if (!constr->conislocal)
1562 break;
1570 * dumpDatabase:
1571 * dump the database definition
1573 static void
1574 dumpDatabase(Archive *AH)
1576 PQExpBuffer dbQry = createPQExpBuffer();
1577 PQExpBuffer delQry = createPQExpBuffer();
1578 PQExpBuffer creaQry = createPQExpBuffer();
1579 PGresult *res;
1580 int ntups;
1581 int i_tableoid,
1582 i_oid,
1583 i_dba,
1584 i_encoding,
1585 i_collate,
1586 i_ctype,
1587 i_frozenxid,
1588 i_tablespace;
1589 CatalogId dbCatId;
1590 DumpId dbDumpId;
1591 const char *datname,
1592 *dba,
1593 *encoding,
1594 *collate,
1595 *ctype,
1596 *tablespace;
1597 uint32 frozenxid;
1599 datname = PQdb(g_conn);
1601 if (g_verbose)
1602 write_msg(NULL, "saving database definition\n");
1604 /* Make sure we are in proper schema */
1605 selectSourceSchema("pg_catalog");
1607 /* Get the database owner and parameters from pg_database */
1608 if (g_fout->remoteVersion >= 80400)
1610 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1611 "(%s datdba) AS dba, "
1612 "pg_encoding_to_char(encoding) AS encoding, "
1613 "datcollate, datctype, datfrozenxid, "
1614 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
1615 "shobj_description(oid, 'pg_database') AS description "
1617 "FROM pg_database "
1618 "WHERE datname = ",
1619 username_subquery);
1620 appendStringLiteralAH(dbQry, datname, AH);
1622 else if (g_fout->remoteVersion >= 80200)
1624 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1625 "(%s datdba) AS dba, "
1626 "pg_encoding_to_char(encoding) AS encoding, "
1627 "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
1628 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
1629 "shobj_description(oid, 'pg_database') AS description "
1631 "FROM pg_database "
1632 "WHERE datname = ",
1633 username_subquery);
1634 appendStringLiteralAH(dbQry, datname, AH);
1636 else if (g_fout->remoteVersion >= 80000)
1638 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1639 "(%s datdba) AS dba, "
1640 "pg_encoding_to_char(encoding) AS encoding, "
1641 "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
1642 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
1643 "FROM pg_database "
1644 "WHERE datname = ",
1645 username_subquery);
1646 appendStringLiteralAH(dbQry, datname, AH);
1648 else if (g_fout->remoteVersion >= 70100)
1650 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1651 "(%s datdba) AS dba, "
1652 "pg_encoding_to_char(encoding) AS encoding, "
1653 "NULL AS datcollate, NULL AS datctype, "
1654 "0 AS datfrozenxid, "
1655 "NULL AS tablespace "
1656 "FROM pg_database "
1657 "WHERE datname = ",
1658 username_subquery);
1659 appendStringLiteralAH(dbQry, datname, AH);
1661 else
1663 appendPQExpBuffer(dbQry, "SELECT "
1664 "(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, "
1665 "oid, "
1666 "(%s datdba) AS dba, "
1667 "pg_encoding_to_char(encoding) AS encoding, "
1668 "NULL AS datcollate, NULL AS datctype, "
1669 "0 AS datfrozenxid, "
1670 "NULL AS tablespace "
1671 "FROM pg_database "
1672 "WHERE datname = ",
1673 username_subquery);
1674 appendStringLiteralAH(dbQry, datname, AH);
1677 res = PQexec(g_conn, dbQry->data);
1678 check_sql_result(res, g_conn, dbQry->data, PGRES_TUPLES_OK);
1680 ntups = PQntuples(res);
1682 if (ntups <= 0)
1684 write_msg(NULL, "missing pg_database entry for database \"%s\"\n",
1685 datname);
1686 exit_nicely();
1689 if (ntups != 1)
1691 write_msg(NULL, "query returned more than one (%d) pg_database entry for database \"%s\"\n",
1692 ntups, datname);
1693 exit_nicely();
1696 i_tableoid = PQfnumber(res, "tableoid");
1697 i_oid = PQfnumber(res, "oid");
1698 i_dba = PQfnumber(res, "dba");
1699 i_encoding = PQfnumber(res, "encoding");
1700 i_collate = PQfnumber(res, "datcollate");
1701 i_ctype = PQfnumber(res, "datctype");
1702 i_frozenxid = PQfnumber(res, "datfrozenxid");
1703 i_tablespace = PQfnumber(res, "tablespace");
1705 dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
1706 dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
1707 dba = PQgetvalue(res, 0, i_dba);
1708 encoding = PQgetvalue(res, 0, i_encoding);
1709 collate = PQgetvalue(res, 0, i_collate);
1710 ctype = PQgetvalue(res, 0, i_ctype);
1711 frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
1712 tablespace = PQgetvalue(res, 0, i_tablespace);
1714 appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
1715 fmtId(datname));
1716 if (strlen(encoding) > 0)
1718 appendPQExpBuffer(creaQry, " ENCODING = ");
1719 appendStringLiteralAH(creaQry, encoding, AH);
1721 if (strlen(collate) > 0)
1723 appendPQExpBuffer(creaQry, " COLLATE = ");
1724 appendStringLiteralAH(creaQry, collate, AH);
1726 if (strlen(ctype) > 0)
1728 appendPQExpBuffer(creaQry, " CTYPE = ");
1729 appendStringLiteralAH(creaQry, ctype, AH);
1731 if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0)
1732 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
1733 fmtId(tablespace));
1734 appendPQExpBuffer(creaQry, ";\n");
1736 if (binary_upgrade)
1738 appendPQExpBuffer(creaQry, "\n-- For binary upgrade, set datfrozenxid.\n");
1739 appendPQExpBuffer(creaQry, "UPDATE pg_database\n"
1740 "SET datfrozenxid = '%u'\n"
1741 "WHERE datname = '%s';\n",
1742 frozenxid, datname);
1745 appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
1746 fmtId(datname));
1748 dbDumpId = createDumpId();
1750 ArchiveEntry(AH,
1751 dbCatId, /* catalog ID */
1752 dbDumpId, /* dump ID */
1753 datname, /* Name */
1754 NULL, /* Namespace */
1755 NULL, /* Tablespace */
1756 dba, /* Owner */
1757 false, /* with oids */
1758 "DATABASE", /* Desc */
1759 SECTION_PRE_DATA, /* Section */
1760 creaQry->data, /* Create */
1761 delQry->data, /* Del */
1762 NULL, /* Copy */
1763 NULL, /* Deps */
1764 0, /* # Deps */
1765 NULL, /* Dumper */
1766 NULL); /* Dumper Arg */
1768 /* Dump DB comment if any */
1769 if (g_fout->remoteVersion >= 80200)
1772 * 8.2 keeps comments on shared objects in a shared table, so we
1773 * cannot use the dumpComment used for other database objects.
1775 char *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
1777 if (comment && strlen(comment))
1779 resetPQExpBuffer(dbQry);
1780 /* Generates warning when loaded into a differently-named database.*/
1781 appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
1782 appendStringLiteralAH(dbQry, comment, AH);
1783 appendPQExpBuffer(dbQry, ";\n");
1785 ArchiveEntry(AH, dbCatId, createDumpId(), datname, NULL, NULL,
1786 dba, false, "COMMENT", SECTION_NONE,
1787 dbQry->data, "", NULL,
1788 &dbDumpId, 1, NULL, NULL);
1791 else
1793 resetPQExpBuffer(dbQry);
1794 appendPQExpBuffer(dbQry, "DATABASE %s", fmtId(datname));
1795 dumpComment(AH, dbQry->data, NULL, "",
1796 dbCatId, 0, dbDumpId);
1799 PQclear(res);
1801 destroyPQExpBuffer(dbQry);
1802 destroyPQExpBuffer(delQry);
1803 destroyPQExpBuffer(creaQry);
1808 * dumpEncoding: put the correct encoding into the archive
1810 static void
1811 dumpEncoding(Archive *AH)
1813 const char *encname = pg_encoding_to_char(AH->encoding);
1814 PQExpBuffer qry = createPQExpBuffer();
1816 if (g_verbose)
1817 write_msg(NULL, "saving encoding = %s\n", encname);
1819 appendPQExpBuffer(qry, "SET client_encoding = ");
1820 appendStringLiteralAH(qry, encname, AH);
1821 appendPQExpBuffer(qry, ";\n");
1823 ArchiveEntry(AH, nilCatalogId, createDumpId(),
1824 "ENCODING", NULL, NULL, "",
1825 false, "ENCODING", SECTION_PRE_DATA,
1826 qry->data, "", NULL,
1827 NULL, 0,
1828 NULL, NULL);
1830 destroyPQExpBuffer(qry);
1835 * dumpStdStrings: put the correct escape string behavior into the archive
1837 static void
1838 dumpStdStrings(Archive *AH)
1840 const char *stdstrings = AH->std_strings ? "on" : "off";
1841 PQExpBuffer qry = createPQExpBuffer();
1843 if (g_verbose)
1844 write_msg(NULL, "saving standard_conforming_strings = %s\n",
1845 stdstrings);
1847 appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
1848 stdstrings);
1850 ArchiveEntry(AH, nilCatalogId, createDumpId(),
1851 "STDSTRINGS", NULL, NULL, "",
1852 false, "STDSTRINGS", SECTION_PRE_DATA,
1853 qry->data, "", NULL,
1854 NULL, 0,
1855 NULL, NULL);
1857 destroyPQExpBuffer(qry);
1862 * hasBlobs:
1863 * Test whether database contains any large objects
1865 static bool
1866 hasBlobs(Archive *AH)
1868 bool result;
1869 const char *blobQry;
1870 PGresult *res;
1872 /* Make sure we are in proper schema */
1873 selectSourceSchema("pg_catalog");
1875 /* Check for BLOB OIDs */
1876 if (AH->remoteVersion >= 70100)
1877 blobQry = "SELECT loid FROM pg_largeobject LIMIT 1";
1878 else
1879 blobQry = "SELECT oid FROM pg_class WHERE relkind = 'l' LIMIT 1";
1881 res = PQexec(g_conn, blobQry);
1882 check_sql_result(res, g_conn, blobQry, PGRES_TUPLES_OK);
1884 result = PQntuples(res) > 0;
1886 PQclear(res);
1888 return result;
1892 * dumpBlobs:
1893 * dump all blobs
1895 static int
1896 dumpBlobs(Archive *AH, void *arg)
1898 const char *blobQry;
1899 const char *blobFetchQry;
1900 PGresult *res;
1901 char buf[LOBBUFSIZE];
1902 int i;
1903 int cnt;
1905 if (g_verbose)
1906 write_msg(NULL, "saving large objects\n");
1908 /* Make sure we are in proper schema */
1909 selectSourceSchema("pg_catalog");
1911 /* Cursor to get all BLOB OIDs */
1912 if (AH->remoteVersion >= 70100)
1913 blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
1914 else
1915 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'";
1917 res = PQexec(g_conn, blobQry);
1918 check_sql_result(res, g_conn, blobQry, PGRES_COMMAND_OK);
1920 /* Command to fetch from cursor */
1921 blobFetchQry = "FETCH 1000 IN bloboid";
1925 PQclear(res);
1927 /* Do a fetch */
1928 res = PQexec(g_conn, blobFetchQry);
1929 check_sql_result(res, g_conn, blobFetchQry, PGRES_TUPLES_OK);
1931 /* Process the tuples, if any */
1932 for (i = 0; i < PQntuples(res); i++)
1934 Oid blobOid;
1935 int loFd;
1937 blobOid = atooid(PQgetvalue(res, i, 0));
1938 /* Open the BLOB */
1939 loFd = lo_open(g_conn, blobOid, INV_READ);
1940 if (loFd == -1)
1942 write_msg(NULL, "dumpBlobs(): could not open large object: %s",
1943 PQerrorMessage(g_conn));
1944 exit_nicely();
1947 StartBlob(AH, blobOid);
1949 /* Now read it in chunks, sending data to archive */
1952 cnt = lo_read(g_conn, loFd, buf, LOBBUFSIZE);
1953 if (cnt < 0)
1955 write_msg(NULL, "dumpBlobs(): error reading large object: %s",
1956 PQerrorMessage(g_conn));
1957 exit_nicely();
1960 WriteData(AH, buf, cnt);
1961 } while (cnt > 0);
1963 lo_close(g_conn, loFd);
1965 EndBlob(AH, blobOid);
1967 } while (PQntuples(res) > 0);
1969 PQclear(res);
1971 return 1;
1975 * dumpBlobComments
1976 * dump all blob comments
1978 * Since we don't provide any way to be selective about dumping blobs,
1979 * there's no need to be selective about their comments either. We put
1980 * all the comments into one big TOC entry.
1982 static int
1983 dumpBlobComments(Archive *AH, void *arg)
1985 const char *blobQry;
1986 const char *blobFetchQry;
1987 PQExpBuffer commentcmd = createPQExpBuffer();
1988 PGresult *res;
1989 int i;
1991 if (g_verbose)
1992 write_msg(NULL, "saving large object comments\n");
1994 /* Make sure we are in proper schema */
1995 selectSourceSchema("pg_catalog");
1997 /* Cursor to get all BLOB comments */
1998 if (AH->remoteVersion >= 70200)
1999 blobQry = "DECLARE blobcmt CURSOR FOR SELECT loid, "
2000 "obj_description(loid, 'pg_largeobject') "
2001 "FROM (SELECT DISTINCT loid FROM pg_largeobject) ss";
2002 else if (AH->remoteVersion >= 70100)
2003 blobQry = "DECLARE blobcmt CURSOR FOR SELECT loid, "
2004 "obj_description(loid) "
2005 "FROM (SELECT DISTINCT loid FROM pg_largeobject) ss";
2006 else
2007 blobQry = "DECLARE blobcmt CURSOR FOR SELECT oid, "
2008 " ( "
2009 " SELECT description "
2010 " FROM pg_description pd "
2011 " WHERE pd.objoid=pc.oid "
2012 " ) "
2013 "FROM pg_class pc WHERE relkind = 'l'";
2015 res = PQexec(g_conn, blobQry);
2016 check_sql_result(res, g_conn, blobQry, PGRES_COMMAND_OK);
2018 /* Command to fetch from cursor */
2019 blobFetchQry = "FETCH 100 IN blobcmt";
2023 PQclear(res);
2025 /* Do a fetch */
2026 res = PQexec(g_conn, blobFetchQry);
2027 check_sql_result(res, g_conn, blobFetchQry, PGRES_TUPLES_OK);
2029 /* Process the tuples, if any */
2030 for (i = 0; i < PQntuples(res); i++)
2032 Oid blobOid;
2033 char *comment;
2035 /* ignore blobs without comments */
2036 if (PQgetisnull(res, i, 1))
2037 continue;
2039 blobOid = atooid(PQgetvalue(res, i, 0));
2040 comment = PQgetvalue(res, i, 1);
2042 printfPQExpBuffer(commentcmd, "COMMENT ON LARGE OBJECT %u IS ",
2043 blobOid);
2044 appendStringLiteralAH(commentcmd, comment, AH);
2045 appendPQExpBuffer(commentcmd, ";\n");
2047 archputs(commentcmd->data, AH);
2049 } while (PQntuples(res) > 0);
2051 PQclear(res);
2053 archputs("\n", AH);
2055 destroyPQExpBuffer(commentcmd);
2057 return 1;
2061 * getNamespaces:
2062 * read all namespaces in the system catalogs and return them in the
2063 * NamespaceInfo* structure
2065 * numNamespaces is set to the number of namespaces read in
2067 NamespaceInfo *
2068 getNamespaces(int *numNamespaces)
2070 PGresult *res;
2071 int ntups;
2072 int i;
2073 PQExpBuffer query;
2074 NamespaceInfo *nsinfo;
2075 int i_tableoid;
2076 int i_oid;
2077 int i_nspname;
2078 int i_rolname;
2079 int i_nspacl;
2082 * Before 7.3, there are no real namespaces; create two dummy entries, one
2083 * for user stuff and one for system stuff.
2085 if (g_fout->remoteVersion < 70300)
2087 nsinfo = (NamespaceInfo *) malloc(2 * sizeof(NamespaceInfo));
2089 nsinfo[0].dobj.objType = DO_NAMESPACE;
2090 nsinfo[0].dobj.catId.tableoid = 0;
2091 nsinfo[0].dobj.catId.oid = 0;
2092 AssignDumpId(&nsinfo[0].dobj);
2093 nsinfo[0].dobj.name = strdup("public");
2094 nsinfo[0].rolname = strdup("");
2095 nsinfo[0].nspacl = strdup("");
2097 selectDumpableNamespace(&nsinfo[0]);
2099 nsinfo[1].dobj.objType = DO_NAMESPACE;
2100 nsinfo[1].dobj.catId.tableoid = 0;
2101 nsinfo[1].dobj.catId.oid = 1;
2102 AssignDumpId(&nsinfo[1].dobj);
2103 nsinfo[1].dobj.name = strdup("pg_catalog");
2104 nsinfo[1].rolname = strdup("");
2105 nsinfo[1].nspacl = strdup("");
2107 selectDumpableNamespace(&nsinfo[1]);
2109 g_namespaces = nsinfo;
2110 g_numNamespaces = *numNamespaces = 2;
2112 return nsinfo;
2115 query = createPQExpBuffer();
2117 /* Make sure we are in proper schema */
2118 selectSourceSchema("pg_catalog");
2121 * we fetch all namespaces including system ones, so that every object we
2122 * read in can be linked to a containing namespace.
2124 appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
2125 "(%s nspowner) AS rolname, "
2126 "nspacl FROM pg_namespace",
2127 username_subquery);
2129 res = PQexec(g_conn, query->data);
2130 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2132 ntups = PQntuples(res);
2134 nsinfo = (NamespaceInfo *) malloc(ntups * sizeof(NamespaceInfo));
2136 i_tableoid = PQfnumber(res, "tableoid");
2137 i_oid = PQfnumber(res, "oid");
2138 i_nspname = PQfnumber(res, "nspname");
2139 i_rolname = PQfnumber(res, "rolname");
2140 i_nspacl = PQfnumber(res, "nspacl");
2142 for (i = 0; i < ntups; i++)
2144 nsinfo[i].dobj.objType = DO_NAMESPACE;
2145 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2146 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2147 AssignDumpId(&nsinfo[i].dobj);
2148 nsinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_nspname));
2149 nsinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2150 nsinfo[i].nspacl = strdup(PQgetvalue(res, i, i_nspacl));
2152 /* Decide whether to dump this namespace */
2153 selectDumpableNamespace(&nsinfo[i]);
2155 if (strlen(nsinfo[i].rolname) == 0)
2156 write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
2157 nsinfo[i].dobj.name);
2160 PQclear(res);
2161 destroyPQExpBuffer(query);
2163 g_namespaces = nsinfo;
2164 g_numNamespaces = *numNamespaces = ntups;
2166 return nsinfo;
2170 * findNamespace:
2171 * given a namespace OID and an object OID, look up the info read by
2172 * getNamespaces
2174 * NB: for pre-7.3 source database, we use object OID to guess whether it's
2175 * a system object or not. In 7.3 and later there is no guessing.
2177 static NamespaceInfo *
2178 findNamespace(Oid nsoid, Oid objoid)
2180 int i;
2182 if (g_fout->remoteVersion >= 70300)
2184 for (i = 0; i < g_numNamespaces; i++)
2186 NamespaceInfo *nsinfo = &g_namespaces[i];
2188 if (nsoid == nsinfo->dobj.catId.oid)
2189 return nsinfo;
2191 write_msg(NULL, "schema with OID %u does not exist\n", nsoid);
2192 exit_nicely();
2194 else
2196 /* This code depends on the layout set up by getNamespaces. */
2197 if (objoid > g_last_builtin_oid)
2198 i = 0; /* user object */
2199 else
2200 i = 1; /* system object */
2201 return &g_namespaces[i];
2204 return NULL; /* keep compiler quiet */
2208 * getTypes:
2209 * read all types in the system catalogs and return them in the
2210 * TypeInfo* structure
2212 * numTypes is set to the number of types read in
2214 * NB: this must run after getFuncs() because we assume we can do
2215 * findFuncByOid().
2217 TypeInfo *
2218 getTypes(int *numTypes)
2220 PGresult *res;
2221 int ntups;
2222 int i;
2223 PQExpBuffer query = createPQExpBuffer();
2224 TypeInfo *tinfo;
2225 ShellTypeInfo *stinfo;
2226 int i_tableoid;
2227 int i_oid;
2228 int i_typname;
2229 int i_typnamespace;
2230 int i_rolname;
2231 int i_typinput;
2232 int i_typoutput;
2233 int i_typelem;
2234 int i_typrelid;
2235 int i_typrelkind;
2236 int i_typtype;
2237 int i_typisdefined;
2238 int i_isarray;
2241 * we include even the built-in types because those may be used as array
2242 * elements by user-defined types
2244 * we filter out the built-in types when we dump out the types
2246 * same approach for undefined (shell) types and array types
2248 * Note: as of 8.3 we can reliably detect whether a type is an
2249 * auto-generated array type by checking the element type's typarray.
2250 * (Before that the test is capable of generating false positives.) We
2251 * still check for name beginning with '_', though, so as to avoid the
2252 * cost of the subselect probe for all standard types. This would have to
2253 * be revisited if the backend ever allows renaming of array types.
2256 /* Make sure we are in proper schema */
2257 selectSourceSchema("pg_catalog");
2259 if (g_fout->remoteVersion >= 80300)
2261 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2262 "typnamespace, "
2263 "(%s typowner) AS rolname, "
2264 "typinput::oid AS typinput, "
2265 "typoutput::oid AS typoutput, typelem, typrelid, "
2266 "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2267 "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2268 "typtype, typisdefined, "
2269 "typname[0] = '_' AND typelem != 0 AND "
2270 "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
2271 "FROM pg_type",
2272 username_subquery);
2274 else if (g_fout->remoteVersion >= 70300)
2276 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2277 "typnamespace, "
2278 "(%s typowner) AS rolname, "
2279 "typinput::oid AS typinput, "
2280 "typoutput::oid AS typoutput, typelem, typrelid, "
2281 "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2282 "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2283 "typtype, typisdefined, "
2284 "typname[0] = '_' AND typelem != 0 AS isarray "
2285 "FROM pg_type",
2286 username_subquery);
2288 else if (g_fout->remoteVersion >= 70100)
2290 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2291 "0::oid AS typnamespace, "
2292 "(%s typowner) AS rolname, "
2293 "typinput::oid AS typinput, "
2294 "typoutput::oid AS typoutput, typelem, typrelid, "
2295 "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2296 "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2297 "typtype, typisdefined, "
2298 "typname[0] = '_' AND typelem != 0 AS isarray "
2299 "FROM pg_type",
2300 username_subquery);
2302 else
2304 appendPQExpBuffer(query, "SELECT "
2305 "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
2306 "oid, typname, "
2307 "0::oid AS typnamespace, "
2308 "(%s typowner) AS rolname, "
2309 "typinput::oid AS typinput, "
2310 "typoutput::oid AS typoutput, typelem, typrelid, "
2311 "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2312 "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2313 "typtype, typisdefined, "
2314 "typname[0] = '_' AND typelem != 0 AS isarray "
2315 "FROM pg_type",
2316 username_subquery);
2319 res = PQexec(g_conn, query->data);
2320 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2322 ntups = PQntuples(res);
2324 tinfo = (TypeInfo *) malloc(ntups * sizeof(TypeInfo));
2326 i_tableoid = PQfnumber(res, "tableoid");
2327 i_oid = PQfnumber(res, "oid");
2328 i_typname = PQfnumber(res, "typname");
2329 i_typnamespace = PQfnumber(res, "typnamespace");
2330 i_rolname = PQfnumber(res, "rolname");
2331 i_typinput = PQfnumber(res, "typinput");
2332 i_typoutput = PQfnumber(res, "typoutput");
2333 i_typelem = PQfnumber(res, "typelem");
2334 i_typrelid = PQfnumber(res, "typrelid");
2335 i_typrelkind = PQfnumber(res, "typrelkind");
2336 i_typtype = PQfnumber(res, "typtype");
2337 i_typisdefined = PQfnumber(res, "typisdefined");
2338 i_isarray = PQfnumber(res, "isarray");
2340 for (i = 0; i < ntups; i++)
2342 tinfo[i].dobj.objType = DO_TYPE;
2343 tinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2344 tinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2345 AssignDumpId(&tinfo[i].dobj);
2346 tinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_typname));
2347 tinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)),
2348 tinfo[i].dobj.catId.oid);
2349 tinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2350 tinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
2351 tinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
2352 tinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
2353 tinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
2354 tinfo[i].shellType = NULL;
2356 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
2357 tinfo[i].isDefined = true;
2358 else
2359 tinfo[i].isDefined = false;
2361 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
2362 tinfo[i].isArray = true;
2363 else
2364 tinfo[i].isArray = false;
2366 /* Decide whether we want to dump it */
2367 selectDumpableType(&tinfo[i]);
2370 * If it's a domain, fetch info about its constraints, if any
2372 tinfo[i].nDomChecks = 0;
2373 tinfo[i].domChecks = NULL;
2374 if (tinfo[i].dobj.dump && tinfo[i].typtype == TYPTYPE_DOMAIN)
2375 getDomainConstraints(&(tinfo[i]));
2378 * If it's a base type, make a DumpableObject representing a shell
2379 * definition of the type. We will need to dump that ahead of the I/O
2380 * functions for the type.
2382 * Note: the shell type doesn't have a catId. You might think it
2383 * should copy the base type's catId, but then it might capture the
2384 * pg_depend entries for the type, which we don't want.
2386 if (tinfo[i].dobj.dump && tinfo[i].typtype == TYPTYPE_BASE)
2388 stinfo = (ShellTypeInfo *) malloc(sizeof(ShellTypeInfo));
2389 stinfo->dobj.objType = DO_SHELL_TYPE;
2390 stinfo->dobj.catId = nilCatalogId;
2391 AssignDumpId(&stinfo->dobj);
2392 stinfo->dobj.name = strdup(tinfo[i].dobj.name);
2393 stinfo->dobj.namespace = tinfo[i].dobj.namespace;
2394 stinfo->baseType = &(tinfo[i]);
2395 tinfo[i].shellType = stinfo;
2398 * Initially mark the shell type as not to be dumped. We'll only
2399 * dump it if the I/O functions need to be dumped; this is taken
2400 * care of while sorting dependencies.
2402 stinfo->dobj.dump = false;
2405 * However, if dumping from pre-7.3, there will be no dependency
2406 * info so we have to fake it here. We only need to worry about
2407 * typinput and typoutput since the other functions only exist
2408 * post-7.3.
2410 if (g_fout->remoteVersion < 70300)
2412 Oid typinput;
2413 Oid typoutput;
2414 FuncInfo *funcInfo;
2416 typinput = atooid(PQgetvalue(res, i, i_typinput));
2417 typoutput = atooid(PQgetvalue(res, i, i_typoutput));
2419 funcInfo = findFuncByOid(typinput);
2420 if (funcInfo && funcInfo->dobj.dump)
2422 /* base type depends on function */
2423 addObjectDependency(&tinfo[i].dobj,
2424 funcInfo->dobj.dumpId);
2425 /* function depends on shell type */
2426 addObjectDependency(&funcInfo->dobj,
2427 stinfo->dobj.dumpId);
2428 /* mark shell type as to be dumped */
2429 stinfo->dobj.dump = true;
2432 funcInfo = findFuncByOid(typoutput);
2433 if (funcInfo && funcInfo->dobj.dump)
2435 /* base type depends on function */
2436 addObjectDependency(&tinfo[i].dobj,
2437 funcInfo->dobj.dumpId);
2438 /* function depends on shell type */
2439 addObjectDependency(&funcInfo->dobj,
2440 stinfo->dobj.dumpId);
2441 /* mark shell type as to be dumped */
2442 stinfo->dobj.dump = true;
2447 if (strlen(tinfo[i].rolname) == 0 && tinfo[i].isDefined)
2448 write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
2449 tinfo[i].dobj.name);
2452 *numTypes = ntups;
2454 PQclear(res);
2456 destroyPQExpBuffer(query);
2458 return tinfo;
2462 * getOperators:
2463 * read all operators in the system catalogs and return them in the
2464 * OprInfo* structure
2466 * numOprs is set to the number of operators read in
2468 OprInfo *
2469 getOperators(int *numOprs)
2471 PGresult *res;
2472 int ntups;
2473 int i;
2474 PQExpBuffer query = createPQExpBuffer();
2475 OprInfo *oprinfo;
2476 int i_tableoid;
2477 int i_oid;
2478 int i_oprname;
2479 int i_oprnamespace;
2480 int i_rolname;
2481 int i_oprcode;
2484 * find all operators, including builtin operators; we filter out
2485 * system-defined operators at dump-out time.
2488 /* Make sure we are in proper schema */
2489 selectSourceSchema("pg_catalog");
2491 if (g_fout->remoteVersion >= 70300)
2493 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
2494 "oprnamespace, "
2495 "(%s oprowner) AS rolname, "
2496 "oprcode::oid AS oprcode "
2497 "FROM pg_operator",
2498 username_subquery);
2500 else if (g_fout->remoteVersion >= 70100)
2502 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
2503 "0::oid AS oprnamespace, "
2504 "(%s oprowner) AS rolname, "
2505 "oprcode::oid AS oprcode "
2506 "FROM pg_operator",
2507 username_subquery);
2509 else
2511 appendPQExpBuffer(query, "SELECT "
2512 "(SELECT oid FROM pg_class WHERE relname = 'pg_operator') AS tableoid, "
2513 "oid, oprname, "
2514 "0::oid AS oprnamespace, "
2515 "(%s oprowner) AS rolname, "
2516 "oprcode::oid AS oprcode "
2517 "FROM pg_operator",
2518 username_subquery);
2521 res = PQexec(g_conn, query->data);
2522 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2524 ntups = PQntuples(res);
2525 *numOprs = ntups;
2527 oprinfo = (OprInfo *) malloc(ntups * sizeof(OprInfo));
2529 i_tableoid = PQfnumber(res, "tableoid");
2530 i_oid = PQfnumber(res, "oid");
2531 i_oprname = PQfnumber(res, "oprname");
2532 i_oprnamespace = PQfnumber(res, "oprnamespace");
2533 i_rolname = PQfnumber(res, "rolname");
2534 i_oprcode = PQfnumber(res, "oprcode");
2536 for (i = 0; i < ntups; i++)
2538 oprinfo[i].dobj.objType = DO_OPERATOR;
2539 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2540 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2541 AssignDumpId(&oprinfo[i].dobj);
2542 oprinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_oprname));
2543 oprinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)),
2544 oprinfo[i].dobj.catId.oid);
2545 oprinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2546 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
2548 /* Decide whether we want to dump it */
2549 selectDumpableObject(&(oprinfo[i].dobj));
2551 if (strlen(oprinfo[i].rolname) == 0)
2552 write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
2553 oprinfo[i].dobj.name);
2556 PQclear(res);
2558 destroyPQExpBuffer(query);
2560 return oprinfo;
2564 * getConversions:
2565 * read all conversions in the system catalogs and return them in the
2566 * ConvInfo* structure
2568 * numConversions is set to the number of conversions read in
2570 ConvInfo *
2571 getConversions(int *numConversions)
2573 PGresult *res;
2574 int ntups;
2575 int i;
2576 PQExpBuffer query = createPQExpBuffer();
2577 ConvInfo *convinfo;
2578 int i_tableoid;
2579 int i_oid;
2580 int i_conname;
2581 int i_connamespace;
2582 int i_rolname;
2584 /* Conversions didn't exist pre-7.3 */
2585 if (g_fout->remoteVersion < 70300)
2587 *numConversions = 0;
2588 return NULL;
2592 * find all conversions, including builtin conversions; we filter out
2593 * system-defined conversions at dump-out time.
2596 /* Make sure we are in proper schema */
2597 selectSourceSchema("pg_catalog");
2599 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
2600 "connamespace, "
2601 "(%s conowner) AS rolname "
2602 "FROM pg_conversion",
2603 username_subquery);
2605 res = PQexec(g_conn, query->data);
2606 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2608 ntups = PQntuples(res);
2609 *numConversions = ntups;
2611 convinfo = (ConvInfo *) malloc(ntups * sizeof(ConvInfo));
2613 i_tableoid = PQfnumber(res, "tableoid");
2614 i_oid = PQfnumber(res, "oid");
2615 i_conname = PQfnumber(res, "conname");
2616 i_connamespace = PQfnumber(res, "connamespace");
2617 i_rolname = PQfnumber(res, "rolname");
2619 for (i = 0; i < ntups; i++)
2621 convinfo[i].dobj.objType = DO_CONVERSION;
2622 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2623 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2624 AssignDumpId(&convinfo[i].dobj);
2625 convinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_conname));
2626 convinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_connamespace)),
2627 convinfo[i].dobj.catId.oid);
2628 convinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2630 /* Decide whether we want to dump it */
2631 selectDumpableObject(&(convinfo[i].dobj));
2634 PQclear(res);
2636 destroyPQExpBuffer(query);
2638 return convinfo;
2642 * getOpclasses:
2643 * read all opclasses in the system catalogs and return them in the
2644 * OpclassInfo* structure
2646 * numOpclasses is set to the number of opclasses read in
2648 OpclassInfo *
2649 getOpclasses(int *numOpclasses)
2651 PGresult *res;
2652 int ntups;
2653 int i;
2654 PQExpBuffer query = createPQExpBuffer();
2655 OpclassInfo *opcinfo;
2656 int i_tableoid;
2657 int i_oid;
2658 int i_opcname;
2659 int i_opcnamespace;
2660 int i_rolname;
2663 * find all opclasses, including builtin opclasses; we filter out
2664 * system-defined opclasses at dump-out time.
2667 /* Make sure we are in proper schema */
2668 selectSourceSchema("pg_catalog");
2670 if (g_fout->remoteVersion >= 70300)
2672 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
2673 "opcnamespace, "
2674 "(%s opcowner) AS rolname "
2675 "FROM pg_opclass",
2676 username_subquery);
2678 else if (g_fout->remoteVersion >= 70100)
2680 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
2681 "0::oid AS opcnamespace, "
2682 "''::name AS rolname "
2683 "FROM pg_opclass");
2685 else
2687 appendPQExpBuffer(query, "SELECT "
2688 "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, "
2689 "oid, opcname, "
2690 "0::oid AS opcnamespace, "
2691 "''::name AS rolname "
2692 "FROM pg_opclass");
2695 res = PQexec(g_conn, query->data);
2696 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2698 ntups = PQntuples(res);
2699 *numOpclasses = ntups;
2701 opcinfo = (OpclassInfo *) malloc(ntups * sizeof(OpclassInfo));
2703 i_tableoid = PQfnumber(res, "tableoid");
2704 i_oid = PQfnumber(res, "oid");
2705 i_opcname = PQfnumber(res, "opcname");
2706 i_opcnamespace = PQfnumber(res, "opcnamespace");
2707 i_rolname = PQfnumber(res, "rolname");
2709 for (i = 0; i < ntups; i++)
2711 opcinfo[i].dobj.objType = DO_OPCLASS;
2712 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2713 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2714 AssignDumpId(&opcinfo[i].dobj);
2715 opcinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_opcname));
2716 opcinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)),
2717 opcinfo[i].dobj.catId.oid);
2718 opcinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2720 /* Decide whether we want to dump it */
2721 selectDumpableObject(&(opcinfo[i].dobj));
2723 if (g_fout->remoteVersion >= 70300)
2725 if (strlen(opcinfo[i].rolname) == 0)
2726 write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
2727 opcinfo[i].dobj.name);
2731 PQclear(res);
2733 destroyPQExpBuffer(query);
2735 return opcinfo;
2739 * getOpfamilies:
2740 * read all opfamilies in the system catalogs and return them in the
2741 * OpfamilyInfo* structure
2743 * numOpfamilies is set to the number of opfamilies read in
2745 OpfamilyInfo *
2746 getOpfamilies(int *numOpfamilies)
2748 PGresult *res;
2749 int ntups;
2750 int i;
2751 PQExpBuffer query;
2752 OpfamilyInfo *opfinfo;
2753 int i_tableoid;
2754 int i_oid;
2755 int i_opfname;
2756 int i_opfnamespace;
2757 int i_rolname;
2759 /* Before 8.3, there is no separate concept of opfamilies */
2760 if (g_fout->remoteVersion < 80300)
2762 *numOpfamilies = 0;
2763 return NULL;
2766 query = createPQExpBuffer();
2769 * find all opfamilies, including builtin opfamilies; we filter out
2770 * system-defined opfamilies at dump-out time.
2773 /* Make sure we are in proper schema */
2774 selectSourceSchema("pg_catalog");
2776 appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
2777 "opfnamespace, "
2778 "(%s opfowner) AS rolname "
2779 "FROM pg_opfamily",
2780 username_subquery);
2782 res = PQexec(g_conn, query->data);
2783 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2785 ntups = PQntuples(res);
2786 *numOpfamilies = ntups;
2788 opfinfo = (OpfamilyInfo *) malloc(ntups * sizeof(OpfamilyInfo));
2790 i_tableoid = PQfnumber(res, "tableoid");
2791 i_oid = PQfnumber(res, "oid");
2792 i_opfname = PQfnumber(res, "opfname");
2793 i_opfnamespace = PQfnumber(res, "opfnamespace");
2794 i_rolname = PQfnumber(res, "rolname");
2796 for (i = 0; i < ntups; i++)
2798 opfinfo[i].dobj.objType = DO_OPFAMILY;
2799 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2800 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2801 AssignDumpId(&opfinfo[i].dobj);
2802 opfinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_opfname));
2803 opfinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)),
2804 opfinfo[i].dobj.catId.oid);
2805 opfinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2807 /* Decide whether we want to dump it */
2808 selectDumpableObject(&(opfinfo[i].dobj));
2810 if (g_fout->remoteVersion >= 70300)
2812 if (strlen(opfinfo[i].rolname) == 0)
2813 write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
2814 opfinfo[i].dobj.name);
2818 PQclear(res);
2820 destroyPQExpBuffer(query);
2822 return opfinfo;
2826 * getAggregates:
2827 * read all the user-defined aggregates in the system catalogs and
2828 * return them in the AggInfo* structure
2830 * numAggs is set to the number of aggregates read in
2832 AggInfo *
2833 getAggregates(int *numAggs)
2835 PGresult *res;
2836 int ntups;
2837 int i;
2838 PQExpBuffer query = createPQExpBuffer();
2839 AggInfo *agginfo;
2840 int i_tableoid;
2841 int i_oid;
2842 int i_aggname;
2843 int i_aggnamespace;
2844 int i_pronargs;
2845 int i_proargtypes;
2846 int i_rolname;
2847 int i_aggacl;
2849 /* Make sure we are in proper schema */
2850 selectSourceSchema("pg_catalog");
2852 /* find all user-defined aggregates */
2854 if (g_fout->remoteVersion >= 80200)
2856 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
2857 "pronamespace AS aggnamespace, "
2858 "pronargs, proargtypes, "
2859 "(%s proowner) AS rolname, "
2860 "proacl AS aggacl "
2861 "FROM pg_proc "
2862 "WHERE proisagg "
2863 "AND pronamespace != "
2864 "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
2865 username_subquery);
2867 else if (g_fout->remoteVersion >= 70300)
2869 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
2870 "pronamespace AS aggnamespace, "
2871 "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
2872 "proargtypes, "
2873 "(%s proowner) AS rolname, "
2874 "proacl AS aggacl "
2875 "FROM pg_proc "
2876 "WHERE proisagg "
2877 "AND pronamespace != "
2878 "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
2879 username_subquery);
2881 else if (g_fout->remoteVersion >= 70100)
2883 appendPQExpBuffer(query, "SELECT tableoid, oid, aggname, "
2884 "0::oid AS aggnamespace, "
2885 "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
2886 "aggbasetype AS proargtypes, "
2887 "(%s aggowner) AS rolname, "
2888 "'{=X}' AS aggacl "
2889 "FROM pg_aggregate "
2890 "where oid > '%u'::oid",
2891 username_subquery,
2892 g_last_builtin_oid);
2894 else
2896 appendPQExpBuffer(query, "SELECT "
2897 "(SELECT oid FROM pg_class WHERE relname = 'pg_aggregate') AS tableoid, "
2898 "oid, aggname, "
2899 "0::oid AS aggnamespace, "
2900 "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
2901 "aggbasetype AS proargtypes, "
2902 "(%s aggowner) AS rolname, "
2903 "'{=X}' AS aggacl "
2904 "FROM pg_aggregate "
2905 "where oid > '%u'::oid",
2906 username_subquery,
2907 g_last_builtin_oid);
2910 res = PQexec(g_conn, query->data);
2911 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2913 ntups = PQntuples(res);
2914 *numAggs = ntups;
2916 agginfo = (AggInfo *) malloc(ntups * sizeof(AggInfo));
2918 i_tableoid = PQfnumber(res, "tableoid");
2919 i_oid = PQfnumber(res, "oid");
2920 i_aggname = PQfnumber(res, "aggname");
2921 i_aggnamespace = PQfnumber(res, "aggnamespace");
2922 i_pronargs = PQfnumber(res, "pronargs");
2923 i_proargtypes = PQfnumber(res, "proargtypes");
2924 i_rolname = PQfnumber(res, "rolname");
2925 i_aggacl = PQfnumber(res, "aggacl");
2927 for (i = 0; i < ntups; i++)
2929 agginfo[i].aggfn.dobj.objType = DO_AGG;
2930 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2931 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2932 AssignDumpId(&agginfo[i].aggfn.dobj);
2933 agginfo[i].aggfn.dobj.name = strdup(PQgetvalue(res, i, i_aggname));
2934 agginfo[i].aggfn.dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)),
2935 agginfo[i].aggfn.dobj.catId.oid);
2936 agginfo[i].aggfn.rolname = strdup(PQgetvalue(res, i, i_rolname));
2937 if (strlen(agginfo[i].aggfn.rolname) == 0)
2938 write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
2939 agginfo[i].aggfn.dobj.name);
2940 agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
2941 agginfo[i].aggfn.prorettype = InvalidOid; /* not saved */
2942 agginfo[i].aggfn.proacl = strdup(PQgetvalue(res, i, i_aggacl));
2943 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
2944 if (agginfo[i].aggfn.nargs == 0)
2945 agginfo[i].aggfn.argtypes = NULL;
2946 else
2948 agginfo[i].aggfn.argtypes = (Oid *) malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
2949 if (g_fout->remoteVersion >= 70300)
2950 parseOidArray(PQgetvalue(res, i, i_proargtypes),
2951 agginfo[i].aggfn.argtypes,
2952 agginfo[i].aggfn.nargs);
2953 else
2954 /* it's just aggbasetype */
2955 agginfo[i].aggfn.argtypes[0] = atooid(PQgetvalue(res, i, i_proargtypes));
2958 /* Decide whether we want to dump it */
2959 selectDumpableObject(&(agginfo[i].aggfn.dobj));
2962 PQclear(res);
2964 destroyPQExpBuffer(query);
2966 return agginfo;
2970 * getFuncs:
2971 * read all the user-defined functions in the system catalogs and
2972 * return them in the FuncInfo* structure
2974 * numFuncs is set to the number of functions read in
2976 FuncInfo *
2977 getFuncs(int *numFuncs)
2979 PGresult *res;
2980 int ntups;
2981 int i;
2982 PQExpBuffer query = createPQExpBuffer();
2983 FuncInfo *finfo;
2984 int i_tableoid;
2985 int i_oid;
2986 int i_proname;
2987 int i_pronamespace;
2988 int i_rolname;
2989 int i_prolang;
2990 int i_pronargs;
2991 int i_proargtypes;
2992 int i_prorettype;
2993 int i_proacl;
2995 /* Make sure we are in proper schema */
2996 selectSourceSchema("pg_catalog");
2998 /* find all user-defined funcs */
3000 if (g_fout->remoteVersion >= 70300)
3002 appendPQExpBuffer(query,
3003 "SELECT tableoid, oid, proname, prolang, "
3004 "pronargs, proargtypes, prorettype, proacl, "
3005 "pronamespace, "
3006 "(%s proowner) AS rolname "
3007 "FROM pg_proc "
3008 "WHERE NOT proisagg "
3009 "AND pronamespace != "
3010 "(SELECT oid FROM pg_namespace "
3011 "WHERE nspname = 'pg_catalog')",
3012 username_subquery);
3014 else if (g_fout->remoteVersion >= 70100)
3016 appendPQExpBuffer(query,
3017 "SELECT tableoid, oid, proname, prolang, "
3018 "pronargs, proargtypes, prorettype, "
3019 "'{=X}' AS proacl, "
3020 "0::oid AS pronamespace, "
3021 "(%s proowner) AS rolname "
3022 "FROM pg_proc "
3023 "WHERE pg_proc.oid > '%u'::oid",
3024 username_subquery,
3025 g_last_builtin_oid);
3027 else
3029 appendPQExpBuffer(query,
3030 "SELECT "
3031 "(SELECT oid FROM pg_class "
3032 " WHERE relname = 'pg_proc') AS tableoid, "
3033 "oid, proname, prolang, "
3034 "pronargs, proargtypes, prorettype, "
3035 "'{=X}' AS proacl, "
3036 "0::oid AS pronamespace, "
3037 "(%s proowner) AS rolname "
3038 "FROM pg_proc "
3039 "where pg_proc.oid > '%u'::oid",
3040 username_subquery,
3041 g_last_builtin_oid);
3044 res = PQexec(g_conn, query->data);
3045 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3047 ntups = PQntuples(res);
3049 *numFuncs = ntups;
3051 finfo = (FuncInfo *) calloc(ntups, sizeof(FuncInfo));
3053 i_tableoid = PQfnumber(res, "tableoid");
3054 i_oid = PQfnumber(res, "oid");
3055 i_proname = PQfnumber(res, "proname");
3056 i_pronamespace = PQfnumber(res, "pronamespace");
3057 i_rolname = PQfnumber(res, "rolname");
3058 i_prolang = PQfnumber(res, "prolang");
3059 i_pronargs = PQfnumber(res, "pronargs");
3060 i_proargtypes = PQfnumber(res, "proargtypes");
3061 i_prorettype = PQfnumber(res, "prorettype");
3062 i_proacl = PQfnumber(res, "proacl");
3064 for (i = 0; i < ntups; i++)
3066 finfo[i].dobj.objType = DO_FUNC;
3067 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3068 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3069 AssignDumpId(&finfo[i].dobj);
3070 finfo[i].dobj.name = strdup(PQgetvalue(res, i, i_proname));
3071 finfo[i].dobj.namespace =
3072 findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)),
3073 finfo[i].dobj.catId.oid);
3074 finfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
3075 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
3076 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
3077 finfo[i].proacl = strdup(PQgetvalue(res, i, i_proacl));
3078 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
3079 if (finfo[i].nargs == 0)
3080 finfo[i].argtypes = NULL;
3081 else
3083 finfo[i].argtypes = (Oid *) malloc(finfo[i].nargs * sizeof(Oid));
3084 parseOidArray(PQgetvalue(res, i, i_proargtypes),
3085 finfo[i].argtypes, finfo[i].nargs);
3088 /* Decide whether we want to dump it */
3089 selectDumpableObject(&(finfo[i].dobj));
3091 if (strlen(finfo[i].rolname) == 0)
3092 write_msg(NULL,
3093 "WARNING: owner of function \"%s\" appears to be invalid\n",
3094 finfo[i].dobj.name);
3097 PQclear(res);
3099 destroyPQExpBuffer(query);
3101 return finfo;
3105 * getTables
3106 * read all the user-defined tables (no indexes, no catalogs)
3107 * in the system catalogs return them in the TableInfo* structure
3109 * numTables is set to the number of tables read in
3111 TableInfo *
3112 getTables(int *numTables)
3114 PGresult *res;
3115 int ntups;
3116 int i;
3117 PQExpBuffer query = createPQExpBuffer();
3118 TableInfo *tblinfo;
3119 int i_reltableoid;
3120 int i_reloid;
3121 int i_relname;
3122 int i_relnamespace;
3123 int i_relkind;
3124 int i_relacl;
3125 int i_rolname;
3126 int i_relchecks;
3127 int i_relhastriggers;
3128 int i_relhasindex;
3129 int i_relhasrules;
3130 int i_relhasoids;
3131 int i_relfrozenxid;
3132 int i_owning_tab;
3133 int i_owning_col;
3134 int i_reltablespace;
3135 int i_reloptions;
3136 int i_toastreloptions;
3138 /* Make sure we are in proper schema */
3139 selectSourceSchema("pg_catalog");
3142 * Find all the tables (including views and sequences).
3144 * We include system catalogs, so that we can work if a user table is
3145 * defined to inherit from a system catalog (pretty weird, but...)
3147 * We ignore tables that are not type 'r' (ordinary relation), 'S'
3148 * (sequence), 'v' (view), or 'c' (composite type).
3150 * Composite-type table entries won't be dumped as such, but we have to
3151 * make a DumpableObject for them so that we can track dependencies of the
3152 * composite type (pg_depend entries for columns of the composite type
3153 * link to the pg_class entry not the pg_type entry).
3155 * Note: in this phase we should collect only a minimal amount of
3156 * information about each table, basically just enough to decide if it is
3157 * interesting. We must fetch all tables in this phase because otherwise
3158 * we cannot correctly identify inherited columns, owned sequences, etc.
3161 if (g_fout->remoteVersion >= 80400)
3164 * Left join to pick up dependency info linking sequences to their
3165 * owning column, if any (note this dependency is AUTO as of 8.2)
3167 appendPQExpBuffer(query,
3168 "SELECT c.tableoid, c.oid, c.relname, "
3169 "c.relacl, c.relkind, c.relnamespace, "
3170 "(%s c.relowner) AS rolname, "
3171 "c.relchecks, c.relhastriggers, "
3172 "c.relhasindex, c.relhasrules, c.relhasoids, "
3173 "c.relfrozenxid, "
3174 "d.refobjid AS owning_tab, "
3175 "d.refobjsubid AS owning_col, "
3176 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
3177 "array_to_string(c.reloptions, ', ') AS reloptions, "
3178 "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
3179 "FROM pg_class c "
3180 "LEFT JOIN pg_depend d ON "
3181 "(c.relkind = '%c' AND "
3182 "d.classid = c.tableoid AND d.objid = c.oid AND "
3183 "d.objsubid = 0 AND "
3184 "d.refclassid = c.tableoid AND d.deptype = 'a') "
3185 "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
3186 "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
3187 "ORDER BY c.oid",
3188 username_subquery,
3189 RELKIND_SEQUENCE,
3190 RELKIND_RELATION, RELKIND_SEQUENCE,
3191 RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3193 else if (g_fout->remoteVersion >= 80200)
3196 * Left join to pick up dependency info linking sequences to their
3197 * owning column, if any (note this dependency is AUTO as of 8.2)
3199 appendPQExpBuffer(query,
3200 "SELECT c.tableoid, c.oid, relname, "
3201 "relacl, relkind, relnamespace, "
3202 "(%s relowner) AS rolname, "
3203 "relchecks, (reltriggers <> 0) AS relhastriggers, "
3204 "relhasindex, relhasrules, relhasoids, "
3205 "relfrozenxid, "
3206 "d.refobjid AS owning_tab, "
3207 "d.refobjsubid AS owning_col, "
3208 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
3209 "array_to_string(c.reloptions, ', ') AS reloptions, "
3210 "NULL AS toast_reloptions "
3211 "FROM pg_class c "
3212 "LEFT JOIN pg_depend d ON "
3213 "(c.relkind = '%c' AND "
3214 "d.classid = c.tableoid AND d.objid = c.oid AND "
3215 "d.objsubid = 0 AND "
3216 "d.refclassid = c.tableoid AND d.deptype = 'a') "
3217 "WHERE relkind in ('%c', '%c', '%c', '%c') "
3218 "ORDER BY c.oid",
3219 username_subquery,
3220 RELKIND_SEQUENCE,
3221 RELKIND_RELATION, RELKIND_SEQUENCE,
3222 RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3224 else if (g_fout->remoteVersion >= 80000)
3227 * Left join to pick up dependency info linking sequences to their
3228 * owning column, if any
3230 appendPQExpBuffer(query,
3231 "SELECT c.tableoid, c.oid, relname, "
3232 "relacl, relkind, relnamespace, "
3233 "(%s relowner) AS rolname, "
3234 "relchecks, (reltriggers <> 0) AS relhastriggers, "
3235 "relhasindex, relhasrules, relhasoids, "
3236 "0 AS relfrozenxid, "
3237 "d.refobjid AS owning_tab, "
3238 "d.refobjsubid AS owning_col, "
3239 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
3240 "NULL AS reloptions, "
3241 "NULL AS toast_reloptions "
3242 "FROM pg_class c "
3243 "LEFT JOIN pg_depend d ON "
3244 "(c.relkind = '%c' AND "
3245 "d.classid = c.tableoid AND d.objid = c.oid AND "
3246 "d.objsubid = 0 AND "
3247 "d.refclassid = c.tableoid AND d.deptype = 'i') "
3248 "WHERE relkind in ('%c', '%c', '%c', '%c') "
3249 "ORDER BY c.oid",
3250 username_subquery,
3251 RELKIND_SEQUENCE,
3252 RELKIND_RELATION, RELKIND_SEQUENCE,
3253 RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3255 else if (g_fout->remoteVersion >= 70300)
3258 * Left join to pick up dependency info linking sequences to their
3259 * owning column, if any
3261 appendPQExpBuffer(query,
3262 "SELECT c.tableoid, c.oid, relname, "
3263 "relacl, relkind, relnamespace, "
3264 "(%s relowner) AS rolname, "
3265 "relchecks, (reltriggers <> 0) AS relhastriggers, "
3266 "relhasindex, relhasrules, relhasoids, "
3267 "0 AS relfrozenxid, "
3268 "d.refobjid AS owning_tab, "
3269 "d.refobjsubid AS owning_col, "
3270 "NULL AS reltablespace, "
3271 "NULL AS reloptions, "
3272 "NULL AS toast_reloptions "
3273 "FROM pg_class c "
3274 "LEFT JOIN pg_depend d ON "
3275 "(c.relkind = '%c' AND "
3276 "d.classid = c.tableoid AND d.objid = c.oid AND "
3277 "d.objsubid = 0 AND "
3278 "d.refclassid = c.tableoid AND d.deptype = 'i') "
3279 "WHERE relkind IN ('%c', '%c', '%c', '%c') "
3280 "ORDER BY c.oid",
3281 username_subquery,
3282 RELKIND_SEQUENCE,
3283 RELKIND_RELATION, RELKIND_SEQUENCE,
3284 RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3286 else if (g_fout->remoteVersion >= 70200)
3288 appendPQExpBuffer(query,
3289 "SELECT tableoid, oid, relname, relacl, relkind, "
3290 "0::oid AS relnamespace, "
3291 "(%s relowner) AS rolname, "
3292 "relchecks, (reltriggers <> 0) AS relhastriggers, "
3293 "relhasindex, relhasrules, relhasoids, "
3294 "0 AS relfrozenxid, "
3295 "NULL::oid AS owning_tab, "
3296 "NULL::int4 AS owning_col, "
3297 "NULL AS reltablespace, "
3298 "NULL AS reloptions, "
3299 "NULL AS toast_reloptions "
3300 "FROM pg_class "
3301 "WHERE relkind IN ('%c', '%c', '%c') "
3302 "ORDER BY oid",
3303 username_subquery,
3304 RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
3306 else if (g_fout->remoteVersion >= 70100)
3308 /* all tables have oids in 7.1 */
3309 appendPQExpBuffer(query,
3310 "SELECT tableoid, oid, relname, relacl, relkind, "
3311 "0::oid AS relnamespace, "
3312 "(%s relowner) AS rolname, "
3313 "relchecks, (reltriggers <> 0) AS relhastriggers, "
3314 "relhasindex, relhasrules, "
3315 "'t'::bool AS relhasoids, "
3316 "0 AS relfrozenxid, "
3317 "NULL::oid AS owning_tab, "
3318 "NULL::int4 AS owning_col, "
3319 "NULL AS reltablespace, "
3320 "NULL AS reloptions, "
3321 "NULL AS toast_reloptions "
3322 "FROM pg_class "
3323 "WHERE relkind IN ('%c', '%c', '%c') "
3324 "ORDER BY oid",
3325 username_subquery,
3326 RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
3328 else
3331 * Before 7.1, view relkind was not set to 'v', so we must check if we
3332 * have a view by looking for a rule in pg_rewrite.
3334 appendPQExpBuffer(query,
3335 "SELECT "
3336 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
3337 "oid, relname, relacl, "
3338 "CASE WHEN relhasrules and relkind = 'r' "
3339 " and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
3340 " r.ev_class = c.oid AND r.ev_type = '1') "
3341 "THEN '%c'::\"char\" "
3342 "ELSE relkind END AS relkind,"
3343 "0::oid AS relnamespace, "
3344 "(%s relowner) AS rolname, "
3345 "relchecks, (reltriggers <> 0) AS relhastriggers, "
3346 "relhasindex, relhasrules, "
3347 "'t'::bool AS relhasoids, "
3348 "0 as relfrozenxid, "
3349 "NULL::oid AS owning_tab, "
3350 "NULL::int4 AS owning_col, "
3351 "NULL AS reltablespace, "
3352 "NULL AS reloptions, "
3353 "NULL AS toast_reloptions "
3354 "FROM pg_class c "
3355 "WHERE relkind IN ('%c', '%c') "
3356 "ORDER BY oid",
3357 RELKIND_VIEW,
3358 username_subquery,
3359 RELKIND_RELATION, RELKIND_SEQUENCE);
3362 res = PQexec(g_conn, query->data);
3363 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3365 ntups = PQntuples(res);
3367 *numTables = ntups;
3370 * Extract data from result and lock dumpable tables. We do the locking
3371 * before anything else, to minimize the window wherein a table could
3372 * disappear under us.
3374 * Note that we have to save info about all tables here, even when dumping
3375 * only one, because we don't yet know which tables might be inheritance
3376 * ancestors of the target table.
3378 tblinfo = (TableInfo *) calloc(ntups, sizeof(TableInfo));
3380 i_reltableoid = PQfnumber(res, "tableoid");
3381 i_reloid = PQfnumber(res, "oid");
3382 i_relname = PQfnumber(res, "relname");
3383 i_relnamespace = PQfnumber(res, "relnamespace");
3384 i_relacl = PQfnumber(res, "relacl");
3385 i_relkind = PQfnumber(res, "relkind");
3386 i_rolname = PQfnumber(res, "rolname");
3387 i_relchecks = PQfnumber(res, "relchecks");
3388 i_relhastriggers = PQfnumber(res, "relhastriggers");
3389 i_relhasindex = PQfnumber(res, "relhasindex");
3390 i_relhasrules = PQfnumber(res, "relhasrules");
3391 i_relhasoids = PQfnumber(res, "relhasoids");
3392 i_relfrozenxid = PQfnumber(res, "relfrozenxid");
3393 i_owning_tab = PQfnumber(res, "owning_tab");
3394 i_owning_col = PQfnumber(res, "owning_col");
3395 i_reltablespace = PQfnumber(res, "reltablespace");
3396 i_reloptions = PQfnumber(res, "reloptions");
3397 i_toastreloptions = PQfnumber(res, "toast_reloptions");
3399 if (lockWaitTimeout && g_fout->remoteVersion >= 70300)
3402 * Arrange to fail instead of waiting forever for a table lock.
3404 * NB: this coding assumes that the only queries issued within
3405 * the following loop are LOCK TABLEs; else the timeout may be
3406 * undesirably applied to other things too.
3408 resetPQExpBuffer(query);
3409 appendPQExpBuffer(query, "SET statement_timeout = ");
3410 appendStringLiteralConn(query, lockWaitTimeout, g_conn);
3411 do_sql_command(g_conn, query->data);
3414 for (i = 0; i < ntups; i++)
3416 tblinfo[i].dobj.objType = DO_TABLE;
3417 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
3418 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
3419 AssignDumpId(&tblinfo[i].dobj);
3420 tblinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_relname));
3421 tblinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)),
3422 tblinfo[i].dobj.catId.oid);
3423 tblinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
3424 tblinfo[i].relacl = strdup(PQgetvalue(res, i, i_relacl));
3425 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
3426 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
3427 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
3428 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
3429 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
3430 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
3431 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
3432 if (PQgetisnull(res, i, i_owning_tab))
3434 tblinfo[i].owning_tab = InvalidOid;
3435 tblinfo[i].owning_col = 0;
3437 else
3439 tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
3440 tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
3442 tblinfo[i].reltablespace = strdup(PQgetvalue(res, i, i_reltablespace));
3443 tblinfo[i].reloptions = strdup(PQgetvalue(res, i, i_reloptions));
3444 tblinfo[i].toast_reloptions = strdup(PQgetvalue(res, i, i_toastreloptions));
3446 /* other fields were zeroed above */
3449 * Decide whether we want to dump this table.
3451 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
3452 tblinfo[i].dobj.dump = false;
3453 else
3454 selectDumpableTable(&tblinfo[i]);
3455 tblinfo[i].interesting = tblinfo[i].dobj.dump;
3458 * Read-lock target tables to make sure they aren't DROPPED or altered
3459 * in schema before we get around to dumping them.
3461 * Note that we don't explicitly lock parents of the target tables; we
3462 * assume our lock on the child is enough to prevent schema
3463 * alterations to parent tables.
3465 * NOTE: it'd be kinda nice to lock views and sequences too, not only
3466 * plain tables, but the backend doesn't presently allow that.
3468 if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION)
3470 resetPQExpBuffer(query);
3471 appendPQExpBuffer(query,
3472 "LOCK TABLE %s IN ACCESS SHARE MODE",
3473 fmtQualifiedId(tblinfo[i].dobj.namespace->dobj.name,
3474 tblinfo[i].dobj.name));
3475 do_sql_command(g_conn, query->data);
3478 /* Emit notice if join for owner failed */
3479 if (strlen(tblinfo[i].rolname) == 0)
3480 write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
3481 tblinfo[i].dobj.name);
3484 if (lockWaitTimeout && g_fout->remoteVersion >= 70300)
3486 do_sql_command(g_conn, "SET statement_timeout = 0");
3489 PQclear(res);
3492 * Force sequences that are "owned" by table columns to be dumped whenever
3493 * their owning table is being dumped.
3495 for (i = 0; i < ntups; i++)
3497 TableInfo *seqinfo = &tblinfo[i];
3498 int j;
3500 if (!OidIsValid(seqinfo->owning_tab))
3501 continue; /* not an owned sequence */
3502 if (seqinfo->dobj.dump)
3503 continue; /* no need to search */
3505 /* can't use findTableByOid yet, unfortunately */
3506 for (j = 0; j < ntups; j++)
3508 if (tblinfo[j].dobj.catId.oid == seqinfo->owning_tab)
3510 if (tblinfo[j].dobj.dump)
3512 seqinfo->interesting = true;
3513 seqinfo->dobj.dump = true;
3515 break;
3520 destroyPQExpBuffer(query);
3522 return tblinfo;
3526 * getInherits
3527 * read all the inheritance information
3528 * from the system catalogs return them in the InhInfo* structure
3530 * numInherits is set to the number of pairs read in
3532 InhInfo *
3533 getInherits(int *numInherits)
3535 PGresult *res;
3536 int ntups;
3537 int i;
3538 PQExpBuffer query = createPQExpBuffer();
3539 InhInfo *inhinfo;
3541 int i_inhrelid;
3542 int i_inhparent;
3544 /* Make sure we are in proper schema */
3545 selectSourceSchema("pg_catalog");
3547 /* find all the inheritance information */
3549 appendPQExpBuffer(query, "SELECT inhrelid, inhparent FROM pg_inherits");
3551 res = PQexec(g_conn, query->data);
3552 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3554 ntups = PQntuples(res);
3556 *numInherits = ntups;
3558 inhinfo = (InhInfo *) malloc(ntups * sizeof(InhInfo));
3560 i_inhrelid = PQfnumber(res, "inhrelid");
3561 i_inhparent = PQfnumber(res, "inhparent");
3563 for (i = 0; i < ntups; i++)
3565 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
3566 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
3569 PQclear(res);
3571 destroyPQExpBuffer(query);
3573 return inhinfo;
3577 * getIndexes
3578 * get information about every index on a dumpable table
3580 * Note: index data is not returned directly to the caller, but it
3581 * does get entered into the DumpableObject tables.
3583 void
3584 getIndexes(TableInfo tblinfo[], int numTables)
3586 int i,
3588 PQExpBuffer query = createPQExpBuffer();
3589 PGresult *res;
3590 IndxInfo *indxinfo;
3591 ConstraintInfo *constrinfo;
3592 int i_tableoid,
3593 i_oid,
3594 i_indexname,
3595 i_indexdef,
3596 i_indnkeys,
3597 i_indkey,
3598 i_indisclustered,
3599 i_contype,
3600 i_conname,
3601 i_contableoid,
3602 i_conoid,
3603 i_tablespace,
3604 i_options;
3605 int ntups;
3607 for (i = 0; i < numTables; i++)
3609 TableInfo *tbinfo = &tblinfo[i];
3611 /* Only plain tables have indexes */
3612 if (tbinfo->relkind != RELKIND_RELATION || !tbinfo->hasindex)
3613 continue;
3615 /* Ignore indexes of tables not to be dumped */
3616 if (!tbinfo->dobj.dump)
3617 continue;
3619 if (g_verbose)
3620 write_msg(NULL, "reading indexes for table \"%s\"\n",
3621 tbinfo->dobj.name);
3623 /* Make sure we are in proper schema so indexdef is right */
3624 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
3627 * The point of the messy-looking outer join is to find a constraint
3628 * that is related by an internal dependency link to the index. If we
3629 * find one, create a CONSTRAINT entry linked to the INDEX entry. We
3630 * assume an index won't have more than one internal dependency.
3632 resetPQExpBuffer(query);
3633 if (g_fout->remoteVersion >= 80200)
3635 appendPQExpBuffer(query,
3636 "SELECT t.tableoid, t.oid, "
3637 "t.relname AS indexname, "
3638 "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
3639 "t.relnatts AS indnkeys, "
3640 "i.indkey, i.indisclustered, "
3641 "c.contype, c.conname, "
3642 "c.tableoid AS contableoid, "
3643 "c.oid AS conoid, "
3644 "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
3645 "array_to_string(t.reloptions, ', ') AS options "
3646 "FROM pg_catalog.pg_index i "
3647 "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
3648 "LEFT JOIN pg_catalog.pg_depend d "
3649 "ON (d.classid = t.tableoid "
3650 "AND d.objid = t.oid "
3651 "AND d.deptype = 'i') "
3652 "LEFT JOIN pg_catalog.pg_constraint c "
3653 "ON (d.refclassid = c.tableoid "
3654 "AND d.refobjid = c.oid) "
3655 "WHERE i.indrelid = '%u'::pg_catalog.oid "
3656 "ORDER BY indexname",
3657 tbinfo->dobj.catId.oid);
3659 else if (g_fout->remoteVersion >= 80000)
3661 appendPQExpBuffer(query,
3662 "SELECT t.tableoid, t.oid, "
3663 "t.relname AS indexname, "
3664 "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
3665 "t.relnatts AS indnkeys, "
3666 "i.indkey, i.indisclustered, "
3667 "c.contype, c.conname, "
3668 "c.tableoid AS contableoid, "
3669 "c.oid AS conoid, "
3670 "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
3671 "null AS options "
3672 "FROM pg_catalog.pg_index i "
3673 "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
3674 "LEFT JOIN pg_catalog.pg_depend d "
3675 "ON (d.classid = t.tableoid "
3676 "AND d.objid = t.oid "
3677 "AND d.deptype = 'i') "
3678 "LEFT JOIN pg_catalog.pg_constraint c "
3679 "ON (d.refclassid = c.tableoid "
3680 "AND d.refobjid = c.oid) "
3681 "WHERE i.indrelid = '%u'::pg_catalog.oid "
3682 "ORDER BY indexname",
3683 tbinfo->dobj.catId.oid);
3685 else if (g_fout->remoteVersion >= 70300)
3687 appendPQExpBuffer(query,
3688 "SELECT t.tableoid, t.oid, "
3689 "t.relname AS indexname, "
3690 "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
3691 "t.relnatts AS indnkeys, "
3692 "i.indkey, i.indisclustered, "
3693 "c.contype, c.conname, "
3694 "c.tableoid AS contableoid, "
3695 "c.oid AS conoid, "
3696 "NULL AS tablespace, "
3697 "null AS options "
3698 "FROM pg_catalog.pg_index i "
3699 "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
3700 "LEFT JOIN pg_catalog.pg_depend d "
3701 "ON (d.classid = t.tableoid "
3702 "AND d.objid = t.oid "
3703 "AND d.deptype = 'i') "
3704 "LEFT JOIN pg_catalog.pg_constraint c "
3705 "ON (d.refclassid = c.tableoid "
3706 "AND d.refobjid = c.oid) "
3707 "WHERE i.indrelid = '%u'::pg_catalog.oid "
3708 "ORDER BY indexname",
3709 tbinfo->dobj.catId.oid);
3711 else if (g_fout->remoteVersion >= 70100)
3713 appendPQExpBuffer(query,
3714 "SELECT t.tableoid, t.oid, "
3715 "t.relname AS indexname, "
3716 "pg_get_indexdef(i.indexrelid) AS indexdef, "
3717 "t.relnatts AS indnkeys, "
3718 "i.indkey, false AS indisclustered, "
3719 "CASE WHEN i.indisprimary THEN 'p'::char "
3720 "ELSE '0'::char END AS contype, "
3721 "t.relname AS conname, "
3722 "0::oid AS contableoid, "
3723 "t.oid AS conoid, "
3724 "NULL AS tablespace, "
3725 "null AS options "
3726 "FROM pg_index i, pg_class t "
3727 "WHERE t.oid = i.indexrelid "
3728 "AND i.indrelid = '%u'::oid "
3729 "ORDER BY indexname",
3730 tbinfo->dobj.catId.oid);
3732 else
3734 appendPQExpBuffer(query,
3735 "SELECT "
3736 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
3737 "t.oid, "
3738 "t.relname AS indexname, "
3739 "pg_get_indexdef(i.indexrelid) AS indexdef, "
3740 "t.relnatts AS indnkeys, "
3741 "i.indkey, false AS indisclustered, "
3742 "CASE WHEN i.indisprimary THEN 'p'::char "
3743 "ELSE '0'::char END AS contype, "
3744 "t.relname AS conname, "
3745 "0::oid AS contableoid, "
3746 "t.oid AS conoid, "
3747 "NULL AS tablespace, "
3748 "null AS options "
3749 "FROM pg_index i, pg_class t "
3750 "WHERE t.oid = i.indexrelid "
3751 "AND i.indrelid = '%u'::oid "
3752 "ORDER BY indexname",
3753 tbinfo->dobj.catId.oid);
3756 res = PQexec(g_conn, query->data);
3757 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3759 ntups = PQntuples(res);
3761 i_tableoid = PQfnumber(res, "tableoid");
3762 i_oid = PQfnumber(res, "oid");
3763 i_indexname = PQfnumber(res, "indexname");
3764 i_indexdef = PQfnumber(res, "indexdef");
3765 i_indnkeys = PQfnumber(res, "indnkeys");
3766 i_indkey = PQfnumber(res, "indkey");
3767 i_indisclustered = PQfnumber(res, "indisclustered");
3768 i_contype = PQfnumber(res, "contype");
3769 i_conname = PQfnumber(res, "conname");
3770 i_contableoid = PQfnumber(res, "contableoid");
3771 i_conoid = PQfnumber(res, "conoid");
3772 i_tablespace = PQfnumber(res, "tablespace");
3773 i_options = PQfnumber(res, "options");
3775 indxinfo = (IndxInfo *) malloc(ntups * sizeof(IndxInfo));
3776 constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
3778 for (j = 0; j < ntups; j++)
3780 char contype;
3782 indxinfo[j].dobj.objType = DO_INDEX;
3783 indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
3784 indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3785 AssignDumpId(&indxinfo[j].dobj);
3786 indxinfo[j].dobj.name = strdup(PQgetvalue(res, j, i_indexname));
3787 indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3788 indxinfo[j].indextable = tbinfo;
3789 indxinfo[j].indexdef = strdup(PQgetvalue(res, j, i_indexdef));
3790 indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
3791 indxinfo[j].tablespace = strdup(PQgetvalue(res, j, i_tablespace));
3792 indxinfo[j].options = strdup(PQgetvalue(res, j, i_options));
3795 * In pre-7.4 releases, indkeys may contain more entries than
3796 * indnkeys says (since indnkeys will be 1 for a functional
3797 * index). We don't actually care about this case since we don't
3798 * examine indkeys except for indexes associated with PRIMARY and
3799 * UNIQUE constraints, which are never functional indexes. But we
3800 * have to allocate enough space to keep parseOidArray from
3801 * complaining.
3803 indxinfo[j].indkeys = (Oid *) malloc(INDEX_MAX_KEYS * sizeof(Oid));
3804 parseOidArray(PQgetvalue(res, j, i_indkey),
3805 indxinfo[j].indkeys, INDEX_MAX_KEYS);
3806 indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
3807 contype = *(PQgetvalue(res, j, i_contype));
3809 if (contype == 'p' || contype == 'u')
3812 * If we found a constraint matching the index, create an
3813 * entry for it.
3815 * In a pre-7.3 database, we take this path iff the index was
3816 * marked indisprimary.
3818 constrinfo[j].dobj.objType = DO_CONSTRAINT;
3819 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
3820 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
3821 AssignDumpId(&constrinfo[j].dobj);
3822 constrinfo[j].dobj.name = strdup(PQgetvalue(res, j, i_conname));
3823 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3824 constrinfo[j].contable = tbinfo;
3825 constrinfo[j].condomain = NULL;
3826 constrinfo[j].contype = contype;
3827 constrinfo[j].condef = NULL;
3828 constrinfo[j].confrelid = InvalidOid;
3829 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
3830 constrinfo[j].conislocal = true;
3831 constrinfo[j].separate = true;
3833 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
3835 /* If pre-7.3 DB, better make sure table comes first */
3836 addObjectDependency(&constrinfo[j].dobj,
3837 tbinfo->dobj.dumpId);
3839 else
3841 /* Plain secondary index */
3842 indxinfo[j].indexconstraint = 0;
3846 PQclear(res);
3849 destroyPQExpBuffer(query);
3853 * getConstraints
3855 * Get info about constraints on dumpable tables.
3857 * Currently handles foreign keys only.
3858 * Unique and primary key constraints are handled with indexes,
3859 * while check constraints are processed in getTableAttrs().
3861 void
3862 getConstraints(TableInfo tblinfo[], int numTables)
3864 int i,
3866 ConstraintInfo *constrinfo;
3867 PQExpBuffer query;
3868 PGresult *res;
3869 int i_contableoid,
3870 i_conoid,
3871 i_conname,
3872 i_confrelid,
3873 i_condef;
3874 int ntups;
3876 /* pg_constraint was created in 7.3, so nothing to do if older */
3877 if (g_fout->remoteVersion < 70300)
3878 return;
3880 query = createPQExpBuffer();
3882 for (i = 0; i < numTables; i++)
3884 TableInfo *tbinfo = &tblinfo[i];
3886 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
3887 continue;
3889 if (g_verbose)
3890 write_msg(NULL, "reading foreign key constraints for table \"%s\"\n",
3891 tbinfo->dobj.name);
3894 * select table schema to ensure constraint expr is qualified if
3895 * needed
3897 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
3899 resetPQExpBuffer(query);
3900 appendPQExpBuffer(query,
3901 "SELECT tableoid, oid, conname, confrelid, "
3902 "pg_catalog.pg_get_constraintdef(oid) AS condef "
3903 "FROM pg_catalog.pg_constraint "
3904 "WHERE conrelid = '%u'::pg_catalog.oid "
3905 "AND contype = 'f'",
3906 tbinfo->dobj.catId.oid);
3907 res = PQexec(g_conn, query->data);
3908 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3910 ntups = PQntuples(res);
3912 i_contableoid = PQfnumber(res, "tableoid");
3913 i_conoid = PQfnumber(res, "oid");
3914 i_conname = PQfnumber(res, "conname");
3915 i_confrelid = PQfnumber(res, "confrelid");
3916 i_condef = PQfnumber(res, "condef");
3918 constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
3920 for (j = 0; j < ntups; j++)
3922 constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
3923 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
3924 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
3925 AssignDumpId(&constrinfo[j].dobj);
3926 constrinfo[j].dobj.name = strdup(PQgetvalue(res, j, i_conname));
3927 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3928 constrinfo[j].contable = tbinfo;
3929 constrinfo[j].condomain = NULL;
3930 constrinfo[j].contype = 'f';
3931 constrinfo[j].condef = strdup(PQgetvalue(res, j, i_condef));
3932 constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
3933 constrinfo[j].conindex = 0;
3934 constrinfo[j].conislocal = true;
3935 constrinfo[j].separate = true;
3938 PQclear(res);
3941 destroyPQExpBuffer(query);
3945 * getDomainConstraints
3947 * Get info about constraints on a domain.
3949 static void
3950 getDomainConstraints(TypeInfo *tinfo)
3952 int i;
3953 ConstraintInfo *constrinfo;
3954 PQExpBuffer query;
3955 PGresult *res;
3956 int i_tableoid,
3957 i_oid,
3958 i_conname,
3959 i_consrc;
3960 int ntups;
3962 /* pg_constraint was created in 7.3, so nothing to do if older */
3963 if (g_fout->remoteVersion < 70300)
3964 return;
3967 * select appropriate schema to ensure names in constraint are properly
3968 * qualified
3970 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
3972 query = createPQExpBuffer();
3974 if (g_fout->remoteVersion >= 70400)
3975 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
3976 "pg_catalog.pg_get_constraintdef(oid) AS consrc "
3977 "FROM pg_catalog.pg_constraint "
3978 "WHERE contypid = '%u'::pg_catalog.oid "
3979 "ORDER BY conname",
3980 tinfo->dobj.catId.oid);
3981 else
3982 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
3983 "'CHECK (' || consrc || ')' AS consrc "
3984 "FROM pg_catalog.pg_constraint "
3985 "WHERE contypid = '%u'::pg_catalog.oid "
3986 "ORDER BY conname",
3987 tinfo->dobj.catId.oid);
3989 res = PQexec(g_conn, query->data);
3990 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3992 ntups = PQntuples(res);
3994 i_tableoid = PQfnumber(res, "tableoid");
3995 i_oid = PQfnumber(res, "oid");
3996 i_conname = PQfnumber(res, "conname");
3997 i_consrc = PQfnumber(res, "consrc");
3999 constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
4001 tinfo->nDomChecks = ntups;
4002 tinfo->domChecks = constrinfo;
4004 for (i = 0; i < ntups; i++)
4006 constrinfo[i].dobj.objType = DO_CONSTRAINT;
4007 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4008 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4009 AssignDumpId(&constrinfo[i].dobj);
4010 constrinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_conname));
4011 constrinfo[i].dobj.namespace = tinfo->dobj.namespace;
4012 constrinfo[i].contable = NULL;
4013 constrinfo[i].condomain = tinfo;
4014 constrinfo[i].contype = 'c';
4015 constrinfo[i].condef = strdup(PQgetvalue(res, i, i_consrc));
4016 constrinfo[i].confrelid = InvalidOid;
4017 constrinfo[i].conindex = 0;
4018 constrinfo[i].conislocal = true;
4019 constrinfo[i].separate = false;
4022 * Make the domain depend on the constraint, ensuring it won't be
4023 * output till any constraint dependencies are OK.
4025 addObjectDependency(&tinfo->dobj,
4026 constrinfo[i].dobj.dumpId);
4029 PQclear(res);
4031 destroyPQExpBuffer(query);
4035 * getRules
4036 * get basic information about every rule in the system
4038 * numRules is set to the number of rules read in
4040 RuleInfo *
4041 getRules(int *numRules)
4043 PGresult *res;
4044 int ntups;
4045 int i;
4046 PQExpBuffer query = createPQExpBuffer();
4047 RuleInfo *ruleinfo;
4048 int i_tableoid;
4049 int i_oid;
4050 int i_rulename;
4051 int i_ruletable;
4052 int i_ev_type;
4053 int i_is_instead;
4054 int i_ev_enabled;
4056 /* Make sure we are in proper schema */
4057 selectSourceSchema("pg_catalog");
4059 if (g_fout->remoteVersion >= 80300)
4061 appendPQExpBuffer(query, "SELECT "
4062 "tableoid, oid, rulename, "
4063 "ev_class AS ruletable, ev_type, is_instead, "
4064 "ev_enabled "
4065 "FROM pg_rewrite "
4066 "ORDER BY oid");
4068 else if (g_fout->remoteVersion >= 70100)
4070 appendPQExpBuffer(query, "SELECT "
4071 "tableoid, oid, rulename, "
4072 "ev_class AS ruletable, ev_type, is_instead, "
4073 "'O'::char AS ev_enabled "
4074 "FROM pg_rewrite "
4075 "ORDER BY oid");
4077 else
4079 appendPQExpBuffer(query, "SELECT "
4080 "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
4081 "oid, rulename, "
4082 "ev_class AS ruletable, ev_type, is_instead, "
4083 "'O'::char AS ev_enabled "
4084 "FROM pg_rewrite "
4085 "ORDER BY oid");
4088 res = PQexec(g_conn, query->data);
4089 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4091 ntups = PQntuples(res);
4093 *numRules = ntups;
4095 ruleinfo = (RuleInfo *) malloc(ntups * sizeof(RuleInfo));
4097 i_tableoid = PQfnumber(res, "tableoid");
4098 i_oid = PQfnumber(res, "oid");
4099 i_rulename = PQfnumber(res, "rulename");
4100 i_ruletable = PQfnumber(res, "ruletable");
4101 i_ev_type = PQfnumber(res, "ev_type");
4102 i_is_instead = PQfnumber(res, "is_instead");
4103 i_ev_enabled = PQfnumber(res, "ev_enabled");
4105 for (i = 0; i < ntups; i++)
4107 Oid ruletableoid;
4109 ruleinfo[i].dobj.objType = DO_RULE;
4110 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4111 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4112 AssignDumpId(&ruleinfo[i].dobj);
4113 ruleinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_rulename));
4114 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
4115 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
4116 if (ruleinfo[i].ruletable == NULL)
4118 write_msg(NULL, "failed sanity check, parent table OID %u of pg_rewrite entry OID %u not found\n",
4119 ruletableoid,
4120 ruleinfo[i].dobj.catId.oid);
4121 exit_nicely();
4123 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
4124 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
4125 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
4126 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
4127 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
4128 if (ruleinfo[i].ruletable)
4131 * If the table is a view, force its ON SELECT rule to be sorted
4132 * before the view itself --- this ensures that any dependencies
4133 * for the rule affect the table's positioning. Other rules are
4134 * forced to appear after their table.
4136 if (ruleinfo[i].ruletable->relkind == RELKIND_VIEW &&
4137 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
4139 addObjectDependency(&ruleinfo[i].ruletable->dobj,
4140 ruleinfo[i].dobj.dumpId);
4141 /* We'll merge the rule into CREATE VIEW, if possible */
4142 ruleinfo[i].separate = false;
4144 else
4146 addObjectDependency(&ruleinfo[i].dobj,
4147 ruleinfo[i].ruletable->dobj.dumpId);
4148 ruleinfo[i].separate = true;
4151 else
4152 ruleinfo[i].separate = true;
4155 PQclear(res);
4157 destroyPQExpBuffer(query);
4159 return ruleinfo;
4163 * getTriggers
4164 * get information about every trigger on a dumpable table
4166 * Note: trigger data is not returned directly to the caller, but it
4167 * does get entered into the DumpableObject tables.
4169 void
4170 getTriggers(TableInfo tblinfo[], int numTables)
4172 int i,
4174 PQExpBuffer query = createPQExpBuffer();
4175 PGresult *res;
4176 TriggerInfo *tginfo;
4177 int i_tableoid,
4178 i_oid,
4179 i_tgname,
4180 i_tgfname,
4181 i_tgtype,
4182 i_tgnargs,
4183 i_tgargs,
4184 i_tgisconstraint,
4185 i_tgconstrname,
4186 i_tgconstrrelid,
4187 i_tgconstrrelname,
4188 i_tgenabled,
4189 i_tgdeferrable,
4190 i_tginitdeferred;
4191 int ntups;
4193 for (i = 0; i < numTables; i++)
4195 TableInfo *tbinfo = &tblinfo[i];
4197 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
4198 continue;
4200 if (g_verbose)
4201 write_msg(NULL, "reading triggers for table \"%s\"\n",
4202 tbinfo->dobj.name);
4205 * select table schema to ensure regproc name is qualified if needed
4207 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
4209 resetPQExpBuffer(query);
4210 if (g_fout->remoteVersion >= 80300)
4213 * We ignore triggers that are tied to a foreign-key constraint
4215 appendPQExpBuffer(query,
4216 "SELECT tgname, "
4217 "tgfoid::pg_catalog.regproc AS tgfname, "
4218 "tgtype, tgnargs, tgargs, tgenabled, "
4219 "tgisconstraint, tgconstrname, tgdeferrable, "
4220 "tgconstrrelid, tginitdeferred, tableoid, oid, "
4221 "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
4222 "FROM pg_catalog.pg_trigger t "
4223 "WHERE tgrelid = '%u'::pg_catalog.oid "
4224 "AND tgconstraint = 0",
4225 tbinfo->dobj.catId.oid);
4227 else if (g_fout->remoteVersion >= 70300)
4230 * We ignore triggers that are tied to a foreign-key constraint,
4231 * but in these versions we have to grovel through pg_constraint
4232 * to find out
4234 appendPQExpBuffer(query,
4235 "SELECT tgname, "
4236 "tgfoid::pg_catalog.regproc AS tgfname, "
4237 "tgtype, tgnargs, tgargs, tgenabled, "
4238 "tgisconstraint, tgconstrname, tgdeferrable, "
4239 "tgconstrrelid, tginitdeferred, tableoid, oid, "
4240 "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
4241 "FROM pg_catalog.pg_trigger t "
4242 "WHERE tgrelid = '%u'::pg_catalog.oid "
4243 "AND (NOT tgisconstraint "
4244 " OR NOT EXISTS"
4245 " (SELECT 1 FROM pg_catalog.pg_depend d "
4246 " JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
4247 " WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
4248 tbinfo->dobj.catId.oid);
4250 else if (g_fout->remoteVersion >= 70100)
4252 appendPQExpBuffer(query,
4253 "SELECT tgname, tgfoid::regproc AS tgfname, "
4254 "tgtype, tgnargs, tgargs, tgenabled, "
4255 "tgisconstraint, tgconstrname, tgdeferrable, "
4256 "tgconstrrelid, tginitdeferred, tableoid, oid, "
4257 "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
4258 " AS tgconstrrelname "
4259 "FROM pg_trigger "
4260 "WHERE tgrelid = '%u'::oid",
4261 tbinfo->dobj.catId.oid);
4263 else
4265 appendPQExpBuffer(query,
4266 "SELECT tgname, tgfoid::regproc AS tgfname, "
4267 "tgtype, tgnargs, tgargs, tgenabled, "
4268 "tgisconstraint, tgconstrname, tgdeferrable, "
4269 "tgconstrrelid, tginitdeferred, "
4270 "(SELECT oid FROM pg_class WHERE relname = 'pg_trigger') AS tableoid, "
4271 "oid, "
4272 "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
4273 " AS tgconstrrelname "
4274 "FROM pg_trigger "
4275 "WHERE tgrelid = '%u'::oid",
4276 tbinfo->dobj.catId.oid);
4278 res = PQexec(g_conn, query->data);
4279 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4281 ntups = PQntuples(res);
4283 i_tableoid = PQfnumber(res, "tableoid");
4284 i_oid = PQfnumber(res, "oid");
4285 i_tgname = PQfnumber(res, "tgname");
4286 i_tgfname = PQfnumber(res, "tgfname");
4287 i_tgtype = PQfnumber(res, "tgtype");
4288 i_tgnargs = PQfnumber(res, "tgnargs");
4289 i_tgargs = PQfnumber(res, "tgargs");
4290 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
4291 i_tgconstrname = PQfnumber(res, "tgconstrname");
4292 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
4293 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
4294 i_tgenabled = PQfnumber(res, "tgenabled");
4295 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
4296 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
4298 tginfo = (TriggerInfo *) malloc(ntups * sizeof(TriggerInfo));
4300 for (j = 0; j < ntups; j++)
4302 tginfo[j].dobj.objType = DO_TRIGGER;
4303 tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
4304 tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
4305 AssignDumpId(&tginfo[j].dobj);
4306 tginfo[j].dobj.name = strdup(PQgetvalue(res, j, i_tgname));
4307 tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
4308 tginfo[j].tgtable = tbinfo;
4309 tginfo[j].tgfname = strdup(PQgetvalue(res, j, i_tgfname));
4310 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
4311 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
4312 tginfo[j].tgargs = strdup(PQgetvalue(res, j, i_tgargs));
4313 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
4314 tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
4315 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
4316 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
4318 if (tginfo[j].tgisconstraint)
4320 tginfo[j].tgconstrname = strdup(PQgetvalue(res, j, i_tgconstrname));
4321 tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
4322 if (OidIsValid(tginfo[j].tgconstrrelid))
4324 if (PQgetisnull(res, j, i_tgconstrrelname))
4326 write_msg(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
4327 tginfo[j].dobj.name, tbinfo->dobj.name,
4328 tginfo[j].tgconstrrelid);
4329 exit_nicely();
4331 tginfo[j].tgconstrrelname = strdup(PQgetvalue(res, j, i_tgconstrrelname));
4333 else
4334 tginfo[j].tgconstrrelname = NULL;
4336 else
4338 tginfo[j].tgconstrname = NULL;
4339 tginfo[j].tgconstrrelid = InvalidOid;
4340 tginfo[j].tgconstrrelname = NULL;
4344 PQclear(res);
4347 destroyPQExpBuffer(query);
4351 * getProcLangs
4352 * get basic information about every procedural language in the system
4354 * numProcLangs is set to the number of langs read in
4356 * NB: this must run after getFuncs() because we assume we can do
4357 * findFuncByOid().
4359 ProcLangInfo *
4360 getProcLangs(int *numProcLangs)
4362 PGresult *res;
4363 int ntups;
4364 int i;
4365 PQExpBuffer query = createPQExpBuffer();
4366 ProcLangInfo *planginfo;
4367 int i_tableoid;
4368 int i_oid;
4369 int i_lanname;
4370 int i_lanpltrusted;
4371 int i_lanplcallfoid;
4372 int i_lanvalidator;
4373 int i_lanacl;
4374 int i_lanowner;
4376 /* Make sure we are in proper schema */
4377 selectSourceSchema("pg_catalog");
4379 if (g_fout->remoteVersion >= 80300)
4381 /* pg_language has a lanowner column */
4382 appendPQExpBuffer(query, "SELECT tableoid, oid, "
4383 "lanname, lanpltrusted, lanplcallfoid, "
4384 "lanvalidator, lanacl, "
4385 "(%s lanowner) AS lanowner "
4386 "FROM pg_language "
4387 "WHERE lanispl "
4388 "ORDER BY oid",
4389 username_subquery);
4391 else if (g_fout->remoteVersion >= 80100)
4393 /* Languages are owned by the bootstrap superuser, OID 10 */
4394 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
4395 "(%s '10') AS lanowner "
4396 "FROM pg_language "
4397 "WHERE lanispl "
4398 "ORDER BY oid",
4399 username_subquery);
4401 else if (g_fout->remoteVersion >= 70400)
4403 /* Languages are owned by the bootstrap superuser, sysid 1 */
4404 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
4405 "(%s '1') AS lanowner "
4406 "FROM pg_language "
4407 "WHERE lanispl "
4408 "ORDER BY oid",
4409 username_subquery);
4411 else if (g_fout->remoteVersion >= 70100)
4413 /* No clear notion of an owner at all before 7.4 ... */
4414 appendPQExpBuffer(query, "SELECT tableoid, oid, * FROM pg_language "
4415 "WHERE lanispl "
4416 "ORDER BY oid");
4418 else
4420 appendPQExpBuffer(query, "SELECT "
4421 "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, "
4422 "oid, * FROM pg_language "
4423 "WHERE lanispl "
4424 "ORDER BY oid");
4427 res = PQexec(g_conn, query->data);
4428 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4430 ntups = PQntuples(res);
4432 *numProcLangs = ntups;
4434 planginfo = (ProcLangInfo *) malloc(ntups * sizeof(ProcLangInfo));
4436 i_tableoid = PQfnumber(res, "tableoid");
4437 i_oid = PQfnumber(res, "oid");
4438 i_lanname = PQfnumber(res, "lanname");
4439 i_lanpltrusted = PQfnumber(res, "lanpltrusted");
4440 i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
4441 /* these may fail and return -1: */
4442 i_lanvalidator = PQfnumber(res, "lanvalidator");
4443 i_lanacl = PQfnumber(res, "lanacl");
4444 i_lanowner = PQfnumber(res, "lanowner");
4446 for (i = 0; i < ntups; i++)
4448 planginfo[i].dobj.objType = DO_PROCLANG;
4449 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4450 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4451 AssignDumpId(&planginfo[i].dobj);
4453 planginfo[i].dobj.name = strdup(PQgetvalue(res, i, i_lanname));
4454 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
4455 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
4456 if (i_lanvalidator >= 0)
4457 planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
4458 else
4459 planginfo[i].lanvalidator = InvalidOid;
4460 if (i_lanacl >= 0)
4461 planginfo[i].lanacl = strdup(PQgetvalue(res, i, i_lanacl));
4462 else
4463 planginfo[i].lanacl = strdup("{=U}");
4464 if (i_lanowner >= 0)
4465 planginfo[i].lanowner = strdup(PQgetvalue(res, i, i_lanowner));
4466 else
4467 planginfo[i].lanowner = strdup("");
4469 if (g_fout->remoteVersion < 70300)
4472 * We need to make a dependency to ensure the function will be
4473 * dumped first. (In 7.3 and later the regular dependency
4474 * mechanism will handle this for us.)
4476 FuncInfo *funcInfo = findFuncByOid(planginfo[i].lanplcallfoid);
4478 if (funcInfo)
4479 addObjectDependency(&planginfo[i].dobj,
4480 funcInfo->dobj.dumpId);
4484 PQclear(res);
4486 destroyPQExpBuffer(query);
4488 return planginfo;
4492 * getCasts
4493 * get basic information about every cast in the system
4495 * numCasts is set to the number of casts read in
4497 CastInfo *
4498 getCasts(int *numCasts)
4500 PGresult *res;
4501 int ntups;
4502 int i;
4503 PQExpBuffer query = createPQExpBuffer();
4504 CastInfo *castinfo;
4505 int i_tableoid;
4506 int i_oid;
4507 int i_castsource;
4508 int i_casttarget;
4509 int i_castfunc;
4510 int i_castcontext;
4511 int i_castmethod;
4513 /* Make sure we are in proper schema */
4514 selectSourceSchema("pg_catalog");
4516 if (g_fout->remoteVersion >= 80400)
4518 appendPQExpBuffer(query, "SELECT tableoid, oid, "
4519 "castsource, casttarget, castfunc, castcontext, "
4520 "castmethod "
4521 "FROM pg_cast ORDER BY 3,4");
4523 else if (g_fout->remoteVersion >= 70300)
4525 appendPQExpBuffer(query, "SELECT tableoid, oid, "
4526 "castsource, casttarget, castfunc, castcontext, "
4527 "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
4528 "FROM pg_cast ORDER BY 3,4");
4530 else
4532 appendPQExpBuffer(query, "SELECT 0 AS tableoid, p.oid, "
4533 "t1.oid AS castsource, t2.oid AS casttarget, "
4534 "p.oid AS castfunc, 'e' AS castcontext, "
4535 "'f' AS castmethod "
4536 "FROM pg_type t1, pg_type t2, pg_proc p "
4537 "WHERE p.pronargs = 1 AND "
4538 "p.proargtypes[0] = t1.oid AND "
4539 "p.prorettype = t2.oid AND p.proname = t2.typname "
4540 "ORDER BY 3,4");
4543 res = PQexec(g_conn, query->data);
4544 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4546 ntups = PQntuples(res);
4548 *numCasts = ntups;
4550 castinfo = (CastInfo *) malloc(ntups * sizeof(CastInfo));
4552 i_tableoid = PQfnumber(res, "tableoid");
4553 i_oid = PQfnumber(res, "oid");
4554 i_castsource = PQfnumber(res, "castsource");
4555 i_casttarget = PQfnumber(res, "casttarget");
4556 i_castfunc = PQfnumber(res, "castfunc");
4557 i_castcontext = PQfnumber(res, "castcontext");
4558 i_castmethod = PQfnumber(res, "castmethod");
4560 for (i = 0; i < ntups; i++)
4562 PQExpBufferData namebuf;
4563 TypeInfo *sTypeInfo;
4564 TypeInfo *tTypeInfo;
4566 castinfo[i].dobj.objType = DO_CAST;
4567 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4568 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4569 AssignDumpId(&castinfo[i].dobj);
4570 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
4571 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
4572 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
4573 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
4574 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
4577 * Try to name cast as concatenation of typnames. This is only used
4578 * for purposes of sorting. If we fail to find either type, the name
4579 * will be an empty string.
4581 initPQExpBuffer(&namebuf);
4582 sTypeInfo = findTypeByOid(castinfo[i].castsource);
4583 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
4584 if (sTypeInfo && tTypeInfo)
4585 appendPQExpBuffer(&namebuf, "%s %s",
4586 sTypeInfo->dobj.name, tTypeInfo->dobj.name);
4587 castinfo[i].dobj.name = namebuf.data;
4589 if (OidIsValid(castinfo[i].castfunc))
4592 * We need to make a dependency to ensure the function will be
4593 * dumped first. (In 7.3 and later the regular dependency
4594 * mechanism will handle this for us.)
4596 FuncInfo *funcInfo;
4598 funcInfo = findFuncByOid(castinfo[i].castfunc);
4599 if (funcInfo)
4600 addObjectDependency(&castinfo[i].dobj,
4601 funcInfo->dobj.dumpId);
4605 PQclear(res);
4607 destroyPQExpBuffer(query);
4609 return castinfo;
4613 * getTableAttrs -
4614 * for each interesting table, read info about its attributes
4615 * (names, types, default values, CHECK constraints, etc)
4617 * This is implemented in a very inefficient way right now, looping
4618 * through the tblinfo and doing a join per table to find the attrs and their
4619 * types. However, because we want type names and so forth to be named
4620 * relative to the schema of each table, we couldn't do it in just one
4621 * query. (Maybe one query per schema?)
4623 * modifies tblinfo
4625 void
4626 getTableAttrs(TableInfo *tblinfo, int numTables)
4628 int i,
4630 PQExpBuffer q = createPQExpBuffer();
4631 int i_attnum;
4632 int i_attname;
4633 int i_atttypname;
4634 int i_atttypmod;
4635 int i_attstattarget;
4636 int i_attstorage;
4637 int i_typstorage;
4638 int i_attnotnull;
4639 int i_atthasdef;
4640 int i_attisdropped;
4641 int i_attlen;
4642 int i_attalign;
4643 int i_attislocal;
4644 PGresult *res;
4645 int ntups;
4646 bool hasdefaults;
4648 for (i = 0; i < numTables; i++)
4650 TableInfo *tbinfo = &tblinfo[i];
4652 /* Don't bother to collect info for sequences */
4653 if (tbinfo->relkind == RELKIND_SEQUENCE)
4654 continue;
4656 /* Don't bother with uninteresting tables, either */
4657 if (!tbinfo->interesting)
4658 continue;
4661 * Make sure we are in proper schema for this table; this allows
4662 * correct retrieval of formatted type names and default exprs
4664 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
4666 /* find all the user attributes and their types */
4669 * we must read the attribute names in attribute number order! because
4670 * we will use the attnum to index into the attnames array later. We
4671 * actually ask to order by "attrelid, attnum" because (at least up to
4672 * 7.3) the planner is not smart enough to realize it needn't re-sort
4673 * the output of an indexscan on pg_attribute_relid_attnum_index.
4675 if (g_verbose)
4676 write_msg(NULL, "finding the columns and types of table \"%s\"\n",
4677 tbinfo->dobj.name);
4679 resetPQExpBuffer(q);
4681 if (g_fout->remoteVersion >= 70300)
4683 /* need left join here to not fail on dropped columns ... */
4684 appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
4685 "a.attstattarget, a.attstorage, t.typstorage, "
4686 "a.attnotnull, a.atthasdef, a.attisdropped, "
4687 "a.attlen, a.attalign, a.attislocal, "
4688 "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname "
4689 "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
4690 "ON a.atttypid = t.oid "
4691 "WHERE a.attrelid = '%u'::pg_catalog.oid "
4692 "AND a.attnum > 0::pg_catalog.int2 "
4693 "ORDER BY a.attrelid, a.attnum",
4694 tbinfo->dobj.catId.oid);
4696 else if (g_fout->remoteVersion >= 70100)
4699 * attstattarget doesn't exist in 7.1. It does exist in 7.2, but
4700 * we don't dump it because we can't tell whether it's been
4701 * explicitly set or was just a default.
4703 appendPQExpBuffer(q, "SELECT a.attnum, a.attname, "
4704 "a.atttypmod, -1 AS attstattarget, a.attstorage, "
4705 "t.typstorage, a.attnotnull, a.atthasdef, "
4706 "false AS attisdropped, 0 AS attlen, "
4707 "' ' AS attalign, false AS attislocal, "
4708 "format_type(t.oid,a.atttypmod) AS atttypname "
4709 "FROM pg_attribute a LEFT JOIN pg_type t "
4710 "ON a.atttypid = t.oid "
4711 "WHERE a.attrelid = '%u'::oid "
4712 "AND a.attnum > 0::int2 "
4713 "ORDER BY a.attrelid, a.attnum",
4714 tbinfo->dobj.catId.oid);
4716 else
4718 /* format_type not available before 7.1 */
4719 appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, "
4720 "-1 AS attstattarget, attstorage, "
4721 "attstorage AS typstorage, "
4722 "attnotnull, atthasdef, false AS attisdropped, "
4723 "0 AS attlen, ' ' AS attalign, "
4724 "false AS attislocal, "
4725 "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname "
4726 "FROM pg_attribute a "
4727 "WHERE attrelid = '%u'::oid "
4728 "AND attnum > 0::int2 "
4729 "ORDER BY attrelid, attnum",
4730 tbinfo->dobj.catId.oid);
4733 res = PQexec(g_conn, q->data);
4734 check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
4736 ntups = PQntuples(res);
4738 i_attnum = PQfnumber(res, "attnum");
4739 i_attname = PQfnumber(res, "attname");
4740 i_atttypname = PQfnumber(res, "atttypname");
4741 i_atttypmod = PQfnumber(res, "atttypmod");
4742 i_attstattarget = PQfnumber(res, "attstattarget");
4743 i_attstorage = PQfnumber(res, "attstorage");
4744 i_typstorage = PQfnumber(res, "typstorage");
4745 i_attnotnull = PQfnumber(res, "attnotnull");
4746 i_atthasdef = PQfnumber(res, "atthasdef");
4747 i_attisdropped = PQfnumber(res, "attisdropped");
4748 i_attlen = PQfnumber(res, "attlen");
4749 i_attalign = PQfnumber(res, "attalign");
4750 i_attislocal = PQfnumber(res, "attislocal");
4752 tbinfo->numatts = ntups;
4753 tbinfo->attnames = (char **) malloc(ntups * sizeof(char *));
4754 tbinfo->atttypnames = (char **) malloc(ntups * sizeof(char *));
4755 tbinfo->atttypmod = (int *) malloc(ntups * sizeof(int));
4756 tbinfo->attstattarget = (int *) malloc(ntups * sizeof(int));
4757 tbinfo->attstorage = (char *) malloc(ntups * sizeof(char));
4758 tbinfo->typstorage = (char *) malloc(ntups * sizeof(char));
4759 tbinfo->attisdropped = (bool *) malloc(ntups * sizeof(bool));
4760 tbinfo->attlen = (int *) malloc(ntups * sizeof(int));
4761 tbinfo->attalign = (char *) malloc(ntups * sizeof(char));
4762 tbinfo->attislocal = (bool *) malloc(ntups * sizeof(bool));
4763 tbinfo->notnull = (bool *) malloc(ntups * sizeof(bool));
4764 tbinfo->attrdefs = (AttrDefInfo **) malloc(ntups * sizeof(AttrDefInfo *));
4765 tbinfo->inhAttrs = (bool *) malloc(ntups * sizeof(bool));
4766 tbinfo->inhAttrDef = (bool *) malloc(ntups * sizeof(bool));
4767 tbinfo->inhNotNull = (bool *) malloc(ntups * sizeof(bool));
4768 hasdefaults = false;
4770 for (j = 0; j < ntups; j++)
4772 if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
4774 write_msg(NULL, "invalid column numbering in table \"%s\"\n",
4775 tbinfo->dobj.name);
4776 exit_nicely();
4778 tbinfo->attnames[j] = strdup(PQgetvalue(res, j, i_attname));
4779 tbinfo->atttypnames[j] = strdup(PQgetvalue(res, j, i_atttypname));
4780 tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
4781 tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
4782 tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
4783 tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
4784 tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
4785 tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
4786 tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
4787 tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
4788 tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
4789 tbinfo->attrdefs[j] = NULL; /* fix below */
4790 if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
4791 hasdefaults = true;
4792 /* these flags will be set in flagInhAttrs() */
4793 tbinfo->inhAttrs[j] = false;
4794 tbinfo->inhAttrDef[j] = false;
4795 tbinfo->inhNotNull[j] = false;
4798 PQclear(res);
4802 * ALTER TABLE DROP COLUMN clears pg_attribute.atttypid, so we
4803 * set the column data type to 'TEXT; we will later drop the
4804 * column.
4806 if (binary_upgrade)
4808 for (j = 0; j < ntups; j++)
4810 if (tbinfo->attisdropped[j])
4811 tbinfo->atttypnames[j] = strdup("TEXT");
4816 * Get info about column defaults
4818 if (hasdefaults)
4820 AttrDefInfo *attrdefs;
4821 int numDefaults;
4823 if (g_verbose)
4824 write_msg(NULL, "finding default expressions of table \"%s\"\n",
4825 tbinfo->dobj.name);
4827 resetPQExpBuffer(q);
4828 if (g_fout->remoteVersion >= 70300)
4830 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
4831 "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
4832 "FROM pg_catalog.pg_attrdef "
4833 "WHERE adrelid = '%u'::pg_catalog.oid",
4834 tbinfo->dobj.catId.oid);
4836 else if (g_fout->remoteVersion >= 70200)
4838 /* 7.2 did not have OIDs in pg_attrdef */
4839 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, adnum, "
4840 "pg_get_expr(adbin, adrelid) AS adsrc "
4841 "FROM pg_attrdef "
4842 "WHERE adrelid = '%u'::oid",
4843 tbinfo->dobj.catId.oid);
4845 else if (g_fout->remoteVersion >= 70100)
4847 /* no pg_get_expr, so must rely on adsrc */
4848 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, adsrc "
4849 "FROM pg_attrdef "
4850 "WHERE adrelid = '%u'::oid",
4851 tbinfo->dobj.catId.oid);
4853 else
4855 /* no pg_get_expr, no tableoid either */
4856 appendPQExpBuffer(q, "SELECT "
4857 "(SELECT oid FROM pg_class WHERE relname = 'pg_attrdef') AS tableoid, "
4858 "oid, adnum, adsrc "
4859 "FROM pg_attrdef "
4860 "WHERE adrelid = '%u'::oid",
4861 tbinfo->dobj.catId.oid);
4863 res = PQexec(g_conn, q->data);
4864 check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
4866 numDefaults = PQntuples(res);
4867 attrdefs = (AttrDefInfo *) malloc(numDefaults * sizeof(AttrDefInfo));
4869 for (j = 0; j < numDefaults; j++)
4871 int adnum;
4873 attrdefs[j].dobj.objType = DO_ATTRDEF;
4874 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
4875 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
4876 AssignDumpId(&attrdefs[j].dobj);
4877 attrdefs[j].adtable = tbinfo;
4878 attrdefs[j].adnum = adnum = atoi(PQgetvalue(res, j, 2));
4879 attrdefs[j].adef_expr = strdup(PQgetvalue(res, j, 3));
4881 attrdefs[j].dobj.name = strdup(tbinfo->dobj.name);
4882 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
4884 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
4887 * Defaults on a VIEW must always be dumped as separate ALTER
4888 * TABLE commands. Defaults on regular tables are dumped as
4889 * part of the CREATE TABLE if possible. To check if it's
4890 * safe, we mark the default as needing to appear before the
4891 * CREATE.
4893 if (tbinfo->relkind == RELKIND_VIEW)
4895 attrdefs[j].separate = true;
4896 /* needed in case pre-7.3 DB: */
4897 addObjectDependency(&attrdefs[j].dobj,
4898 tbinfo->dobj.dumpId);
4900 else
4902 attrdefs[j].separate = false;
4903 addObjectDependency(&tbinfo->dobj,
4904 attrdefs[j].dobj.dumpId);
4907 if (adnum <= 0 || adnum > ntups)
4909 write_msg(NULL, "invalid adnum value %d for table \"%s\"\n",
4910 adnum, tbinfo->dobj.name);
4911 exit_nicely();
4913 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
4915 PQclear(res);
4919 * Get info about table CHECK constraints
4921 if (tbinfo->ncheck > 0)
4923 ConstraintInfo *constrs;
4924 int numConstrs;
4926 if (g_verbose)
4927 write_msg(NULL, "finding check constraints for table \"%s\"\n",
4928 tbinfo->dobj.name);
4930 resetPQExpBuffer(q);
4931 if (g_fout->remoteVersion >= 80400)
4933 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
4934 "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
4935 "conislocal "
4936 "FROM pg_catalog.pg_constraint "
4937 "WHERE conrelid = '%u'::pg_catalog.oid "
4938 " AND contype = 'c' "
4939 "ORDER BY conname",
4940 tbinfo->dobj.catId.oid);
4942 else if (g_fout->remoteVersion >= 70400)
4944 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
4945 "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
4946 "true AS conislocal "
4947 "FROM pg_catalog.pg_constraint "
4948 "WHERE conrelid = '%u'::pg_catalog.oid "
4949 " AND contype = 'c' "
4950 "ORDER BY conname",
4951 tbinfo->dobj.catId.oid);
4953 else if (g_fout->remoteVersion >= 70300)
4955 /* no pg_get_constraintdef, must use consrc */
4956 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
4957 "'CHECK (' || consrc || ')' AS consrc, "
4958 "true AS conislocal "
4959 "FROM pg_catalog.pg_constraint "
4960 "WHERE conrelid = '%u'::pg_catalog.oid "
4961 " AND contype = 'c' "
4962 "ORDER BY conname",
4963 tbinfo->dobj.catId.oid);
4965 else if (g_fout->remoteVersion >= 70200)
4967 /* 7.2 did not have OIDs in pg_relcheck */
4968 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, "
4969 "rcname AS conname, "
4970 "'CHECK (' || rcsrc || ')' AS consrc, "
4971 "true AS conislocal "
4972 "FROM pg_relcheck "
4973 "WHERE rcrelid = '%u'::oid "
4974 "ORDER BY rcname",
4975 tbinfo->dobj.catId.oid);
4977 else if (g_fout->remoteVersion >= 70100)
4979 appendPQExpBuffer(q, "SELECT tableoid, oid, "
4980 "rcname AS conname, "
4981 "'CHECK (' || rcsrc || ')' AS consrc, "
4982 "true AS conislocal "
4983 "FROM pg_relcheck "
4984 "WHERE rcrelid = '%u'::oid "
4985 "ORDER BY rcname",
4986 tbinfo->dobj.catId.oid);
4988 else
4990 /* no tableoid in 7.0 */
4991 appendPQExpBuffer(q, "SELECT "
4992 "(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
4993 "oid, rcname AS conname, "
4994 "'CHECK (' || rcsrc || ')' AS consrc, "
4995 "true AS conislocal "
4996 "FROM pg_relcheck "
4997 "WHERE rcrelid = '%u'::oid "
4998 "ORDER BY rcname",
4999 tbinfo->dobj.catId.oid);
5001 res = PQexec(g_conn, q->data);
5002 check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
5004 numConstrs = PQntuples(res);
5005 if (numConstrs != tbinfo->ncheck)
5007 write_msg(NULL, "expected %d check constraints on table \"%s\" but found %d\n",
5008 tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
5009 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
5010 exit_nicely();
5013 constrs = (ConstraintInfo *) malloc(numConstrs * sizeof(ConstraintInfo));
5014 tbinfo->checkexprs = constrs;
5016 for (j = 0; j < numConstrs; j++)
5018 constrs[j].dobj.objType = DO_CONSTRAINT;
5019 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
5020 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
5021 AssignDumpId(&constrs[j].dobj);
5022 constrs[j].dobj.name = strdup(PQgetvalue(res, j, 2));
5023 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
5024 constrs[j].contable = tbinfo;
5025 constrs[j].condomain = NULL;
5026 constrs[j].contype = 'c';
5027 constrs[j].condef = strdup(PQgetvalue(res, j, 3));
5028 constrs[j].confrelid = InvalidOid;
5029 constrs[j].conindex = 0;
5030 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
5031 constrs[j].separate = false;
5033 constrs[j].dobj.dump = tbinfo->dobj.dump;
5036 * Mark the constraint as needing to appear before the table
5037 * --- this is so that any other dependencies of the
5038 * constraint will be emitted before we try to create the
5039 * table.
5041 addObjectDependency(&tbinfo->dobj,
5042 constrs[j].dobj.dumpId);
5045 * If the constraint is inherited, this will be detected
5046 * later (in pre-8.4 databases). We also detect later if the
5047 * constraint must be split out from the table definition.
5050 PQclear(res);
5054 destroyPQExpBuffer(q);
5059 * getTSParsers:
5060 * read all text search parsers in the system catalogs and return them
5061 * in the TSParserInfo* structure
5063 * numTSParsers is set to the number of parsers read in
5065 TSParserInfo *
5066 getTSParsers(int *numTSParsers)
5068 PGresult *res;
5069 int ntups;
5070 int i;
5071 PQExpBuffer query = createPQExpBuffer();
5072 TSParserInfo *prsinfo;
5073 int i_tableoid;
5074 int i_oid;
5075 int i_prsname;
5076 int i_prsnamespace;
5077 int i_prsstart;
5078 int i_prstoken;
5079 int i_prsend;
5080 int i_prsheadline;
5081 int i_prslextype;
5083 /* Before 8.3, there is no built-in text search support */
5084 if (g_fout->remoteVersion < 80300)
5086 *numTSParsers = 0;
5087 return NULL;
5091 * find all text search objects, including builtin ones; we filter out
5092 * system-defined objects at dump-out time.
5095 /* Make sure we are in proper schema */
5096 selectSourceSchema("pg_catalog");
5098 appendPQExpBuffer(query, "SELECT tableoid, oid, prsname, prsnamespace, "
5099 "prsstart::oid, prstoken::oid, "
5100 "prsend::oid, prsheadline::oid, prslextype::oid "
5101 "FROM pg_ts_parser");
5103 res = PQexec(g_conn, query->data);
5104 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5106 ntups = PQntuples(res);
5107 *numTSParsers = ntups;
5109 prsinfo = (TSParserInfo *) malloc(ntups * sizeof(TSParserInfo));
5111 i_tableoid = PQfnumber(res, "tableoid");
5112 i_oid = PQfnumber(res, "oid");
5113 i_prsname = PQfnumber(res, "prsname");
5114 i_prsnamespace = PQfnumber(res, "prsnamespace");
5115 i_prsstart = PQfnumber(res, "prsstart");
5116 i_prstoken = PQfnumber(res, "prstoken");
5117 i_prsend = PQfnumber(res, "prsend");
5118 i_prsheadline = PQfnumber(res, "prsheadline");
5119 i_prslextype = PQfnumber(res, "prslextype");
5121 for (i = 0; i < ntups; i++)
5123 prsinfo[i].dobj.objType = DO_TSPARSER;
5124 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5125 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5126 AssignDumpId(&prsinfo[i].dobj);
5127 prsinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_prsname));
5128 prsinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)),
5129 prsinfo[i].dobj.catId.oid);
5130 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
5131 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
5132 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
5133 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
5134 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
5136 /* Decide whether we want to dump it */
5137 selectDumpableObject(&(prsinfo[i].dobj));
5140 PQclear(res);
5142 destroyPQExpBuffer(query);
5144 return prsinfo;
5148 * getTSDictionaries:
5149 * read all text search dictionaries in the system catalogs and return them
5150 * in the TSDictInfo* structure
5152 * numTSDicts is set to the number of dictionaries read in
5154 TSDictInfo *
5155 getTSDictionaries(int *numTSDicts)
5157 PGresult *res;
5158 int ntups;
5159 int i;
5160 PQExpBuffer query = createPQExpBuffer();
5161 TSDictInfo *dictinfo;
5162 int i_tableoid;
5163 int i_oid;
5164 int i_dictname;
5165 int i_dictnamespace;
5166 int i_rolname;
5167 int i_dicttemplate;
5168 int i_dictinitoption;
5170 /* Before 8.3, there is no built-in text search support */
5171 if (g_fout->remoteVersion < 80300)
5173 *numTSDicts = 0;
5174 return NULL;
5177 /* Make sure we are in proper schema */
5178 selectSourceSchema("pg_catalog");
5180 appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
5181 "dictnamespace, (%s dictowner) AS rolname, "
5182 "dicttemplate, dictinitoption "
5183 "FROM pg_ts_dict",
5184 username_subquery);
5186 res = PQexec(g_conn, query->data);
5187 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5189 ntups = PQntuples(res);
5190 *numTSDicts = ntups;
5192 dictinfo = (TSDictInfo *) malloc(ntups * sizeof(TSDictInfo));
5194 i_tableoid = PQfnumber(res, "tableoid");
5195 i_oid = PQfnumber(res, "oid");
5196 i_dictname = PQfnumber(res, "dictname");
5197 i_dictnamespace = PQfnumber(res, "dictnamespace");
5198 i_rolname = PQfnumber(res, "rolname");
5199 i_dictinitoption = PQfnumber(res, "dictinitoption");
5200 i_dicttemplate = PQfnumber(res, "dicttemplate");
5202 for (i = 0; i < ntups; i++)
5204 dictinfo[i].dobj.objType = DO_TSDICT;
5205 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5206 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5207 AssignDumpId(&dictinfo[i].dobj);
5208 dictinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_dictname));
5209 dictinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)),
5210 dictinfo[i].dobj.catId.oid);
5211 dictinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
5212 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
5213 if (PQgetisnull(res, i, i_dictinitoption))
5214 dictinfo[i].dictinitoption = NULL;
5215 else
5216 dictinfo[i].dictinitoption = strdup(PQgetvalue(res, i, i_dictinitoption));
5218 /* Decide whether we want to dump it */
5219 selectDumpableObject(&(dictinfo[i].dobj));
5222 PQclear(res);
5224 destroyPQExpBuffer(query);
5226 return dictinfo;
5230 * getTSTemplates:
5231 * read all text search templates in the system catalogs and return them
5232 * in the TSTemplateInfo* structure
5234 * numTSTemplates is set to the number of templates read in
5236 TSTemplateInfo *
5237 getTSTemplates(int *numTSTemplates)
5239 PGresult *res;
5240 int ntups;
5241 int i;
5242 PQExpBuffer query = createPQExpBuffer();
5243 TSTemplateInfo *tmplinfo;
5244 int i_tableoid;
5245 int i_oid;
5246 int i_tmplname;
5247 int i_tmplnamespace;
5248 int i_tmplinit;
5249 int i_tmpllexize;
5251 /* Before 8.3, there is no built-in text search support */
5252 if (g_fout->remoteVersion < 80300)
5254 *numTSTemplates = 0;
5255 return NULL;
5258 /* Make sure we are in proper schema */
5259 selectSourceSchema("pg_catalog");
5261 appendPQExpBuffer(query, "SELECT tableoid, oid, tmplname, "
5262 "tmplnamespace, tmplinit::oid, tmpllexize::oid "
5263 "FROM pg_ts_template");
5265 res = PQexec(g_conn, query->data);
5266 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5268 ntups = PQntuples(res);
5269 *numTSTemplates = ntups;
5271 tmplinfo = (TSTemplateInfo *) malloc(ntups * sizeof(TSTemplateInfo));
5273 i_tableoid = PQfnumber(res, "tableoid");
5274 i_oid = PQfnumber(res, "oid");
5275 i_tmplname = PQfnumber(res, "tmplname");
5276 i_tmplnamespace = PQfnumber(res, "tmplnamespace");
5277 i_tmplinit = PQfnumber(res, "tmplinit");
5278 i_tmpllexize = PQfnumber(res, "tmpllexize");
5280 for (i = 0; i < ntups; i++)
5282 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
5283 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5284 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5285 AssignDumpId(&tmplinfo[i].dobj);
5286 tmplinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_tmplname));
5287 tmplinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)),
5288 tmplinfo[i].dobj.catId.oid);
5289 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
5290 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
5292 /* Decide whether we want to dump it */
5293 selectDumpableObject(&(tmplinfo[i].dobj));
5296 PQclear(res);
5298 destroyPQExpBuffer(query);
5300 return tmplinfo;
5304 * getTSConfigurations:
5305 * read all text search configurations in the system catalogs and return
5306 * them in the TSConfigInfo* structure
5308 * numTSConfigs is set to the number of configurations read in
5310 TSConfigInfo *
5311 getTSConfigurations(int *numTSConfigs)
5313 PGresult *res;
5314 int ntups;
5315 int i;
5316 PQExpBuffer query = createPQExpBuffer();
5317 TSConfigInfo *cfginfo;
5318 int i_tableoid;
5319 int i_oid;
5320 int i_cfgname;
5321 int i_cfgnamespace;
5322 int i_rolname;
5323 int i_cfgparser;
5325 /* Before 8.3, there is no built-in text search support */
5326 if (g_fout->remoteVersion < 80300)
5328 *numTSConfigs = 0;
5329 return NULL;
5332 /* Make sure we are in proper schema */
5333 selectSourceSchema("pg_catalog");
5335 appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
5336 "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
5337 "FROM pg_ts_config",
5338 username_subquery);
5340 res = PQexec(g_conn, query->data);
5341 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5343 ntups = PQntuples(res);
5344 *numTSConfigs = ntups;
5346 cfginfo = (TSConfigInfo *) malloc(ntups * sizeof(TSConfigInfo));
5348 i_tableoid = PQfnumber(res, "tableoid");
5349 i_oid = PQfnumber(res, "oid");
5350 i_cfgname = PQfnumber(res, "cfgname");
5351 i_cfgnamespace = PQfnumber(res, "cfgnamespace");
5352 i_rolname = PQfnumber(res, "rolname");
5353 i_cfgparser = PQfnumber(res, "cfgparser");
5355 for (i = 0; i < ntups; i++)
5357 cfginfo[i].dobj.objType = DO_TSCONFIG;
5358 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5359 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5360 AssignDumpId(&cfginfo[i].dobj);
5361 cfginfo[i].dobj.name = strdup(PQgetvalue(res, i, i_cfgname));
5362 cfginfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)),
5363 cfginfo[i].dobj.catId.oid);
5364 cfginfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
5365 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
5367 /* Decide whether we want to dump it */
5368 selectDumpableObject(&(cfginfo[i].dobj));
5371 PQclear(res);
5373 destroyPQExpBuffer(query);
5375 return cfginfo;
5379 * getForeignDataWrappers:
5380 * read all foreign-data wrappers in the system catalogs and return
5381 * them in the FdwInfo* structure
5383 * numForeignDataWrappers is set to the number of fdws read in
5385 FdwInfo *
5386 getForeignDataWrappers(int *numForeignDataWrappers)
5388 PGresult *res;
5389 int ntups;
5390 int i;
5391 PQExpBuffer query = createPQExpBuffer();
5392 FdwInfo *fdwinfo;
5393 int i_oid;
5394 int i_fdwname;
5395 int i_rolname;
5396 int i_fdwvalidator;
5397 int i_fdwacl;
5398 int i_fdwoptions;
5400 /* Before 8.4, there are no foreign-data wrappers */
5401 if (g_fout->remoteVersion < 80400)
5403 *numForeignDataWrappers = 0;
5404 return NULL;
5407 /* Make sure we are in proper schema */
5408 selectSourceSchema("pg_catalog");
5410 appendPQExpBuffer(query, "SELECT oid, fdwname, "
5411 "(%s fdwowner) AS rolname, fdwvalidator::pg_catalog.regproc, fdwacl,"
5412 "array_to_string(ARRAY("
5413 " SELECT option_name || ' ' || quote_literal(option_value) "
5414 " FROM pg_options_to_table(fdwoptions)), ', ') AS fdwoptions "
5415 "FROM pg_foreign_data_wrapper",
5416 username_subquery);
5418 res = PQexec(g_conn, query->data);
5419 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5421 ntups = PQntuples(res);
5422 *numForeignDataWrappers = ntups;
5424 fdwinfo = (FdwInfo *) malloc(ntups * sizeof(FdwInfo));
5426 i_oid = PQfnumber(res, "oid");
5427 i_fdwname = PQfnumber(res, "fdwname");
5428 i_rolname = PQfnumber(res, "rolname");
5429 i_fdwvalidator = PQfnumber(res, "fdwvalidator");
5430 i_fdwacl = PQfnumber(res, "fdwacl");
5431 i_fdwoptions = PQfnumber(res, "fdwoptions");
5433 for (i = 0; i < ntups; i++)
5435 fdwinfo[i].dobj.objType = DO_FDW;
5436 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5437 AssignDumpId(&fdwinfo[i].dobj);
5438 fdwinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_fdwname));
5439 fdwinfo[i].dobj.namespace = NULL;
5440 fdwinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
5441 fdwinfo[i].fdwvalidator = strdup(PQgetvalue(res, i, i_fdwvalidator));
5442 fdwinfo[i].fdwoptions = strdup(PQgetvalue(res, i, i_fdwoptions));
5443 fdwinfo[i].fdwacl = strdup(PQgetvalue(res, i, i_fdwacl));
5446 /* Decide whether we want to dump it */
5447 selectDumpableObject(&(fdwinfo[i].dobj));
5450 PQclear(res);
5452 destroyPQExpBuffer(query);
5454 return fdwinfo;
5458 * getForeignServers:
5459 * read all foreign servers in the system catalogs and return
5460 * them in the ForeignServerInfo * structure
5462 * numForeignServers is set to the number of servers read in
5464 ForeignServerInfo *
5465 getForeignServers(int *numForeignServers)
5467 PGresult *res;
5468 int ntups;
5469 int i;
5470 PQExpBuffer query = createPQExpBuffer();
5471 ForeignServerInfo *srvinfo;
5472 int i_oid;
5473 int i_srvname;
5474 int i_rolname;
5475 int i_srvfdw;
5476 int i_srvtype;
5477 int i_srvversion;
5478 int i_srvacl;
5479 int i_srvoptions;
5481 /* Before 8.4, there are no foreign servers */
5482 if (g_fout->remoteVersion < 80400)
5484 *numForeignServers = 0;
5485 return NULL;
5488 /* Make sure we are in proper schema */
5489 selectSourceSchema("pg_catalog");
5491 appendPQExpBuffer(query, "SELECT oid, srvname, "
5492 "(%s srvowner) AS rolname, "
5493 "srvfdw, srvtype, srvversion, srvacl,"
5494 "array_to_string(ARRAY("
5495 " SELECT option_name || ' ' || quote_literal(option_value) "
5496 " FROM pg_options_to_table(srvoptions)), ', ') AS srvoptions "
5497 "FROM pg_foreign_server",
5498 username_subquery);
5500 res = PQexec(g_conn, query->data);
5501 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5503 ntups = PQntuples(res);
5504 *numForeignServers = ntups;
5506 srvinfo = (ForeignServerInfo *) malloc(ntups * sizeof(ForeignServerInfo));
5508 i_oid = PQfnumber(res, "oid");
5509 i_srvname = PQfnumber(res, "srvname");
5510 i_rolname = PQfnumber(res, "rolname");
5511 i_srvfdw = PQfnumber(res, "srvfdw");
5512 i_srvtype = PQfnumber(res, "srvtype");
5513 i_srvversion = PQfnumber(res, "srvversion");
5514 i_srvacl = PQfnumber(res, "srvacl");
5515 i_srvoptions = PQfnumber(res, "srvoptions");
5517 for (i = 0; i < ntups; i++)
5519 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
5520 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5521 AssignDumpId(&srvinfo[i].dobj);
5522 srvinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_srvname));
5523 srvinfo[i].dobj.namespace = NULL;
5524 srvinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
5525 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
5526 srvinfo[i].srvtype = strdup(PQgetvalue(res, i, i_srvtype));
5527 srvinfo[i].srvversion = strdup(PQgetvalue(res, i, i_srvversion));
5528 srvinfo[i].srvoptions = strdup(PQgetvalue(res, i, i_srvoptions));
5529 srvinfo[i].srvacl = strdup(PQgetvalue(res, i, i_srvacl));
5531 /* Decide whether we want to dump it */
5532 selectDumpableObject(&(srvinfo[i].dobj));
5535 PQclear(res);
5537 destroyPQExpBuffer(query);
5539 return srvinfo;
5543 * dumpComment --
5545 * This routine is used to dump any comments associated with the
5546 * object handed to this routine. The routine takes a constant character
5547 * string for the target part of the comment-creation command, plus
5548 * the namespace and owner of the object (for labeling the ArchiveEntry),
5549 * plus catalog ID and subid which are the lookup key for pg_description,
5550 * plus the dump ID for the object (for setting a dependency).
5551 * If a matching pg_description entry is found, it is dumped.
5553 * Note: although this routine takes a dumpId for dependency purposes,
5554 * that purpose is just to mark the dependency in the emitted dump file
5555 * for possible future use by pg_restore. We do NOT use it for determining
5556 * ordering of the comment in the dump file, because this routine is called
5557 * after dependency sorting occurs. This routine should be called just after
5558 * calling ArchiveEntry() for the specified object.
5560 static void
5561 dumpComment(Archive *fout, const char *target,
5562 const char *namespace, const char *owner,
5563 CatalogId catalogId, int subid, DumpId dumpId)
5565 CommentItem *comments;
5566 int ncomments;
5568 /* Comments are SCHEMA not data */
5569 if (dataOnly)
5570 return;
5572 /* Search for comments associated with catalogId, using table */
5573 ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
5574 &comments);
5576 /* Is there one matching the subid? */
5577 while (ncomments > 0)
5579 if (comments->objsubid == subid)
5580 break;
5581 comments++;
5582 ncomments--;
5585 /* If a comment exists, build COMMENT ON statement */
5586 if (ncomments > 0)
5588 PQExpBuffer query = createPQExpBuffer();
5590 appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
5591 appendStringLiteralAH(query, comments->descr, fout);
5592 appendPQExpBuffer(query, ";\n");
5595 * We mark comments as SECTION_NONE because they really belong
5596 * in the same section as their parent, whether that is
5597 * pre-data or post-data.
5599 ArchiveEntry(fout, nilCatalogId, createDumpId(),
5600 target, namespace, NULL, owner,
5601 false, "COMMENT", SECTION_NONE,
5602 query->data, "", NULL,
5603 &(dumpId), 1,
5604 NULL, NULL);
5606 destroyPQExpBuffer(query);
5611 * dumpTableComment --
5613 * As above, but dump comments for both the specified table (or view)
5614 * and its columns.
5616 static void
5617 dumpTableComment(Archive *fout, TableInfo *tbinfo,
5618 const char *reltypename)
5620 CommentItem *comments;
5621 int ncomments;
5622 PQExpBuffer query;
5623 PQExpBuffer target;
5625 /* Comments are SCHEMA not data */
5626 if (dataOnly)
5627 return;
5629 /* Search for comments associated with relation, using table */
5630 ncomments = findComments(fout,
5631 tbinfo->dobj.catId.tableoid,
5632 tbinfo->dobj.catId.oid,
5633 &comments);
5635 /* If comments exist, build COMMENT ON statements */
5636 if (ncomments <= 0)
5637 return;
5639 query = createPQExpBuffer();
5640 target = createPQExpBuffer();
5642 while (ncomments > 0)
5644 const char *descr = comments->descr;
5645 int objsubid = comments->objsubid;
5647 if (objsubid == 0)
5649 resetPQExpBuffer(target);
5650 appendPQExpBuffer(target, "%s %s", reltypename,
5651 fmtId(tbinfo->dobj.name));
5653 resetPQExpBuffer(query);
5654 appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
5655 appendStringLiteralAH(query, descr, fout);
5656 appendPQExpBuffer(query, ";\n");
5658 ArchiveEntry(fout, nilCatalogId, createDumpId(),
5659 target->data,
5660 tbinfo->dobj.namespace->dobj.name,
5661 NULL, tbinfo->rolname,
5662 false, "COMMENT", SECTION_NONE,
5663 query->data, "", NULL,
5664 &(tbinfo->dobj.dumpId), 1,
5665 NULL, NULL);
5667 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
5669 resetPQExpBuffer(target);
5670 appendPQExpBuffer(target, "COLUMN %s.",
5671 fmtId(tbinfo->dobj.name));
5672 appendPQExpBuffer(target, "%s",
5673 fmtId(tbinfo->attnames[objsubid - 1]));
5675 resetPQExpBuffer(query);
5676 appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
5677 appendStringLiteralAH(query, descr, fout);
5678 appendPQExpBuffer(query, ";\n");
5680 ArchiveEntry(fout, nilCatalogId, createDumpId(),
5681 target->data,
5682 tbinfo->dobj.namespace->dobj.name,
5683 NULL, tbinfo->rolname,
5684 false, "COMMENT", SECTION_NONE,
5685 query->data, "", NULL,
5686 &(tbinfo->dobj.dumpId), 1,
5687 NULL, NULL);
5690 comments++;
5691 ncomments--;
5694 destroyPQExpBuffer(query);
5695 destroyPQExpBuffer(target);
5699 * findComments --
5701 * Find the comment(s), if any, associated with the given object. All the
5702 * objsubid values associated with the given classoid/objoid are found with
5703 * one search.
5705 static int
5706 findComments(Archive *fout, Oid classoid, Oid objoid,
5707 CommentItem **items)
5709 /* static storage for table of comments */
5710 static CommentItem *comments = NULL;
5711 static int ncomments = -1;
5713 CommentItem *middle = NULL;
5714 CommentItem *low;
5715 CommentItem *high;
5716 int nmatch;
5718 /* Get comments if we didn't already */
5719 if (ncomments < 0)
5720 ncomments = collectComments(fout, &comments);
5723 * Pre-7.2, pg_description does not contain classoid, so collectComments
5724 * just stores a zero. If there's a collision on object OID, well, you
5725 * get duplicate comments.
5727 if (fout->remoteVersion < 70200)
5728 classoid = 0;
5731 * Do binary search to find some item matching the object.
5733 low = &comments[0];
5734 high = &comments[ncomments - 1];
5735 while (low <= high)
5737 middle = low + (high - low) / 2;
5739 if (classoid < middle->classoid)
5740 high = middle - 1;
5741 else if (classoid > middle->classoid)
5742 low = middle + 1;
5743 else if (objoid < middle->objoid)
5744 high = middle - 1;
5745 else if (objoid > middle->objoid)
5746 low = middle + 1;
5747 else
5748 break; /* found a match */
5751 if (low > high) /* no matches */
5753 *items = NULL;
5754 return 0;
5758 * Now determine how many items match the object. The search loop
5759 * invariant still holds: only items between low and high inclusive could
5760 * match.
5762 nmatch = 1;
5763 while (middle > low)
5765 if (classoid != middle[-1].classoid ||
5766 objoid != middle[-1].objoid)
5767 break;
5768 middle--;
5769 nmatch++;
5772 *items = middle;
5774 middle += nmatch;
5775 while (middle <= high)
5777 if (classoid != middle->classoid ||
5778 objoid != middle->objoid)
5779 break;
5780 middle++;
5781 nmatch++;
5784 return nmatch;
5788 * collectComments --
5790 * Construct a table of all comments available for database objects.
5791 * We used to do per-object queries for the comments, but it's much faster
5792 * to pull them all over at once, and on most databases the memory cost
5793 * isn't high.
5795 * The table is sorted by classoid/objid/objsubid for speed in lookup.
5797 static int
5798 collectComments(Archive *fout, CommentItem **items)
5800 PGresult *res;
5801 PQExpBuffer query;
5802 int i_description;
5803 int i_classoid;
5804 int i_objoid;
5805 int i_objsubid;
5806 int ntups;
5807 int i;
5808 CommentItem *comments;
5811 * Note we do NOT change source schema here; preserve the caller's
5812 * setting, instead.
5815 query = createPQExpBuffer();
5817 if (fout->remoteVersion >= 70300)
5819 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
5820 "FROM pg_catalog.pg_description "
5821 "ORDER BY classoid, objoid, objsubid");
5823 else if (fout->remoteVersion >= 70200)
5825 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
5826 "FROM pg_description "
5827 "ORDER BY classoid, objoid, objsubid");
5829 else
5831 /* Note: this will fail to find attribute comments in pre-7.2... */
5832 appendPQExpBuffer(query, "SELECT description, 0 AS classoid, objoid, 0 AS objsubid "
5833 "FROM pg_description "
5834 "ORDER BY objoid");
5837 res = PQexec(g_conn, query->data);
5838 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5840 /* Construct lookup table containing OIDs in numeric form */
5842 i_description = PQfnumber(res, "description");
5843 i_classoid = PQfnumber(res, "classoid");
5844 i_objoid = PQfnumber(res, "objoid");
5845 i_objsubid = PQfnumber(res, "objsubid");
5847 ntups = PQntuples(res);
5849 comments = (CommentItem *) malloc(ntups * sizeof(CommentItem));
5851 for (i = 0; i < ntups; i++)
5853 comments[i].descr = PQgetvalue(res, i, i_description);
5854 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
5855 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
5856 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
5859 /* Do NOT free the PGresult since we are keeping pointers into it */
5860 destroyPQExpBuffer(query);
5862 *items = comments;
5863 return ntups;
5867 * dumpDumpableObject
5869 * This routine and its subsidiaries are responsible for creating
5870 * ArchiveEntries (TOC objects) for each object to be dumped.
5872 static void
5873 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
5875 switch (dobj->objType)
5877 case DO_NAMESPACE:
5878 dumpNamespace(fout, (NamespaceInfo *) dobj);
5879 break;
5880 case DO_TYPE:
5881 dumpType(fout, (TypeInfo *) dobj);
5882 break;
5883 case DO_SHELL_TYPE:
5884 dumpShellType(fout, (ShellTypeInfo *) dobj);
5885 break;
5886 case DO_FUNC:
5887 dumpFunc(fout, (FuncInfo *) dobj);
5888 break;
5889 case DO_AGG:
5890 dumpAgg(fout, (AggInfo *) dobj);
5891 break;
5892 case DO_OPERATOR:
5893 dumpOpr(fout, (OprInfo *) dobj);
5894 break;
5895 case DO_OPCLASS:
5896 dumpOpclass(fout, (OpclassInfo *) dobj);
5897 break;
5898 case DO_OPFAMILY:
5899 dumpOpfamily(fout, (OpfamilyInfo *) dobj);
5900 break;
5901 case DO_CONVERSION:
5902 dumpConversion(fout, (ConvInfo *) dobj);
5903 break;
5904 case DO_TABLE:
5905 dumpTable(fout, (TableInfo *) dobj);
5906 break;
5907 case DO_ATTRDEF:
5908 dumpAttrDef(fout, (AttrDefInfo *) dobj);
5909 break;
5910 case DO_INDEX:
5911 dumpIndex(fout, (IndxInfo *) dobj);
5912 break;
5913 case DO_RULE:
5914 dumpRule(fout, (RuleInfo *) dobj);
5915 break;
5916 case DO_TRIGGER:
5917 dumpTrigger(fout, (TriggerInfo *) dobj);
5918 break;
5919 case DO_CONSTRAINT:
5920 dumpConstraint(fout, (ConstraintInfo *) dobj);
5921 break;
5922 case DO_FK_CONSTRAINT:
5923 dumpConstraint(fout, (ConstraintInfo *) dobj);
5924 break;
5925 case DO_PROCLANG:
5926 dumpProcLang(fout, (ProcLangInfo *) dobj);
5927 break;
5928 case DO_CAST:
5929 dumpCast(fout, (CastInfo *) dobj);
5930 break;
5931 case DO_TABLE_DATA:
5932 dumpTableData(fout, (TableDataInfo *) dobj);
5933 break;
5934 case DO_DUMMY_TYPE:
5935 /* table rowtypes and array types are never dumped separately */
5936 break;
5937 case DO_TSPARSER:
5938 dumpTSParser(fout, (TSParserInfo *) dobj);
5939 break;
5940 case DO_TSDICT:
5941 dumpTSDictionary(fout, (TSDictInfo *) dobj);
5942 break;
5943 case DO_TSTEMPLATE:
5944 dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
5945 break;
5946 case DO_TSCONFIG:
5947 dumpTSConfig(fout, (TSConfigInfo *) dobj);
5948 break;
5949 case DO_FDW:
5950 dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
5951 break;
5952 case DO_FOREIGN_SERVER:
5953 dumpForeignServer(fout, (ForeignServerInfo *) dobj);
5954 break;
5955 case DO_BLOBS:
5956 ArchiveEntry(fout, dobj->catId, dobj->dumpId,
5957 dobj->name, NULL, NULL, "",
5958 false, "BLOBS", SECTION_DATA,
5959 "", "", NULL,
5960 dobj->dependencies, dobj->nDeps,
5961 dumpBlobs, NULL);
5962 break;
5963 case DO_BLOB_COMMENTS:
5964 ArchiveEntry(fout, dobj->catId, dobj->dumpId,
5965 dobj->name, NULL, NULL, "",
5966 false, "BLOB COMMENTS", SECTION_DATA,
5967 "", "", NULL,
5968 dobj->dependencies, dobj->nDeps,
5969 dumpBlobComments, NULL);
5970 break;
5975 * dumpNamespace
5976 * writes out to fout the queries to recreate a user-defined namespace
5978 static void
5979 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
5981 PQExpBuffer q;
5982 PQExpBuffer delq;
5983 char *qnspname;
5985 /* Skip if not to be dumped */
5986 if (!nspinfo->dobj.dump || dataOnly)
5987 return;
5989 /* don't dump dummy namespace from pre-7.3 source */
5990 if (strlen(nspinfo->dobj.name) == 0)
5991 return;
5993 q = createPQExpBuffer();
5994 delq = createPQExpBuffer();
5996 qnspname = strdup(fmtId(nspinfo->dobj.name));
5998 appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
6000 appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
6002 ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
6003 nspinfo->dobj.name,
6004 NULL, NULL,
6005 nspinfo->rolname,
6006 false, "SCHEMA", SECTION_PRE_DATA,
6007 q->data, delq->data, NULL,
6008 nspinfo->dobj.dependencies, nspinfo->dobj.nDeps,
6009 NULL, NULL);
6011 /* Dump Schema Comments */
6012 resetPQExpBuffer(q);
6013 appendPQExpBuffer(q, "SCHEMA %s", qnspname);
6014 dumpComment(fout, q->data,
6015 NULL, nspinfo->rolname,
6016 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
6018 dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
6019 qnspname, NULL, nspinfo->dobj.name, NULL,
6020 nspinfo->rolname, nspinfo->nspacl);
6022 free(qnspname);
6024 destroyPQExpBuffer(q);
6025 destroyPQExpBuffer(delq);
6029 * dumpType
6030 * writes out to fout the queries to recreate a user-defined type
6032 static void
6033 dumpType(Archive *fout, TypeInfo *tinfo)
6035 /* Skip if not to be dumped */
6036 if (!tinfo->dobj.dump || dataOnly)
6037 return;
6039 /* Dump out in proper style */
6040 if (tinfo->typtype == TYPTYPE_BASE)
6041 dumpBaseType(fout, tinfo);
6042 else if (tinfo->typtype == TYPTYPE_DOMAIN)
6043 dumpDomain(fout, tinfo);
6044 else if (tinfo->typtype == TYPTYPE_COMPOSITE)
6045 dumpCompositeType(fout, tinfo);
6046 else if (tinfo->typtype == TYPTYPE_ENUM)
6047 dumpEnumType(fout, tinfo);
6051 * dumpEnumType
6052 * writes out to fout the queries to recreate a user-defined enum type
6054 static void
6055 dumpEnumType(Archive *fout, TypeInfo *tinfo)
6057 PQExpBuffer q = createPQExpBuffer();
6058 PQExpBuffer delq = createPQExpBuffer();
6059 PQExpBuffer query = createPQExpBuffer();
6060 PGresult *res;
6061 int num,
6063 char *label;
6065 /* Set proper schema search path so regproc references list correctly */
6066 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6068 appendPQExpBuffer(query, "SELECT enumlabel FROM pg_catalog.pg_enum "
6069 "WHERE enumtypid = '%u'"
6070 "ORDER BY oid",
6071 tinfo->dobj.catId.oid);
6073 res = PQexec(g_conn, query->data);
6074 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6076 num = PQntuples(res);
6077 /* should be at least 1 value */
6078 if (num == 0)
6080 write_msg(NULL, "no label definitions found for enum ID %u\n", tinfo->dobj.catId.oid);
6081 exit_nicely();
6085 * DROP must be fully qualified in case same name appears in pg_catalog.
6086 * CASCADE shouldn't be required here as for normal types since the I/O
6087 * functions are generic and do not get dropped.
6089 appendPQExpBuffer(delq, "DROP TYPE %s.",
6090 fmtId(tinfo->dobj.namespace->dobj.name));
6091 appendPQExpBuffer(delq, "%s;\n",
6092 fmtId(tinfo->dobj.name));
6093 appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (\n",
6094 fmtId(tinfo->dobj.name));
6095 for (i = 0; i < num; i++)
6097 label = PQgetvalue(res, i, 0);
6098 if (i > 0)
6099 appendPQExpBuffer(q, ",\n");
6100 appendPQExpBuffer(q, " ");
6101 appendStringLiteralAH(q, label, fout);
6103 appendPQExpBuffer(q, "\n);\n");
6105 ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
6106 tinfo->dobj.name,
6107 tinfo->dobj.namespace->dobj.name,
6108 NULL,
6109 tinfo->rolname, false,
6110 "TYPE", SECTION_PRE_DATA,
6111 q->data, delq->data, NULL,
6112 tinfo->dobj.dependencies, tinfo->dobj.nDeps,
6113 NULL, NULL);
6115 /* Dump Type Comments */
6116 resetPQExpBuffer(q);
6118 appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->dobj.name));
6119 dumpComment(fout, q->data,
6120 tinfo->dobj.namespace->dobj.name, tinfo->rolname,
6121 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
6123 PQclear(res);
6124 destroyPQExpBuffer(q);
6125 destroyPQExpBuffer(delq);
6126 destroyPQExpBuffer(query);
6130 * dumpBaseType
6131 * writes out to fout the queries to recreate a user-defined base type
6133 static void
6134 dumpBaseType(Archive *fout, TypeInfo *tinfo)
6136 PQExpBuffer q = createPQExpBuffer();
6137 PQExpBuffer delq = createPQExpBuffer();
6138 PQExpBuffer query = createPQExpBuffer();
6139 PGresult *res;
6140 int ntups;
6141 char *typlen;
6142 char *typinput;
6143 char *typoutput;
6144 char *typreceive;
6145 char *typsend;
6146 char *typmodin;
6147 char *typmodout;
6148 char *typanalyze;
6149 Oid typinputoid;
6150 Oid typoutputoid;
6151 Oid typreceiveoid;
6152 Oid typsendoid;
6153 Oid typmodinoid;
6154 Oid typmodoutoid;
6155 Oid typanalyzeoid;
6156 char *typcategory;
6157 char *typispreferred;
6158 char *typdelim;
6159 char *typbyval;
6160 char *typalign;
6161 char *typstorage;
6162 char *typdefault;
6163 bool typdefault_is_literal = false;
6165 /* Set proper schema search path so regproc references list correctly */
6166 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6168 /* Fetch type-specific details */
6169 if (fout->remoteVersion >= 80400)
6171 appendPQExpBuffer(query, "SELECT typlen, "
6172 "typinput, typoutput, typreceive, typsend, "
6173 "typmodin, typmodout, typanalyze, "
6174 "typinput::pg_catalog.oid AS typinputoid, "
6175 "typoutput::pg_catalog.oid AS typoutputoid, "
6176 "typreceive::pg_catalog.oid AS typreceiveoid, "
6177 "typsend::pg_catalog.oid AS typsendoid, "
6178 "typmodin::pg_catalog.oid AS typmodinoid, "
6179 "typmodout::pg_catalog.oid AS typmodoutoid, "
6180 "typanalyze::pg_catalog.oid AS typanalyzeoid, "
6181 "typcategory, typispreferred, "
6182 "typdelim, typbyval, typalign, typstorage, "
6183 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6184 "FROM pg_catalog.pg_type "
6185 "WHERE oid = '%u'::pg_catalog.oid",
6186 tinfo->dobj.catId.oid);
6188 else if (fout->remoteVersion >= 80300)
6190 appendPQExpBuffer(query, "SELECT typlen, "
6191 "typinput, typoutput, typreceive, typsend, "
6192 "typmodin, typmodout, typanalyze, "
6193 "typinput::pg_catalog.oid AS typinputoid, "
6194 "typoutput::pg_catalog.oid AS typoutputoid, "
6195 "typreceive::pg_catalog.oid AS typreceiveoid, "
6196 "typsend::pg_catalog.oid AS typsendoid, "
6197 "typmodin::pg_catalog.oid AS typmodinoid, "
6198 "typmodout::pg_catalog.oid AS typmodoutoid, "
6199 "typanalyze::pg_catalog.oid AS typanalyzeoid, "
6200 "'U' AS typcategory, false AS typispreferred, "
6201 "typdelim, typbyval, typalign, typstorage, "
6202 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6203 "FROM pg_catalog.pg_type "
6204 "WHERE oid = '%u'::pg_catalog.oid",
6205 tinfo->dobj.catId.oid);
6207 else if (fout->remoteVersion >= 80000)
6209 appendPQExpBuffer(query, "SELECT typlen, "
6210 "typinput, typoutput, typreceive, typsend, "
6211 "'-' AS typmodin, '-' AS typmodout, "
6212 "typanalyze, "
6213 "typinput::pg_catalog.oid AS typinputoid, "
6214 "typoutput::pg_catalog.oid AS typoutputoid, "
6215 "typreceive::pg_catalog.oid AS typreceiveoid, "
6216 "typsend::pg_catalog.oid AS typsendoid, "
6217 "0 AS typmodinoid, 0 AS typmodoutoid, "
6218 "typanalyze::pg_catalog.oid AS typanalyzeoid, "
6219 "'U' AS typcategory, false AS typispreferred, "
6220 "typdelim, typbyval, typalign, typstorage, "
6221 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6222 "FROM pg_catalog.pg_type "
6223 "WHERE oid = '%u'::pg_catalog.oid",
6224 tinfo->dobj.catId.oid);
6226 else if (fout->remoteVersion >= 70400)
6228 appendPQExpBuffer(query, "SELECT typlen, "
6229 "typinput, typoutput, typreceive, typsend, "
6230 "'-' AS typmodin, '-' AS typmodout, "
6231 "'-' AS typanalyze, "
6232 "typinput::pg_catalog.oid AS typinputoid, "
6233 "typoutput::pg_catalog.oid AS typoutputoid, "
6234 "typreceive::pg_catalog.oid AS typreceiveoid, "
6235 "typsend::pg_catalog.oid AS typsendoid, "
6236 "0 AS typmodinoid, 0 AS typmodoutoid, "
6237 "0 AS typanalyzeoid, "
6238 "'U' AS typcategory, false AS typispreferred, "
6239 "typdelim, typbyval, typalign, typstorage, "
6240 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6241 "FROM pg_catalog.pg_type "
6242 "WHERE oid = '%u'::pg_catalog.oid",
6243 tinfo->dobj.catId.oid);
6245 else if (fout->remoteVersion >= 70300)
6247 appendPQExpBuffer(query, "SELECT typlen, "
6248 "typinput, typoutput, "
6249 "'-' AS typreceive, '-' AS typsend, "
6250 "'-' AS typmodin, '-' AS typmodout, "
6251 "'-' AS typanalyze, "
6252 "typinput::pg_catalog.oid AS typinputoid, "
6253 "typoutput::pg_catalog.oid AS typoutputoid, "
6254 "0 AS typreceiveoid, 0 AS typsendoid, "
6255 "0 AS typmodinoid, 0 AS typmodoutoid, "
6256 "0 AS typanalyzeoid, "
6257 "'U' AS typcategory, false AS typispreferred, "
6258 "typdelim, typbyval, typalign, typstorage, "
6259 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6260 "FROM pg_catalog.pg_type "
6261 "WHERE oid = '%u'::pg_catalog.oid",
6262 tinfo->dobj.catId.oid);
6264 else if (fout->remoteVersion >= 70200)
6267 * Note: although pre-7.3 catalogs contain typreceive and typsend,
6268 * ignore them because they are not right.
6270 appendPQExpBuffer(query, "SELECT typlen, "
6271 "typinput, typoutput, "
6272 "'-' AS typreceive, '-' AS typsend, "
6273 "'-' AS typmodin, '-' AS typmodout, "
6274 "'-' AS typanalyze, "
6275 "typinput::oid AS typinputoid, "
6276 "typoutput::oid AS typoutputoid, "
6277 "0 AS typreceiveoid, 0 AS typsendoid, "
6278 "0 AS typmodinoid, 0 AS typmodoutoid, "
6279 "0 AS typanalyzeoid, "
6280 "'U' AS typcategory, false AS typispreferred, "
6281 "typdelim, typbyval, typalign, typstorage, "
6282 "NULL AS typdefaultbin, typdefault "
6283 "FROM pg_type "
6284 "WHERE oid = '%u'::oid",
6285 tinfo->dobj.catId.oid);
6287 else if (fout->remoteVersion >= 70100)
6290 * Ignore pre-7.2 typdefault; the field exists but has an unusable
6291 * representation.
6293 appendPQExpBuffer(query, "SELECT typlen, "
6294 "typinput, typoutput, "
6295 "'-' AS typreceive, '-' AS typsend, "
6296 "'-' AS typmodin, '-' AS typmodout, "
6297 "'-' AS typanalyze, "
6298 "typinput::oid AS typinputoid, "
6299 "typoutput::oid AS typoutputoid, "
6300 "0 AS typreceiveoid, 0 AS typsendoid, "
6301 "0 AS typmodinoid, 0 AS typmodoutoid, "
6302 "0 AS typanalyzeoid, "
6303 "'U' AS typcategory, false AS typispreferred, "
6304 "typdelim, typbyval, typalign, typstorage, "
6305 "NULL AS typdefaultbin, NULL AS typdefault "
6306 "FROM pg_type "
6307 "WHERE oid = '%u'::oid",
6308 tinfo->dobj.catId.oid);
6310 else
6312 appendPQExpBuffer(query, "SELECT typlen, "
6313 "typinput, typoutput, "
6314 "'-' AS typreceive, '-' AS typsend, "
6315 "'-' AS typmodin, '-' AS typmodout, "
6316 "'-' AS typanalyze, "
6317 "typinput::oid AS typinputoid, "
6318 "typoutput::oid AS typoutputoid, "
6319 "0 AS typreceiveoid, 0 AS typsendoid, "
6320 "0 AS typmodinoid, 0 AS typmodoutoid, "
6321 "0 AS typanalyzeoid, "
6322 "'U' AS typcategory, false AS typispreferred, "
6323 "typdelim, typbyval, typalign, "
6324 "'p'::char AS typstorage, "
6325 "NULL AS typdefaultbin, NULL AS typdefault "
6326 "FROM pg_type "
6327 "WHERE oid = '%u'::oid",
6328 tinfo->dobj.catId.oid);
6331 res = PQexec(g_conn, query->data);
6332 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6334 /* Expecting a single result only */
6335 ntups = PQntuples(res);
6336 if (ntups != 1)
6338 write_msg(NULL, "query returned %d rows instead of one: %s\n",
6339 ntups, query->data);
6340 exit_nicely();
6343 typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
6344 typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
6345 typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
6346 typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
6347 typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
6348 typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
6349 typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
6350 typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
6351 typinputoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typinputoid")));
6352 typoutputoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typoutputoid")));
6353 typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
6354 typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
6355 typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
6356 typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
6357 typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
6358 typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
6359 typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
6360 typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
6361 typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
6362 typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
6363 typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
6364 if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
6365 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
6366 else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
6368 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
6369 typdefault_is_literal = true; /* it needs quotes */
6371 else
6372 typdefault = NULL;
6375 * DROP must be fully qualified in case same name appears in pg_catalog.
6376 * The reason we include CASCADE is that the circular dependency between
6377 * the type and its I/O functions makes it impossible to drop the type any
6378 * other way.
6380 appendPQExpBuffer(delq, "DROP TYPE %s.",
6381 fmtId(tinfo->dobj.namespace->dobj.name));
6382 appendPQExpBuffer(delq, "%s CASCADE;\n",
6383 fmtId(tinfo->dobj.name));
6385 appendPQExpBuffer(q,
6386 "CREATE TYPE %s (\n"
6387 " INTERNALLENGTH = %s",
6388 fmtId(tinfo->dobj.name),
6389 (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
6391 if (fout->remoteVersion >= 70300)
6393 /* regproc result is correctly quoted as of 7.3 */
6394 appendPQExpBuffer(q, ",\n INPUT = %s", typinput);
6395 appendPQExpBuffer(q, ",\n OUTPUT = %s", typoutput);
6396 if (OidIsValid(typreceiveoid))
6397 appendPQExpBuffer(q, ",\n RECEIVE = %s", typreceive);
6398 if (OidIsValid(typsendoid))
6399 appendPQExpBuffer(q, ",\n SEND = %s", typsend);
6400 if (OidIsValid(typmodinoid))
6401 appendPQExpBuffer(q, ",\n TYPMOD_IN = %s", typmodin);
6402 if (OidIsValid(typmodoutoid))
6403 appendPQExpBuffer(q, ",\n TYPMOD_OUT = %s", typmodout);
6404 if (OidIsValid(typanalyzeoid))
6405 appendPQExpBuffer(q, ",\n ANALYZE = %s", typanalyze);
6407 else
6409 /* regproc delivers an unquoted name before 7.3 */
6410 /* cannot combine these because fmtId uses static result area */
6411 appendPQExpBuffer(q, ",\n INPUT = %s", fmtId(typinput));
6412 appendPQExpBuffer(q, ",\n OUTPUT = %s", fmtId(typoutput));
6413 /* receive/send/typmodin/typmodout/analyze need not be printed */
6416 if (typdefault != NULL)
6418 appendPQExpBuffer(q, ",\n DEFAULT = ");
6419 if (typdefault_is_literal)
6420 appendStringLiteralAH(q, typdefault, fout);
6421 else
6422 appendPQExpBufferStr(q, typdefault);
6425 if (OidIsValid(tinfo->typelem))
6427 char *elemType;
6429 /* reselect schema in case changed by function dump */
6430 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6431 elemType = getFormattedTypeName(tinfo->typelem, zeroAsOpaque);
6432 appendPQExpBuffer(q, ",\n ELEMENT = %s", elemType);
6433 free(elemType);
6436 if (strcmp(typcategory, "U") != 0)
6438 appendPQExpBuffer(q, ",\n CATEGORY = ");
6439 appendStringLiteralAH(q, typcategory, fout);
6442 if (strcmp(typispreferred, "t") == 0)
6443 appendPQExpBuffer(q, ",\n PREFERRED = true");
6445 if (typdelim && strcmp(typdelim, ",") != 0)
6447 appendPQExpBuffer(q, ",\n DELIMITER = ");
6448 appendStringLiteralAH(q, typdelim, fout);
6451 if (strcmp(typalign, "c") == 0)
6452 appendPQExpBuffer(q, ",\n ALIGNMENT = char");
6453 else if (strcmp(typalign, "s") == 0)
6454 appendPQExpBuffer(q, ",\n ALIGNMENT = int2");
6455 else if (strcmp(typalign, "i") == 0)
6456 appendPQExpBuffer(q, ",\n ALIGNMENT = int4");
6457 else if (strcmp(typalign, "d") == 0)
6458 appendPQExpBuffer(q, ",\n ALIGNMENT = double");
6460 if (strcmp(typstorage, "p") == 0)
6461 appendPQExpBuffer(q, ",\n STORAGE = plain");
6462 else if (strcmp(typstorage, "e") == 0)
6463 appendPQExpBuffer(q, ",\n STORAGE = external");
6464 else if (strcmp(typstorage, "x") == 0)
6465 appendPQExpBuffer(q, ",\n STORAGE = extended");
6466 else if (strcmp(typstorage, "m") == 0)
6467 appendPQExpBuffer(q, ",\n STORAGE = main");
6469 if (strcmp(typbyval, "t") == 0)
6470 appendPQExpBuffer(q, ",\n PASSEDBYVALUE");
6472 appendPQExpBuffer(q, "\n);\n");
6474 ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
6475 tinfo->dobj.name,
6476 tinfo->dobj.namespace->dobj.name,
6477 NULL,
6478 tinfo->rolname, false,
6479 "TYPE", SECTION_PRE_DATA,
6480 q->data, delq->data, NULL,
6481 tinfo->dobj.dependencies, tinfo->dobj.nDeps,
6482 NULL, NULL);
6484 /* Dump Type Comments */
6485 resetPQExpBuffer(q);
6487 appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->dobj.name));
6488 dumpComment(fout, q->data,
6489 tinfo->dobj.namespace->dobj.name, tinfo->rolname,
6490 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
6492 PQclear(res);
6493 destroyPQExpBuffer(q);
6494 destroyPQExpBuffer(delq);
6495 destroyPQExpBuffer(query);
6499 * dumpDomain
6500 * writes out to fout the queries to recreate a user-defined domain
6502 static void
6503 dumpDomain(Archive *fout, TypeInfo *tinfo)
6505 PQExpBuffer q = createPQExpBuffer();
6506 PQExpBuffer delq = createPQExpBuffer();
6507 PQExpBuffer query = createPQExpBuffer();
6508 PGresult *res;
6509 int ntups;
6510 int i;
6511 char *typnotnull;
6512 char *typdefn;
6513 char *typdefault;
6514 bool typdefault_is_literal = false;
6516 /* Set proper schema search path so type references list correctly */
6517 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6519 /* Fetch domain specific details */
6520 /* We assume here that remoteVersion must be at least 70300 */
6521 appendPQExpBuffer(query, "SELECT typnotnull, "
6522 "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
6523 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6524 "FROM pg_catalog.pg_type "
6525 "WHERE oid = '%u'::pg_catalog.oid",
6526 tinfo->dobj.catId.oid);
6528 res = PQexec(g_conn, query->data);
6529 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6531 /* Expecting a single result only */
6532 ntups = PQntuples(res);
6533 if (ntups != 1)
6535 write_msg(NULL, "query returned %d rows instead of one: %s\n",
6536 ntups, query->data);
6537 exit_nicely();
6540 typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
6541 typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
6542 if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
6543 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
6544 else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
6546 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
6547 typdefault_is_literal = true; /* it needs quotes */
6549 else
6550 typdefault = NULL;
6552 appendPQExpBuffer(q,
6553 "CREATE DOMAIN %s AS %s",
6554 fmtId(tinfo->dobj.name),
6555 typdefn);
6557 if (typnotnull[0] == 't')
6558 appendPQExpBuffer(q, " NOT NULL");
6560 if (typdefault != NULL)
6562 appendPQExpBuffer(q, " DEFAULT ");
6563 if (typdefault_is_literal)
6564 appendStringLiteralAH(q, typdefault, fout);
6565 else
6566 appendPQExpBufferStr(q, typdefault);
6569 PQclear(res);
6572 * Add any CHECK constraints for the domain
6574 for (i = 0; i < tinfo->nDomChecks; i++)
6576 ConstraintInfo *domcheck = &(tinfo->domChecks[i]);
6578 if (!domcheck->separate)
6579 appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
6580 fmtId(domcheck->dobj.name), domcheck->condef);
6583 appendPQExpBuffer(q, ";\n");
6586 * DROP must be fully qualified in case same name appears in pg_catalog
6588 appendPQExpBuffer(delq, "DROP DOMAIN %s.",
6589 fmtId(tinfo->dobj.namespace->dobj.name));
6590 appendPQExpBuffer(delq, "%s;\n",
6591 fmtId(tinfo->dobj.name));
6593 ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
6594 tinfo->dobj.name,
6595 tinfo->dobj.namespace->dobj.name,
6596 NULL,
6597 tinfo->rolname, false,
6598 "DOMAIN", SECTION_PRE_DATA,
6599 q->data, delq->data, NULL,
6600 tinfo->dobj.dependencies, tinfo->dobj.nDeps,
6601 NULL, NULL);
6603 /* Dump Domain Comments */
6604 resetPQExpBuffer(q);
6606 appendPQExpBuffer(q, "DOMAIN %s", fmtId(tinfo->dobj.name));
6607 dumpComment(fout, q->data,
6608 tinfo->dobj.namespace->dobj.name, tinfo->rolname,
6609 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
6611 destroyPQExpBuffer(q);
6612 destroyPQExpBuffer(delq);
6613 destroyPQExpBuffer(query);
6617 * dumpCompositeType
6618 * writes out to fout the queries to recreate a user-defined stand-alone
6619 * composite type
6621 static void
6622 dumpCompositeType(Archive *fout, TypeInfo *tinfo)
6624 PQExpBuffer q = createPQExpBuffer();
6625 PQExpBuffer delq = createPQExpBuffer();
6626 PQExpBuffer query = createPQExpBuffer();
6627 PGresult *res;
6628 int ntups;
6629 int i_attname;
6630 int i_atttypdefn;
6631 int i;
6633 /* Set proper schema search path so type references list correctly */
6634 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6636 /* Fetch type specific details */
6637 /* We assume here that remoteVersion must be at least 70300 */
6639 appendPQExpBuffer(query, "SELECT a.attname, "
6640 "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn "
6641 "FROM pg_catalog.pg_type t, pg_catalog.pg_attribute a "
6642 "WHERE t.oid = '%u'::pg_catalog.oid "
6643 "AND a.attrelid = t.typrelid "
6644 "AND NOT a.attisdropped "
6645 "ORDER BY a.attnum ",
6646 tinfo->dobj.catId.oid);
6648 res = PQexec(g_conn, query->data);
6649 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6651 /* Expecting at least a single result */
6652 ntups = PQntuples(res);
6653 if (ntups < 1)
6655 write_msg(NULL, "query returned no rows: %s\n", query->data);
6656 exit_nicely();
6659 i_attname = PQfnumber(res, "attname");
6660 i_atttypdefn = PQfnumber(res, "atttypdefn");
6662 appendPQExpBuffer(q, "CREATE TYPE %s AS (",
6663 fmtId(tinfo->dobj.name));
6665 for (i = 0; i < ntups; i++)
6667 char *attname;
6668 char *atttypdefn;
6670 attname = PQgetvalue(res, i, i_attname);
6671 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
6673 appendPQExpBuffer(q, "\n\t%s %s", fmtId(attname), atttypdefn);
6674 if (i < ntups - 1)
6675 appendPQExpBuffer(q, ",");
6677 appendPQExpBuffer(q, "\n);\n");
6680 * DROP must be fully qualified in case same name appears in pg_catalog
6682 appendPQExpBuffer(delq, "DROP TYPE %s.",
6683 fmtId(tinfo->dobj.namespace->dobj.name));
6684 appendPQExpBuffer(delq, "%s;\n",
6685 fmtId(tinfo->dobj.name));
6687 ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
6688 tinfo->dobj.name,
6689 tinfo->dobj.namespace->dobj.name,
6690 NULL,
6691 tinfo->rolname, false,
6692 "TYPE", SECTION_PRE_DATA,
6693 q->data, delq->data, NULL,
6694 tinfo->dobj.dependencies, tinfo->dobj.nDeps,
6695 NULL, NULL);
6698 /* Dump Type Comments */
6699 resetPQExpBuffer(q);
6701 appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->dobj.name));
6702 dumpComment(fout, q->data,
6703 tinfo->dobj.namespace->dobj.name, tinfo->rolname,
6704 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
6706 PQclear(res);
6707 destroyPQExpBuffer(q);
6708 destroyPQExpBuffer(delq);
6709 destroyPQExpBuffer(query);
6713 * dumpShellType
6714 * writes out to fout the queries to create a shell type
6716 * We dump a shell definition in advance of the I/O functions for the type.
6718 static void
6719 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
6721 PQExpBuffer q;
6723 /* Skip if not to be dumped */
6724 if (!stinfo->dobj.dump || dataOnly)
6725 return;
6727 q = createPQExpBuffer();
6730 * Note the lack of a DROP command for the shell type; any required DROP
6731 * is driven off the base type entry, instead. This interacts with
6732 * _printTocEntry()'s use of the presence of a DROP command to decide
6733 * whether an entry needs an ALTER OWNER command. We don't want to alter
6734 * the shell type's owner immediately on creation; that should happen only
6735 * after it's filled in, otherwise the backend complains.
6738 appendPQExpBuffer(q, "CREATE TYPE %s;\n",
6739 fmtId(stinfo->dobj.name));
6741 ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
6742 stinfo->dobj.name,
6743 stinfo->dobj.namespace->dobj.name,
6744 NULL,
6745 stinfo->baseType->rolname, false,
6746 "SHELL TYPE", SECTION_PRE_DATA,
6747 q->data, "", NULL,
6748 stinfo->dobj.dependencies, stinfo->dobj.nDeps,
6749 NULL, NULL);
6751 destroyPQExpBuffer(q);
6755 * Determine whether we want to dump definitions for procedural languages.
6756 * Since the languages themselves don't have schemas, we can't rely on
6757 * the normal schema-based selection mechanism. We choose to dump them
6758 * whenever neither --schema nor --table was given. (Before 8.1, we used
6759 * the dump flag of the PL's call handler function, but in 8.1 this will
6760 * probably always be false since call handlers are created in pg_catalog.)
6762 * For some backwards compatibility with the older behavior, we forcibly
6763 * dump a PL if its handler function (and validator if any) are in a
6764 * dumpable namespace. That case is not checked here.
6766 static bool
6767 shouldDumpProcLangs(void)
6769 if (!include_everything)
6770 return false;
6771 /* And they're schema not data */
6772 if (dataOnly)
6773 return false;
6774 return true;
6778 * dumpProcLang
6779 * writes out to fout the queries to recreate a user-defined
6780 * procedural language
6782 static void
6783 dumpProcLang(Archive *fout, ProcLangInfo *plang)
6785 PQExpBuffer defqry;
6786 PQExpBuffer delqry;
6787 bool useParams;
6788 char *qlanname;
6789 char *lanschema;
6790 FuncInfo *funcInfo;
6791 FuncInfo *validatorInfo = NULL;
6793 if (dataOnly)
6794 return;
6797 * Try to find the support function(s). It is not an error if we don't
6798 * find them --- if the functions are in the pg_catalog schema, as is
6799 * standard in 8.1 and up, then we won't have loaded them. (In this case
6800 * we will emit a parameterless CREATE LANGUAGE command, which will
6801 * require PL template knowledge in the backend to reload.)
6804 funcInfo = findFuncByOid(plang->lanplcallfoid);
6805 if (funcInfo != NULL && !funcInfo->dobj.dump)
6806 funcInfo = NULL; /* treat not-dumped same as not-found */
6808 if (OidIsValid(plang->lanvalidator))
6810 validatorInfo = findFuncByOid(plang->lanvalidator);
6811 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
6812 validatorInfo = NULL;
6816 * If the functions are dumpable then emit a traditional CREATE LANGUAGE
6817 * with parameters. Otherwise, dump only if shouldDumpProcLangs() says to
6818 * dump it.
6820 useParams = (funcInfo != NULL &&
6821 (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
6823 if (!useParams && !shouldDumpProcLangs())
6824 return;
6826 defqry = createPQExpBuffer();
6827 delqry = createPQExpBuffer();
6829 qlanname = strdup(fmtId(plang->dobj.name));
6832 * If dumping a HANDLER clause, treat the language as being in the handler
6833 * function's schema; this avoids cluttering the HANDLER clause. Otherwise
6834 * it doesn't really have a schema.
6836 if (useParams)
6837 lanschema = funcInfo->dobj.namespace->dobj.name;
6838 else
6839 lanschema = NULL;
6841 appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
6842 qlanname);
6844 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
6845 (useParams && plang->lanpltrusted) ? "TRUSTED " : "",
6846 qlanname);
6847 if (useParams)
6849 appendPQExpBuffer(defqry, " HANDLER %s",
6850 fmtId(funcInfo->dobj.name));
6851 if (OidIsValid(plang->lanvalidator))
6853 appendPQExpBuffer(defqry, " VALIDATOR ");
6854 /* Cope with possibility that validator is in different schema */
6855 if (validatorInfo->dobj.namespace != funcInfo->dobj.namespace)
6856 appendPQExpBuffer(defqry, "%s.",
6857 fmtId(validatorInfo->dobj.namespace->dobj.name));
6858 appendPQExpBuffer(defqry, "%s",
6859 fmtId(validatorInfo->dobj.name));
6862 appendPQExpBuffer(defqry, ";\n");
6864 ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
6865 plang->dobj.name,
6866 lanschema, NULL, plang->lanowner,
6867 false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
6868 defqry->data, delqry->data, NULL,
6869 plang->dobj.dependencies, plang->dobj.nDeps,
6870 NULL, NULL);
6872 /* Dump Proc Lang Comments */
6873 resetPQExpBuffer(defqry);
6874 appendPQExpBuffer(defqry, "LANGUAGE %s", qlanname);
6875 dumpComment(fout, defqry->data,
6876 NULL, "",
6877 plang->dobj.catId, 0, plang->dobj.dumpId);
6879 if (plang->lanpltrusted)
6880 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
6881 qlanname, NULL, plang->dobj.name,
6882 lanschema,
6883 plang->lanowner, plang->lanacl);
6885 free(qlanname);
6887 destroyPQExpBuffer(defqry);
6888 destroyPQExpBuffer(delqry);
6892 * format_function_arguments: generate function name and argument list
6894 * This is used when we can rely on pg_get_function_arguments to format
6895 * the argument list.
6897 static char *format_function_arguments(FuncInfo *finfo, char *funcargs)
6899 PQExpBufferData fn;
6901 initPQExpBuffer(&fn);
6902 appendPQExpBuffer(&fn, "%s(%s)", fmtId(finfo->dobj.name), funcargs);
6903 return fn.data;
6907 * format_function_arguments_old: generate function name and argument list
6909 * The argument type names are qualified if needed. The function name
6910 * is never qualified.
6912 * This is used only with pre-8.4 servers, so we aren't expecting to see
6913 * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
6915 * Any or all of allargtypes, argmodes, argnames may be NULL.
6917 static char *
6918 format_function_arguments_old(FuncInfo *finfo, int nallargs,
6919 char **allargtypes,
6920 char **argmodes,
6921 char **argnames)
6923 PQExpBufferData fn;
6924 int j;
6926 initPQExpBuffer(&fn);
6927 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
6928 for (j = 0; j < nallargs; j++)
6930 Oid typid;
6931 char *typname;
6932 const char *argmode;
6933 const char *argname;
6935 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
6936 typname = getFormattedTypeName(typid, zeroAsOpaque);
6938 if (argmodes)
6940 switch (argmodes[j][0])
6942 case PROARGMODE_IN:
6943 argmode = "";
6944 break;
6945 case PROARGMODE_OUT:
6946 argmode = "OUT ";
6947 break;
6948 case PROARGMODE_INOUT:
6949 argmode = "INOUT ";
6950 break;
6951 default:
6952 write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
6953 argmode = "";
6954 break;
6957 else
6958 argmode = "";
6960 argname = argnames ? argnames[j] : (char *) NULL;
6961 if (argname && argname[0] == '\0')
6962 argname = NULL;
6964 appendPQExpBuffer(&fn, "%s%s%s%s%s",
6965 (j > 0) ? ", " : "",
6966 argmode,
6967 argname ? fmtId(argname) : "",
6968 argname ? " " : "",
6969 typname);
6970 free(typname);
6972 appendPQExpBuffer(&fn, ")");
6973 return fn.data;
6977 * format_function_signature: generate function name and argument list
6979 * This is like format_function_arguments_old except that only a minimal
6980 * list of input argument types is generated; this is sufficient to
6981 * reference the function, but not to define it.
6983 * If honor_quotes is false then the function name is never quoted.
6984 * This is appropriate for use in TOC tags, but not in SQL commands.
6986 static char *
6987 format_function_signature(FuncInfo *finfo, bool honor_quotes)
6989 PQExpBufferData fn;
6990 int j;
6992 initPQExpBuffer(&fn);
6993 if (honor_quotes)
6994 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
6995 else
6996 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
6997 for (j = 0; j < finfo->nargs; j++)
6999 char *typname;
7001 typname = getFormattedTypeName(finfo->argtypes[j], zeroAsOpaque);
7003 appendPQExpBuffer(&fn, "%s%s",
7004 (j > 0) ? ", " : "",
7005 typname);
7006 free(typname);
7008 appendPQExpBuffer(&fn, ")");
7009 return fn.data;
7014 * dumpFunc:
7015 * dump out one function
7017 static void
7018 dumpFunc(Archive *fout, FuncInfo *finfo)
7020 PQExpBuffer query;
7021 PQExpBuffer q;
7022 PQExpBuffer delqry;
7023 PQExpBuffer asPart;
7024 PGresult *res;
7025 char *funcsig; /* identity signature */
7026 char *funcfullsig; /* full signature */
7027 char *funcsig_tag;
7028 int ntups;
7029 char *proretset;
7030 char *prosrc;
7031 char *probin;
7032 char *funcargs;
7033 char *funciargs;
7034 char *funcresult;
7035 char *proallargtypes;
7036 char *proargmodes;
7037 char *proargnames;
7038 char *proiswindow;
7039 char *provolatile;
7040 char *proisstrict;
7041 char *prosecdef;
7042 char *proconfig;
7043 char *procost;
7044 char *prorows;
7045 char *lanname;
7046 char *rettypename;
7047 int nallargs;
7048 char **allargtypes = NULL;
7049 char **argmodes = NULL;
7050 char **argnames = NULL;
7051 char **configitems = NULL;
7052 int nconfigitems = 0;
7053 int i;
7055 /* Skip if not to be dumped */
7056 if (!finfo->dobj.dump || dataOnly)
7057 return;
7059 query = createPQExpBuffer();
7060 q = createPQExpBuffer();
7061 delqry = createPQExpBuffer();
7062 asPart = createPQExpBuffer();
7064 /* Set proper schema search path so type references list correctly */
7065 selectSourceSchema(finfo->dobj.namespace->dobj.name);
7067 /* Fetch function-specific details */
7068 if (g_fout->remoteVersion >= 80400)
7071 * In 8.4 and up we rely on pg_get_function_arguments and
7072 * pg_get_function_result instead of examining proallargtypes etc.
7074 appendPQExpBuffer(query,
7075 "SELECT proretset, prosrc, probin, "
7076 "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
7077 "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
7078 "pg_catalog.pg_get_function_result(oid) AS funcresult, "
7079 "proiswindow, provolatile, proisstrict, prosecdef, "
7080 "proconfig, procost, prorows, "
7081 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7082 "FROM pg_catalog.pg_proc "
7083 "WHERE oid = '%u'::pg_catalog.oid",
7084 finfo->dobj.catId.oid);
7086 else if (g_fout->remoteVersion >= 80300)
7088 appendPQExpBuffer(query,
7089 "SELECT proretset, prosrc, probin, "
7090 "proallargtypes, proargmodes, proargnames, "
7091 "false AS proiswindow, "
7092 "provolatile, proisstrict, prosecdef, "
7093 "proconfig, procost, prorows, "
7094 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7095 "FROM pg_catalog.pg_proc "
7096 "WHERE oid = '%u'::pg_catalog.oid",
7097 finfo->dobj.catId.oid);
7099 else if (g_fout->remoteVersion >= 80100)
7101 appendPQExpBuffer(query,
7102 "SELECT proretset, prosrc, probin, "
7103 "proallargtypes, proargmodes, proargnames, "
7104 "false AS proiswindow, "
7105 "provolatile, proisstrict, prosecdef, "
7106 "null AS proconfig, 0 AS procost, 0 AS prorows, "
7107 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7108 "FROM pg_catalog.pg_proc "
7109 "WHERE oid = '%u'::pg_catalog.oid",
7110 finfo->dobj.catId.oid);
7112 else if (g_fout->remoteVersion >= 80000)
7114 appendPQExpBuffer(query,
7115 "SELECT proretset, prosrc, probin, "
7116 "null AS proallargtypes, "
7117 "null AS proargmodes, "
7118 "proargnames, "
7119 "false AS proiswindow, "
7120 "provolatile, proisstrict, prosecdef, "
7121 "null AS proconfig, 0 AS procost, 0 AS prorows, "
7122 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7123 "FROM pg_catalog.pg_proc "
7124 "WHERE oid = '%u'::pg_catalog.oid",
7125 finfo->dobj.catId.oid);
7127 else if (g_fout->remoteVersion >= 70300)
7129 appendPQExpBuffer(query,
7130 "SELECT proretset, prosrc, probin, "
7131 "null AS proallargtypes, "
7132 "null AS proargmodes, "
7133 "null AS proargnames, "
7134 "false AS proiswindow, "
7135 "provolatile, proisstrict, prosecdef, "
7136 "null AS proconfig, 0 AS procost, 0 AS prorows, "
7137 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7138 "FROM pg_catalog.pg_proc "
7139 "WHERE oid = '%u'::pg_catalog.oid",
7140 finfo->dobj.catId.oid);
7142 else if (g_fout->remoteVersion >= 70100)
7144 appendPQExpBuffer(query,
7145 "SELECT proretset, prosrc, probin, "
7146 "null AS proallargtypes, "
7147 "null AS proargmodes, "
7148 "null AS proargnames, "
7149 "false AS proiswindow, "
7150 "case when proiscachable then 'i' else 'v' end AS provolatile, "
7151 "proisstrict, "
7152 "false AS prosecdef, "
7153 "null AS proconfig, 0 AS procost, 0 AS prorows, "
7154 "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
7155 "FROM pg_proc "
7156 "WHERE oid = '%u'::oid",
7157 finfo->dobj.catId.oid);
7159 else
7161 appendPQExpBuffer(query,
7162 "SELECT proretset, prosrc, probin, "
7163 "null AS proallargtypes, "
7164 "null AS proargmodes, "
7165 "null AS proargnames, "
7166 "false AS proiswindow, "
7167 "CASE WHEN proiscachable THEN 'i' ELSE 'v' END AS provolatile, "
7168 "false AS proisstrict, "
7169 "false AS prosecdef, "
7170 "NULL AS proconfig, 0 AS procost, 0 AS prorows, "
7171 "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
7172 "FROM pg_proc "
7173 "WHERE oid = '%u'::oid",
7174 finfo->dobj.catId.oid);
7177 res = PQexec(g_conn, query->data);
7178 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7180 /* Expecting a single result only */
7181 ntups = PQntuples(res);
7182 if (ntups != 1)
7184 write_msg(NULL, "query returned %d rows instead of one: %s\n",
7185 ntups, query->data);
7186 exit_nicely();
7189 proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
7190 prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
7191 probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
7192 if (g_fout->remoteVersion >= 80400)
7194 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
7195 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
7196 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
7197 proallargtypes = proargmodes = proargnames = NULL;
7199 else
7201 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
7202 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
7203 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
7204 funcargs = funciargs = funcresult = NULL;
7206 proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow"));
7207 provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
7208 proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
7209 prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
7210 proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
7211 procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
7212 prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
7213 lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
7216 * See backend/commands/functioncmds.c for details of how the 'AS' clause
7217 * is used. In 8.4 and up, an unused probin is NULL (here ""); previous
7218 * versions would set it to "-". There are no known cases in which prosrc
7219 * is unused, so the tests below for "-" are probably useless.
7221 if (probin[0] != '\0' && strcmp(probin, "-") != 0)
7223 appendPQExpBuffer(asPart, "AS ");
7224 appendStringLiteralAH(asPart, probin, fout);
7225 if (strcmp(prosrc, "-") != 0)
7227 appendPQExpBuffer(asPart, ", ");
7230 * where we have bin, use dollar quoting if allowed and src
7231 * contains quote or backslash; else use regular quoting.
7233 if (disable_dollar_quoting ||
7234 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
7235 appendStringLiteralAH(asPart, prosrc, fout);
7236 else
7237 appendStringLiteralDQ(asPart, prosrc, NULL);
7240 else
7242 if (strcmp(prosrc, "-") != 0)
7244 appendPQExpBuffer(asPart, "AS ");
7245 /* with no bin, dollar quote src unconditionally if allowed */
7246 if (disable_dollar_quoting)
7247 appendStringLiteralAH(asPart, prosrc, fout);
7248 else
7249 appendStringLiteralDQ(asPart, prosrc, NULL);
7253 nallargs = finfo->nargs; /* unless we learn different from allargs */
7255 if (proallargtypes && *proallargtypes)
7257 int nitems = 0;
7259 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
7260 nitems < finfo->nargs)
7262 write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
7263 if (allargtypes)
7264 free(allargtypes);
7265 allargtypes = NULL;
7267 else
7268 nallargs = nitems;
7271 if (proargmodes && *proargmodes)
7273 int nitems = 0;
7275 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
7276 nitems != nallargs)
7278 write_msg(NULL, "WARNING: could not parse proargmodes array\n");
7279 if (argmodes)
7280 free(argmodes);
7281 argmodes = NULL;
7285 if (proargnames && *proargnames)
7287 int nitems = 0;
7289 if (!parsePGArray(proargnames, &argnames, &nitems) ||
7290 nitems != nallargs)
7292 write_msg(NULL, "WARNING: could not parse proargnames array\n");
7293 if (argnames)
7294 free(argnames);
7295 argnames = NULL;
7299 if (proconfig && *proconfig)
7301 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
7303 write_msg(NULL, "WARNING: could not parse proconfig array\n");
7304 if (configitems)
7305 free(configitems);
7306 configitems = NULL;
7307 nconfigitems = 0;
7311 if (funcargs)
7313 /* 8.4 or later; we rely on server-side code for most of the work */
7314 funcfullsig = format_function_arguments(finfo, funcargs);
7315 funcsig = format_function_arguments(finfo, funciargs);
7317 else
7319 /* pre-8.4, do it ourselves */
7320 funcsig = format_function_arguments_old(finfo, nallargs, allargtypes,
7321 argmodes, argnames);
7322 funcfullsig = funcsig;
7325 funcsig_tag = format_function_signature(finfo, false);
7328 * DROP must be fully qualified in case same name appears in pg_catalog
7330 appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
7331 fmtId(finfo->dobj.namespace->dobj.name),
7332 funcsig);
7334 appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig);
7335 if (funcresult)
7336 appendPQExpBuffer(q, "RETURNS %s", funcresult);
7337 else
7339 rettypename = getFormattedTypeName(finfo->prorettype, zeroAsOpaque);
7340 appendPQExpBuffer(q, "RETURNS %s%s",
7341 (proretset[0] == 't') ? "SETOF " : "",
7342 rettypename);
7343 free(rettypename);
7346 appendPQExpBuffer(q, "\n LANGUAGE %s", fmtId(lanname));
7348 if (proiswindow[0] == 't')
7349 appendPQExpBuffer(q, " WINDOW");
7351 if (provolatile[0] != PROVOLATILE_VOLATILE)
7353 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
7354 appendPQExpBuffer(q, " IMMUTABLE");
7355 else if (provolatile[0] == PROVOLATILE_STABLE)
7356 appendPQExpBuffer(q, " STABLE");
7357 else if (provolatile[0] != PROVOLATILE_VOLATILE)
7359 write_msg(NULL, "unrecognized provolatile value for function \"%s\"\n",
7360 finfo->dobj.name);
7361 exit_nicely();
7365 if (proisstrict[0] == 't')
7366 appendPQExpBuffer(q, " STRICT");
7368 if (prosecdef[0] == 't')
7369 appendPQExpBuffer(q, " SECURITY DEFINER");
7372 * COST and ROWS are emitted only if present and not default, so as not to
7373 * break backwards-compatibility of the dump without need. Keep this code
7374 * in sync with the defaults in functioncmds.c.
7376 if (strcmp(procost, "0") != 0)
7378 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
7380 /* default cost is 1 */
7381 if (strcmp(procost, "1") != 0)
7382 appendPQExpBuffer(q, " COST %s", procost);
7384 else
7386 /* default cost is 100 */
7387 if (strcmp(procost, "100") != 0)
7388 appendPQExpBuffer(q, " COST %s", procost);
7391 if (proretset[0] == 't' &&
7392 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
7393 appendPQExpBuffer(q, " ROWS %s", prorows);
7395 for (i = 0; i < nconfigitems; i++)
7397 /* we feel free to scribble on configitems[] here */
7398 char *configitem = configitems[i];
7399 char *pos;
7401 pos = strchr(configitem, '=');
7402 if (pos == NULL)
7403 continue;
7404 *pos++ = '\0';
7405 appendPQExpBuffer(q, "\n SET %s TO ", fmtId(configitem));
7408 * Some GUC variable names are 'LIST' type and hence must not be
7409 * quoted.
7411 if (pg_strcasecmp(configitem, "DateStyle") == 0
7412 || pg_strcasecmp(configitem, "search_path") == 0)
7413 appendPQExpBuffer(q, "%s", pos);
7414 else
7415 appendStringLiteralAH(q, pos, fout);
7418 appendPQExpBuffer(q, "\n %s;\n", asPart->data);
7420 ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
7421 funcsig_tag,
7422 finfo->dobj.namespace->dobj.name,
7423 NULL,
7424 finfo->rolname, false,
7425 "FUNCTION", SECTION_PRE_DATA,
7426 q->data, delqry->data, NULL,
7427 finfo->dobj.dependencies, finfo->dobj.nDeps,
7428 NULL, NULL);
7430 /* Dump Function Comments */
7431 resetPQExpBuffer(q);
7432 appendPQExpBuffer(q, "FUNCTION %s", funcsig);
7433 dumpComment(fout, q->data,
7434 finfo->dobj.namespace->dobj.name, finfo->rolname,
7435 finfo->dobj.catId, 0, finfo->dobj.dumpId);
7437 dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
7438 funcsig, NULL, funcsig_tag,
7439 finfo->dobj.namespace->dobj.name,
7440 finfo->rolname, finfo->proacl);
7442 PQclear(res);
7444 destroyPQExpBuffer(query);
7445 destroyPQExpBuffer(q);
7446 destroyPQExpBuffer(delqry);
7447 destroyPQExpBuffer(asPart);
7448 free(funcsig);
7449 free(funcsig_tag);
7450 if (allargtypes)
7451 free(allargtypes);
7452 if (argmodes)
7453 free(argmodes);
7454 if (argnames)
7455 free(argnames);
7456 if (configitems)
7457 free(configitems);
7462 * Dump a user-defined cast
7464 static void
7465 dumpCast(Archive *fout, CastInfo *cast)
7467 PQExpBuffer defqry;
7468 PQExpBuffer delqry;
7469 PQExpBuffer castsig;
7470 FuncInfo *funcInfo = NULL;
7471 TypeInfo *sourceInfo;
7472 TypeInfo *targetInfo;
7474 if (dataOnly)
7475 return;
7477 if (OidIsValid(cast->castfunc))
7479 funcInfo = findFuncByOid(cast->castfunc);
7480 if (funcInfo == NULL)
7481 return;
7485 * As per discussion we dump casts if one or more of the underlying
7486 * objects (the conversion function and the two data types) are not
7487 * builtin AND if all of the non-builtin objects are included in the dump.
7488 * Builtin meaning, the namespace name does not start with "pg_".
7490 sourceInfo = findTypeByOid(cast->castsource);
7491 targetInfo = findTypeByOid(cast->casttarget);
7493 if (sourceInfo == NULL || targetInfo == NULL)
7494 return;
7497 * Skip this cast if all objects are from pg_
7499 if ((funcInfo == NULL ||
7500 strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
7501 strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) == 0 &&
7502 strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) == 0)
7503 return;
7506 * Skip cast if function isn't from pg_ and is not to be dumped.
7508 if (funcInfo &&
7509 strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
7510 !funcInfo->dobj.dump)
7511 return;
7514 * Same for the source type
7516 if (strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
7517 !sourceInfo->dobj.dump)
7518 return;
7521 * and the target type.
7523 if (strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
7524 !targetInfo->dobj.dump)
7525 return;
7527 /* Make sure we are in proper schema (needed for getFormattedTypeName) */
7528 selectSourceSchema("pg_catalog");
7530 defqry = createPQExpBuffer();
7531 delqry = createPQExpBuffer();
7532 castsig = createPQExpBuffer();
7534 appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
7535 getFormattedTypeName(cast->castsource, zeroAsNone),
7536 getFormattedTypeName(cast->casttarget, zeroAsNone));
7538 appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
7539 getFormattedTypeName(cast->castsource, zeroAsNone),
7540 getFormattedTypeName(cast->casttarget, zeroAsNone));
7542 switch(cast->castmethod)
7544 case COERCION_METHOD_BINARY:
7545 appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
7546 break;
7547 case COERCION_METHOD_INOUT:
7548 appendPQExpBuffer(defqry, "WITH INOUT");
7549 break;
7550 case COERCION_METHOD_FUNCTION:
7552 * Always qualify the function name, in case it is not in
7553 * pg_catalog schema (format_function_signature won't qualify it).
7555 appendPQExpBuffer(defqry, "WITH FUNCTION %s.",
7556 fmtId(funcInfo->dobj.namespace->dobj.name));
7557 appendPQExpBuffer(defqry, "%s",
7558 format_function_signature(funcInfo, true));
7559 break;
7560 default:
7561 write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
7564 if (cast->castcontext == 'a')
7565 appendPQExpBuffer(defqry, " AS ASSIGNMENT");
7566 else if (cast->castcontext == 'i')
7567 appendPQExpBuffer(defqry, " AS IMPLICIT");
7568 appendPQExpBuffer(defqry, ";\n");
7570 appendPQExpBuffer(castsig, "CAST (%s AS %s)",
7571 getFormattedTypeName(cast->castsource, zeroAsNone),
7572 getFormattedTypeName(cast->casttarget, zeroAsNone));
7574 ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
7575 castsig->data,
7576 "pg_catalog", NULL, "",
7577 false, "CAST", SECTION_PRE_DATA,
7578 defqry->data, delqry->data, NULL,
7579 cast->dobj.dependencies, cast->dobj.nDeps,
7580 NULL, NULL);
7582 /* Dump Cast Comments */
7583 resetPQExpBuffer(defqry);
7584 appendPQExpBuffer(defqry, "CAST (%s AS %s)",
7585 getFormattedTypeName(cast->castsource, zeroAsNone),
7586 getFormattedTypeName(cast->casttarget, zeroAsNone));
7587 dumpComment(fout, defqry->data,
7588 NULL, "",
7589 cast->dobj.catId, 0, cast->dobj.dumpId);
7591 destroyPQExpBuffer(defqry);
7592 destroyPQExpBuffer(delqry);
7593 destroyPQExpBuffer(castsig);
7597 * dumpOpr
7598 * write out a single operator definition
7600 static void
7601 dumpOpr(Archive *fout, OprInfo *oprinfo)
7603 PQExpBuffer query;
7604 PQExpBuffer q;
7605 PQExpBuffer delq;
7606 PQExpBuffer oprid;
7607 PQExpBuffer details;
7608 const char *name;
7609 PGresult *res;
7610 int ntups;
7611 int i_oprkind;
7612 int i_oprcode;
7613 int i_oprleft;
7614 int i_oprright;
7615 int i_oprcom;
7616 int i_oprnegate;
7617 int i_oprrest;
7618 int i_oprjoin;
7619 int i_oprcanmerge;
7620 int i_oprcanhash;
7621 char *oprkind;
7622 char *oprcode;
7623 char *oprleft;
7624 char *oprright;
7625 char *oprcom;
7626 char *oprnegate;
7627 char *oprrest;
7628 char *oprjoin;
7629 char *oprcanmerge;
7630 char *oprcanhash;
7632 /* Skip if not to be dumped */
7633 if (!oprinfo->dobj.dump || dataOnly)
7634 return;
7637 * some operators are invalid because they were the result of user
7638 * defining operators before commutators exist
7640 if (!OidIsValid(oprinfo->oprcode))
7641 return;
7643 query = createPQExpBuffer();
7644 q = createPQExpBuffer();
7645 delq = createPQExpBuffer();
7646 oprid = createPQExpBuffer();
7647 details = createPQExpBuffer();
7649 /* Make sure we are in proper schema so regoperator works correctly */
7650 selectSourceSchema(oprinfo->dobj.namespace->dobj.name);
7652 if (g_fout->remoteVersion >= 80300)
7654 appendPQExpBuffer(query, "SELECT oprkind, "
7655 "oprcode::pg_catalog.regprocedure, "
7656 "oprleft::pg_catalog.regtype, "
7657 "oprright::pg_catalog.regtype, "
7658 "oprcom::pg_catalog.regoperator, "
7659 "oprnegate::pg_catalog.regoperator, "
7660 "oprrest::pg_catalog.regprocedure, "
7661 "oprjoin::pg_catalog.regprocedure, "
7662 "oprcanmerge, oprcanhash "
7663 "FROM pg_catalog.pg_operator "
7664 "WHERE oid = '%u'::pg_catalog.oid",
7665 oprinfo->dobj.catId.oid);
7667 else if (g_fout->remoteVersion >= 70300)
7669 appendPQExpBuffer(query, "SELECT oprkind, "
7670 "oprcode::pg_catalog.regprocedure, "
7671 "oprleft::pg_catalog.regtype, "
7672 "oprright::pg_catalog.regtype, "
7673 "oprcom::pg_catalog.regoperator, "
7674 "oprnegate::pg_catalog.regoperator, "
7675 "oprrest::pg_catalog.regprocedure, "
7676 "oprjoin::pg_catalog.regprocedure, "
7677 "(oprlsortop != 0) AS oprcanmerge, "
7678 "oprcanhash "
7679 "FROM pg_catalog.pg_operator "
7680 "WHERE oid = '%u'::pg_catalog.oid",
7681 oprinfo->dobj.catId.oid);
7683 else if (g_fout->remoteVersion >= 70100)
7685 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
7686 "CASE WHEN oprleft = 0 THEN '-' "
7687 "ELSE format_type(oprleft, NULL) END AS oprleft, "
7688 "CASE WHEN oprright = 0 THEN '-' "
7689 "ELSE format_type(oprright, NULL) END AS oprright, "
7690 "oprcom, oprnegate, oprrest, oprjoin, "
7691 "(oprlsortop != 0) AS oprcanmerge, "
7692 "oprcanhash "
7693 "FROM pg_operator "
7694 "WHERE oid = '%u'::oid",
7695 oprinfo->dobj.catId.oid);
7697 else
7699 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
7700 "CASE WHEN oprleft = 0 THEN '-'::name "
7701 "ELSE (SELECT typname FROM pg_type WHERE oid = oprleft) END AS oprleft, "
7702 "CASE WHEN oprright = 0 THEN '-'::name "
7703 "ELSE (SELECT typname FROM pg_type WHERE oid = oprright) END AS oprright, "
7704 "oprcom, oprnegate, oprrest, oprjoin, "
7705 "(oprlsortop != 0) AS oprcanmerge, "
7706 "oprcanhash "
7707 "FROM pg_operator "
7708 "WHERE oid = '%u'::oid",
7709 oprinfo->dobj.catId.oid);
7712 res = PQexec(g_conn, query->data);
7713 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7715 /* Expecting a single result only */
7716 ntups = PQntuples(res);
7717 if (ntups != 1)
7719 write_msg(NULL, "query returned %d rows instead of one: %s\n",
7720 ntups, query->data);
7721 exit_nicely();
7724 i_oprkind = PQfnumber(res, "oprkind");
7725 i_oprcode = PQfnumber(res, "oprcode");
7726 i_oprleft = PQfnumber(res, "oprleft");
7727 i_oprright = PQfnumber(res, "oprright");
7728 i_oprcom = PQfnumber(res, "oprcom");
7729 i_oprnegate = PQfnumber(res, "oprnegate");
7730 i_oprrest = PQfnumber(res, "oprrest");
7731 i_oprjoin = PQfnumber(res, "oprjoin");
7732 i_oprcanmerge = PQfnumber(res, "oprcanmerge");
7733 i_oprcanhash = PQfnumber(res, "oprcanhash");
7735 oprkind = PQgetvalue(res, 0, i_oprkind);
7736 oprcode = PQgetvalue(res, 0, i_oprcode);
7737 oprleft = PQgetvalue(res, 0, i_oprleft);
7738 oprright = PQgetvalue(res, 0, i_oprright);
7739 oprcom = PQgetvalue(res, 0, i_oprcom);
7740 oprnegate = PQgetvalue(res, 0, i_oprnegate);
7741 oprrest = PQgetvalue(res, 0, i_oprrest);
7742 oprjoin = PQgetvalue(res, 0, i_oprjoin);
7743 oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
7744 oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
7746 appendPQExpBuffer(details, " PROCEDURE = %s",
7747 convertRegProcReference(oprcode));
7749 appendPQExpBuffer(oprid, "%s (",
7750 oprinfo->dobj.name);
7753 * right unary means there's a left arg and left unary means there's a
7754 * right arg
7756 if (strcmp(oprkind, "r") == 0 ||
7757 strcmp(oprkind, "b") == 0)
7759 if (g_fout->remoteVersion >= 70100)
7760 name = oprleft;
7761 else
7762 name = fmtId(oprleft);
7763 appendPQExpBuffer(details, ",\n LEFTARG = %s", name);
7764 appendPQExpBuffer(oprid, "%s", name);
7766 else
7767 appendPQExpBuffer(oprid, "NONE");
7769 if (strcmp(oprkind, "l") == 0 ||
7770 strcmp(oprkind, "b") == 0)
7772 if (g_fout->remoteVersion >= 70100)
7773 name = oprright;
7774 else
7775 name = fmtId(oprright);
7776 appendPQExpBuffer(details, ",\n RIGHTARG = %s", name);
7777 appendPQExpBuffer(oprid, ", %s)", name);
7779 else
7780 appendPQExpBuffer(oprid, ", NONE)");
7782 name = convertOperatorReference(oprcom);
7783 if (name)
7784 appendPQExpBuffer(details, ",\n COMMUTATOR = %s", name);
7786 name = convertOperatorReference(oprnegate);
7787 if (name)
7788 appendPQExpBuffer(details, ",\n NEGATOR = %s", name);
7790 if (strcmp(oprcanmerge, "t") == 0)
7791 appendPQExpBuffer(details, ",\n MERGES");
7793 if (strcmp(oprcanhash, "t") == 0)
7794 appendPQExpBuffer(details, ",\n HASHES");
7796 name = convertRegProcReference(oprrest);
7797 if (name)
7798 appendPQExpBuffer(details, ",\n RESTRICT = %s", name);
7800 name = convertRegProcReference(oprjoin);
7801 if (name)
7802 appendPQExpBuffer(details, ",\n JOIN = %s", name);
7805 * DROP must be fully qualified in case same name appears in pg_catalog
7807 appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
7808 fmtId(oprinfo->dobj.namespace->dobj.name),
7809 oprid->data);
7811 appendPQExpBuffer(q, "CREATE OPERATOR %s (\n%s\n);\n",
7812 oprinfo->dobj.name, details->data);
7814 ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
7815 oprinfo->dobj.name,
7816 oprinfo->dobj.namespace->dobj.name,
7817 NULL,
7818 oprinfo->rolname,
7819 false, "OPERATOR", SECTION_PRE_DATA,
7820 q->data, delq->data, NULL,
7821 oprinfo->dobj.dependencies, oprinfo->dobj.nDeps,
7822 NULL, NULL);
7824 /* Dump Operator Comments */
7825 resetPQExpBuffer(q);
7826 appendPQExpBuffer(q, "OPERATOR %s", oprid->data);
7827 dumpComment(fout, q->data,
7828 oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
7829 oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
7831 PQclear(res);
7833 destroyPQExpBuffer(query);
7834 destroyPQExpBuffer(q);
7835 destroyPQExpBuffer(delq);
7836 destroyPQExpBuffer(oprid);
7837 destroyPQExpBuffer(details);
7841 * Convert a function reference obtained from pg_operator
7843 * Returns what to print, or NULL if function references is InvalidOid
7845 * In 7.3 the input is a REGPROCEDURE display; we have to strip the
7846 * argument-types part. In prior versions, the input is a REGPROC display.
7848 static const char *
7849 convertRegProcReference(const char *proc)
7851 /* In all cases "-" means a null reference */
7852 if (strcmp(proc, "-") == 0)
7853 return NULL;
7855 if (g_fout->remoteVersion >= 70300)
7857 char *name;
7858 char *paren;
7859 bool inquote;
7861 name = strdup(proc);
7862 /* find non-double-quoted left paren */
7863 inquote = false;
7864 for (paren = name; *paren; paren++)
7866 if (*paren == '(' && !inquote)
7868 *paren = '\0';
7869 break;
7871 if (*paren == '"')
7872 inquote = !inquote;
7874 return name;
7877 /* REGPROC before 7.3 does not quote its result */
7878 return fmtId(proc);
7882 * Convert an operator cross-reference obtained from pg_operator
7884 * Returns what to print, or NULL to print nothing
7886 * In 7.3 and up the input is a REGOPERATOR display; we have to strip the
7887 * argument-types part, and add OPERATOR() decoration if the name is
7888 * schema-qualified. In older versions, the input is just a numeric OID,
7889 * which we search our operator list for.
7891 static const char *
7892 convertOperatorReference(const char *opr)
7894 OprInfo *oprInfo;
7896 /* In all cases "0" means a null reference */
7897 if (strcmp(opr, "0") == 0)
7898 return NULL;
7900 if (g_fout->remoteVersion >= 70300)
7902 char *name;
7903 char *oname;
7904 char *ptr;
7905 bool inquote;
7906 bool sawdot;
7908 name = strdup(opr);
7909 /* find non-double-quoted left paren, and check for non-quoted dot */
7910 inquote = false;
7911 sawdot = false;
7912 for (ptr = name; *ptr; ptr++)
7914 if (*ptr == '"')
7915 inquote = !inquote;
7916 else if (*ptr == '.' && !inquote)
7917 sawdot = true;
7918 else if (*ptr == '(' && !inquote)
7920 *ptr = '\0';
7921 break;
7924 /* If not schema-qualified, don't need to add OPERATOR() */
7925 if (!sawdot)
7926 return name;
7927 oname = malloc(strlen(name) + 11);
7928 sprintf(oname, "OPERATOR(%s)", name);
7929 free(name);
7930 return oname;
7933 oprInfo = findOprByOid(atooid(opr));
7934 if (oprInfo == NULL)
7936 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
7937 opr);
7938 return NULL;
7940 return oprInfo->dobj.name;
7944 * Convert a function OID obtained from pg_ts_parser or pg_ts_template
7946 * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
7947 * argument lists of these functions are predetermined. Note that the
7948 * caller should ensure we are in the proper schema, because the results
7949 * are search path dependent!
7951 static const char *
7952 convertTSFunction(Oid funcOid)
7954 char *result;
7955 char query[128];
7956 PGresult *res;
7957 int ntups;
7959 snprintf(query, sizeof(query),
7960 "SELECT '%u'::pg_catalog.regproc", funcOid);
7961 res = PQexec(g_conn, query);
7962 check_sql_result(res, g_conn, query, PGRES_TUPLES_OK);
7964 ntups = PQntuples(res);
7965 if (ntups != 1)
7967 write_msg(NULL, "query returned %d rows instead of one: %s\n",
7968 ntups, query);
7969 exit_nicely();
7972 result = strdup(PQgetvalue(res, 0, 0));
7974 PQclear(res);
7976 return result;
7981 * dumpOpclass
7982 * write out a single operator class definition
7984 static void
7985 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
7987 PQExpBuffer query;
7988 PQExpBuffer q;
7989 PQExpBuffer delq;
7990 PGresult *res;
7991 int ntups;
7992 int i_opcintype;
7993 int i_opckeytype;
7994 int i_opcdefault;
7995 int i_opcfamily;
7996 int i_opcfamilynsp;
7997 int i_amname;
7998 int i_amopstrategy;
7999 int i_amopreqcheck;
8000 int i_amopopr;
8001 int i_amprocnum;
8002 int i_amproc;
8003 char *opcintype;
8004 char *opckeytype;
8005 char *opcdefault;
8006 char *opcfamily;
8007 char *opcfamilynsp;
8008 char *amname;
8009 char *amopstrategy;
8010 char *amopreqcheck;
8011 char *amopopr;
8012 char *amprocnum;
8013 char *amproc;
8014 bool needComma;
8015 int i;
8017 /* Skip if not to be dumped */
8018 if (!opcinfo->dobj.dump || dataOnly)
8019 return;
8022 * XXX currently we do not implement dumping of operator classes from
8023 * pre-7.3 databases. This could be done but it seems not worth the
8024 * trouble.
8026 if (g_fout->remoteVersion < 70300)
8027 return;
8029 query = createPQExpBuffer();
8030 q = createPQExpBuffer();
8031 delq = createPQExpBuffer();
8033 /* Make sure we are in proper schema so regoperator works correctly */
8034 selectSourceSchema(opcinfo->dobj.namespace->dobj.name);
8036 /* Get additional fields from the pg_opclass row */
8037 if (g_fout->remoteVersion >= 80300)
8039 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
8040 "opckeytype::pg_catalog.regtype, "
8041 "opcdefault, "
8042 "opfname AS opcfamily, "
8043 "nspname AS opcfamilynsp, "
8044 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
8045 "FROM pg_catalog.pg_opclass c "
8046 "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
8047 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
8048 "WHERE c.oid = '%u'::pg_catalog.oid",
8049 opcinfo->dobj.catId.oid);
8051 else
8053 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
8054 "opckeytype::pg_catalog.regtype, "
8055 "opcdefault, "
8056 "NULL AS opcfamily, "
8057 "NULL AS opcfamilynsp, "
8058 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
8059 "FROM pg_catalog.pg_opclass "
8060 "WHERE oid = '%u'::pg_catalog.oid",
8061 opcinfo->dobj.catId.oid);
8064 res = PQexec(g_conn, query->data);
8065 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8067 /* Expecting a single result only */
8068 ntups = PQntuples(res);
8069 if (ntups != 1)
8071 write_msg(NULL, "query returned %d rows instead of one: %s\n",
8072 ntups, query->data);
8073 exit_nicely();
8076 i_opcintype = PQfnumber(res, "opcintype");
8077 i_opckeytype = PQfnumber(res, "opckeytype");
8078 i_opcdefault = PQfnumber(res, "opcdefault");
8079 i_opcfamily = PQfnumber(res, "opcfamily");
8080 i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
8081 i_amname = PQfnumber(res, "amname");
8083 opcintype = PQgetvalue(res, 0, i_opcintype);
8084 opckeytype = PQgetvalue(res, 0, i_opckeytype);
8085 opcdefault = PQgetvalue(res, 0, i_opcdefault);
8086 opcfamily = PQgetvalue(res, 0, i_opcfamily);
8087 opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
8088 /* amname will still be needed after we PQclear res */
8089 amname = strdup(PQgetvalue(res, 0, i_amname));
8092 * DROP must be fully qualified in case same name appears in pg_catalog
8094 appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
8095 fmtId(opcinfo->dobj.namespace->dobj.name));
8096 appendPQExpBuffer(delq, ".%s",
8097 fmtId(opcinfo->dobj.name));
8098 appendPQExpBuffer(delq, " USING %s;\n",
8099 fmtId(amname));
8101 /* Build the fixed portion of the CREATE command */
8102 appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n ",
8103 fmtId(opcinfo->dobj.name));
8104 if (strcmp(opcdefault, "t") == 0)
8105 appendPQExpBuffer(q, "DEFAULT ");
8106 appendPQExpBuffer(q, "FOR TYPE %s USING %s",
8107 opcintype,
8108 fmtId(amname));
8109 if (strlen(opcfamily) > 0 &&
8110 (strcmp(opcfamily, opcinfo->dobj.name) != 0 ||
8111 strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
8113 appendPQExpBuffer(q, " FAMILY ");
8114 if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
8115 appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
8116 appendPQExpBuffer(q, "%s", fmtId(opcfamily));
8118 appendPQExpBuffer(q, " AS\n ");
8120 needComma = false;
8122 if (strcmp(opckeytype, "-") != 0)
8124 appendPQExpBuffer(q, "STORAGE %s",
8125 opckeytype);
8126 needComma = true;
8129 PQclear(res);
8132 * Now fetch and print the OPERATOR entries (pg_amop rows).
8134 resetPQExpBuffer(query);
8136 if (g_fout->remoteVersion >= 80400)
8139 * Print only those opfamily members that are tied to the opclass by
8140 * pg_depend entries.
8142 * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping
8143 * an older server's table in which it is used. Would it be better
8144 * to silently ignore it?
8146 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
8147 "amopopr::pg_catalog.regoperator "
8148 "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
8149 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
8150 "AND refobjid = '%u'::pg_catalog.oid "
8151 "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
8152 "AND objid = ao.oid "
8153 "ORDER BY amopstrategy",
8154 opcinfo->dobj.catId.oid);
8156 else if (g_fout->remoteVersion >= 80300)
8159 * Print only those opfamily members that are tied to the opclass by
8160 * pg_depend entries.
8162 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
8163 "amopopr::pg_catalog.regoperator "
8164 "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
8165 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
8166 "AND refobjid = '%u'::pg_catalog.oid "
8167 "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
8168 "AND objid = ao.oid "
8169 "ORDER BY amopstrategy",
8170 opcinfo->dobj.catId.oid);
8172 else
8174 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
8175 "amopopr::pg_catalog.regoperator "
8176 "FROM pg_catalog.pg_amop "
8177 "WHERE amopclaid = '%u'::pg_catalog.oid "
8178 "ORDER BY amopstrategy",
8179 opcinfo->dobj.catId.oid);
8182 res = PQexec(g_conn, query->data);
8183 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8185 ntups = PQntuples(res);
8187 i_amopstrategy = PQfnumber(res, "amopstrategy");
8188 i_amopreqcheck = PQfnumber(res, "amopreqcheck");
8189 i_amopopr = PQfnumber(res, "amopopr");
8191 for (i = 0; i < ntups; i++)
8193 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
8194 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
8195 amopopr = PQgetvalue(res, i, i_amopopr);
8197 if (needComma)
8198 appendPQExpBuffer(q, " ,\n ");
8200 appendPQExpBuffer(q, "OPERATOR %s %s",
8201 amopstrategy, amopopr);
8202 if (strcmp(amopreqcheck, "t") == 0)
8203 appendPQExpBuffer(q, " RECHECK");
8205 needComma = true;
8208 PQclear(res);
8211 * Now fetch and print the FUNCTION entries (pg_amproc rows).
8213 resetPQExpBuffer(query);
8215 if (g_fout->remoteVersion >= 80300)
8218 * Print only those opfamily members that are tied to the opclass by
8219 * pg_depend entries.
8221 appendPQExpBuffer(query, "SELECT amprocnum, "
8222 "amproc::pg_catalog.regprocedure "
8223 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
8224 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
8225 "AND refobjid = '%u'::pg_catalog.oid "
8226 "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
8227 "AND objid = ap.oid "
8228 "ORDER BY amprocnum",
8229 opcinfo->dobj.catId.oid);
8231 else
8233 appendPQExpBuffer(query, "SELECT amprocnum, "
8234 "amproc::pg_catalog.regprocedure "
8235 "FROM pg_catalog.pg_amproc "
8236 "WHERE amopclaid = '%u'::pg_catalog.oid "
8237 "ORDER BY amprocnum",
8238 opcinfo->dobj.catId.oid);
8241 res = PQexec(g_conn, query->data);
8242 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8244 ntups = PQntuples(res);
8246 i_amprocnum = PQfnumber(res, "amprocnum");
8247 i_amproc = PQfnumber(res, "amproc");
8249 for (i = 0; i < ntups; i++)
8251 amprocnum = PQgetvalue(res, i, i_amprocnum);
8252 amproc = PQgetvalue(res, i, i_amproc);
8254 if (needComma)
8255 appendPQExpBuffer(q, " ,\n ");
8257 appendPQExpBuffer(q, "FUNCTION %s %s",
8258 amprocnum, amproc);
8260 needComma = true;
8263 PQclear(res);
8265 appendPQExpBuffer(q, ";\n");
8267 ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
8268 opcinfo->dobj.name,
8269 opcinfo->dobj.namespace->dobj.name,
8270 NULL,
8271 opcinfo->rolname,
8272 false, "OPERATOR CLASS", SECTION_PRE_DATA,
8273 q->data, delq->data, NULL,
8274 opcinfo->dobj.dependencies, opcinfo->dobj.nDeps,
8275 NULL, NULL);
8277 /* Dump Operator Class Comments */
8278 resetPQExpBuffer(q);
8279 appendPQExpBuffer(q, "OPERATOR CLASS %s",
8280 fmtId(opcinfo->dobj.name));
8281 appendPQExpBuffer(q, " USING %s",
8282 fmtId(amname));
8283 dumpComment(fout, q->data,
8284 NULL, opcinfo->rolname,
8285 opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
8287 free(amname);
8288 destroyPQExpBuffer(query);
8289 destroyPQExpBuffer(q);
8290 destroyPQExpBuffer(delq);
8294 * dumpOpfamily
8295 * write out a single operator family definition
8297 static void
8298 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
8300 PQExpBuffer query;
8301 PQExpBuffer q;
8302 PQExpBuffer delq;
8303 PGresult *res;
8304 PGresult *res_ops;
8305 PGresult *res_procs;
8306 int ntups;
8307 int i_amname;
8308 int i_amopstrategy;
8309 int i_amopreqcheck;
8310 int i_amopopr;
8311 int i_amprocnum;
8312 int i_amproc;
8313 int i_amproclefttype;
8314 int i_amprocrighttype;
8315 char *amname;
8316 char *amopstrategy;
8317 char *amopreqcheck;
8318 char *amopopr;
8319 char *amprocnum;
8320 char *amproc;
8321 char *amproclefttype;
8322 char *amprocrighttype;
8323 bool needComma;
8324 int i;
8326 /* Skip if not to be dumped */
8327 if (!opfinfo->dobj.dump || dataOnly)
8328 return;
8331 * We want to dump the opfamily only if (1) it contains "loose" operators
8332 * or functions, or (2) it contains an opclass with a different name or
8333 * owner. Otherwise it's sufficient to let it be created during creation
8334 * of the contained opclass, and not dumping it improves portability of
8335 * the dump. Since we have to fetch the loose operators/funcs anyway, do
8336 * that first.
8339 query = createPQExpBuffer();
8340 q = createPQExpBuffer();
8341 delq = createPQExpBuffer();
8343 /* Make sure we are in proper schema so regoperator works correctly */
8344 selectSourceSchema(opfinfo->dobj.namespace->dobj.name);
8347 * Fetch only those opfamily members that are tied directly to the
8348 * opfamily by pg_depend entries.
8350 if (g_fout->remoteVersion >= 80400)
8353 * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping
8354 * an older server's table in which it is used. Would it be better
8355 * to silently ignore it?
8357 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
8358 "amopopr::pg_catalog.regoperator "
8359 "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
8360 "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8361 "AND refobjid = '%u'::pg_catalog.oid "
8362 "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
8363 "AND objid = ao.oid "
8364 "ORDER BY amopstrategy",
8365 opfinfo->dobj.catId.oid);
8367 else
8369 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
8370 "amopopr::pg_catalog.regoperator "
8371 "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
8372 "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8373 "AND refobjid = '%u'::pg_catalog.oid "
8374 "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
8375 "AND objid = ao.oid "
8376 "ORDER BY amopstrategy",
8377 opfinfo->dobj.catId.oid);
8380 res_ops = PQexec(g_conn, query->data);
8381 check_sql_result(res_ops, g_conn, query->data, PGRES_TUPLES_OK);
8383 resetPQExpBuffer(query);
8385 appendPQExpBuffer(query, "SELECT amprocnum, "
8386 "amproc::pg_catalog.regprocedure, "
8387 "amproclefttype::pg_catalog.regtype, "
8388 "amprocrighttype::pg_catalog.regtype "
8389 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
8390 "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8391 "AND refobjid = '%u'::pg_catalog.oid "
8392 "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
8393 "AND objid = ap.oid "
8394 "ORDER BY amprocnum",
8395 opfinfo->dobj.catId.oid);
8397 res_procs = PQexec(g_conn, query->data);
8398 check_sql_result(res_procs, g_conn, query->data, PGRES_TUPLES_OK);
8400 if (PQntuples(res_ops) == 0 && PQntuples(res_procs) == 0)
8402 /* No loose members, so check contained opclasses */
8403 resetPQExpBuffer(query);
8405 appendPQExpBuffer(query, "SELECT 1 "
8406 "FROM pg_catalog.pg_opclass c, pg_catalog.pg_opfamily f, pg_catalog.pg_depend "
8407 "WHERE f.oid = '%u'::pg_catalog.oid "
8408 "AND refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8409 "AND refobjid = f.oid "
8410 "AND classid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
8411 "AND objid = c.oid "
8412 "AND (opcname != opfname OR opcnamespace != opfnamespace OR opcowner != opfowner) "
8413 "LIMIT 1",
8414 opfinfo->dobj.catId.oid);
8416 res = PQexec(g_conn, query->data);
8417 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8419 if (PQntuples(res) == 0)
8421 /* no need to dump it, so bail out */
8422 PQclear(res);
8423 PQclear(res_ops);
8424 PQclear(res_procs);
8425 destroyPQExpBuffer(query);
8426 destroyPQExpBuffer(q);
8427 destroyPQExpBuffer(delq);
8428 return;
8431 PQclear(res);
8434 /* Get additional fields from the pg_opfamily row */
8435 resetPQExpBuffer(query);
8437 appendPQExpBuffer(query, "SELECT "
8438 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
8439 "FROM pg_catalog.pg_opfamily "
8440 "WHERE oid = '%u'::pg_catalog.oid",
8441 opfinfo->dobj.catId.oid);
8443 res = PQexec(g_conn, query->data);
8444 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8446 /* Expecting a single result only */
8447 ntups = PQntuples(res);
8448 if (ntups != 1)
8450 write_msg(NULL, "query returned %d rows instead of one: %s\n",
8451 ntups, query->data);
8452 exit_nicely();
8455 i_amname = PQfnumber(res, "amname");
8457 /* amname will still be needed after we PQclear res */
8458 amname = strdup(PQgetvalue(res, 0, i_amname));
8461 * DROP must be fully qualified in case same name appears in pg_catalog
8463 appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
8464 fmtId(opfinfo->dobj.namespace->dobj.name));
8465 appendPQExpBuffer(delq, ".%s",
8466 fmtId(opfinfo->dobj.name));
8467 appendPQExpBuffer(delq, " USING %s;\n",
8468 fmtId(amname));
8470 /* Build the fixed portion of the CREATE command */
8471 appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
8472 fmtId(opfinfo->dobj.name));
8473 appendPQExpBuffer(q, " USING %s;\n",
8474 fmtId(amname));
8476 PQclear(res);
8478 /* Do we need an ALTER to add loose members? */
8479 if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
8481 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
8482 fmtId(opfinfo->dobj.name));
8483 appendPQExpBuffer(q, " USING %s ADD\n ",
8484 fmtId(amname));
8486 needComma = false;
8489 * Now fetch and print the OPERATOR entries (pg_amop rows).
8491 ntups = PQntuples(res_ops);
8493 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
8494 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
8495 i_amopopr = PQfnumber(res_ops, "amopopr");
8497 for (i = 0; i < ntups; i++)
8499 amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
8500 amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
8501 amopopr = PQgetvalue(res_ops, i, i_amopopr);
8503 if (needComma)
8504 appendPQExpBuffer(q, " ,\n ");
8506 appendPQExpBuffer(q, "OPERATOR %s %s",
8507 amopstrategy, amopopr);
8508 if (strcmp(amopreqcheck, "t") == 0)
8509 appendPQExpBuffer(q, " RECHECK");
8511 needComma = true;
8515 * Now fetch and print the FUNCTION entries (pg_amproc rows).
8517 ntups = PQntuples(res_procs);
8519 i_amprocnum = PQfnumber(res_procs, "amprocnum");
8520 i_amproc = PQfnumber(res_procs, "amproc");
8521 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
8522 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
8524 for (i = 0; i < ntups; i++)
8526 amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
8527 amproc = PQgetvalue(res_procs, i, i_amproc);
8528 amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
8529 amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
8531 if (needComma)
8532 appendPQExpBuffer(q, " ,\n ");
8534 appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
8535 amprocnum, amproclefttype, amprocrighttype,
8536 amproc);
8538 needComma = true;
8541 appendPQExpBuffer(q, ";\n");
8544 ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
8545 opfinfo->dobj.name,
8546 opfinfo->dobj.namespace->dobj.name,
8547 NULL,
8548 opfinfo->rolname,
8549 false, "OPERATOR FAMILY", SECTION_PRE_DATA,
8550 q->data, delq->data, NULL,
8551 opfinfo->dobj.dependencies, opfinfo->dobj.nDeps,
8552 NULL, NULL);
8554 /* Dump Operator Family Comments */
8555 resetPQExpBuffer(q);
8556 appendPQExpBuffer(q, "OPERATOR FAMILY %s",
8557 fmtId(opfinfo->dobj.name));
8558 appendPQExpBuffer(q, " USING %s",
8559 fmtId(amname));
8560 dumpComment(fout, q->data,
8561 NULL, opfinfo->rolname,
8562 opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
8564 free(amname);
8565 PQclear(res_ops);
8566 PQclear(res_procs);
8567 destroyPQExpBuffer(query);
8568 destroyPQExpBuffer(q);
8569 destroyPQExpBuffer(delq);
8573 * dumpConversion
8574 * write out a single conversion definition
8576 static void
8577 dumpConversion(Archive *fout, ConvInfo *convinfo)
8579 PQExpBuffer query;
8580 PQExpBuffer q;
8581 PQExpBuffer delq;
8582 PQExpBuffer details;
8583 PGresult *res;
8584 int ntups;
8585 int i_conname;
8586 int i_conforencoding;
8587 int i_contoencoding;
8588 int i_conproc;
8589 int i_condefault;
8590 const char *conname;
8591 const char *conforencoding;
8592 const char *contoencoding;
8593 const char *conproc;
8594 bool condefault;
8596 /* Skip if not to be dumped */
8597 if (!convinfo->dobj.dump || dataOnly)
8598 return;
8600 query = createPQExpBuffer();
8601 q = createPQExpBuffer();
8602 delq = createPQExpBuffer();
8603 details = createPQExpBuffer();
8605 /* Make sure we are in proper schema */
8606 selectSourceSchema(convinfo->dobj.namespace->dobj.name);
8608 /* Get conversion-specific details */
8609 appendPQExpBuffer(query, "SELECT conname, "
8610 "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
8611 "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
8612 "conproc, condefault "
8613 "FROM pg_catalog.pg_conversion c "
8614 "WHERE c.oid = '%u'::pg_catalog.oid",
8615 convinfo->dobj.catId.oid);
8617 res = PQexec(g_conn, query->data);
8618 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8620 /* Expecting a single result only */
8621 ntups = PQntuples(res);
8622 if (ntups != 1)
8624 write_msg(NULL, "query returned %d rows instead of one: %s\n",
8625 ntups, query->data);
8626 exit_nicely();
8629 i_conname = PQfnumber(res, "conname");
8630 i_conforencoding = PQfnumber(res, "conforencoding");
8631 i_contoencoding = PQfnumber(res, "contoencoding");
8632 i_conproc = PQfnumber(res, "conproc");
8633 i_condefault = PQfnumber(res, "condefault");
8635 conname = PQgetvalue(res, 0, i_conname);
8636 conforencoding = PQgetvalue(res, 0, i_conforencoding);
8637 contoencoding = PQgetvalue(res, 0, i_contoencoding);
8638 conproc = PQgetvalue(res, 0, i_conproc);
8639 condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
8642 * DROP must be fully qualified in case same name appears in pg_catalog
8644 appendPQExpBuffer(delq, "DROP CONVERSION %s",
8645 fmtId(convinfo->dobj.namespace->dobj.name));
8646 appendPQExpBuffer(delq, ".%s;\n",
8647 fmtId(convinfo->dobj.name));
8649 appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
8650 (condefault) ? "DEFAULT " : "",
8651 fmtId(convinfo->dobj.name));
8652 appendStringLiteralAH(q, conforencoding, fout);
8653 appendPQExpBuffer(q, " TO ");
8654 appendStringLiteralAH(q, contoencoding, fout);
8655 /* regproc is automatically quoted in 7.3 and above */
8656 appendPQExpBuffer(q, " FROM %s;\n", conproc);
8658 ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
8659 convinfo->dobj.name,
8660 convinfo->dobj.namespace->dobj.name,
8661 NULL,
8662 convinfo->rolname,
8663 false, "CONVERSION", SECTION_PRE_DATA,
8664 q->data, delq->data, NULL,
8665 convinfo->dobj.dependencies, convinfo->dobj.nDeps,
8666 NULL, NULL);
8668 /* Dump Conversion Comments */
8669 resetPQExpBuffer(q);
8670 appendPQExpBuffer(q, "CONVERSION %s", fmtId(convinfo->dobj.name));
8671 dumpComment(fout, q->data,
8672 convinfo->dobj.namespace->dobj.name, convinfo->rolname,
8673 convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
8675 PQclear(res);
8677 destroyPQExpBuffer(query);
8678 destroyPQExpBuffer(q);
8679 destroyPQExpBuffer(delq);
8680 destroyPQExpBuffer(details);
8684 * format_aggregate_signature: generate aggregate name and argument list
8686 * The argument type names are qualified if needed. The aggregate name
8687 * is never qualified.
8689 static char *
8690 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
8692 PQExpBufferData buf;
8693 int j;
8695 initPQExpBuffer(&buf);
8696 if (honor_quotes)
8697 appendPQExpBuffer(&buf, "%s",
8698 fmtId(agginfo->aggfn.dobj.name));
8699 else
8700 appendPQExpBuffer(&buf, "%s", agginfo->aggfn.dobj.name);
8702 if (agginfo->aggfn.nargs == 0)
8703 appendPQExpBuffer(&buf, "(*)");
8704 else
8706 appendPQExpBuffer(&buf, "(");
8707 for (j = 0; j < agginfo->aggfn.nargs; j++)
8709 char *typname;
8711 typname = getFormattedTypeName(agginfo->aggfn.argtypes[j], zeroAsOpaque);
8713 appendPQExpBuffer(&buf, "%s%s",
8714 (j > 0) ? ", " : "",
8715 typname);
8716 free(typname);
8718 appendPQExpBuffer(&buf, ")");
8720 return buf.data;
8724 * dumpAgg
8725 * write out a single aggregate definition
8727 static void
8728 dumpAgg(Archive *fout, AggInfo *agginfo)
8730 PQExpBuffer query;
8731 PQExpBuffer q;
8732 PQExpBuffer delq;
8733 PQExpBuffer details;
8734 char *aggsig;
8735 char *aggsig_tag;
8736 PGresult *res;
8737 int ntups;
8738 int i_aggtransfn;
8739 int i_aggfinalfn;
8740 int i_aggsortop;
8741 int i_aggtranstype;
8742 int i_agginitval;
8743 int i_convertok;
8744 const char *aggtransfn;
8745 const char *aggfinalfn;
8746 const char *aggsortop;
8747 const char *aggtranstype;
8748 const char *agginitval;
8749 bool convertok;
8751 /* Skip if not to be dumped */
8752 if (!agginfo->aggfn.dobj.dump || dataOnly)
8753 return;
8755 query = createPQExpBuffer();
8756 q = createPQExpBuffer();
8757 delq = createPQExpBuffer();
8758 details = createPQExpBuffer();
8760 /* Make sure we are in proper schema */
8761 selectSourceSchema(agginfo->aggfn.dobj.namespace->dobj.name);
8763 /* Get aggregate-specific details */
8764 if (g_fout->remoteVersion >= 80100)
8766 appendPQExpBuffer(query, "SELECT aggtransfn, "
8767 "aggfinalfn, aggtranstype::pg_catalog.regtype, "
8768 "aggsortop::pg_catalog.regoperator, "
8769 "agginitval, "
8770 "'t'::boolean AS convertok "
8771 "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
8772 "WHERE a.aggfnoid = p.oid "
8773 "AND p.oid = '%u'::pg_catalog.oid",
8774 agginfo->aggfn.dobj.catId.oid);
8776 else if (g_fout->remoteVersion >= 70300)
8778 appendPQExpBuffer(query, "SELECT aggtransfn, "
8779 "aggfinalfn, aggtranstype::pg_catalog.regtype, "
8780 "0 AS aggsortop, "
8781 "agginitval, "
8782 "'t'::boolean AS convertok "
8783 "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
8784 "WHERE a.aggfnoid = p.oid "
8785 "AND p.oid = '%u'::pg_catalog.oid",
8786 agginfo->aggfn.dobj.catId.oid);
8788 else if (g_fout->remoteVersion >= 70100)
8790 appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
8791 "format_type(aggtranstype, NULL) AS aggtranstype, "
8792 "0 AS aggsortop, "
8793 "agginitval, "
8794 "'t'::boolean AS convertok "
8795 "FROM pg_aggregate "
8796 "WHERE oid = '%u'::oid",
8797 agginfo->aggfn.dobj.catId.oid);
8799 else
8801 appendPQExpBuffer(query, "SELECT aggtransfn1 AS aggtransfn, "
8802 "aggfinalfn, "
8803 "(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
8804 "0 AS aggsortop, "
8805 "agginitval1 AS agginitval, "
8806 "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
8807 "FROM pg_aggregate "
8808 "WHERE oid = '%u'::oid",
8809 agginfo->aggfn.dobj.catId.oid);
8812 res = PQexec(g_conn, query->data);
8813 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8815 /* Expecting a single result only */
8816 ntups = PQntuples(res);
8817 if (ntups != 1)
8819 write_msg(NULL, "query returned %d rows instead of one: %s\n",
8820 ntups, query->data);
8821 exit_nicely();
8824 i_aggtransfn = PQfnumber(res, "aggtransfn");
8825 i_aggfinalfn = PQfnumber(res, "aggfinalfn");
8826 i_aggsortop = PQfnumber(res, "aggsortop");
8827 i_aggtranstype = PQfnumber(res, "aggtranstype");
8828 i_agginitval = PQfnumber(res, "agginitval");
8829 i_convertok = PQfnumber(res, "convertok");
8831 aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
8832 aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
8833 aggsortop = PQgetvalue(res, 0, i_aggsortop);
8834 aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
8835 agginitval = PQgetvalue(res, 0, i_agginitval);
8836 convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
8838 aggsig = format_aggregate_signature(agginfo, fout, true);
8839 aggsig_tag = format_aggregate_signature(agginfo, fout, false);
8841 if (!convertok)
8843 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
8844 aggsig);
8845 return;
8848 if (g_fout->remoteVersion >= 70300)
8850 /* If using 7.3's regproc or regtype, data is already quoted */
8851 appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
8852 aggtransfn,
8853 aggtranstype);
8855 else if (g_fout->remoteVersion >= 70100)
8857 /* format_type quotes, regproc does not */
8858 appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
8859 fmtId(aggtransfn),
8860 aggtranstype);
8862 else
8864 /* need quotes all around */
8865 appendPQExpBuffer(details, " SFUNC = %s,\n",
8866 fmtId(aggtransfn));
8867 appendPQExpBuffer(details, " STYPE = %s",
8868 fmtId(aggtranstype));
8871 if (!PQgetisnull(res, 0, i_agginitval))
8873 appendPQExpBuffer(details, ",\n INITCOND = ");
8874 appendStringLiteralAH(details, agginitval, fout);
8877 if (strcmp(aggfinalfn, "-") != 0)
8879 appendPQExpBuffer(details, ",\n FINALFUNC = %s",
8880 aggfinalfn);
8883 aggsortop = convertOperatorReference(aggsortop);
8884 if (aggsortop)
8886 appendPQExpBuffer(details, ",\n SORTOP = %s",
8887 aggsortop);
8891 * DROP must be fully qualified in case same name appears in pg_catalog
8893 appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
8894 fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
8895 aggsig);
8897 appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
8898 aggsig, details->data);
8900 ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
8901 aggsig_tag,
8902 agginfo->aggfn.dobj.namespace->dobj.name,
8903 NULL,
8904 agginfo->aggfn.rolname,
8905 false, "AGGREGATE", SECTION_PRE_DATA,
8906 q->data, delq->data, NULL,
8907 agginfo->aggfn.dobj.dependencies, agginfo->aggfn.dobj.nDeps,
8908 NULL, NULL);
8910 /* Dump Aggregate Comments */
8911 resetPQExpBuffer(q);
8912 appendPQExpBuffer(q, "AGGREGATE %s", aggsig);
8913 dumpComment(fout, q->data,
8914 agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
8915 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
8918 * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
8919 * command look like a function's GRANT; in particular this affects the
8920 * syntax for zero-argument aggregates.
8922 free(aggsig);
8923 free(aggsig_tag);
8925 aggsig = format_function_signature(&agginfo->aggfn, true);
8926 aggsig_tag = format_function_signature(&agginfo->aggfn, false);
8928 dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
8929 "FUNCTION",
8930 aggsig, NULL, aggsig_tag,
8931 agginfo->aggfn.dobj.namespace->dobj.name,
8932 agginfo->aggfn.rolname, agginfo->aggfn.proacl);
8934 free(aggsig);
8935 free(aggsig_tag);
8937 PQclear(res);
8939 destroyPQExpBuffer(query);
8940 destroyPQExpBuffer(q);
8941 destroyPQExpBuffer(delq);
8942 destroyPQExpBuffer(details);
8946 * dumpTSParser
8947 * write out a single text search parser
8949 static void
8950 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
8952 PQExpBuffer q;
8953 PQExpBuffer delq;
8955 /* Skip if not to be dumped */
8956 if (!prsinfo->dobj.dump || dataOnly)
8957 return;
8959 q = createPQExpBuffer();
8960 delq = createPQExpBuffer();
8962 /* Make sure we are in proper schema */
8963 selectSourceSchema(prsinfo->dobj.namespace->dobj.name);
8965 appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
8966 fmtId(prsinfo->dobj.name));
8968 appendPQExpBuffer(q, " START = %s,\n",
8969 convertTSFunction(prsinfo->prsstart));
8970 appendPQExpBuffer(q, " GETTOKEN = %s,\n",
8971 convertTSFunction(prsinfo->prstoken));
8972 appendPQExpBuffer(q, " END = %s,\n",
8973 convertTSFunction(prsinfo->prsend));
8974 if (prsinfo->prsheadline != InvalidOid)
8975 appendPQExpBuffer(q, " HEADLINE = %s,\n",
8976 convertTSFunction(prsinfo->prsheadline));
8977 appendPQExpBuffer(q, " LEXTYPES = %s );\n",
8978 convertTSFunction(prsinfo->prslextype));
8981 * DROP must be fully qualified in case same name appears in pg_catalog
8983 appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s",
8984 fmtId(prsinfo->dobj.namespace->dobj.name));
8985 appendPQExpBuffer(delq, ".%s;\n",
8986 fmtId(prsinfo->dobj.name));
8988 ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
8989 prsinfo->dobj.name,
8990 prsinfo->dobj.namespace->dobj.name,
8991 NULL,
8993 false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
8994 q->data, delq->data, NULL,
8995 prsinfo->dobj.dependencies, prsinfo->dobj.nDeps,
8996 NULL, NULL);
8998 /* Dump Parser Comments */
8999 resetPQExpBuffer(q);
9000 appendPQExpBuffer(q, "TEXT SEARCH PARSER %s",
9001 fmtId(prsinfo->dobj.name));
9002 dumpComment(fout, q->data,
9003 NULL, "",
9004 prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
9006 destroyPQExpBuffer(q);
9007 destroyPQExpBuffer(delq);
9011 * dumpTSDictionary
9012 * write out a single text search dictionary
9014 static void
9015 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
9017 PQExpBuffer q;
9018 PQExpBuffer delq;
9019 PQExpBuffer query;
9020 PGresult *res;
9021 int ntups;
9022 char *nspname;
9023 char *tmplname;
9025 /* Skip if not to be dumped */
9026 if (!dictinfo->dobj.dump || dataOnly)
9027 return;
9029 q = createPQExpBuffer();
9030 delq = createPQExpBuffer();
9031 query = createPQExpBuffer();
9033 /* Fetch name and namespace of the dictionary's template */
9034 selectSourceSchema("pg_catalog");
9035 appendPQExpBuffer(query, "SELECT nspname, tmplname "
9036 "FROM pg_ts_template p, pg_namespace n "
9037 "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
9038 dictinfo->dicttemplate);
9039 res = PQexec(g_conn, query->data);
9040 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9041 ntups = PQntuples(res);
9042 if (ntups != 1)
9044 write_msg(NULL, "query returned %d rows instead of one: %s\n",
9045 ntups, query->data);
9046 exit_nicely();
9048 nspname = PQgetvalue(res, 0, 0);
9049 tmplname = PQgetvalue(res, 0, 1);
9051 /* Make sure we are in proper schema */
9052 selectSourceSchema(dictinfo->dobj.namespace->dobj.name);
9054 appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
9055 fmtId(dictinfo->dobj.name));
9057 appendPQExpBuffer(q, " TEMPLATE = ");
9058 if (strcmp(nspname, dictinfo->dobj.namespace->dobj.name) != 0)
9059 appendPQExpBuffer(q, "%s.", fmtId(nspname));
9060 appendPQExpBuffer(q, "%s", fmtId(tmplname));
9062 PQclear(res);
9064 /* the dictinitoption can be dumped straight into the command */
9065 if (dictinfo->dictinitoption)
9066 appendPQExpBuffer(q, ",\n %s", dictinfo->dictinitoption);
9068 appendPQExpBuffer(q, " );\n");
9071 * DROP must be fully qualified in case same name appears in pg_catalog
9073 appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s",
9074 fmtId(dictinfo->dobj.namespace->dobj.name));
9075 appendPQExpBuffer(delq, ".%s;\n",
9076 fmtId(dictinfo->dobj.name));
9078 ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
9079 dictinfo->dobj.name,
9080 dictinfo->dobj.namespace->dobj.name,
9081 NULL,
9082 dictinfo->rolname,
9083 false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
9084 q->data, delq->data, NULL,
9085 dictinfo->dobj.dependencies, dictinfo->dobj.nDeps,
9086 NULL, NULL);
9088 /* Dump Dictionary Comments */
9089 resetPQExpBuffer(q);
9090 appendPQExpBuffer(q, "TEXT SEARCH DICTIONARY %s",
9091 fmtId(dictinfo->dobj.name));
9092 dumpComment(fout, q->data,
9093 NULL, dictinfo->rolname,
9094 dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
9096 destroyPQExpBuffer(q);
9097 destroyPQExpBuffer(delq);
9098 destroyPQExpBuffer(query);
9102 * dumpTSTemplate
9103 * write out a single text search template
9105 static void
9106 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
9108 PQExpBuffer q;
9109 PQExpBuffer delq;
9111 /* Skip if not to be dumped */
9112 if (!tmplinfo->dobj.dump || dataOnly)
9113 return;
9115 q = createPQExpBuffer();
9116 delq = createPQExpBuffer();
9118 /* Make sure we are in proper schema */
9119 selectSourceSchema(tmplinfo->dobj.namespace->dobj.name);
9121 appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
9122 fmtId(tmplinfo->dobj.name));
9124 if (tmplinfo->tmplinit != InvalidOid)
9125 appendPQExpBuffer(q, " INIT = %s,\n",
9126 convertTSFunction(tmplinfo->tmplinit));
9127 appendPQExpBuffer(q, " LEXIZE = %s );\n",
9128 convertTSFunction(tmplinfo->tmpllexize));
9131 * DROP must be fully qualified in case same name appears in pg_catalog
9133 appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s",
9134 fmtId(tmplinfo->dobj.namespace->dobj.name));
9135 appendPQExpBuffer(delq, ".%s;\n",
9136 fmtId(tmplinfo->dobj.name));
9138 ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
9139 tmplinfo->dobj.name,
9140 tmplinfo->dobj.namespace->dobj.name,
9141 NULL,
9143 false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
9144 q->data, delq->data, NULL,
9145 tmplinfo->dobj.dependencies, tmplinfo->dobj.nDeps,
9146 NULL, NULL);
9148 /* Dump Template Comments */
9149 resetPQExpBuffer(q);
9150 appendPQExpBuffer(q, "TEXT SEARCH TEMPLATE %s",
9151 fmtId(tmplinfo->dobj.name));
9152 dumpComment(fout, q->data,
9153 NULL, "",
9154 tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
9156 destroyPQExpBuffer(q);
9157 destroyPQExpBuffer(delq);
9161 * dumpTSConfig
9162 * write out a single text search configuration
9164 static void
9165 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
9167 PQExpBuffer q;
9168 PQExpBuffer delq;
9169 PQExpBuffer query;
9170 PGresult *res;
9171 char *nspname;
9172 char *prsname;
9173 int ntups,
9175 int i_tokenname;
9176 int i_dictname;
9178 /* Skip if not to be dumped */
9179 if (!cfginfo->dobj.dump || dataOnly)
9180 return;
9182 q = createPQExpBuffer();
9183 delq = createPQExpBuffer();
9184 query = createPQExpBuffer();
9186 /* Fetch name and namespace of the config's parser */
9187 selectSourceSchema("pg_catalog");
9188 appendPQExpBuffer(query, "SELECT nspname, prsname "
9189 "FROM pg_ts_parser p, pg_namespace n "
9190 "WHERE p.oid = '%u' AND n.oid = prsnamespace",
9191 cfginfo->cfgparser);
9192 res = PQexec(g_conn, query->data);
9193 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9194 ntups = PQntuples(res);
9195 if (ntups != 1)
9197 write_msg(NULL, "query returned %d rows instead of one: %s\n",
9198 ntups, query->data);
9199 exit_nicely();
9201 nspname = PQgetvalue(res, 0, 0);
9202 prsname = PQgetvalue(res, 0, 1);
9204 /* Make sure we are in proper schema */
9205 selectSourceSchema(cfginfo->dobj.namespace->dobj.name);
9207 appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
9208 fmtId(cfginfo->dobj.name));
9210 appendPQExpBuffer(q, " PARSER = ");
9211 if (strcmp(nspname, cfginfo->dobj.namespace->dobj.name) != 0)
9212 appendPQExpBuffer(q, "%s.", fmtId(nspname));
9213 appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
9215 PQclear(res);
9217 resetPQExpBuffer(query);
9218 appendPQExpBuffer(query,
9219 "SELECT \n"
9220 " ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t \n"
9221 " WHERE t.tokid = m.maptokentype ) AS tokenname, \n"
9222 " m.mapdict::pg_catalog.regdictionary AS dictname \n"
9223 "FROM pg_catalog.pg_ts_config_map AS m \n"
9224 "WHERE m.mapcfg = '%u' \n"
9225 "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
9226 cfginfo->cfgparser, cfginfo->dobj.catId.oid);
9228 res = PQexec(g_conn, query->data);
9229 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9230 ntups = PQntuples(res);
9232 i_tokenname = PQfnumber(res, "tokenname");
9233 i_dictname = PQfnumber(res, "dictname");
9235 for (i = 0; i < ntups; i++)
9237 char *tokenname = PQgetvalue(res, i, i_tokenname);
9238 char *dictname = PQgetvalue(res, i, i_dictname);
9240 if (i == 0 ||
9241 strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
9243 /* starting a new token type, so start a new command */
9244 if (i > 0)
9245 appendPQExpBuffer(q, ";\n");
9246 appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
9247 fmtId(cfginfo->dobj.name));
9248 /* tokenname needs quoting, dictname does NOT */
9249 appendPQExpBuffer(q, " ADD MAPPING FOR %s WITH %s",
9250 fmtId(tokenname), dictname);
9252 else
9253 appendPQExpBuffer(q, ", %s", dictname);
9256 if (ntups > 0)
9257 appendPQExpBuffer(q, ";\n");
9259 PQclear(res);
9262 * DROP must be fully qualified in case same name appears in pg_catalog
9264 appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s",
9265 fmtId(cfginfo->dobj.namespace->dobj.name));
9266 appendPQExpBuffer(delq, ".%s;\n",
9267 fmtId(cfginfo->dobj.name));
9269 ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
9270 cfginfo->dobj.name,
9271 cfginfo->dobj.namespace->dobj.name,
9272 NULL,
9273 cfginfo->rolname,
9274 false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
9275 q->data, delq->data, NULL,
9276 cfginfo->dobj.dependencies, cfginfo->dobj.nDeps,
9277 NULL, NULL);
9279 /* Dump Configuration Comments */
9280 resetPQExpBuffer(q);
9281 appendPQExpBuffer(q, "TEXT SEARCH CONFIGURATION %s",
9282 fmtId(cfginfo->dobj.name));
9283 dumpComment(fout, q->data,
9284 NULL, cfginfo->rolname,
9285 cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
9287 destroyPQExpBuffer(q);
9288 destroyPQExpBuffer(delq);
9289 destroyPQExpBuffer(query);
9293 * dumpForeignDataWrapper
9294 * write out a single foreign-data wrapper definition
9296 static void
9297 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
9299 PQExpBuffer q;
9300 PQExpBuffer delq;
9301 char *namecopy;
9303 /* Skip if not to be dumped */
9304 if (!fdwinfo->dobj.dump || dataOnly)
9305 return;
9307 q = createPQExpBuffer();
9308 delq = createPQExpBuffer();
9310 appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
9311 fmtId(fdwinfo->dobj.name));
9313 if (fdwinfo->fdwvalidator && strcmp(fdwinfo->fdwvalidator, "-") != 0)
9314 appendPQExpBuffer(q, " VALIDATOR %s",
9315 fdwinfo->fdwvalidator);
9317 if (fdwinfo->fdwoptions && strlen(fdwinfo->fdwoptions) > 0)
9318 appendPQExpBuffer(q, " OPTIONS (%s)", fdwinfo->fdwoptions);
9320 appendPQExpBuffer(q, ";\n");
9322 appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
9323 fmtId(fdwinfo->dobj.name));
9325 ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
9326 fdwinfo->dobj.name,
9327 NULL,
9328 NULL,
9329 fdwinfo->rolname,
9330 false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
9331 q->data, delq->data, NULL,
9332 fdwinfo->dobj.dependencies, fdwinfo->dobj.nDeps,
9333 NULL, NULL);
9335 /* Handle the ACL */
9336 namecopy = strdup(fmtId(fdwinfo->dobj.name));
9337 dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
9338 "FOREIGN DATA WRAPPER",
9339 namecopy, NULL, fdwinfo->dobj.name,
9340 NULL, fdwinfo->rolname,
9341 fdwinfo->fdwacl);
9342 free(namecopy);
9344 destroyPQExpBuffer(q);
9345 destroyPQExpBuffer(delq);
9349 * dumpForeignServer
9350 * write out a foreign server definition
9352 static void
9353 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
9355 PQExpBuffer q;
9356 PQExpBuffer delq;
9357 PQExpBuffer query;
9358 PGresult *res;
9359 int ntups;
9360 char *namecopy;
9361 char *fdwname;
9363 /* Skip if not to be dumped */
9364 if (!srvinfo->dobj.dump || dataOnly)
9365 return;
9367 q = createPQExpBuffer();
9368 delq = createPQExpBuffer();
9369 query = createPQExpBuffer();
9371 /* look up the foreign-data wrapper */
9372 appendPQExpBuffer(query, "SELECT fdwname "
9373 "FROM pg_foreign_data_wrapper w "
9374 "WHERE w.oid = '%u'",
9375 srvinfo->srvfdw);
9376 res = PQexec(g_conn, query->data);
9377 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9378 ntups = PQntuples(res);
9379 if (ntups != 1)
9381 write_msg(NULL, "query returned %d rows instead of one: %s\n",
9382 ntups, query->data);
9383 exit_nicely();
9385 fdwname = PQgetvalue(res, 0, 0);
9387 appendPQExpBuffer(q, "CREATE SERVER %s", fmtId(srvinfo->dobj.name));
9388 if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
9389 appendPQExpBuffer(q, " TYPE '%s'", srvinfo->srvtype);
9390 if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
9391 appendPQExpBuffer(q, " VERSION '%s'", srvinfo->srvversion);
9393 appendPQExpBuffer(q, " FOREIGN DATA WRAPPER ");
9394 appendPQExpBuffer(q, "%s", fmtId(fdwname));
9396 if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
9397 appendPQExpBuffer(q, " OPTIONS (%s)", srvinfo->srvoptions);
9399 appendPQExpBuffer(q, ";\n");
9401 appendPQExpBuffer(delq, "DROP SERVER %s;\n",
9402 fmtId(srvinfo->dobj.name));
9404 ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
9405 srvinfo->dobj.name,
9406 NULL,
9407 NULL,
9408 srvinfo->rolname,
9409 false, "SERVER", SECTION_PRE_DATA,
9410 q->data, delq->data, NULL,
9411 srvinfo->dobj.dependencies, srvinfo->dobj.nDeps,
9412 NULL, NULL);
9414 /* Handle the ACL */
9415 namecopy = strdup(fmtId(srvinfo->dobj.name));
9416 dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
9417 "SERVER",
9418 namecopy, NULL, srvinfo->dobj.name,
9419 NULL, srvinfo->rolname,
9420 srvinfo->srvacl);
9421 free(namecopy);
9423 /* Dump user mappings */
9424 resetPQExpBuffer(q);
9425 appendPQExpBuffer(q, "SERVER %s", fmtId(srvinfo->dobj.name));
9426 dumpUserMappings(fout, q->data,
9427 srvinfo->dobj.name, NULL,
9428 srvinfo->rolname,
9429 srvinfo->dobj.catId, srvinfo->dobj.dumpId);
9431 destroyPQExpBuffer(q);
9432 destroyPQExpBuffer(delq);
9436 * dumpUserMappings
9438 * This routine is used to dump any user mappings associated with the
9439 * server handed to this routine. Should be called after ArchiveEntry()
9440 * for the server.
9442 static void
9443 dumpUserMappings(Archive *fout, const char *target,
9444 const char *servername, const char *namespace,
9445 const char *owner,
9446 CatalogId catalogId, DumpId dumpId)
9448 PQExpBuffer q;
9449 PQExpBuffer delq;
9450 PQExpBuffer query;
9451 PQExpBuffer tag;
9452 PGresult *res;
9453 int ntups;
9454 int i_umuser;
9455 int i_umoptions;
9456 int i;
9458 q = createPQExpBuffer();
9459 tag = createPQExpBuffer();
9460 delq = createPQExpBuffer();
9461 query = createPQExpBuffer();
9463 appendPQExpBuffer(query,
9464 "SELECT (%s umuser) AS umuser, "
9465 "array_to_string(ARRAY(SELECT option_name || ' ' || quote_literal(option_value) FROM pg_options_to_table(umoptions)), ', ') AS umoptions\n"
9466 "FROM pg_user_mapping "
9467 "WHERE umserver=%u",
9468 username_subquery,
9469 catalogId.oid);
9471 res = PQexec(g_conn, query->data);
9472 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9474 ntups = PQntuples(res);
9475 i_umuser = PQfnumber(res, "umuser");
9476 i_umoptions = PQfnumber(res, "umoptions");
9478 for (i = 0; i < ntups; i++)
9480 char *umuser;
9481 char *umoptions;
9483 umuser = PQgetvalue(res, i, i_umuser);
9484 umoptions = PQgetvalue(res, i, i_umoptions);
9486 resetPQExpBuffer(q);
9487 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(umuser));
9488 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
9490 if (umoptions && strlen(umoptions) > 0)
9491 appendPQExpBuffer(q, " OPTIONS (%s)", umoptions);
9493 appendPQExpBuffer(q, ";\n");
9495 resetPQExpBuffer(delq);
9496 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s SERVER %s;\n", fmtId(umuser), fmtId(servername));
9498 resetPQExpBuffer(tag);
9499 appendPQExpBuffer(tag, "USER MAPPING %s %s", fmtId(umuser), target);
9501 ArchiveEntry(fout, nilCatalogId, createDumpId(),
9502 tag->data,
9503 namespace,
9504 NULL,
9505 owner, false,
9506 "USER MAPPING", SECTION_PRE_DATA,
9507 q->data, delq->data, NULL,
9508 &dumpId, 1,
9509 NULL, NULL);
9512 PQclear(res);
9514 destroyPQExpBuffer(query);
9515 destroyPQExpBuffer(delq);
9516 destroyPQExpBuffer(q);
9519 /*----------
9520 * Write out grant/revoke information
9522 * 'objCatId' is the catalog ID of the underlying object.
9523 * 'objDumpId' is the dump ID of the underlying object.
9524 * 'type' must be TABLE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, or TABLESPACE.
9525 * 'name' is the formatted name of the object. Must be quoted etc. already.
9526 * 'subname' is the formatted name of the sub-object, if any. Must be quoted.
9527 * 'tag' is the tag for the archive entry (typ. unquoted name of object).
9528 * 'nspname' is the namespace the object is in (NULL if none).
9529 * 'owner' is the owner, NULL if there is no owner (for languages).
9530 * 'acls' is the string read out of the fooacl system catalog field;
9531 * it will be parsed here.
9532 *----------
9534 static void
9535 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
9536 const char *type, const char *name, const char *subname,
9537 const char *tag, const char *nspname, const char *owner,
9538 const char *acls)
9540 PQExpBuffer sql;
9542 /* Do nothing if ACL dump is not enabled */
9543 if (dataOnly || aclsSkip)
9544 return;
9546 sql = createPQExpBuffer();
9548 if (!buildACLCommands(name, subname, type, acls, owner, fout->remoteVersion, sql))
9550 write_msg(NULL, "could not parse ACL list (%s) for object \"%s\" (%s)\n",
9551 acls, name, type);
9552 exit_nicely();
9555 if (sql->len > 0)
9556 ArchiveEntry(fout, nilCatalogId, createDumpId(),
9557 tag, nspname,
9558 NULL,
9559 owner ? owner : "",
9560 false, "ACL", SECTION_NONE,
9561 sql->data, "", NULL,
9562 &(objDumpId), 1,
9563 NULL, NULL);
9565 destroyPQExpBuffer(sql);
9569 * dumpTable
9570 * write out to fout the declarations (not data) of a user-defined table
9572 static void
9573 dumpTable(Archive *fout, TableInfo *tbinfo)
9575 if (tbinfo->dobj.dump)
9577 char *namecopy;
9579 if (tbinfo->relkind == RELKIND_SEQUENCE)
9580 dumpSequence(fout, tbinfo);
9581 else if (!dataOnly)
9582 dumpTableSchema(fout, tbinfo);
9584 /* Handle the ACL here */
9585 namecopy = strdup(fmtId(tbinfo->dobj.name));
9586 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
9587 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE",
9588 namecopy, NULL, tbinfo->dobj.name,
9589 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
9590 tbinfo->relacl);
9593 * Handle column ACLs, if any. Note: we pull these with a separate
9594 * query rather than trying to fetch them during getTableAttrs, so
9595 * that we won't miss ACLs on system columns.
9597 if (g_fout->remoteVersion >= 80400)
9599 PQExpBuffer query = createPQExpBuffer();
9600 PGresult *res;
9601 int i;
9603 appendPQExpBuffer(query,
9604 "SELECT attname, attacl FROM pg_catalog.pg_attribute "
9605 "WHERE attrelid = '%u' AND NOT attisdropped AND attacl IS NOT NULL "
9606 "ORDER BY attnum",
9607 tbinfo->dobj.catId.oid);
9608 res = PQexec(g_conn, query->data);
9609 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9611 for (i = 0; i < PQntuples(res); i++)
9613 char *attname = PQgetvalue(res, i, 0);
9614 char *attacl = PQgetvalue(res, i, 1);
9615 char *attnamecopy;
9616 char *acltag;
9618 attnamecopy = strdup(fmtId(attname));
9619 acltag = malloc(strlen(tbinfo->dobj.name) + strlen(attname) + 2);
9620 sprintf(acltag, "%s.%s", tbinfo->dobj.name, attname);
9621 /* Column's GRANT type is always TABLE */
9622 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
9623 namecopy, attnamecopy, acltag,
9624 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
9625 attacl);
9626 free(attnamecopy);
9627 free(acltag);
9629 PQclear(res);
9630 destroyPQExpBuffer(query);
9633 free(namecopy);
9638 * dumpTableSchema
9639 * write the declaration (not data) of one user-defined table or view
9641 static void
9642 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
9644 PQExpBuffer query = createPQExpBuffer();
9645 PQExpBuffer q = createPQExpBuffer();
9646 PQExpBuffer delq = createPQExpBuffer();
9647 PGresult *res;
9648 int numParents;
9649 TableInfo **parents;
9650 int actual_atts; /* number of attrs in this CREATE statment */
9651 char *reltypename;
9652 char *storage;
9653 int j,
9656 /* Make sure we are in proper schema */
9657 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
9659 /* Is it a table or a view? */
9660 if (tbinfo->relkind == RELKIND_VIEW)
9662 char *viewdef;
9664 reltypename = "VIEW";
9666 /* Fetch the view definition */
9667 if (g_fout->remoteVersion >= 70300)
9669 /* Beginning in 7.3, viewname is not unique; rely on OID */
9670 appendPQExpBuffer(query,
9671 "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
9672 tbinfo->dobj.catId.oid);
9674 else
9676 appendPQExpBuffer(query, "SELECT definition AS viewdef "
9677 "FROM pg_views WHERE viewname = ");
9678 appendStringLiteralAH(query, tbinfo->dobj.name, fout);
9679 appendPQExpBuffer(query, ";");
9682 res = PQexec(g_conn, query->data);
9683 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9685 if (PQntuples(res) != 1)
9687 if (PQntuples(res) < 1)
9688 write_msg(NULL, "query to obtain definition of view \"%s\" returned no data\n",
9689 tbinfo->dobj.name);
9690 else
9691 write_msg(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
9692 tbinfo->dobj.name);
9693 exit_nicely();
9696 viewdef = PQgetvalue(res, 0, 0);
9698 if (strlen(viewdef) == 0)
9700 write_msg(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
9701 tbinfo->dobj.name);
9702 exit_nicely();
9706 * DROP must be fully qualified in case same name appears in
9707 * pg_catalog
9709 appendPQExpBuffer(delq, "DROP VIEW %s.",
9710 fmtId(tbinfo->dobj.namespace->dobj.name));
9711 appendPQExpBuffer(delq, "%s;\n",
9712 fmtId(tbinfo->dobj.name));
9714 appendPQExpBuffer(q, "CREATE VIEW %s AS\n %s\n",
9715 fmtId(tbinfo->dobj.name), viewdef);
9717 PQclear(res);
9719 else
9721 reltypename = "TABLE";
9722 numParents = tbinfo->numParents;
9723 parents = tbinfo->parents;
9726 * DROP must be fully qualified in case same name appears in
9727 * pg_catalog
9729 appendPQExpBuffer(delq, "DROP TABLE %s.",
9730 fmtId(tbinfo->dobj.namespace->dobj.name));
9731 appendPQExpBuffer(delq, "%s;\n",
9732 fmtId(tbinfo->dobj.name));
9734 appendPQExpBuffer(q, "CREATE TABLE %s (",
9735 fmtId(tbinfo->dobj.name));
9736 actual_atts = 0;
9737 for (j = 0; j < tbinfo->numatts; j++)
9739 /* Is this one of the table's own attrs, and not dropped ? */
9740 if (!tbinfo->inhAttrs[j] &&
9741 (!tbinfo->attisdropped[j] || binary_upgrade))
9743 /* Format properly if not first attr */
9744 if (actual_atts > 0)
9745 appendPQExpBuffer(q, ",");
9746 appendPQExpBuffer(q, "\n ");
9748 /* Attribute name */
9749 appendPQExpBuffer(q, "%s ",
9750 fmtId(tbinfo->attnames[j]));
9752 /* Attribute type */
9753 if (g_fout->remoteVersion >= 70100)
9755 appendPQExpBuffer(q, "%s",
9756 tbinfo->atttypnames[j]);
9758 else
9760 /* If no format_type, fake it */
9761 appendPQExpBuffer(q, "%s",
9762 myFormatType(tbinfo->atttypnames[j],
9763 tbinfo->atttypmod[j]));
9767 * Default value --- suppress if inherited or to be printed
9768 * separately.
9770 if (tbinfo->attrdefs[j] != NULL &&
9771 !tbinfo->inhAttrDef[j] &&
9772 !tbinfo->attrdefs[j]->separate)
9773 appendPQExpBuffer(q, " DEFAULT %s",
9774 tbinfo->attrdefs[j]->adef_expr);
9777 * Not Null constraint --- suppress if inherited
9779 if (tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
9780 appendPQExpBuffer(q, " NOT NULL");
9782 actual_atts++;
9787 * Add non-inherited CHECK constraints, if any.
9789 for (j = 0; j < tbinfo->ncheck; j++)
9791 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
9793 if (constr->separate || !constr->conislocal)
9794 continue;
9796 if (actual_atts > 0)
9797 appendPQExpBuffer(q, ",\n ");
9799 appendPQExpBuffer(q, "CONSTRAINT %s ",
9800 fmtId(constr->dobj.name));
9801 appendPQExpBuffer(q, "%s", constr->condef);
9803 actual_atts++;
9806 appendPQExpBuffer(q, "\n)");
9808 if (numParents > 0)
9810 appendPQExpBuffer(q, "\nINHERITS (");
9811 for (k = 0; k < numParents; k++)
9813 TableInfo *parentRel = parents[k];
9815 if (k > 0)
9816 appendPQExpBuffer(q, ", ");
9817 if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
9818 appendPQExpBuffer(q, "%s.",
9819 fmtId(parentRel->dobj.namespace->dobj.name));
9820 appendPQExpBuffer(q, "%s",
9821 fmtId(parentRel->dobj.name));
9823 appendPQExpBuffer(q, ")");
9826 if ((tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) ||
9827 (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0))
9829 bool addcomma = false;
9831 appendPQExpBuffer(q, "\nWITH (");
9832 if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
9834 addcomma = true;
9835 appendPQExpBuffer(q, "%s", tbinfo->reloptions);
9837 if (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0)
9839 appendPQExpBuffer(q, "%s%s", addcomma ? ", " : "",
9840 tbinfo->toast_reloptions);
9842 appendPQExpBuffer(q, ")");
9845 appendPQExpBuffer(q, ";\n");
9848 * For binary-compatible heap files, we create dropped columns
9849 * above and drop them here.
9851 if (binary_upgrade)
9853 for (j = 0; j < tbinfo->numatts; j++)
9855 if (tbinfo->attisdropped[j])
9857 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
9858 fmtId(tbinfo->dobj.name));
9859 appendPQExpBuffer(q, "DROP COLUMN %s;\n",
9860 fmtId(tbinfo->attnames[j]));
9863 * ALTER TABLE DROP COLUMN clears pg_attribute.atttypid,
9864 * so we have to set pg_attribute.attlen and
9865 * pg_attribute.attalign values because that is what
9866 * is used to skip over dropped columns in the heap tuples.
9867 * We have atttypmod, but it seems impossible to know the
9868 * correct data type that will yield pg_attribute values
9869 * that match the old installation.
9870 * See comment in backend/catalog/heap.c::RemoveAttributeById()
9872 appendPQExpBuffer(q, "\n-- For binary upgrade, recreate dropped column's length and alignment.\n");
9873 appendPQExpBuffer(q, "UPDATE pg_attribute\n"
9874 "SET attlen = %d, "
9875 "attalign = '%c'\n"
9876 "WHERE attname = '%s'\n"
9877 " AND attrelid = \n"
9878 " (\n"
9879 " SELECT oid\n"
9880 " FROM pg_class\n"
9881 " WHERE relnamespace = "
9882 "(SELECT oid FROM pg_namespace "
9883 "WHERE nspname = CURRENT_SCHEMA)\n"
9884 " AND relname = '%s'\n"
9885 " );\n",
9886 tbinfo->attlen[j],
9887 tbinfo->attalign[j],
9888 tbinfo->attnames[j],
9889 tbinfo->dobj.name);
9892 appendPQExpBuffer(q, "\n-- For binary upgrade, set relfrozenxid.\n");
9893 appendPQExpBuffer(q, "UPDATE pg_class\n"
9894 "SET relfrozenxid = '%u'\n"
9895 "WHERE relname = '%s'\n"
9896 " AND relnamespace = "
9897 "(SELECT oid FROM pg_namespace "
9898 "WHERE nspname = CURRENT_SCHEMA);\n",
9899 tbinfo->frozenxid,
9900 tbinfo->dobj.name);
9903 /* Loop dumping statistics and storage statements */
9904 for (j = 0; j < tbinfo->numatts; j++)
9907 * Dump per-column statistics information. We only issue an ALTER
9908 * TABLE statement if the attstattarget entry for this column is
9909 * non-negative (i.e. it's not the default value)
9911 if (tbinfo->attstattarget[j] >= 0 &&
9912 !tbinfo->attisdropped[j])
9914 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
9915 fmtId(tbinfo->dobj.name));
9916 appendPQExpBuffer(q, "ALTER COLUMN %s ",
9917 fmtId(tbinfo->attnames[j]));
9918 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
9919 tbinfo->attstattarget[j]);
9923 * Dump per-column storage information. The statement is only
9924 * dumped if the storage has been changed from the type's default.
9926 if (!tbinfo->attisdropped[j] && tbinfo->attstorage[j] != tbinfo->typstorage[j])
9928 switch (tbinfo->attstorage[j])
9930 case 'p':
9931 storage = "PLAIN";
9932 break;
9933 case 'e':
9934 storage = "EXTERNAL";
9935 break;
9936 case 'm':
9937 storage = "MAIN";
9938 break;
9939 case 'x':
9940 storage = "EXTENDED";
9941 break;
9942 default:
9943 storage = NULL;
9947 * Only dump the statement if it's a storage type we recognize
9949 if (storage != NULL)
9951 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
9952 fmtId(tbinfo->dobj.name));
9953 appendPQExpBuffer(q, "ALTER COLUMN %s ",
9954 fmtId(tbinfo->attnames[j]));
9955 appendPQExpBuffer(q, "SET STORAGE %s;\n",
9956 storage);
9962 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
9963 tbinfo->dobj.name,
9964 tbinfo->dobj.namespace->dobj.name,
9965 (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
9966 tbinfo->rolname,
9967 (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
9968 reltypename, SECTION_PRE_DATA,
9969 q->data, delq->data, NULL,
9970 tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
9971 NULL, NULL);
9973 /* Dump Table Comments */
9974 dumpTableComment(fout, tbinfo, reltypename);
9976 /* Dump comments on inlined table constraints */
9977 for (j = 0; j < tbinfo->ncheck; j++)
9979 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
9981 if (constr->separate || !constr->conislocal)
9982 continue;
9984 dumpTableConstraintComment(fout, constr);
9987 destroyPQExpBuffer(query);
9988 destroyPQExpBuffer(q);
9989 destroyPQExpBuffer(delq);
9993 * dumpAttrDef --- dump an attribute's default-value declaration
9995 static void
9996 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
9998 TableInfo *tbinfo = adinfo->adtable;
9999 int adnum = adinfo->adnum;
10000 PQExpBuffer q;
10001 PQExpBuffer delq;
10003 /* Only print it if "separate" mode is selected */
10004 if (!tbinfo->dobj.dump || !adinfo->separate || dataOnly)
10005 return;
10007 /* Don't print inherited defaults, either */
10008 if (tbinfo->inhAttrDef[adnum - 1])
10009 return;
10011 q = createPQExpBuffer();
10012 delq = createPQExpBuffer();
10014 appendPQExpBuffer(q, "ALTER TABLE %s ",
10015 fmtId(tbinfo->dobj.name));
10016 appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
10017 fmtId(tbinfo->attnames[adnum - 1]),
10018 adinfo->adef_expr);
10021 * DROP must be fully qualified in case same name appears in pg_catalog
10023 appendPQExpBuffer(delq, "ALTER TABLE %s.",
10024 fmtId(tbinfo->dobj.namespace->dobj.name));
10025 appendPQExpBuffer(delq, "%s ",
10026 fmtId(tbinfo->dobj.name));
10027 appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
10028 fmtId(tbinfo->attnames[adnum - 1]));
10030 ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
10031 tbinfo->attnames[adnum - 1],
10032 tbinfo->dobj.namespace->dobj.name,
10033 NULL,
10034 tbinfo->rolname,
10035 false, "DEFAULT", SECTION_PRE_DATA,
10036 q->data, delq->data, NULL,
10037 adinfo->dobj.dependencies, adinfo->dobj.nDeps,
10038 NULL, NULL);
10040 destroyPQExpBuffer(q);
10041 destroyPQExpBuffer(delq);
10045 * getAttrName: extract the correct name for an attribute
10047 * The array tblInfo->attnames[] only provides names of user attributes;
10048 * if a system attribute number is supplied, we have to fake it.
10049 * We also do a little bit of bounds checking for safety's sake.
10051 static const char *
10052 getAttrName(int attrnum, TableInfo *tblInfo)
10054 if (attrnum > 0 && attrnum <= tblInfo->numatts)
10055 return tblInfo->attnames[attrnum - 1];
10056 switch (attrnum)
10058 case SelfItemPointerAttributeNumber:
10059 return "ctid";
10060 case ObjectIdAttributeNumber:
10061 return "oid";
10062 case MinTransactionIdAttributeNumber:
10063 return "xmin";
10064 case MinCommandIdAttributeNumber:
10065 return "cmin";
10066 case MaxTransactionIdAttributeNumber:
10067 return "xmax";
10068 case MaxCommandIdAttributeNumber:
10069 return "cmax";
10070 case TableOidAttributeNumber:
10071 return "tableoid";
10073 write_msg(NULL, "invalid column number %d for table \"%s\"\n",
10074 attrnum, tblInfo->dobj.name);
10075 exit_nicely();
10076 return NULL; /* keep compiler quiet */
10080 * dumpIndex
10081 * write out to fout a user-defined index
10083 static void
10084 dumpIndex(Archive *fout, IndxInfo *indxinfo)
10086 TableInfo *tbinfo = indxinfo->indextable;
10087 PQExpBuffer q;
10088 PQExpBuffer delq;
10090 if (dataOnly)
10091 return;
10093 q = createPQExpBuffer();
10094 delq = createPQExpBuffer();
10097 * If there's an associated constraint, don't dump the index per se, but
10098 * do dump any comment for it. (This is safe because dependency ordering
10099 * will have ensured the constraint is emitted first.)
10101 if (indxinfo->indexconstraint == 0)
10103 /* Plain secondary index */
10104 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
10106 /* If the index is clustered, we need to record that. */
10107 if (indxinfo->indisclustered)
10109 appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
10110 fmtId(tbinfo->dobj.name));
10111 appendPQExpBuffer(q, " ON %s;\n",
10112 fmtId(indxinfo->dobj.name));
10116 * DROP must be fully qualified in case same name appears in
10117 * pg_catalog
10119 appendPQExpBuffer(delq, "DROP INDEX %s.",
10120 fmtId(tbinfo->dobj.namespace->dobj.name));
10121 appendPQExpBuffer(delq, "%s;\n",
10122 fmtId(indxinfo->dobj.name));
10124 ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
10125 indxinfo->dobj.name,
10126 tbinfo->dobj.namespace->dobj.name,
10127 indxinfo->tablespace,
10128 tbinfo->rolname, false,
10129 "INDEX", SECTION_POST_DATA,
10130 q->data, delq->data, NULL,
10131 indxinfo->dobj.dependencies, indxinfo->dobj.nDeps,
10132 NULL, NULL);
10135 /* Dump Index Comments */
10136 resetPQExpBuffer(q);
10137 appendPQExpBuffer(q, "INDEX %s",
10138 fmtId(indxinfo->dobj.name));
10139 dumpComment(fout, q->data,
10140 tbinfo->dobj.namespace->dobj.name,
10141 tbinfo->rolname,
10142 indxinfo->dobj.catId, 0, indxinfo->dobj.dumpId);
10144 destroyPQExpBuffer(q);
10145 destroyPQExpBuffer(delq);
10149 * dumpConstraint
10150 * write out to fout a user-defined constraint
10152 static void
10153 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
10155 TableInfo *tbinfo = coninfo->contable;
10156 PQExpBuffer q;
10157 PQExpBuffer delq;
10159 /* Skip if not to be dumped */
10160 if (!coninfo->dobj.dump || dataOnly)
10161 return;
10163 q = createPQExpBuffer();
10164 delq = createPQExpBuffer();
10166 if (coninfo->contype == 'p' || coninfo->contype == 'u')
10168 /* Index-related constraint */
10169 IndxInfo *indxinfo;
10170 int k;
10172 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
10174 if (indxinfo == NULL)
10176 write_msg(NULL, "missing index for constraint \"%s\"\n",
10177 coninfo->dobj.name);
10178 exit_nicely();
10181 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
10182 fmtId(tbinfo->dobj.name));
10183 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s (",
10184 fmtId(coninfo->dobj.name),
10185 coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
10187 for (k = 0; k < indxinfo->indnkeys; k++)
10189 int indkey = (int) indxinfo->indkeys[k];
10190 const char *attname;
10192 if (indkey == InvalidAttrNumber)
10193 break;
10194 attname = getAttrName(indkey, tbinfo);
10196 appendPQExpBuffer(q, "%s%s",
10197 (k == 0) ? "" : ", ",
10198 fmtId(attname));
10201 appendPQExpBuffer(q, ")");
10203 if (indxinfo->options && strlen(indxinfo->options) > 0)
10204 appendPQExpBuffer(q, " WITH (%s)", indxinfo->options);
10206 appendPQExpBuffer(q, ";\n");
10208 /* If the index is clustered, we need to record that. */
10209 if (indxinfo->indisclustered)
10211 appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
10212 fmtId(tbinfo->dobj.name));
10213 appendPQExpBuffer(q, " ON %s;\n",
10214 fmtId(indxinfo->dobj.name));
10218 * DROP must be fully qualified in case same name appears in
10219 * pg_catalog
10221 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
10222 fmtId(tbinfo->dobj.namespace->dobj.name));
10223 appendPQExpBuffer(delq, "%s ",
10224 fmtId(tbinfo->dobj.name));
10225 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
10226 fmtId(coninfo->dobj.name));
10228 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
10229 coninfo->dobj.name,
10230 tbinfo->dobj.namespace->dobj.name,
10231 indxinfo->tablespace,
10232 tbinfo->rolname, false,
10233 "CONSTRAINT", SECTION_POST_DATA,
10234 q->data, delq->data, NULL,
10235 coninfo->dobj.dependencies, coninfo->dobj.nDeps,
10236 NULL, NULL);
10238 else if (coninfo->contype == 'f')
10241 * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
10242 * current table data is not processed
10244 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
10245 fmtId(tbinfo->dobj.name));
10246 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
10247 fmtId(coninfo->dobj.name),
10248 coninfo->condef);
10251 * DROP must be fully qualified in case same name appears in
10252 * pg_catalog
10254 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
10255 fmtId(tbinfo->dobj.namespace->dobj.name));
10256 appendPQExpBuffer(delq, "%s ",
10257 fmtId(tbinfo->dobj.name));
10258 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
10259 fmtId(coninfo->dobj.name));
10261 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
10262 coninfo->dobj.name,
10263 tbinfo->dobj.namespace->dobj.name,
10264 NULL,
10265 tbinfo->rolname, false,
10266 "FK CONSTRAINT", SECTION_POST_DATA,
10267 q->data, delq->data, NULL,
10268 coninfo->dobj.dependencies, coninfo->dobj.nDeps,
10269 NULL, NULL);
10271 else if (coninfo->contype == 'c' && tbinfo)
10273 /* CHECK constraint on a table */
10275 /* Ignore if not to be dumped separately */
10276 if (coninfo->separate)
10278 /* not ONLY since we want it to propagate to children */
10279 appendPQExpBuffer(q, "ALTER TABLE %s\n",
10280 fmtId(tbinfo->dobj.name));
10281 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
10282 fmtId(coninfo->dobj.name),
10283 coninfo->condef);
10286 * DROP must be fully qualified in case same name appears in
10287 * pg_catalog
10289 appendPQExpBuffer(delq, "ALTER TABLE %s.",
10290 fmtId(tbinfo->dobj.namespace->dobj.name));
10291 appendPQExpBuffer(delq, "%s ",
10292 fmtId(tbinfo->dobj.name));
10293 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
10294 fmtId(coninfo->dobj.name));
10296 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
10297 coninfo->dobj.name,
10298 tbinfo->dobj.namespace->dobj.name,
10299 NULL,
10300 tbinfo->rolname, false,
10301 "CHECK CONSTRAINT", SECTION_POST_DATA,
10302 q->data, delq->data, NULL,
10303 coninfo->dobj.dependencies, coninfo->dobj.nDeps,
10304 NULL, NULL);
10307 else if (coninfo->contype == 'c' && tbinfo == NULL)
10309 /* CHECK constraint on a domain */
10310 TypeInfo *tinfo = coninfo->condomain;
10312 /* Ignore if not to be dumped separately */
10313 if (coninfo->separate)
10315 appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
10316 fmtId(tinfo->dobj.name));
10317 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
10318 fmtId(coninfo->dobj.name),
10319 coninfo->condef);
10322 * DROP must be fully qualified in case same name appears in
10323 * pg_catalog
10325 appendPQExpBuffer(delq, "ALTER DOMAIN %s.",
10326 fmtId(tinfo->dobj.namespace->dobj.name));
10327 appendPQExpBuffer(delq, "%s ",
10328 fmtId(tinfo->dobj.name));
10329 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
10330 fmtId(coninfo->dobj.name));
10332 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
10333 coninfo->dobj.name,
10334 tinfo->dobj.namespace->dobj.name,
10335 NULL,
10336 tinfo->rolname, false,
10337 "CHECK CONSTRAINT", SECTION_POST_DATA,
10338 q->data, delq->data, NULL,
10339 coninfo->dobj.dependencies, coninfo->dobj.nDeps,
10340 NULL, NULL);
10343 else
10345 write_msg(NULL, "unrecognized constraint type: %c\n", coninfo->contype);
10346 exit_nicely();
10349 /* Dump Constraint Comments --- only works for table constraints */
10350 if (tbinfo && coninfo->separate)
10351 dumpTableConstraintComment(fout, coninfo);
10353 destroyPQExpBuffer(q);
10354 destroyPQExpBuffer(delq);
10358 * dumpTableConstraintComment --- dump a constraint's comment if any
10360 * This is split out because we need the function in two different places
10361 * depending on whether the constraint is dumped as part of CREATE TABLE
10362 * or as a separate ALTER command.
10364 static void
10365 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
10367 TableInfo *tbinfo = coninfo->contable;
10368 PQExpBuffer q = createPQExpBuffer();
10370 appendPQExpBuffer(q, "CONSTRAINT %s ",
10371 fmtId(coninfo->dobj.name));
10372 appendPQExpBuffer(q, "ON %s",
10373 fmtId(tbinfo->dobj.name));
10374 dumpComment(fout, q->data,
10375 tbinfo->dobj.namespace->dobj.name,
10376 tbinfo->rolname,
10377 coninfo->dobj.catId, 0,
10378 coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
10380 destroyPQExpBuffer(q);
10384 * findLastBuiltInOid -
10385 * find the last built in oid
10387 * For 7.1 and 7.2, we do this by retrieving datlastsysoid from the
10388 * pg_database entry for the current database
10390 static Oid
10391 findLastBuiltinOid_V71(const char *dbname)
10393 PGresult *res;
10394 int ntups;
10395 Oid last_oid;
10396 PQExpBuffer query = createPQExpBuffer();
10398 resetPQExpBuffer(query);
10399 appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
10400 appendStringLiteralAH(query, dbname, g_fout);
10402 res = PQexec(g_conn, query->data);
10403 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10405 ntups = PQntuples(res);
10406 if (ntups < 1)
10408 write_msg(NULL, "missing pg_database entry for this database\n");
10409 exit_nicely();
10411 if (ntups > 1)
10413 write_msg(NULL, "found more than one pg_database entry for this database\n");
10414 exit_nicely();
10416 last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
10417 PQclear(res);
10418 destroyPQExpBuffer(query);
10419 return last_oid;
10423 * findLastBuiltInOid -
10424 * find the last built in oid
10426 * For 7.0, we do this by assuming that the last thing that initdb does is to
10427 * create the pg_indexes view. This sucks in general, but seeing that 7.0.x
10428 * initdb won't be changing anymore, it'll do.
10430 static Oid
10431 findLastBuiltinOid_V70(void)
10433 PGresult *res;
10434 int ntups;
10435 int last_oid;
10437 res = PQexec(g_conn,
10438 "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'");
10439 check_sql_result(res, g_conn,
10440 "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'",
10441 PGRES_TUPLES_OK);
10442 ntups = PQntuples(res);
10443 if (ntups < 1)
10445 write_msg(NULL, "could not find entry for pg_indexes in pg_class\n");
10446 exit_nicely();
10448 if (ntups > 1)
10450 write_msg(NULL, "found more than one entry for pg_indexes in pg_class\n");
10451 exit_nicely();
10453 last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
10454 PQclear(res);
10455 return last_oid;
10458 static void
10459 dumpSequence(Archive *fout, TableInfo *tbinfo)
10461 PGresult *res;
10462 char *startv,
10463 *last,
10464 *incby,
10465 *maxv = NULL,
10466 *minv = NULL,
10467 *cache;
10468 char bufm[100],
10469 bufx[100];
10470 bool cycled,
10471 called;
10472 PQExpBuffer query = createPQExpBuffer();
10473 PQExpBuffer delqry = createPQExpBuffer();
10475 /* Make sure we are in proper schema */
10476 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
10478 snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
10479 snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
10481 if (g_fout->remoteVersion >= 80400)
10483 appendPQExpBuffer(query,
10484 "SELECT sequence_name, "
10485 "start_value, last_value, increment_by, "
10486 "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
10487 " WHEN increment_by < 0 AND max_value = -1 THEN NULL "
10488 " ELSE max_value "
10489 "END AS max_value, "
10490 "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
10491 " WHEN increment_by < 0 AND min_value = %s THEN NULL "
10492 " ELSE min_value "
10493 "END AS min_value, "
10494 "cache_value, is_cycled, is_called from %s",
10495 bufx, bufm,
10496 fmtId(tbinfo->dobj.name));
10498 else
10500 appendPQExpBuffer(query,
10501 "SELECT sequence_name, "
10502 "0 AS start_value, last_value, increment_by, "
10503 "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
10504 " WHEN increment_by < 0 AND max_value = -1 THEN NULL "
10505 " ELSE max_value "
10506 "END AS max_value, "
10507 "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
10508 " WHEN increment_by < 0 AND min_value = %s THEN NULL "
10509 " ELSE min_value "
10510 "END AS min_value, "
10511 "cache_value, is_cycled, is_called from %s",
10512 bufx, bufm,
10513 fmtId(tbinfo->dobj.name));
10516 res = PQexec(g_conn, query->data);
10517 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10519 if (PQntuples(res) != 1)
10521 write_msg(NULL, "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
10522 tbinfo->dobj.name, PQntuples(res));
10523 exit_nicely();
10526 /* Disable this check: it fails if sequence has been renamed */
10527 #ifdef NOT_USED
10528 if (strcmp(PQgetvalue(res, 0, 0), tbinfo->dobj.name) != 0)
10530 write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
10531 tbinfo->dobj.name, PQgetvalue(res, 0, 0));
10532 exit_nicely();
10534 #endif
10536 startv = PQgetvalue(res, 0, 1);
10537 last = PQgetvalue(res, 0, 2);
10538 incby = PQgetvalue(res, 0, 3);
10539 if (!PQgetisnull(res, 0, 4))
10540 maxv = PQgetvalue(res, 0, 4);
10541 if (!PQgetisnull(res, 0, 5))
10542 minv = PQgetvalue(res, 0, 5);
10543 cache = PQgetvalue(res, 0, 6);
10544 cycled = (strcmp(PQgetvalue(res, 0, 7), "t") == 0);
10545 called = (strcmp(PQgetvalue(res, 0, 8), "t") == 0);
10548 * The logic we use for restoring sequences is as follows:
10550 * Add a CREATE SEQUENCE statement as part of a "schema" dump (use
10551 * last_val for start if called is false, else use min_val for start_val).
10552 * Also, if the sequence is owned by a column, add an ALTER SEQUENCE OWNED
10553 * BY command for it.
10555 * Add a 'SETVAL(seq, last_val, iscalled)' as part of a "data" dump.
10557 if (!dataOnly)
10559 resetPQExpBuffer(delqry);
10562 * DROP must be fully qualified in case same name appears in
10563 * pg_catalog
10565 appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
10566 fmtId(tbinfo->dobj.namespace->dobj.name));
10567 appendPQExpBuffer(delqry, "%s;\n",
10568 fmtId(tbinfo->dobj.name));
10570 resetPQExpBuffer(query);
10571 appendPQExpBuffer(query,
10572 "CREATE SEQUENCE %s\n",
10573 fmtId(tbinfo->dobj.name));
10575 if (g_fout->remoteVersion >= 80400)
10576 appendPQExpBuffer(query, " START WITH %s\n", startv);
10577 else
10580 * Versions before 8.4 did not remember the true start value. If
10581 * is_called is false then the sequence has never been incremented
10582 * so we can use last_val. Otherwise punt and let it default.
10584 if (!called)
10585 appendPQExpBuffer(query, " START WITH %s\n", last);
10588 appendPQExpBuffer(query, " INCREMENT BY %s\n", incby);
10590 if (maxv)
10591 appendPQExpBuffer(query, " MAXVALUE %s\n", maxv);
10592 else
10593 appendPQExpBuffer(query, " NO MAXVALUE\n");
10595 if (minv)
10596 appendPQExpBuffer(query, " MINVALUE %s\n", minv);
10597 else
10598 appendPQExpBuffer(query, " NO MINVALUE\n");
10600 appendPQExpBuffer(query,
10601 " CACHE %s%s",
10602 cache, (cycled ? "\n CYCLE" : ""));
10604 appendPQExpBuffer(query, ";\n");
10606 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
10607 tbinfo->dobj.name,
10608 tbinfo->dobj.namespace->dobj.name,
10609 NULL,
10610 tbinfo->rolname,
10611 false, "SEQUENCE", SECTION_PRE_DATA,
10612 query->data, delqry->data, NULL,
10613 tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
10614 NULL, NULL);
10617 * If the sequence is owned by a table column, emit the ALTER for it
10618 * as a separate TOC entry immediately following the sequence's own
10619 * entry. It's OK to do this rather than using full sorting logic,
10620 * because the dependency that tells us it's owned will have forced
10621 * the table to be created first. We can't just include the ALTER in
10622 * the TOC entry because it will fail if we haven't reassigned the
10623 * sequence owner to match the table's owner.
10625 * We need not schema-qualify the table reference because both
10626 * sequence and table must be in the same schema.
10628 if (OidIsValid(tbinfo->owning_tab))
10630 TableInfo *owning_tab = findTableByOid(tbinfo->owning_tab);
10632 if (owning_tab && owning_tab->dobj.dump)
10634 resetPQExpBuffer(query);
10635 appendPQExpBuffer(query, "ALTER SEQUENCE %s",
10636 fmtId(tbinfo->dobj.name));
10637 appendPQExpBuffer(query, " OWNED BY %s",
10638 fmtId(owning_tab->dobj.name));
10639 appendPQExpBuffer(query, ".%s;\n",
10640 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
10642 ArchiveEntry(fout, nilCatalogId, createDumpId(),
10643 tbinfo->dobj.name,
10644 tbinfo->dobj.namespace->dobj.name,
10645 NULL,
10646 tbinfo->rolname,
10647 false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
10648 query->data, "", NULL,
10649 &(tbinfo->dobj.dumpId), 1,
10650 NULL, NULL);
10654 /* Dump Sequence Comments */
10655 resetPQExpBuffer(query);
10656 appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
10657 dumpComment(fout, query->data,
10658 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
10659 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
10662 if (!schemaOnly)
10664 resetPQExpBuffer(query);
10665 appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
10666 appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
10667 appendPQExpBuffer(query, ", %s, %s);\n",
10668 last, (called ? "true" : "false"));
10670 ArchiveEntry(fout, nilCatalogId, createDumpId(),
10671 tbinfo->dobj.name,
10672 tbinfo->dobj.namespace->dobj.name,
10673 NULL,
10674 tbinfo->rolname,
10675 false, "SEQUENCE SET", SECTION_PRE_DATA,
10676 query->data, "", NULL,
10677 &(tbinfo->dobj.dumpId), 1,
10678 NULL, NULL);
10681 PQclear(res);
10683 destroyPQExpBuffer(query);
10684 destroyPQExpBuffer(delqry);
10687 static void
10688 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
10690 TableInfo *tbinfo = tginfo->tgtable;
10691 PQExpBuffer query;
10692 PQExpBuffer delqry;
10693 const char *p;
10694 int findx;
10696 if (dataOnly)
10697 return;
10699 query = createPQExpBuffer();
10700 delqry = createPQExpBuffer();
10703 * DROP must be fully qualified in case same name appears in pg_catalog
10705 appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
10706 fmtId(tginfo->dobj.name));
10707 appendPQExpBuffer(delqry, "ON %s.",
10708 fmtId(tbinfo->dobj.namespace->dobj.name));
10709 appendPQExpBuffer(delqry, "%s;\n",
10710 fmtId(tbinfo->dobj.name));
10712 if (tginfo->tgisconstraint)
10714 appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
10715 appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
10717 else
10719 appendPQExpBuffer(query, "CREATE TRIGGER ");
10720 appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
10722 appendPQExpBuffer(query, "\n ");
10724 /* Trigger type */
10725 findx = 0;
10726 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
10727 appendPQExpBuffer(query, "BEFORE");
10728 else
10729 appendPQExpBuffer(query, "AFTER");
10730 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
10732 appendPQExpBuffer(query, " INSERT");
10733 findx++;
10735 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
10737 if (findx > 0)
10738 appendPQExpBuffer(query, " OR DELETE");
10739 else
10740 appendPQExpBuffer(query, " DELETE");
10741 findx++;
10743 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
10745 if (findx > 0)
10746 appendPQExpBuffer(query, " OR UPDATE");
10747 else
10748 appendPQExpBuffer(query, " UPDATE");
10750 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
10752 if (findx > 0)
10753 appendPQExpBuffer(query, " OR TRUNCATE");
10754 else
10755 appendPQExpBuffer(query, " TRUNCATE");
10757 appendPQExpBuffer(query, " ON %s\n",
10758 fmtId(tbinfo->dobj.name));
10760 if (tginfo->tgisconstraint)
10762 if (OidIsValid(tginfo->tgconstrrelid))
10764 /* If we are using regclass, name is already quoted */
10765 if (g_fout->remoteVersion >= 70300)
10766 appendPQExpBuffer(query, " FROM %s\n ",
10767 tginfo->tgconstrrelname);
10768 else
10769 appendPQExpBuffer(query, " FROM %s\n ",
10770 fmtId(tginfo->tgconstrrelname));
10772 if (!tginfo->tgdeferrable)
10773 appendPQExpBuffer(query, "NOT ");
10774 appendPQExpBuffer(query, "DEFERRABLE INITIALLY ");
10775 if (tginfo->tginitdeferred)
10776 appendPQExpBuffer(query, "DEFERRED\n");
10777 else
10778 appendPQExpBuffer(query, "IMMEDIATE\n");
10781 if (TRIGGER_FOR_ROW(tginfo->tgtype))
10782 appendPQExpBuffer(query, " FOR EACH ROW\n ");
10783 else
10784 appendPQExpBuffer(query, " FOR EACH STATEMENT\n ");
10786 /* In 7.3, result of regproc is already quoted */
10787 if (g_fout->remoteVersion >= 70300)
10788 appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
10789 tginfo->tgfname);
10790 else
10791 appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
10792 fmtId(tginfo->tgfname));
10794 p = tginfo->tgargs;
10795 for (findx = 0; findx < tginfo->tgnargs; findx++)
10797 const char *s = p;
10799 /* Set 'p' to end of arg string. marked by '\000' */
10800 for (;;)
10802 p = strchr(p, '\\');
10803 if (p == NULL)
10805 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
10806 tginfo->tgargs,
10807 tginfo->dobj.name,
10808 tbinfo->dobj.name);
10809 exit_nicely();
10811 p++;
10812 if (*p == '\\') /* is it '\\'? */
10814 p++;
10815 continue;
10817 if (p[0] == '0' && p[1] == '0' && p[2] == '0') /* is it '\000'? */
10818 break;
10820 p--;
10822 appendPQExpBufferChar(query, '\'');
10823 while (s < p)
10825 if (*s == '\'')
10826 appendPQExpBufferChar(query, '\'');
10829 * bytea unconditionally doubles backslashes, so we suppress the
10830 * doubling for standard_conforming_strings.
10832 if (fout->std_strings && *s == '\\' && s[1] == '\\')
10833 s++;
10834 appendPQExpBufferChar(query, *s++);
10836 appendPQExpBufferChar(query, '\'');
10837 appendPQExpBuffer(query,
10838 (findx < tginfo->tgnargs - 1) ? ", " : "");
10839 p = p + 4;
10841 appendPQExpBuffer(query, ");\n");
10843 if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
10845 appendPQExpBuffer(query, "\nALTER TABLE %s ",
10846 fmtId(tbinfo->dobj.name));
10847 switch (tginfo->tgenabled)
10849 case 'D':
10850 case 'f':
10851 appendPQExpBuffer(query, "DISABLE");
10852 break;
10853 case 'A':
10854 appendPQExpBuffer(query, "ENABLE ALWAYS");
10855 break;
10856 case 'R':
10857 appendPQExpBuffer(query, "ENABLE REPLICA");
10858 break;
10859 default:
10860 appendPQExpBuffer(query, "ENABLE");
10861 break;
10863 appendPQExpBuffer(query, " TRIGGER %s;\n",
10864 fmtId(tginfo->dobj.name));
10867 ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
10868 tginfo->dobj.name,
10869 tbinfo->dobj.namespace->dobj.name,
10870 NULL,
10871 tbinfo->rolname, false,
10872 "TRIGGER", SECTION_POST_DATA,
10873 query->data, delqry->data, NULL,
10874 tginfo->dobj.dependencies, tginfo->dobj.nDeps,
10875 NULL, NULL);
10877 resetPQExpBuffer(query);
10878 appendPQExpBuffer(query, "TRIGGER %s ",
10879 fmtId(tginfo->dobj.name));
10880 appendPQExpBuffer(query, "ON %s",
10881 fmtId(tbinfo->dobj.name));
10883 dumpComment(fout, query->data,
10884 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
10885 tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
10887 destroyPQExpBuffer(query);
10888 destroyPQExpBuffer(delqry);
10892 * dumpRule
10893 * Dump a rule
10895 static void
10896 dumpRule(Archive *fout, RuleInfo *rinfo)
10898 TableInfo *tbinfo = rinfo->ruletable;
10899 PQExpBuffer query;
10900 PQExpBuffer cmd;
10901 PQExpBuffer delcmd;
10902 PGresult *res;
10904 /* Skip if not to be dumped */
10905 if (!rinfo->dobj.dump || dataOnly)
10906 return;
10909 * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
10910 * we do not want to dump it as a separate object.
10912 if (!rinfo->separate)
10913 return;
10916 * Make sure we are in proper schema.
10918 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
10920 query = createPQExpBuffer();
10921 cmd = createPQExpBuffer();
10922 delcmd = createPQExpBuffer();
10924 if (g_fout->remoteVersion >= 70300)
10926 appendPQExpBuffer(query,
10927 "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid) AS definition",
10928 rinfo->dobj.catId.oid);
10930 else
10932 /* Rule name was unique before 7.3 ... */
10933 appendPQExpBuffer(query,
10934 "SELECT pg_get_ruledef('%s') AS definition",
10935 rinfo->dobj.name);
10938 res = PQexec(g_conn, query->data);
10939 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10941 if (PQntuples(res) != 1)
10943 write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
10944 rinfo->dobj.name, tbinfo->dobj.name);
10945 exit_nicely();
10948 printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
10951 * Add the command to alter the rules replication firing semantics if it
10952 * differs from the default.
10954 if (rinfo->ev_enabled != 'O')
10956 appendPQExpBuffer(cmd, "ALTER TABLE %s.",
10957 fmtId(tbinfo->dobj.namespace->dobj.name));
10958 appendPQExpBuffer(cmd, "%s ",
10959 fmtId(tbinfo->dobj.name));
10960 switch (rinfo->ev_enabled)
10962 case 'A':
10963 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
10964 fmtId(rinfo->dobj.name));
10965 break;
10966 case 'R':
10967 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
10968 fmtId(rinfo->dobj.name));
10969 break;
10970 case 'D':
10971 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
10972 fmtId(rinfo->dobj.name));
10973 break;
10978 * DROP must be fully qualified in case same name appears in pg_catalog
10980 appendPQExpBuffer(delcmd, "DROP RULE %s ",
10981 fmtId(rinfo->dobj.name));
10982 appendPQExpBuffer(delcmd, "ON %s.",
10983 fmtId(tbinfo->dobj.namespace->dobj.name));
10984 appendPQExpBuffer(delcmd, "%s;\n",
10985 fmtId(tbinfo->dobj.name));
10987 ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
10988 rinfo->dobj.name,
10989 tbinfo->dobj.namespace->dobj.name,
10990 NULL,
10991 tbinfo->rolname, false,
10992 "RULE", SECTION_POST_DATA,
10993 cmd->data, delcmd->data, NULL,
10994 rinfo->dobj.dependencies, rinfo->dobj.nDeps,
10995 NULL, NULL);
10997 /* Dump rule comments */
10998 resetPQExpBuffer(query);
10999 appendPQExpBuffer(query, "RULE %s",
11000 fmtId(rinfo->dobj.name));
11001 appendPQExpBuffer(query, " ON %s",
11002 fmtId(tbinfo->dobj.name));
11003 dumpComment(fout, query->data,
11004 tbinfo->dobj.namespace->dobj.name,
11005 tbinfo->rolname,
11006 rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
11008 PQclear(res);
11010 destroyPQExpBuffer(query);
11011 destroyPQExpBuffer(cmd);
11012 destroyPQExpBuffer(delcmd);
11016 * getDependencies --- obtain available dependency data
11018 static void
11019 getDependencies(void)
11021 PQExpBuffer query;
11022 PGresult *res;
11023 int ntups,
11025 int i_classid,
11026 i_objid,
11027 i_refclassid,
11028 i_refobjid,
11029 i_deptype;
11030 DumpableObject *dobj,
11031 *refdobj;
11033 /* No dependency info available before 7.3 */
11034 if (g_fout->remoteVersion < 70300)
11035 return;
11037 if (g_verbose)
11038 write_msg(NULL, "reading dependency data\n");
11040 /* Make sure we are in proper schema */
11041 selectSourceSchema("pg_catalog");
11043 query = createPQExpBuffer();
11045 appendPQExpBuffer(query, "SELECT "
11046 "classid, objid, refclassid, refobjid, deptype "
11047 "FROM pg_depend "
11048 "WHERE deptype != 'p' "
11049 "ORDER BY 1,2");
11051 res = PQexec(g_conn, query->data);
11052 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11054 ntups = PQntuples(res);
11056 i_classid = PQfnumber(res, "classid");
11057 i_objid = PQfnumber(res, "objid");
11058 i_refclassid = PQfnumber(res, "refclassid");
11059 i_refobjid = PQfnumber(res, "refobjid");
11060 i_deptype = PQfnumber(res, "deptype");
11063 * Since we ordered the SELECT by referencing ID, we can expect that
11064 * multiple entries for the same object will appear together; this saves
11065 * on searches.
11067 dobj = NULL;
11069 for (i = 0; i < ntups; i++)
11071 CatalogId objId;
11072 CatalogId refobjId;
11073 char deptype;
11075 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
11076 objId.oid = atooid(PQgetvalue(res, i, i_objid));
11077 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
11078 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
11079 deptype = *(PQgetvalue(res, i, i_deptype));
11081 if (dobj == NULL ||
11082 dobj->catId.tableoid != objId.tableoid ||
11083 dobj->catId.oid != objId.oid)
11084 dobj = findObjectByCatalogId(objId);
11087 * Failure to find objects mentioned in pg_depend is not unexpected,
11088 * since for example we don't collect info about TOAST tables.
11090 if (dobj == NULL)
11092 #ifdef NOT_USED
11093 fprintf(stderr, "no referencing object %u %u\n",
11094 objId.tableoid, objId.oid);
11095 #endif
11096 continue;
11099 refdobj = findObjectByCatalogId(refobjId);
11101 if (refdobj == NULL)
11103 #ifdef NOT_USED
11104 fprintf(stderr, "no referenced object %u %u\n",
11105 refobjId.tableoid, refobjId.oid);
11106 #endif
11107 continue;
11111 * Ordinarily, table rowtypes have implicit dependencies on their
11112 * tables. However, for a composite type the implicit dependency goes
11113 * the other way in pg_depend; which is the right thing for DROP but
11114 * it doesn't produce the dependency ordering we need. So in that one
11115 * case, we reverse the direction of the dependency.
11117 if (deptype == 'i' &&
11118 dobj->objType == DO_TABLE &&
11119 refdobj->objType == DO_TYPE)
11120 addObjectDependency(refdobj, dobj->dumpId);
11121 else
11122 /* normal case */
11123 addObjectDependency(dobj, refdobj->dumpId);
11126 PQclear(res);
11128 destroyPQExpBuffer(query);
11133 * selectSourceSchema - make the specified schema the active search path
11134 * in the source database.
11136 * NB: pg_catalog is explicitly searched after the specified schema;
11137 * so user names are only qualified if they are cross-schema references,
11138 * and system names are only qualified if they conflict with a user name
11139 * in the current schema.
11141 * Whenever the selected schema is not pg_catalog, be careful to qualify
11142 * references to system catalogs and types in our emitted commands!
11144 static void
11145 selectSourceSchema(const char *schemaName)
11147 static char *curSchemaName = NULL;
11148 PQExpBuffer query;
11150 /* Not relevant if fetching from pre-7.3 DB */
11151 if (g_fout->remoteVersion < 70300)
11152 return;
11153 /* Ignore null schema names */
11154 if (schemaName == NULL || *schemaName == '\0')
11155 return;
11156 /* Optimize away repeated selection of same schema */
11157 if (curSchemaName && strcmp(curSchemaName, schemaName) == 0)
11158 return;
11160 query = createPQExpBuffer();
11161 appendPQExpBuffer(query, "SET search_path = %s",
11162 fmtId(schemaName));
11163 if (strcmp(schemaName, "pg_catalog") != 0)
11164 appendPQExpBuffer(query, ", pg_catalog");
11166 do_sql_command(g_conn, query->data);
11168 destroyPQExpBuffer(query);
11169 if (curSchemaName)
11170 free(curSchemaName);
11171 curSchemaName = strdup(schemaName);
11175 * getFormattedTypeName - retrieve a nicely-formatted type name for the
11176 * given type name.
11178 * NB: in 7.3 and up the result may depend on the currently-selected
11179 * schema; this is why we don't try to cache the names.
11181 static char *
11182 getFormattedTypeName(Oid oid, OidOptions opts)
11184 char *result;
11185 PQExpBuffer query;
11186 PGresult *res;
11187 int ntups;
11189 if (oid == 0)
11191 if ((opts & zeroAsOpaque) != 0)
11192 return strdup(g_opaque_type);
11193 else if ((opts & zeroAsAny) != 0)
11194 return strdup("'any'");
11195 else if ((opts & zeroAsStar) != 0)
11196 return strdup("*");
11197 else if ((opts & zeroAsNone) != 0)
11198 return strdup("NONE");
11201 query = createPQExpBuffer();
11202 if (g_fout->remoteVersion >= 70300)
11204 appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
11205 oid);
11207 else if (g_fout->remoteVersion >= 70100)
11209 appendPQExpBuffer(query, "SELECT format_type('%u'::oid, NULL)",
11210 oid);
11212 else
11214 appendPQExpBuffer(query, "SELECT typname "
11215 "FROM pg_type "
11216 "WHERE oid = '%u'::oid",
11217 oid);
11220 res = PQexec(g_conn, query->data);
11221 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11223 /* Expecting a single result only */
11224 ntups = PQntuples(res);
11225 if (ntups != 1)
11227 write_msg(NULL, "query returned %d rows instead of one: %s\n",
11228 ntups, query->data);
11229 exit_nicely();
11232 if (g_fout->remoteVersion >= 70100)
11234 /* already quoted */
11235 result = strdup(PQgetvalue(res, 0, 0));
11237 else
11239 /* may need to quote it */
11240 result = strdup(fmtId(PQgetvalue(res, 0, 0)));
11243 PQclear(res);
11244 destroyPQExpBuffer(query);
11246 return result;
11250 * myFormatType --- local implementation of format_type for use with 7.0.
11252 static char *
11253 myFormatType(const char *typname, int32 typmod)
11255 char *result;
11256 bool isarray = false;
11257 PQExpBuffer buf = createPQExpBuffer();
11259 /* Handle array types */
11260 if (typname[0] == '_')
11262 isarray = true;
11263 typname++;
11266 /* Show lengths on bpchar and varchar */
11267 if (!strcmp(typname, "bpchar"))
11269 int len = (typmod - VARHDRSZ);
11271 appendPQExpBuffer(buf, "character");
11272 if (len > 1)
11273 appendPQExpBuffer(buf, "(%d)",
11274 typmod - VARHDRSZ);
11276 else if (!strcmp(typname, "varchar"))
11278 appendPQExpBuffer(buf, "character varying");
11279 if (typmod != -1)
11280 appendPQExpBuffer(buf, "(%d)",
11281 typmod - VARHDRSZ);
11283 else if (!strcmp(typname, "numeric"))
11285 appendPQExpBuffer(buf, "numeric");
11286 if (typmod != -1)
11288 int32 tmp_typmod;
11289 int precision;
11290 int scale;
11292 tmp_typmod = typmod - VARHDRSZ;
11293 precision = (tmp_typmod >> 16) & 0xffff;
11294 scale = tmp_typmod & 0xffff;
11295 appendPQExpBuffer(buf, "(%d,%d)",
11296 precision, scale);
11301 * char is an internal single-byte data type; Let's make sure we force it
11302 * through with quotes. - thomas 1998-12-13
11304 else if (strcmp(typname, "char") == 0)
11305 appendPQExpBuffer(buf, "\"char\"");
11306 else
11307 appendPQExpBuffer(buf, "%s", fmtId(typname));
11309 /* Append array qualifier for array types */
11310 if (isarray)
11311 appendPQExpBuffer(buf, "[]");
11313 result = strdup(buf->data);
11314 destroyPQExpBuffer(buf);
11316 return result;
11320 * fmtQualifiedId - convert a qualified name to the proper format for
11321 * the source database.
11323 * Like fmtId, use the result before calling again.
11325 static const char *
11326 fmtQualifiedId(const char *schema, const char *id)
11328 static PQExpBuffer id_return = NULL;
11330 if (id_return) /* first time through? */
11331 resetPQExpBuffer(id_return);
11332 else
11333 id_return = createPQExpBuffer();
11335 /* Suppress schema name if fetching from pre-7.3 DB */
11336 if (g_fout->remoteVersion >= 70300 && schema && *schema)
11338 appendPQExpBuffer(id_return, "%s.",
11339 fmtId(schema));
11341 appendPQExpBuffer(id_return, "%s",
11342 fmtId(id));
11344 return id_return->data;
11348 * Return a column list clause for the given relation.
11350 * Special case: if there are no undropped columns in the relation, return
11351 * "", not an invalid "()" column list.
11353 static const char *
11354 fmtCopyColumnList(const TableInfo *ti)
11356 static PQExpBuffer q = NULL;
11357 int numatts = ti->numatts;
11358 char **attnames = ti->attnames;
11359 bool *attisdropped = ti->attisdropped;
11360 bool needComma;
11361 int i;
11363 if (q) /* first time through? */
11364 resetPQExpBuffer(q);
11365 else
11366 q = createPQExpBuffer();
11368 appendPQExpBuffer(q, "(");
11369 needComma = false;
11370 for (i = 0; i < numatts; i++)
11372 if (attisdropped[i])
11373 continue;
11374 if (needComma)
11375 appendPQExpBuffer(q, ", ");
11376 appendPQExpBuffer(q, "%s", fmtId(attnames[i]));
11377 needComma = true;
11380 if (!needComma)
11381 return ""; /* no undropped columns */
11383 appendPQExpBuffer(q, ")");
11384 return q->data;
11388 * Convenience subroutine to execute a SQL command and check for
11389 * COMMAND_OK status.
11391 static void
11392 do_sql_command(PGconn *conn, const char *query)
11394 PGresult *res;
11396 res = PQexec(conn, query);
11397 check_sql_result(res, conn, query, PGRES_COMMAND_OK);
11398 PQclear(res);
11402 * Convenience subroutine to verify a SQL command succeeded,
11403 * and exit with a useful error message if not.
11405 static void
11406 check_sql_result(PGresult *res, PGconn *conn, const char *query,
11407 ExecStatusType expected)
11409 const char *err;
11411 if (res && PQresultStatus(res) == expected)
11412 return; /* A-OK */
11414 write_msg(NULL, "SQL command failed\n");
11415 if (res)
11416 err = PQresultErrorMessage(res);
11417 else
11418 err = PQerrorMessage(conn);
11419 write_msg(NULL, "Error message from server: %s", err);
11420 write_msg(NULL, "The command was: %s\n", query);
11421 exit_nicely();