Disallow empty passwords in LDAP authentication, the same way
[PostgreSQL.git] / src / bin / pg_dump / pg_dump.c
blob4199bdbf62fae4aa741d6e115c578acbdc7aa886
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 #include "access/attnum.h"
34 #include "access/sysattr.h"
35 #include "catalog/pg_cast.h"
36 #include "catalog/pg_class.h"
37 #include "catalog/pg_proc.h"
38 #include "catalog/pg_trigger.h"
39 #include "catalog/pg_type.h"
40 #include "libpq/libpq-fs.h"
42 #include "pg_backup_archiver.h"
43 #include "dumputils.h"
45 extern char *optarg;
46 extern int optind,
47 opterr;
50 typedef struct
52 const char *descr; /* comment for an object */
53 Oid classoid; /* object class (catalog OID) */
54 Oid objoid; /* object OID */
55 int objsubid; /* subobject (table column #) */
56 } CommentItem;
59 /* global decls */
60 bool g_verbose; /* User wants verbose narration of our
61 * activities. */
62 Archive *g_fout; /* the script file */
63 PGconn *g_conn; /* the database connection */
65 /* various user-settable parameters */
66 bool schemaOnly;
67 bool dataOnly;
68 bool aclsSkip;
69 const char *lockWaitTimeout;
71 /* subquery used to convert user ID (eg, datdba) to user name */
72 static const char *username_subquery;
74 /* obsolete as of 7.3: */
75 static Oid g_last_builtin_oid; /* value of the last builtin oid */
78 * Object inclusion/exclusion lists
80 * The string lists record the patterns given by command-line switches,
81 * which we then convert to lists of OIDs of matching objects.
83 static SimpleStringList schema_include_patterns = {NULL, NULL};
84 static SimpleOidList schema_include_oids = {NULL, NULL};
85 static SimpleStringList schema_exclude_patterns = {NULL, NULL};
86 static SimpleOidList schema_exclude_oids = {NULL, NULL};
88 static SimpleStringList table_include_patterns = {NULL, NULL};
89 static SimpleOidList table_include_oids = {NULL, NULL};
90 static SimpleStringList table_exclude_patterns = {NULL, NULL};
91 static SimpleOidList table_exclude_oids = {NULL, NULL};
93 /* default, if no "inclusion" switches appear, is to dump everything */
94 static bool include_everything = true;
96 char g_opaque_type[10]; /* name for the opaque type */
98 /* placeholders for the delimiters for comments */
99 char g_comment_start[10];
100 char g_comment_end[10];
102 static const CatalogId nilCatalogId = {0, 0};
104 /* these are to avoid passing around info for findNamespace() */
105 static NamespaceInfo *g_namespaces;
106 static int g_numNamespaces;
108 /* flags for various command-line long options */
109 static int binary_upgrade = 0;
110 static int disable_dollar_quoting = 0;
111 static int dump_inserts = 0;
112 static int column_inserts = 0;
115 static void help(const char *progname);
116 static void expand_schema_name_patterns(SimpleStringList *patterns,
117 SimpleOidList *oids);
118 static void expand_table_name_patterns(SimpleStringList *patterns,
119 SimpleOidList *oids);
120 static NamespaceInfo *findNamespace(Oid nsoid, Oid objoid);
121 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
122 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
123 static void dumpComment(Archive *fout, const char *target,
124 const char *namespace, const char *owner,
125 CatalogId catalogId, int subid, DumpId dumpId);
126 static int findComments(Archive *fout, Oid classoid, Oid objoid,
127 CommentItem **items);
128 static int collectComments(Archive *fout, CommentItem **items);
129 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
130 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
131 static void dumpType(Archive *fout, TypeInfo *tinfo);
132 static void dumpBaseType(Archive *fout, TypeInfo *tinfo);
133 static void dumpEnumType(Archive *fout, TypeInfo *tinfo);
134 static void dumpDomain(Archive *fout, TypeInfo *tinfo);
135 static void dumpCompositeType(Archive *fout, TypeInfo *tinfo);
136 static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
137 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
138 static void dumpFunc(Archive *fout, FuncInfo *finfo);
139 static void dumpCast(Archive *fout, CastInfo *cast);
140 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
141 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
142 static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
143 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
144 static void dumpRule(Archive *fout, RuleInfo *rinfo);
145 static void dumpAgg(Archive *fout, AggInfo *agginfo);
146 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
147 static void dumpTable(Archive *fout, TableInfo *tbinfo);
148 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
149 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
150 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
151 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
152 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
153 static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
154 static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
155 static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
156 static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
157 static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
158 static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
159 static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
160 static void dumpUserMappings(Archive *fout, const char *target,
161 const char *servername, const char *namespace,
162 const char *owner, CatalogId catalogId, DumpId dumpId);
164 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
165 const char *type, const char *name, const char *subname,
166 const char *tag, const char *nspname, const char *owner,
167 const char *acls);
169 static void getDependencies(void);
170 static void getDomainConstraints(TypeInfo *tinfo);
171 static void getTableData(TableInfo *tblinfo, int numTables, bool oids);
172 static void getTableDataFKConstraints(void);
173 static char *format_function_arguments(FuncInfo *finfo, char *funcargs);
174 static char *format_function_arguments_old(FuncInfo *finfo, int nallargs,
175 char **allargtypes,
176 char **argmodes,
177 char **argnames);
178 static char *format_function_signature(FuncInfo *finfo, bool honor_quotes);
179 static const char *convertRegProcReference(const char *proc);
180 static const char *convertOperatorReference(const char *opr);
181 static const char *convertTSFunction(Oid funcOid);
182 static Oid findLastBuiltinOid_V71(const char *);
183 static Oid findLastBuiltinOid_V70(void);
184 static void selectSourceSchema(const char *schemaName);
185 static char *getFormattedTypeName(Oid oid, OidOptions opts);
186 static char *myFormatType(const char *typname, int32 typmod);
187 static const char *fmtQualifiedId(const char *schema, const char *id);
188 static bool hasBlobs(Archive *AH);
189 static int dumpBlobs(Archive *AH, void *arg);
190 static int dumpBlobComments(Archive *AH, void *arg);
191 static void dumpDatabase(Archive *AH);
192 static void dumpEncoding(Archive *AH);
193 static void dumpStdStrings(Archive *AH);
194 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
195 static const char *fmtCopyColumnList(const TableInfo *ti);
196 static void do_sql_command(PGconn *conn, const char *query);
197 static void check_sql_result(PGresult *res, PGconn *conn, const char *query,
198 ExecStatusType expected);
202 main(int argc, char **argv)
204 int c;
205 const char *filename = NULL;
206 const char *format = "p";
207 const char *dbname = NULL;
208 const char *pghost = NULL;
209 const char *pgport = NULL;
210 const char *username = NULL;
211 const char *dumpencoding = NULL;
212 const char *std_strings;
213 bool oids = false;
214 TableInfo *tblinfo;
215 int numTables;
216 DumpableObject **dobjs;
217 int numObjs;
218 int i;
219 enum trivalue prompt_password = TRI_DEFAULT;
220 int compressLevel = -1;
221 int plainText = 0;
222 int outputClean = 0;
223 int outputCreate = 0;
224 bool outputBlobs = false;
225 int outputNoOwner = 0;
226 char *outputSuperuser = NULL;
227 char *use_role = NULL;
228 int my_version;
229 int optindex;
230 RestoreOptions *ropt;
232 static int disable_triggers = 0;
233 static int outputNoTablespaces = 0;
234 static int use_setsessauth = 0;
236 struct option long_options[] = {
237 {"data-only", no_argument, NULL, 'a'},
238 {"blobs", no_argument, NULL, 'b'},
239 {"clean", no_argument, NULL, 'c'},
240 {"create", no_argument, NULL, 'C'},
241 {"file", required_argument, NULL, 'f'},
242 {"format", required_argument, NULL, 'F'},
243 {"host", required_argument, NULL, 'h'},
244 {"ignore-version", no_argument, NULL, 'i'},
245 {"no-reconnect", no_argument, NULL, 'R'},
246 {"oids", no_argument, NULL, 'o'},
247 {"no-owner", no_argument, NULL, 'O'},
248 {"port", required_argument, NULL, 'p'},
249 {"schema", required_argument, NULL, 'n'},
250 {"exclude-schema", required_argument, NULL, 'N'},
251 {"schema-only", no_argument, NULL, 's'},
252 {"superuser", required_argument, NULL, 'S'},
253 {"table", required_argument, NULL, 't'},
254 {"exclude-table", required_argument, NULL, 'T'},
255 {"no-password", no_argument, NULL, 'w'},
256 {"password", no_argument, NULL, 'W'},
257 {"username", required_argument, NULL, 'U'},
258 {"verbose", no_argument, NULL, 'v'},
259 {"no-privileges", no_argument, NULL, 'x'},
260 {"no-acl", no_argument, NULL, 'x'},
261 {"compress", required_argument, NULL, 'Z'},
262 {"encoding", required_argument, NULL, 'E'},
263 {"help", no_argument, NULL, '?'},
264 {"version", no_argument, NULL, 'V'},
267 * the following options don't have an equivalent short option letter
269 {"attribute-inserts", no_argument, &column_inserts, 1},
270 {"binary-upgrade", no_argument, &binary_upgrade, 1},
271 {"column-inserts", no_argument, &column_inserts, 1},
272 {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
273 {"disable-triggers", no_argument, &disable_triggers, 1},
274 {"inserts", no_argument, &dump_inserts, 1},
275 {"lock-wait-timeout", required_argument, NULL, 2},
276 {"no-tablespaces", no_argument, &outputNoTablespaces, 1},
277 {"role", required_argument, NULL, 3},
278 {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
280 {NULL, 0, NULL, 0}
283 set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
285 g_verbose = false;
287 strcpy(g_comment_start, "-- ");
288 g_comment_end[0] = '\0';
289 strcpy(g_opaque_type, "opaque");
291 dataOnly = schemaOnly = false;
292 lockWaitTimeout = NULL;
294 progname = get_progname(argv[0]);
296 /* Set default options based on progname */
297 if (strcmp(progname, "pg_backup") == 0)
298 format = "c";
300 if (argc > 1)
302 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
304 help(progname);
305 exit(0);
307 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
309 puts("pg_dump (PostgreSQL) " PG_VERSION);
310 exit(0);
314 while ((c = getopt_long(argc, argv, "abcCE:f:F:h:in:N:oOp:RsS:t:T:U:vwWxX:Z:",
315 long_options, &optindex)) != -1)
317 switch (c)
319 case 'a': /* Dump data only */
320 dataOnly = true;
321 break;
323 case 'b': /* Dump blobs */
324 outputBlobs = true;
325 break;
327 case 'c': /* clean (i.e., drop) schema prior to create */
328 outputClean = 1;
329 break;
331 case 'C': /* Create DB */
332 outputCreate = 1;
333 break;
335 case 'E': /* Dump encoding */
336 dumpencoding = optarg;
337 break;
339 case 'f':
340 filename = optarg;
341 break;
343 case 'F':
344 format = optarg;
345 break;
347 case 'h': /* server host */
348 pghost = optarg;
349 break;
351 case 'i':
352 /* ignored, deprecated option */
353 break;
355 case 'n': /* include schema(s) */
356 simple_string_list_append(&schema_include_patterns, optarg);
357 include_everything = false;
358 break;
360 case 'N': /* exclude schema(s) */
361 simple_string_list_append(&schema_exclude_patterns, optarg);
362 break;
364 case 'o': /* Dump oids */
365 oids = true;
366 break;
368 case 'O': /* Don't reconnect to match owner */
369 outputNoOwner = 1;
370 break;
372 case 'p': /* server port */
373 pgport = optarg;
374 break;
376 case 'R':
377 /* no-op, still accepted for backwards compatibility */
378 break;
380 case 's': /* dump schema only */
381 schemaOnly = true;
382 break;
384 case 'S': /* Username for superuser in plain text output */
385 outputSuperuser = strdup(optarg);
386 break;
388 case 't': /* include table(s) */
389 simple_string_list_append(&table_include_patterns, optarg);
390 include_everything = false;
391 break;
393 case 'T': /* exclude table(s) */
394 simple_string_list_append(&table_exclude_patterns, optarg);
395 break;
397 case 'U':
398 username = optarg;
399 break;
401 case 'v': /* verbose */
402 g_verbose = true;
403 break;
405 case 'w':
406 prompt_password = TRI_NO;
407 break;
409 case 'W':
410 prompt_password = TRI_YES;
411 break;
413 case 'x': /* skip ACL dump */
414 aclsSkip = true;
415 break;
417 case 'X':
418 /* -X is a deprecated alternative to long options */
419 if (strcmp(optarg, "disable-dollar-quoting") == 0)
420 disable_dollar_quoting = 1;
421 else if (strcmp(optarg, "disable-triggers") == 0)
422 disable_triggers = 1;
423 else if (strcmp(optarg, "no-tablespaces") == 0)
424 outputNoTablespaces = 1;
425 else if (strcmp(optarg, "use-set-session-authorization") == 0)
426 use_setsessauth = 1;
427 else
429 fprintf(stderr,
430 _("%s: invalid -X option -- %s\n"),
431 progname, optarg);
432 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
433 exit(1);
435 break;
437 case 'Z': /* Compression Level */
438 compressLevel = atoi(optarg);
439 break;
441 case 0:
442 /* This covers the long options equivalent to -X xxx. */
443 break;
445 case 2: /* lock-wait-timeout */
446 lockWaitTimeout = optarg;
447 break;
449 case 3: /* SET ROLE */
450 use_role = optarg;
451 break;
453 default:
454 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
455 exit(1);
459 if (optind < (argc - 1))
461 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
462 progname, argv[optind + 1]);
463 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
464 progname);
465 exit(1);
468 /* Get database name from command line */
469 if (optind < argc)
470 dbname = argv[optind];
472 /* --column-inserts implies --inserts */
473 if (column_inserts)
474 dump_inserts = 1;
476 if (dataOnly && schemaOnly)
478 write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
479 exit(1);
482 if (dataOnly && outputClean)
484 write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
485 exit(1);
488 if (dump_inserts && oids)
490 write_msg(NULL, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
491 write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
492 exit(1);
495 /* open the output file */
496 if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
498 /* This is used by pg_dumpall, and is not documented */
499 plainText = 1;
500 g_fout = CreateArchive(filename, archNull, 0, archModeAppend);
502 else if (pg_strcasecmp(format, "c") == 0 || pg_strcasecmp(format, "custom") == 0)
503 g_fout = CreateArchive(filename, archCustom, compressLevel, archModeWrite);
504 else if (pg_strcasecmp(format, "f") == 0 || pg_strcasecmp(format, "file") == 0)
507 * Dump files into the current directory; for demonstration only, not
508 * documented.
510 g_fout = CreateArchive(filename, archFiles, compressLevel, archModeWrite);
512 else if (pg_strcasecmp(format, "p") == 0 || pg_strcasecmp(format, "plain") == 0)
514 plainText = 1;
515 g_fout = CreateArchive(filename, archNull, 0, archModeWrite);
517 else if (pg_strcasecmp(format, "t") == 0 || pg_strcasecmp(format, "tar") == 0)
518 g_fout = CreateArchive(filename, archTar, compressLevel, archModeWrite);
519 else
521 write_msg(NULL, "invalid output format \"%s\" specified\n", format);
522 exit(1);
525 if (g_fout == NULL)
527 write_msg(NULL, "could not open output file \"%s\" for writing\n", filename);
528 exit(1);
531 /* Let the archiver know how noisy to be */
532 g_fout->verbose = g_verbose;
534 my_version = parse_version(PG_VERSION);
535 if (my_version < 0)
537 write_msg(NULL, "could not parse version string \"%s\"\n", PG_VERSION);
538 exit(1);
542 * We allow the server to be back to 7.0, and up to any minor release of
543 * our own major version. (See also version check in pg_dumpall.c.)
545 g_fout->minRemoteVersion = 70000;
546 g_fout->maxRemoteVersion = (my_version / 100) * 100 + 99;
549 * Open the database using the Archiver, so it knows about it. Errors mean
550 * death.
552 g_conn = ConnectDatabase(g_fout, dbname, pghost, pgport,
553 username, prompt_password);
555 /* Set the client encoding if requested */
556 if (dumpencoding)
558 if (PQsetClientEncoding(g_conn, dumpencoding) < 0)
560 write_msg(NULL, "invalid client encoding \"%s\" specified\n",
561 dumpencoding);
562 exit(1);
567 * Get the active encoding and the standard_conforming_strings setting, so
568 * we know how to escape strings.
570 g_fout->encoding = PQclientEncoding(g_conn);
572 std_strings = PQparameterStatus(g_conn, "standard_conforming_strings");
573 g_fout->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
575 /* Set the role if requested */
576 if (use_role && g_fout->remoteVersion >= 80100)
578 PQExpBuffer query = createPQExpBuffer();
580 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
581 do_sql_command(g_conn, query->data);
582 destroyPQExpBuffer(query);
585 /* Set the datestyle to ISO to ensure the dump's portability */
586 do_sql_command(g_conn, "SET DATESTYLE = ISO");
588 /* Likewise, avoid using sql_standard intervalstyle */
589 if (g_fout->remoteVersion >= 80400)
590 do_sql_command(g_conn, "SET INTERVALSTYLE = POSTGRES");
593 * If supported, set extra_float_digits so that we can dump float data
594 * exactly (given correctly implemented float I/O code, anyway)
596 if (g_fout->remoteVersion >= 70400)
597 do_sql_command(g_conn, "SET extra_float_digits TO 2");
600 * If synchronized scanning is supported, disable it, to prevent
601 * unpredictable changes in row ordering across a dump and reload.
603 if (g_fout->remoteVersion >= 80300)
604 do_sql_command(g_conn, "SET synchronize_seqscans TO off");
607 * Disable timeouts if supported.
609 if (g_fout->remoteVersion >= 70300)
610 do_sql_command(g_conn, "SET statement_timeout = 0");
613 * Start serializable transaction to dump consistent data.
615 do_sql_command(g_conn, "BEGIN");
617 do_sql_command(g_conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
619 /* Select the appropriate subquery to convert user IDs to names */
620 if (g_fout->remoteVersion >= 80100)
621 username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
622 else if (g_fout->remoteVersion >= 70300)
623 username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
624 else
625 username_subquery = "SELECT usename FROM pg_user WHERE usesysid =";
627 /* Find the last built-in OID, if needed */
628 if (g_fout->remoteVersion < 70300)
630 if (g_fout->remoteVersion >= 70100)
631 g_last_builtin_oid = findLastBuiltinOid_V71(PQdb(g_conn));
632 else
633 g_last_builtin_oid = findLastBuiltinOid_V70();
634 if (g_verbose)
635 write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
638 /* Expand schema selection patterns into OID lists */
639 if (schema_include_patterns.head != NULL)
641 expand_schema_name_patterns(&schema_include_patterns,
642 &schema_include_oids);
643 if (schema_include_oids.head == NULL)
645 write_msg(NULL, "No matching schemas were found\n");
646 exit_nicely();
649 expand_schema_name_patterns(&schema_exclude_patterns,
650 &schema_exclude_oids);
651 /* non-matching exclusion patterns aren't an error */
653 /* Expand table selection patterns into OID lists */
654 if (table_include_patterns.head != NULL)
656 expand_table_name_patterns(&table_include_patterns,
657 &table_include_oids);
658 if (table_include_oids.head == NULL)
660 write_msg(NULL, "No matching tables were found\n");
661 exit_nicely();
664 expand_table_name_patterns(&table_exclude_patterns,
665 &table_exclude_oids);
666 /* non-matching exclusion patterns aren't an error */
669 * Dumping blobs is now default unless we saw an inclusion switch or -s
670 * ... but even if we did see one of these, -b turns it back on.
672 if (include_everything && !schemaOnly)
673 outputBlobs = true;
676 * Now scan the database and create DumpableObject structs for all the
677 * objects we intend to dump.
679 tblinfo = getSchemaData(&numTables);
681 if (g_fout->remoteVersion < 80400)
682 guessConstraintInheritance(tblinfo, numTables);
684 if (!schemaOnly)
686 getTableData(tblinfo, numTables, oids);
687 if (dataOnly)
688 getTableDataFKConstraints();
691 if (outputBlobs && hasBlobs(g_fout))
693 /* Add placeholders to allow correct sorting of blobs */
694 DumpableObject *blobobj;
695 DumpableObject *blobcobj;
697 blobobj = (DumpableObject *) malloc(sizeof(DumpableObject));
698 blobobj->objType = DO_BLOBS;
699 blobobj->catId = nilCatalogId;
700 AssignDumpId(blobobj);
701 blobobj->name = strdup("BLOBS");
703 blobcobj = (DumpableObject *) malloc(sizeof(DumpableObject));
704 blobcobj->objType = DO_BLOB_COMMENTS;
705 blobcobj->catId = nilCatalogId;
706 AssignDumpId(blobcobj);
707 blobcobj->name = strdup("BLOB COMMENTS");
708 addObjectDependency(blobcobj, blobobj->dumpId);
712 * Collect dependency data to assist in ordering the objects.
714 getDependencies();
717 * Sort the objects into a safe dump order (no forward references).
719 * In 7.3 or later, we can rely on dependency information to help us
720 * determine a safe order, so the initial sort is mostly for cosmetic
721 * purposes: we sort by name to ensure that logically identical schemas
722 * will dump identically. Before 7.3 we don't have dependencies and we
723 * use OID ordering as an (unreliable) guide to creation order.
725 getDumpableObjects(&dobjs, &numObjs);
727 if (g_fout->remoteVersion >= 70300)
728 sortDumpableObjectsByTypeName(dobjs, numObjs);
729 else
730 sortDumpableObjectsByTypeOid(dobjs, numObjs);
732 sortDumpableObjects(dobjs, numObjs);
735 * Create archive TOC entries for all the objects to be dumped, in a safe
736 * order.
739 /* First the special ENCODING and STDSTRINGS entries. */
740 dumpEncoding(g_fout);
741 dumpStdStrings(g_fout);
743 /* The database item is always next, unless we don't want it at all */
744 if (include_everything && !dataOnly)
745 dumpDatabase(g_fout);
747 /* Now the rearrangeable objects. */
748 for (i = 0; i < numObjs; i++)
749 dumpDumpableObject(g_fout, dobjs[i]);
752 * And finally we can do the actual output.
754 if (plainText)
756 ropt = NewRestoreOptions();
757 ropt->filename = (char *) filename;
758 ropt->dropSchema = outputClean;
759 ropt->aclsSkip = aclsSkip;
760 ropt->superuser = outputSuperuser;
761 ropt->create = outputCreate;
762 ropt->noOwner = outputNoOwner;
763 ropt->noTablespace = outputNoTablespaces;
764 ropt->disable_triggers = disable_triggers;
765 ropt->use_setsessauth = use_setsessauth;
766 ropt->dataOnly = dataOnly;
768 if (compressLevel == -1)
769 ropt->compression = 0;
770 else
771 ropt->compression = compressLevel;
773 ropt->suppressDumpWarnings = true; /* We've already shown them */
775 RestoreArchive(g_fout, ropt);
778 CloseArchive(g_fout);
780 PQfinish(g_conn);
782 exit(0);
786 static void
787 help(const char *progname)
789 printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
790 printf(_("Usage:\n"));
791 printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
793 printf(_("\nGeneral options:\n"));
794 printf(_(" -f, --file=FILENAME output file name\n"));
795 printf(_(" -F, --format=c|t|p output file format (custom, tar, plain text)\n"));
796 printf(_(" -v, --verbose verbose mode\n"));
797 printf(_(" -Z, --compress=0-9 compression level for compressed formats\n"));
798 printf(_(" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
799 printf(_(" --help show this help, then exit\n"));
800 printf(_(" --version output version information, then exit\n"));
802 printf(_("\nOptions controlling the output content:\n"));
803 printf(_(" -a, --data-only dump only the data, not the schema\n"));
804 printf(_(" -b, --blobs include large objects in dump\n"));
805 printf(_(" -c, --clean clean (drop) database objects before recreating\n"));
806 printf(_(" -C, --create include commands to create database in dump\n"));
807 printf(_(" -E, --encoding=ENCODING dump the data in encoding ENCODING\n"));
808 printf(_(" -n, --schema=SCHEMA dump the named schema(s) only\n"));
809 printf(_(" -N, --exclude-schema=SCHEMA do NOT dump the named schema(s)\n"));
810 printf(_(" -o, --oids include OIDs in dump\n"));
811 printf(_(" -O, --no-owner skip restoration of object ownership in\n"
812 " plain-text format\n"));
813 printf(_(" -s, --schema-only dump only the schema, no data\n"));
814 printf(_(" -S, --superuser=NAME superuser user name to use in plain-text format\n"));
815 printf(_(" -t, --table=TABLE dump the named table(s) only\n"));
816 printf(_(" -T, --exclude-table=TABLE do NOT dump the named table(s)\n"));
817 printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
818 printf(_(" --binary-upgrade for use by upgrade utilities only\n"));
819 printf(_(" --inserts dump data as INSERT commands, rather than COPY\n"));
820 printf(_(" --column-inserts dump data as INSERT commands with column names\n"));
821 printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n"));
822 printf(_(" --disable-triggers disable triggers during data-only restore\n"));
823 printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
824 printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
825 printf(_(" --use-set-session-authorization\n"
826 " use SET SESSION AUTHORIZATION commands instead of\n"
827 " ALTER OWNER commands to set ownership\n"));
829 printf(_("\nConnection options:\n"));
830 printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
831 printf(_(" -p, --port=PORT database server port number\n"));
832 printf(_(" -U, --username=NAME connect as specified database user\n"));
833 printf(_(" -w, --no-password never prompt for password\n"));
834 printf(_(" -W, --password force password prompt (should happen automatically)\n"));
836 printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
837 "variable value is used.\n\n"));
838 printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
841 void
842 exit_nicely(void)
844 PQfinish(g_conn);
845 if (g_verbose)
846 write_msg(NULL, "*** aborted because of error\n");
847 exit(1);
851 * Find the OIDs of all schemas matching the given list of patterns,
852 * and append them to the given OID list.
854 static void
855 expand_schema_name_patterns(SimpleStringList *patterns, SimpleOidList *oids)
857 PQExpBuffer query;
858 PGresult *res;
859 SimpleStringListCell *cell;
860 int i;
862 if (patterns->head == NULL)
863 return; /* nothing to do */
865 if (g_fout->remoteVersion < 70300)
867 write_msg(NULL, "server version must be at least 7.3 to use schema selection switches\n");
868 exit_nicely();
871 query = createPQExpBuffer();
874 * We use UNION ALL rather than UNION; this might sometimes result in
875 * duplicate entries in the OID list, but we don't care.
878 for (cell = patterns->head; cell; cell = cell->next)
880 if (cell != patterns->head)
881 appendPQExpBuffer(query, "UNION ALL\n");
882 appendPQExpBuffer(query,
883 "SELECT oid FROM pg_catalog.pg_namespace n\n");
884 processSQLNamePattern(g_conn, query, cell->val, false, false,
885 NULL, "n.nspname", NULL,
886 NULL);
889 res = PQexec(g_conn, query->data);
890 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
892 for (i = 0; i < PQntuples(res); i++)
894 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
897 PQclear(res);
898 destroyPQExpBuffer(query);
902 * Find the OIDs of all tables matching the given list of patterns,
903 * and append them to the given OID list.
905 static void
906 expand_table_name_patterns(SimpleStringList *patterns, SimpleOidList *oids)
908 PQExpBuffer query;
909 PGresult *res;
910 SimpleStringListCell *cell;
911 int i;
913 if (patterns->head == NULL)
914 return; /* nothing to do */
916 query = createPQExpBuffer();
919 * We use UNION ALL rather than UNION; this might sometimes result in
920 * duplicate entries in the OID list, but we don't care.
923 for (cell = patterns->head; cell; cell = cell->next)
925 if (cell != patterns->head)
926 appendPQExpBuffer(query, "UNION ALL\n");
927 appendPQExpBuffer(query,
928 "SELECT c.oid"
929 "\nFROM pg_catalog.pg_class c"
930 "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
931 "\nWHERE c.relkind in ('%c', '%c', '%c')\n",
932 RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
933 processSQLNamePattern(g_conn, query, cell->val, true, false,
934 "n.nspname", "c.relname", NULL,
935 "pg_catalog.pg_table_is_visible(c.oid)");
938 res = PQexec(g_conn, query->data);
939 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
941 for (i = 0; i < PQntuples(res); i++)
943 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
946 PQclear(res);
947 destroyPQExpBuffer(query);
951 * selectDumpableNamespace: policy-setting subroutine
952 * Mark a namespace as to be dumped or not
954 static void
955 selectDumpableNamespace(NamespaceInfo *nsinfo)
958 * If specific tables are being dumped, do not dump any complete
959 * namespaces. If specific namespaces are being dumped, dump just those
960 * namespaces. Otherwise, dump all non-system namespaces.
962 if (table_include_oids.head != NULL)
963 nsinfo->dobj.dump = false;
964 else if (schema_include_oids.head != NULL)
965 nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
966 nsinfo->dobj.catId.oid);
967 else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
968 strcmp(nsinfo->dobj.name, "information_schema") == 0)
969 nsinfo->dobj.dump = false;
970 else
971 nsinfo->dobj.dump = true;
974 * In any case, a namespace can be excluded by an exclusion switch
976 if (nsinfo->dobj.dump &&
977 simple_oid_list_member(&schema_exclude_oids,
978 nsinfo->dobj.catId.oid))
979 nsinfo->dobj.dump = false;
983 * selectDumpableTable: policy-setting subroutine
984 * Mark a table as to be dumped or not
986 static void
987 selectDumpableTable(TableInfo *tbinfo)
990 * If specific tables are being dumped, dump just those tables; else, dump
991 * according to the parent namespace's dump flag.
993 if (table_include_oids.head != NULL)
994 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
995 tbinfo->dobj.catId.oid);
996 else
997 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
1000 * In any case, a table can be excluded by an exclusion switch
1002 if (tbinfo->dobj.dump &&
1003 simple_oid_list_member(&table_exclude_oids,
1004 tbinfo->dobj.catId.oid))
1005 tbinfo->dobj.dump = false;
1009 * selectDumpableType: policy-setting subroutine
1010 * Mark a type as to be dumped or not
1012 * If it's a table's rowtype or an autogenerated array type, we also apply a
1013 * special type code to facilitate sorting into the desired order. (We don't
1014 * want to consider those to be ordinary types because that would bring tables
1015 * up into the datatype part of the dump order.) Those tests should be made
1016 * first to ensure the objType change is applied regardless of namespace etc.
1018 static void
1019 selectDumpableType(TypeInfo *tinfo)
1021 /* skip complex types, except for standalone composite types */
1022 if (OidIsValid(tinfo->typrelid) &&
1023 tinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1025 tinfo->dobj.dump = false;
1026 tinfo->dobj.objType = DO_DUMMY_TYPE;
1029 /* skip auto-generated array types */
1030 else if (tinfo->isArray)
1032 tinfo->dobj.dump = false;
1033 tinfo->dobj.objType = DO_DUMMY_TYPE;
1036 /* dump only types in dumpable namespaces */
1037 else if (!tinfo->dobj.namespace->dobj.dump)
1038 tinfo->dobj.dump = false;
1040 /* skip undefined placeholder types */
1041 else if (!tinfo->isDefined)
1042 tinfo->dobj.dump = false;
1044 else
1045 tinfo->dobj.dump = true;
1049 * selectDumpableObject: policy-setting subroutine
1050 * Mark a generic dumpable object as to be dumped or not
1052 * Use this only for object types without a special-case routine above.
1054 static void
1055 selectDumpableObject(DumpableObject *dobj)
1058 * Default policy is to dump if parent namespace is dumpable, or always
1059 * for non-namespace-associated items.
1061 if (dobj->namespace)
1062 dobj->dump = dobj->namespace->dobj.dump;
1063 else
1064 dobj->dump = true;
1068 * Dump a table's contents for loading using the COPY command
1069 * - this routine is called by the Archiver when it wants the table
1070 * to be dumped.
1073 static int
1074 dumpTableData_copy(Archive *fout, void *dcontext)
1076 TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1077 TableInfo *tbinfo = tdinfo->tdtable;
1078 const char *classname = tbinfo->dobj.name;
1079 const bool hasoids = tbinfo->hasoids;
1080 const bool oids = tdinfo->oids;
1081 PQExpBuffer q = createPQExpBuffer();
1082 PGresult *res;
1083 int ret;
1084 char *copybuf;
1085 const char *column_list;
1087 if (g_verbose)
1088 write_msg(NULL, "dumping contents of table %s\n", classname);
1091 * Make sure we are in proper schema. We will qualify the table name
1092 * below anyway (in case its name conflicts with a pg_catalog table); but
1093 * this ensures reproducible results in case the table contains regproc,
1094 * regclass, etc columns.
1096 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
1099 * If possible, specify the column list explicitly so that we have no
1100 * possibility of retrieving data in the wrong column order. (The default
1101 * column ordering of COPY will not be what we want in certain corner
1102 * cases involving ADD COLUMN and inheritance.)
1104 if (g_fout->remoteVersion >= 70300)
1105 column_list = fmtCopyColumnList(tbinfo);
1106 else
1107 column_list = ""; /* can't select columns in COPY */
1109 if (oids && hasoids)
1111 appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
1112 fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1113 classname),
1114 column_list);
1116 else
1118 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1119 fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1120 classname),
1121 column_list);
1123 res = PQexec(g_conn, q->data);
1124 check_sql_result(res, g_conn, q->data, PGRES_COPY_OUT);
1125 PQclear(res);
1127 for (;;)
1129 ret = PQgetCopyData(g_conn, &copybuf, 0);
1131 if (ret < 0)
1132 break; /* done or error */
1134 if (copybuf)
1136 WriteData(fout, copybuf, ret);
1137 PQfreemem(copybuf);
1140 /* ----------
1141 * THROTTLE:
1143 * There was considerable discussion in late July, 2000 regarding
1144 * slowing down pg_dump when backing up large tables. Users with both
1145 * slow & fast (multi-processor) machines experienced performance
1146 * degradation when doing a backup.
1148 * Initial attempts based on sleeping for a number of ms for each ms
1149 * of work were deemed too complex, then a simple 'sleep in each loop'
1150 * implementation was suggested. The latter failed because the loop
1151 * was too tight. Finally, the following was implemented:
1153 * If throttle is non-zero, then
1154 * See how long since the last sleep.
1155 * Work out how long to sleep (based on ratio).
1156 * If sleep is more than 100ms, then
1157 * sleep
1158 * reset timer
1159 * EndIf
1160 * EndIf
1162 * where the throttle value was the number of ms to sleep per ms of
1163 * work. The calculation was done in each loop.
1165 * Most of the hard work is done in the backend, and this solution
1166 * still did not work particularly well: on slow machines, the ratio
1167 * was 50:1, and on medium paced machines, 1:1, and on fast
1168 * multi-processor machines, it had little or no effect, for reasons
1169 * that were unclear.
1171 * Further discussion ensued, and the proposal was dropped.
1173 * For those people who want this feature, it can be implemented using
1174 * gettimeofday in each loop, calculating the time since last sleep,
1175 * multiplying that by the sleep ratio, then if the result is more
1176 * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1177 * function to sleep for a subsecond period ie.
1179 * select(0, NULL, NULL, NULL, &tvi);
1181 * This will return after the interval specified in the structure tvi.
1182 * Finally, call gettimeofday again to save the 'last sleep time'.
1183 * ----------
1186 archprintf(fout, "\\.\n\n\n");
1188 if (ret == -2)
1190 /* copy data transfer failed */
1191 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
1192 write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
1193 write_msg(NULL, "The command was: %s\n", q->data);
1194 exit_nicely();
1197 /* Check command status and return to normal libpq state */
1198 res = PQgetResult(g_conn);
1199 check_sql_result(res, g_conn, q->data, PGRES_COMMAND_OK);
1200 PQclear(res);
1202 destroyPQExpBuffer(q);
1203 return 1;
1206 static int
1207 dumpTableData_insert(Archive *fout, void *dcontext)
1209 TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1210 TableInfo *tbinfo = tdinfo->tdtable;
1211 const char *classname = tbinfo->dobj.name;
1212 PQExpBuffer q = createPQExpBuffer();
1213 PGresult *res;
1214 int tuple;
1215 int nfields;
1216 int field;
1219 * Make sure we are in proper schema. We will qualify the table name
1220 * below anyway (in case its name conflicts with a pg_catalog table); but
1221 * this ensures reproducible results in case the table contains regproc,
1222 * regclass, etc columns.
1224 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
1226 if (fout->remoteVersion >= 70100)
1228 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1229 "SELECT * FROM ONLY %s",
1230 fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1231 classname));
1233 else
1235 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1236 "SELECT * FROM %s",
1237 fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1238 classname));
1241 res = PQexec(g_conn, q->data);
1242 check_sql_result(res, g_conn, q->data, PGRES_COMMAND_OK);
1246 PQclear(res);
1248 res = PQexec(g_conn, "FETCH 100 FROM _pg_dump_cursor");
1249 check_sql_result(res, g_conn, "FETCH 100 FROM _pg_dump_cursor",
1250 PGRES_TUPLES_OK);
1251 nfields = PQnfields(res);
1252 for (tuple = 0; tuple < PQntuples(res); tuple++)
1254 archprintf(fout, "INSERT INTO %s ", fmtId(classname));
1255 if (nfields == 0)
1257 /* corner case for zero-column table */
1258 archprintf(fout, "DEFAULT VALUES;\n");
1259 continue;
1261 if (column_inserts)
1263 resetPQExpBuffer(q);
1264 appendPQExpBuffer(q, "(");
1265 for (field = 0; field < nfields; field++)
1267 if (field > 0)
1268 appendPQExpBuffer(q, ", ");
1269 appendPQExpBufferStr(q, fmtId(PQfname(res, field)));
1271 appendPQExpBuffer(q, ") ");
1272 archputs(q->data, fout);
1274 archprintf(fout, "VALUES (");
1275 for (field = 0; field < nfields; field++)
1277 if (field > 0)
1278 archprintf(fout, ", ");
1279 if (PQgetisnull(res, tuple, field))
1281 archprintf(fout, "NULL");
1282 continue;
1285 /* XXX This code is partially duplicated in ruleutils.c */
1286 switch (PQftype(res, field))
1288 case INT2OID:
1289 case INT4OID:
1290 case INT8OID:
1291 case OIDOID:
1292 case FLOAT4OID:
1293 case FLOAT8OID:
1294 case NUMERICOID:
1297 * These types are printed without quotes unless
1298 * they contain values that aren't accepted by the
1299 * scanner unquoted (e.g., 'NaN'). Note that
1300 * strtod() and friends might accept NaN, so we
1301 * can't use that to test.
1303 * In reality we only need to defend against
1304 * infinity and NaN, so we need not get too crazy
1305 * about pattern matching here.
1307 const char *s = PQgetvalue(res, tuple, field);
1309 if (strspn(s, "0123456789 +-eE.") == strlen(s))
1310 archprintf(fout, "%s", s);
1311 else
1312 archprintf(fout, "'%s'", s);
1314 break;
1316 case BITOID:
1317 case VARBITOID:
1318 archprintf(fout, "B'%s'",
1319 PQgetvalue(res, tuple, field));
1320 break;
1322 case BOOLOID:
1323 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
1324 archprintf(fout, "true");
1325 else
1326 archprintf(fout, "false");
1327 break;
1329 default:
1330 /* All other types are printed as string literals. */
1331 resetPQExpBuffer(q);
1332 appendStringLiteralAH(q,
1333 PQgetvalue(res, tuple, field),
1334 fout);
1335 archputs(q->data, fout);
1336 break;
1339 archprintf(fout, ");\n");
1341 } while (PQntuples(res) > 0);
1343 PQclear(res);
1345 archprintf(fout, "\n\n");
1347 do_sql_command(g_conn, "CLOSE _pg_dump_cursor");
1349 destroyPQExpBuffer(q);
1350 return 1;
1355 * dumpTableData -
1356 * dump the contents of a single table
1358 * Actually, this just makes an ArchiveEntry for the table contents.
1360 static void
1361 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
1363 TableInfo *tbinfo = tdinfo->tdtable;
1364 PQExpBuffer copyBuf = createPQExpBuffer();
1365 DataDumperPtr dumpFn;
1366 char *copyStmt;
1368 if (!dump_inserts)
1370 /* Dump/restore using COPY */
1371 dumpFn = dumpTableData_copy;
1372 /* must use 2 steps here 'cause fmtId is nonreentrant */
1373 appendPQExpBuffer(copyBuf, "COPY %s ",
1374 fmtId(tbinfo->dobj.name));
1375 appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
1376 fmtCopyColumnList(tbinfo),
1377 (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
1378 copyStmt = copyBuf->data;
1380 else
1382 /* Restore using INSERT */
1383 dumpFn = dumpTableData_insert;
1384 copyStmt = NULL;
1387 ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
1388 tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
1389 NULL, tbinfo->rolname,
1390 false, "TABLE DATA", SECTION_DATA,
1391 "", "", copyStmt,
1392 tdinfo->dobj.dependencies, tdinfo->dobj.nDeps,
1393 dumpFn, tdinfo);
1395 destroyPQExpBuffer(copyBuf);
1399 * getTableData -
1400 * set up dumpable objects representing the contents of tables
1402 static void
1403 getTableData(TableInfo *tblinfo, int numTables, bool oids)
1405 int i;
1407 for (i = 0; i < numTables; i++)
1409 /* Skip VIEWs (no data to dump) */
1410 if (tblinfo[i].relkind == RELKIND_VIEW)
1411 continue;
1412 /* Skip SEQUENCEs (handled elsewhere) */
1413 if (tblinfo[i].relkind == RELKIND_SEQUENCE)
1414 continue;
1416 if (tblinfo[i].dobj.dump)
1418 TableDataInfo *tdinfo;
1420 tdinfo = (TableDataInfo *) malloc(sizeof(TableDataInfo));
1422 tdinfo->dobj.objType = DO_TABLE_DATA;
1425 * Note: use tableoid 0 so that this object won't be mistaken for
1426 * something that pg_depend entries apply to.
1428 tdinfo->dobj.catId.tableoid = 0;
1429 tdinfo->dobj.catId.oid = tblinfo[i].dobj.catId.oid;
1430 AssignDumpId(&tdinfo->dobj);
1431 tdinfo->dobj.name = tblinfo[i].dobj.name;
1432 tdinfo->dobj.namespace = tblinfo[i].dobj.namespace;
1433 tdinfo->tdtable = &(tblinfo[i]);
1434 tdinfo->oids = oids;
1435 addObjectDependency(&tdinfo->dobj, tblinfo[i].dobj.dumpId);
1437 tblinfo[i].dataObj = tdinfo;
1443 * getTableDataFKConstraints -
1444 * add dump-order dependencies reflecting foreign key constraints
1446 * This code is executed only in a data-only dump --- in schema+data dumps
1447 * we handle foreign key issues by not creating the FK constraints until
1448 * after the data is loaded. In a data-only dump, however, we want to
1449 * order the table data objects in such a way that a table's referenced
1450 * tables are restored first. (In the presence of circular references or
1451 * self-references this may be impossible; we'll detect and complain about
1452 * that during the dependency sorting step.)
1454 static void
1455 getTableDataFKConstraints(void)
1457 DumpableObject **dobjs;
1458 int numObjs;
1459 int i;
1461 /* Search through all the dumpable objects for FK constraints */
1462 getDumpableObjects(&dobjs, &numObjs);
1463 for (i = 0; i < numObjs; i++)
1465 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
1467 ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
1468 TableInfo *ftable;
1470 /* Not interesting unless both tables are to be dumped */
1471 if (cinfo->contable == NULL ||
1472 cinfo->contable->dataObj == NULL)
1473 continue;
1474 ftable = findTableByOid(cinfo->confrelid);
1475 if (ftable == NULL ||
1476 ftable->dataObj == NULL)
1477 continue;
1480 * Okay, make referencing table's TABLE_DATA object depend on the
1481 * referenced table's TABLE_DATA object.
1483 addObjectDependency(&cinfo->contable->dataObj->dobj,
1484 ftable->dataObj->dobj.dumpId);
1487 free(dobjs);
1492 * guessConstraintInheritance:
1493 * In pre-8.4 databases, we can't tell for certain which constraints
1494 * are inherited. We assume a CHECK constraint is inherited if its name
1495 * matches the name of any constraint in the parent. Originally this code
1496 * tried to compare the expression texts, but that can fail for various
1497 * reasons --- for example, if the parent and child tables are in different
1498 * schemas, reverse-listing of function calls may produce different text
1499 * (schema-qualified or not) depending on search path.
1501 * In 8.4 and up we can rely on the conislocal field to decide which
1502 * constraints must be dumped; much safer.
1504 * This function assumes all conislocal flags were initialized to TRUE.
1505 * It clears the flag on anything that seems to be inherited.
1507 static void
1508 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
1510 int i,
1514 for (i = 0; i < numTables; i++)
1516 TableInfo *tbinfo = &(tblinfo[i]);
1517 int numParents;
1518 TableInfo **parents;
1519 TableInfo *parent;
1521 /* Sequences and views never have parents */
1522 if (tbinfo->relkind == RELKIND_SEQUENCE ||
1523 tbinfo->relkind == RELKIND_VIEW)
1524 continue;
1526 /* Don't bother computing anything for non-target tables, either */
1527 if (!tbinfo->dobj.dump)
1528 continue;
1530 numParents = tbinfo->numParents;
1531 parents = tbinfo->parents;
1533 if (numParents == 0)
1534 continue; /* nothing to see here, move along */
1536 /* scan for inherited CHECK constraints */
1537 for (j = 0; j < tbinfo->ncheck; j++)
1539 ConstraintInfo *constr;
1541 constr = &(tbinfo->checkexprs[j]);
1543 for (k = 0; k < numParents; k++)
1545 int l;
1547 parent = parents[k];
1548 for (l = 0; l < parent->ncheck; l++)
1550 ConstraintInfo *pconstr = &(parent->checkexprs[l]);
1552 if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
1554 constr->conislocal = false;
1555 break;
1558 if (!constr->conislocal)
1559 break;
1567 * dumpDatabase:
1568 * dump the database definition
1570 static void
1571 dumpDatabase(Archive *AH)
1573 PQExpBuffer dbQry = createPQExpBuffer();
1574 PQExpBuffer delQry = createPQExpBuffer();
1575 PQExpBuffer creaQry = createPQExpBuffer();
1576 PGresult *res;
1577 int ntups;
1578 int i_tableoid,
1579 i_oid,
1580 i_dba,
1581 i_encoding,
1582 i_collate,
1583 i_ctype,
1584 i_frozenxid,
1585 i_tablespace;
1586 CatalogId dbCatId;
1587 DumpId dbDumpId;
1588 const char *datname,
1589 *dba,
1590 *encoding,
1591 *collate,
1592 *ctype,
1593 *tablespace;
1594 uint32 frozenxid;
1596 datname = PQdb(g_conn);
1598 if (g_verbose)
1599 write_msg(NULL, "saving database definition\n");
1601 /* Make sure we are in proper schema */
1602 selectSourceSchema("pg_catalog");
1604 /* Get the database owner and parameters from pg_database */
1605 if (g_fout->remoteVersion >= 80400)
1607 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1608 "(%s datdba) AS dba, "
1609 "pg_encoding_to_char(encoding) AS encoding, "
1610 "datcollate, datctype, datfrozenxid, "
1611 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
1612 "shobj_description(oid, 'pg_database') AS description "
1614 "FROM pg_database "
1615 "WHERE datname = ",
1616 username_subquery);
1617 appendStringLiteralAH(dbQry, datname, AH);
1619 else if (g_fout->remoteVersion >= 80200)
1621 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1622 "(%s datdba) AS dba, "
1623 "pg_encoding_to_char(encoding) AS encoding, "
1624 "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
1625 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
1626 "shobj_description(oid, 'pg_database') AS description "
1628 "FROM pg_database "
1629 "WHERE datname = ",
1630 username_subquery);
1631 appendStringLiteralAH(dbQry, datname, AH);
1633 else if (g_fout->remoteVersion >= 80000)
1635 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1636 "(%s datdba) AS dba, "
1637 "pg_encoding_to_char(encoding) AS encoding, "
1638 "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
1639 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
1640 "FROM pg_database "
1641 "WHERE datname = ",
1642 username_subquery);
1643 appendStringLiteralAH(dbQry, datname, AH);
1645 else if (g_fout->remoteVersion >= 70100)
1647 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1648 "(%s datdba) AS dba, "
1649 "pg_encoding_to_char(encoding) AS encoding, "
1650 "NULL AS datcollate, NULL AS datctype, "
1651 "0 AS datfrozenxid, "
1652 "NULL AS tablespace "
1653 "FROM pg_database "
1654 "WHERE datname = ",
1655 username_subquery);
1656 appendStringLiteralAH(dbQry, datname, AH);
1658 else
1660 appendPQExpBuffer(dbQry, "SELECT "
1661 "(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, "
1662 "oid, "
1663 "(%s datdba) AS dba, "
1664 "pg_encoding_to_char(encoding) AS encoding, "
1665 "NULL AS datcollate, NULL AS datctype, "
1666 "0 AS datfrozenxid, "
1667 "NULL AS tablespace "
1668 "FROM pg_database "
1669 "WHERE datname = ",
1670 username_subquery);
1671 appendStringLiteralAH(dbQry, datname, AH);
1674 res = PQexec(g_conn, dbQry->data);
1675 check_sql_result(res, g_conn, dbQry->data, PGRES_TUPLES_OK);
1677 ntups = PQntuples(res);
1679 if (ntups <= 0)
1681 write_msg(NULL, "missing pg_database entry for database \"%s\"\n",
1682 datname);
1683 exit_nicely();
1686 if (ntups != 1)
1688 write_msg(NULL, "query returned more than one (%d) pg_database entry for database \"%s\"\n",
1689 ntups, datname);
1690 exit_nicely();
1693 i_tableoid = PQfnumber(res, "tableoid");
1694 i_oid = PQfnumber(res, "oid");
1695 i_dba = PQfnumber(res, "dba");
1696 i_encoding = PQfnumber(res, "encoding");
1697 i_collate = PQfnumber(res, "datcollate");
1698 i_ctype = PQfnumber(res, "datctype");
1699 i_frozenxid = PQfnumber(res, "datfrozenxid");
1700 i_tablespace = PQfnumber(res, "tablespace");
1702 dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
1703 dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
1704 dba = PQgetvalue(res, 0, i_dba);
1705 encoding = PQgetvalue(res, 0, i_encoding);
1706 collate = PQgetvalue(res, 0, i_collate);
1707 ctype = PQgetvalue(res, 0, i_ctype);
1708 frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
1709 tablespace = PQgetvalue(res, 0, i_tablespace);
1711 appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
1712 fmtId(datname));
1713 if (strlen(encoding) > 0)
1715 appendPQExpBuffer(creaQry, " ENCODING = ");
1716 appendStringLiteralAH(creaQry, encoding, AH);
1718 if (strlen(collate) > 0)
1720 appendPQExpBuffer(creaQry, " LC_COLLATE = ");
1721 appendStringLiteralAH(creaQry, collate, AH);
1723 if (strlen(ctype) > 0)
1725 appendPQExpBuffer(creaQry, " LC_CTYPE = ");
1726 appendStringLiteralAH(creaQry, ctype, AH);
1728 if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0)
1729 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
1730 fmtId(tablespace));
1731 appendPQExpBuffer(creaQry, ";\n");
1733 if (binary_upgrade)
1735 appendPQExpBuffer(creaQry, "\n-- For binary upgrade, set datfrozenxid.\n");
1736 appendPQExpBuffer(creaQry, "UPDATE pg_database\n"
1737 "SET datfrozenxid = '%u'\n"
1738 "WHERE datname = ",
1739 frozenxid);
1740 appendStringLiteralAH(creaQry, datname, AH);
1741 appendPQExpBuffer(creaQry, ";\n");
1744 appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
1745 fmtId(datname));
1747 dbDumpId = createDumpId();
1749 ArchiveEntry(AH,
1750 dbCatId, /* catalog ID */
1751 dbDumpId, /* dump ID */
1752 datname, /* Name */
1753 NULL, /* Namespace */
1754 NULL, /* Tablespace */
1755 dba, /* Owner */
1756 false, /* with oids */
1757 "DATABASE", /* Desc */
1758 SECTION_PRE_DATA, /* Section */
1759 creaQry->data, /* Create */
1760 delQry->data, /* Del */
1761 NULL, /* Copy */
1762 NULL, /* Deps */
1763 0, /* # Deps */
1764 NULL, /* Dumper */
1765 NULL); /* Dumper Arg */
1767 /* Dump DB comment if any */
1768 if (g_fout->remoteVersion >= 80200)
1771 * 8.2 keeps comments on shared objects in a shared table, so we
1772 * cannot use the dumpComment used for other database objects.
1774 char *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
1776 if (comment && strlen(comment))
1778 resetPQExpBuffer(dbQry);
1781 * Generates warning when loaded into a differently-named
1782 * database.
1784 appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
1785 appendStringLiteralAH(dbQry, comment, AH);
1786 appendPQExpBuffer(dbQry, ";\n");
1788 ArchiveEntry(AH, dbCatId, createDumpId(), datname, NULL, NULL,
1789 dba, false, "COMMENT", SECTION_NONE,
1790 dbQry->data, "", NULL,
1791 &dbDumpId, 1, NULL, NULL);
1794 else
1796 resetPQExpBuffer(dbQry);
1797 appendPQExpBuffer(dbQry, "DATABASE %s", fmtId(datname));
1798 dumpComment(AH, dbQry->data, NULL, "",
1799 dbCatId, 0, dbDumpId);
1802 PQclear(res);
1804 destroyPQExpBuffer(dbQry);
1805 destroyPQExpBuffer(delQry);
1806 destroyPQExpBuffer(creaQry);
1811 * dumpEncoding: put the correct encoding into the archive
1813 static void
1814 dumpEncoding(Archive *AH)
1816 const char *encname = pg_encoding_to_char(AH->encoding);
1817 PQExpBuffer qry = createPQExpBuffer();
1819 if (g_verbose)
1820 write_msg(NULL, "saving encoding = %s\n", encname);
1822 appendPQExpBuffer(qry, "SET client_encoding = ");
1823 appendStringLiteralAH(qry, encname, AH);
1824 appendPQExpBuffer(qry, ";\n");
1826 ArchiveEntry(AH, nilCatalogId, createDumpId(),
1827 "ENCODING", NULL, NULL, "",
1828 false, "ENCODING", SECTION_PRE_DATA,
1829 qry->data, "", NULL,
1830 NULL, 0,
1831 NULL, NULL);
1833 destroyPQExpBuffer(qry);
1838 * dumpStdStrings: put the correct escape string behavior into the archive
1840 static void
1841 dumpStdStrings(Archive *AH)
1843 const char *stdstrings = AH->std_strings ? "on" : "off";
1844 PQExpBuffer qry = createPQExpBuffer();
1846 if (g_verbose)
1847 write_msg(NULL, "saving standard_conforming_strings = %s\n",
1848 stdstrings);
1850 appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
1851 stdstrings);
1853 ArchiveEntry(AH, nilCatalogId, createDumpId(),
1854 "STDSTRINGS", NULL, NULL, "",
1855 false, "STDSTRINGS", SECTION_PRE_DATA,
1856 qry->data, "", NULL,
1857 NULL, 0,
1858 NULL, NULL);
1860 destroyPQExpBuffer(qry);
1865 * hasBlobs:
1866 * Test whether database contains any large objects
1868 static bool
1869 hasBlobs(Archive *AH)
1871 bool result;
1872 const char *blobQry;
1873 PGresult *res;
1875 /* Make sure we are in proper schema */
1876 selectSourceSchema("pg_catalog");
1878 /* Check for BLOB OIDs */
1879 if (AH->remoteVersion >= 70100)
1880 blobQry = "SELECT loid FROM pg_largeobject LIMIT 1";
1881 else
1882 blobQry = "SELECT oid FROM pg_class WHERE relkind = 'l' LIMIT 1";
1884 res = PQexec(g_conn, blobQry);
1885 check_sql_result(res, g_conn, blobQry, PGRES_TUPLES_OK);
1887 result = PQntuples(res) > 0;
1889 PQclear(res);
1891 return result;
1895 * dumpBlobs:
1896 * dump all blobs
1898 static int
1899 dumpBlobs(Archive *AH, void *arg)
1901 const char *blobQry;
1902 const char *blobFetchQry;
1903 PGresult *res;
1904 char buf[LOBBUFSIZE];
1905 int i;
1906 int cnt;
1908 if (g_verbose)
1909 write_msg(NULL, "saving large objects\n");
1911 /* Make sure we are in proper schema */
1912 selectSourceSchema("pg_catalog");
1914 /* Cursor to get all BLOB OIDs */
1915 if (AH->remoteVersion >= 70100)
1916 blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
1917 else
1918 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'";
1920 res = PQexec(g_conn, blobQry);
1921 check_sql_result(res, g_conn, blobQry, PGRES_COMMAND_OK);
1923 /* Command to fetch from cursor */
1924 blobFetchQry = "FETCH 1000 IN bloboid";
1928 PQclear(res);
1930 /* Do a fetch */
1931 res = PQexec(g_conn, blobFetchQry);
1932 check_sql_result(res, g_conn, blobFetchQry, PGRES_TUPLES_OK);
1934 /* Process the tuples, if any */
1935 for (i = 0; i < PQntuples(res); i++)
1937 Oid blobOid;
1938 int loFd;
1940 blobOid = atooid(PQgetvalue(res, i, 0));
1941 /* Open the BLOB */
1942 loFd = lo_open(g_conn, blobOid, INV_READ);
1943 if (loFd == -1)
1945 write_msg(NULL, "dumpBlobs(): could not open large object: %s",
1946 PQerrorMessage(g_conn));
1947 exit_nicely();
1950 StartBlob(AH, blobOid);
1952 /* Now read it in chunks, sending data to archive */
1955 cnt = lo_read(g_conn, loFd, buf, LOBBUFSIZE);
1956 if (cnt < 0)
1958 write_msg(NULL, "dumpBlobs(): error reading large object: %s",
1959 PQerrorMessage(g_conn));
1960 exit_nicely();
1963 WriteData(AH, buf, cnt);
1964 } while (cnt > 0);
1966 lo_close(g_conn, loFd);
1968 EndBlob(AH, blobOid);
1970 } while (PQntuples(res) > 0);
1972 PQclear(res);
1974 return 1;
1978 * dumpBlobComments
1979 * dump all blob comments
1981 * Since we don't provide any way to be selective about dumping blobs,
1982 * there's no need to be selective about their comments either. We put
1983 * all the comments into one big TOC entry.
1985 static int
1986 dumpBlobComments(Archive *AH, void *arg)
1988 const char *blobQry;
1989 const char *blobFetchQry;
1990 PQExpBuffer commentcmd = createPQExpBuffer();
1991 PGresult *res;
1992 int i;
1994 if (g_verbose)
1995 write_msg(NULL, "saving large object comments\n");
1997 /* Make sure we are in proper schema */
1998 selectSourceSchema("pg_catalog");
2000 /* Cursor to get all BLOB comments */
2001 if (AH->remoteVersion >= 70300)
2002 blobQry = "DECLARE blobcmt CURSOR FOR SELECT loid, "
2003 "obj_description(loid, 'pg_largeobject') "
2004 "FROM (SELECT DISTINCT loid FROM "
2005 "pg_description d JOIN pg_largeobject l ON (objoid = loid) "
2006 "WHERE classoid = 'pg_largeobject'::regclass) ss";
2007 else if (AH->remoteVersion >= 70200)
2008 blobQry = "DECLARE blobcmt CURSOR FOR SELECT loid, "
2009 "obj_description(loid, 'pg_largeobject') "
2010 "FROM (SELECT DISTINCT loid FROM pg_largeobject) ss";
2011 else if (AH->remoteVersion >= 70100)
2012 blobQry = "DECLARE blobcmt CURSOR FOR SELECT loid, "
2013 "obj_description(loid) "
2014 "FROM (SELECT DISTINCT loid FROM pg_largeobject) ss";
2015 else
2016 blobQry = "DECLARE blobcmt CURSOR FOR SELECT oid, "
2017 " ( "
2018 " SELECT description "
2019 " FROM pg_description pd "
2020 " WHERE pd.objoid=pc.oid "
2021 " ) "
2022 "FROM pg_class pc WHERE relkind = 'l'";
2024 res = PQexec(g_conn, blobQry);
2025 check_sql_result(res, g_conn, blobQry, PGRES_COMMAND_OK);
2027 /* Command to fetch from cursor */
2028 blobFetchQry = "FETCH 100 IN blobcmt";
2032 PQclear(res);
2034 /* Do a fetch */
2035 res = PQexec(g_conn, blobFetchQry);
2036 check_sql_result(res, g_conn, blobFetchQry, PGRES_TUPLES_OK);
2038 /* Process the tuples, if any */
2039 for (i = 0; i < PQntuples(res); i++)
2041 Oid blobOid;
2042 char *comment;
2044 /* ignore blobs without comments */
2045 if (PQgetisnull(res, i, 1))
2046 continue;
2048 blobOid = atooid(PQgetvalue(res, i, 0));
2049 comment = PQgetvalue(res, i, 1);
2051 printfPQExpBuffer(commentcmd, "COMMENT ON LARGE OBJECT %u IS ",
2052 blobOid);
2053 appendStringLiteralAH(commentcmd, comment, AH);
2054 appendPQExpBuffer(commentcmd, ";\n");
2056 archputs(commentcmd->data, AH);
2058 } while (PQntuples(res) > 0);
2060 PQclear(res);
2062 archputs("\n", AH);
2064 destroyPQExpBuffer(commentcmd);
2066 return 1;
2070 * getNamespaces:
2071 * read all namespaces in the system catalogs and return them in the
2072 * NamespaceInfo* structure
2074 * numNamespaces is set to the number of namespaces read in
2076 NamespaceInfo *
2077 getNamespaces(int *numNamespaces)
2079 PGresult *res;
2080 int ntups;
2081 int i;
2082 PQExpBuffer query;
2083 NamespaceInfo *nsinfo;
2084 int i_tableoid;
2085 int i_oid;
2086 int i_nspname;
2087 int i_rolname;
2088 int i_nspacl;
2091 * Before 7.3, there are no real namespaces; create two dummy entries, one
2092 * for user stuff and one for system stuff.
2094 if (g_fout->remoteVersion < 70300)
2096 nsinfo = (NamespaceInfo *) malloc(2 * sizeof(NamespaceInfo));
2098 nsinfo[0].dobj.objType = DO_NAMESPACE;
2099 nsinfo[0].dobj.catId.tableoid = 0;
2100 nsinfo[0].dobj.catId.oid = 0;
2101 AssignDumpId(&nsinfo[0].dobj);
2102 nsinfo[0].dobj.name = strdup("public");
2103 nsinfo[0].rolname = strdup("");
2104 nsinfo[0].nspacl = strdup("");
2106 selectDumpableNamespace(&nsinfo[0]);
2108 nsinfo[1].dobj.objType = DO_NAMESPACE;
2109 nsinfo[1].dobj.catId.tableoid = 0;
2110 nsinfo[1].dobj.catId.oid = 1;
2111 AssignDumpId(&nsinfo[1].dobj);
2112 nsinfo[1].dobj.name = strdup("pg_catalog");
2113 nsinfo[1].rolname = strdup("");
2114 nsinfo[1].nspacl = strdup("");
2116 selectDumpableNamespace(&nsinfo[1]);
2118 g_namespaces = nsinfo;
2119 g_numNamespaces = *numNamespaces = 2;
2121 return nsinfo;
2124 query = createPQExpBuffer();
2126 /* Make sure we are in proper schema */
2127 selectSourceSchema("pg_catalog");
2130 * we fetch all namespaces including system ones, so that every object we
2131 * read in can be linked to a containing namespace.
2133 appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
2134 "(%s nspowner) AS rolname, "
2135 "nspacl FROM pg_namespace",
2136 username_subquery);
2138 res = PQexec(g_conn, query->data);
2139 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2141 ntups = PQntuples(res);
2143 nsinfo = (NamespaceInfo *) malloc(ntups * sizeof(NamespaceInfo));
2145 i_tableoid = PQfnumber(res, "tableoid");
2146 i_oid = PQfnumber(res, "oid");
2147 i_nspname = PQfnumber(res, "nspname");
2148 i_rolname = PQfnumber(res, "rolname");
2149 i_nspacl = PQfnumber(res, "nspacl");
2151 for (i = 0; i < ntups; i++)
2153 nsinfo[i].dobj.objType = DO_NAMESPACE;
2154 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2155 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2156 AssignDumpId(&nsinfo[i].dobj);
2157 nsinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_nspname));
2158 nsinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2159 nsinfo[i].nspacl = strdup(PQgetvalue(res, i, i_nspacl));
2161 /* Decide whether to dump this namespace */
2162 selectDumpableNamespace(&nsinfo[i]);
2164 if (strlen(nsinfo[i].rolname) == 0)
2165 write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
2166 nsinfo[i].dobj.name);
2169 PQclear(res);
2170 destroyPQExpBuffer(query);
2172 g_namespaces = nsinfo;
2173 g_numNamespaces = *numNamespaces = ntups;
2175 return nsinfo;
2179 * findNamespace:
2180 * given a namespace OID and an object OID, look up the info read by
2181 * getNamespaces
2183 * NB: for pre-7.3 source database, we use object OID to guess whether it's
2184 * a system object or not. In 7.3 and later there is no guessing.
2186 static NamespaceInfo *
2187 findNamespace(Oid nsoid, Oid objoid)
2189 int i;
2191 if (g_fout->remoteVersion >= 70300)
2193 for (i = 0; i < g_numNamespaces; i++)
2195 NamespaceInfo *nsinfo = &g_namespaces[i];
2197 if (nsoid == nsinfo->dobj.catId.oid)
2198 return nsinfo;
2200 write_msg(NULL, "schema with OID %u does not exist\n", nsoid);
2201 exit_nicely();
2203 else
2205 /* This code depends on the layout set up by getNamespaces. */
2206 if (objoid > g_last_builtin_oid)
2207 i = 0; /* user object */
2208 else
2209 i = 1; /* system object */
2210 return &g_namespaces[i];
2213 return NULL; /* keep compiler quiet */
2217 * getTypes:
2218 * read all types in the system catalogs and return them in the
2219 * TypeInfo* structure
2221 * numTypes is set to the number of types read in
2223 * NB: this must run after getFuncs() because we assume we can do
2224 * findFuncByOid().
2226 TypeInfo *
2227 getTypes(int *numTypes)
2229 PGresult *res;
2230 int ntups;
2231 int i;
2232 PQExpBuffer query = createPQExpBuffer();
2233 TypeInfo *tinfo;
2234 ShellTypeInfo *stinfo;
2235 int i_tableoid;
2236 int i_oid;
2237 int i_typname;
2238 int i_typnamespace;
2239 int i_rolname;
2240 int i_typinput;
2241 int i_typoutput;
2242 int i_typelem;
2243 int i_typrelid;
2244 int i_typrelkind;
2245 int i_typtype;
2246 int i_typisdefined;
2247 int i_isarray;
2250 * we include even the built-in types because those may be used as array
2251 * elements by user-defined types
2253 * we filter out the built-in types when we dump out the types
2255 * same approach for undefined (shell) types and array types
2257 * Note: as of 8.3 we can reliably detect whether a type is an
2258 * auto-generated array type by checking the element type's typarray.
2259 * (Before that the test is capable of generating false positives.) We
2260 * still check for name beginning with '_', though, so as to avoid the
2261 * cost of the subselect probe for all standard types. This would have to
2262 * be revisited if the backend ever allows renaming of array types.
2265 /* Make sure we are in proper schema */
2266 selectSourceSchema("pg_catalog");
2268 if (g_fout->remoteVersion >= 80300)
2270 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2271 "typnamespace, "
2272 "(%s typowner) AS rolname, "
2273 "typinput::oid AS typinput, "
2274 "typoutput::oid AS typoutput, typelem, typrelid, "
2275 "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2276 "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2277 "typtype, typisdefined, "
2278 "typname[0] = '_' AND typelem != 0 AND "
2279 "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
2280 "FROM pg_type",
2281 username_subquery);
2283 else if (g_fout->remoteVersion >= 70300)
2285 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2286 "typnamespace, "
2287 "(%s typowner) AS rolname, "
2288 "typinput::oid AS typinput, "
2289 "typoutput::oid AS typoutput, typelem, typrelid, "
2290 "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2291 "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2292 "typtype, typisdefined, "
2293 "typname[0] = '_' AND typelem != 0 AS isarray "
2294 "FROM pg_type",
2295 username_subquery);
2297 else if (g_fout->remoteVersion >= 70100)
2299 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2300 "0::oid AS typnamespace, "
2301 "(%s typowner) AS rolname, "
2302 "typinput::oid AS typinput, "
2303 "typoutput::oid AS typoutput, typelem, typrelid, "
2304 "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2305 "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2306 "typtype, typisdefined, "
2307 "typname[0] = '_' AND typelem != 0 AS isarray "
2308 "FROM pg_type",
2309 username_subquery);
2311 else
2313 appendPQExpBuffer(query, "SELECT "
2314 "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
2315 "oid, typname, "
2316 "0::oid AS typnamespace, "
2317 "(%s typowner) AS rolname, "
2318 "typinput::oid AS typinput, "
2319 "typoutput::oid AS typoutput, typelem, typrelid, "
2320 "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2321 "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2322 "typtype, typisdefined, "
2323 "typname[0] = '_' AND typelem != 0 AS isarray "
2324 "FROM pg_type",
2325 username_subquery);
2328 res = PQexec(g_conn, query->data);
2329 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2331 ntups = PQntuples(res);
2333 tinfo = (TypeInfo *) malloc(ntups * sizeof(TypeInfo));
2335 i_tableoid = PQfnumber(res, "tableoid");
2336 i_oid = PQfnumber(res, "oid");
2337 i_typname = PQfnumber(res, "typname");
2338 i_typnamespace = PQfnumber(res, "typnamespace");
2339 i_rolname = PQfnumber(res, "rolname");
2340 i_typinput = PQfnumber(res, "typinput");
2341 i_typoutput = PQfnumber(res, "typoutput");
2342 i_typelem = PQfnumber(res, "typelem");
2343 i_typrelid = PQfnumber(res, "typrelid");
2344 i_typrelkind = PQfnumber(res, "typrelkind");
2345 i_typtype = PQfnumber(res, "typtype");
2346 i_typisdefined = PQfnumber(res, "typisdefined");
2347 i_isarray = PQfnumber(res, "isarray");
2349 for (i = 0; i < ntups; i++)
2351 tinfo[i].dobj.objType = DO_TYPE;
2352 tinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2353 tinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2354 AssignDumpId(&tinfo[i].dobj);
2355 tinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_typname));
2356 tinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)),
2357 tinfo[i].dobj.catId.oid);
2358 tinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2359 tinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
2360 tinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
2361 tinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
2362 tinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
2363 tinfo[i].shellType = NULL;
2365 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
2366 tinfo[i].isDefined = true;
2367 else
2368 tinfo[i].isDefined = false;
2370 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
2371 tinfo[i].isArray = true;
2372 else
2373 tinfo[i].isArray = false;
2375 /* Decide whether we want to dump it */
2376 selectDumpableType(&tinfo[i]);
2379 * If it's a domain, fetch info about its constraints, if any
2381 tinfo[i].nDomChecks = 0;
2382 tinfo[i].domChecks = NULL;
2383 if (tinfo[i].dobj.dump && tinfo[i].typtype == TYPTYPE_DOMAIN)
2384 getDomainConstraints(&(tinfo[i]));
2387 * If it's a base type, make a DumpableObject representing a shell
2388 * definition of the type. We will need to dump that ahead of the I/O
2389 * functions for the type.
2391 * Note: the shell type doesn't have a catId. You might think it
2392 * should copy the base type's catId, but then it might capture the
2393 * pg_depend entries for the type, which we don't want.
2395 if (tinfo[i].dobj.dump && tinfo[i].typtype == TYPTYPE_BASE)
2397 stinfo = (ShellTypeInfo *) malloc(sizeof(ShellTypeInfo));
2398 stinfo->dobj.objType = DO_SHELL_TYPE;
2399 stinfo->dobj.catId = nilCatalogId;
2400 AssignDumpId(&stinfo->dobj);
2401 stinfo->dobj.name = strdup(tinfo[i].dobj.name);
2402 stinfo->dobj.namespace = tinfo[i].dobj.namespace;
2403 stinfo->baseType = &(tinfo[i]);
2404 tinfo[i].shellType = stinfo;
2407 * Initially mark the shell type as not to be dumped. We'll only
2408 * dump it if the I/O functions need to be dumped; this is taken
2409 * care of while sorting dependencies.
2411 stinfo->dobj.dump = false;
2414 * However, if dumping from pre-7.3, there will be no dependency
2415 * info so we have to fake it here. We only need to worry about
2416 * typinput and typoutput since the other functions only exist
2417 * post-7.3.
2419 if (g_fout->remoteVersion < 70300)
2421 Oid typinput;
2422 Oid typoutput;
2423 FuncInfo *funcInfo;
2425 typinput = atooid(PQgetvalue(res, i, i_typinput));
2426 typoutput = atooid(PQgetvalue(res, i, i_typoutput));
2428 funcInfo = findFuncByOid(typinput);
2429 if (funcInfo && funcInfo->dobj.dump)
2431 /* base type depends on function */
2432 addObjectDependency(&tinfo[i].dobj,
2433 funcInfo->dobj.dumpId);
2434 /* function depends on shell type */
2435 addObjectDependency(&funcInfo->dobj,
2436 stinfo->dobj.dumpId);
2437 /* mark shell type as to be dumped */
2438 stinfo->dobj.dump = true;
2441 funcInfo = findFuncByOid(typoutput);
2442 if (funcInfo && funcInfo->dobj.dump)
2444 /* base type depends on function */
2445 addObjectDependency(&tinfo[i].dobj,
2446 funcInfo->dobj.dumpId);
2447 /* function depends on shell type */
2448 addObjectDependency(&funcInfo->dobj,
2449 stinfo->dobj.dumpId);
2450 /* mark shell type as to be dumped */
2451 stinfo->dobj.dump = true;
2456 if (strlen(tinfo[i].rolname) == 0 && tinfo[i].isDefined)
2457 write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
2458 tinfo[i].dobj.name);
2461 *numTypes = ntups;
2463 PQclear(res);
2465 destroyPQExpBuffer(query);
2467 return tinfo;
2471 * getOperators:
2472 * read all operators in the system catalogs and return them in the
2473 * OprInfo* structure
2475 * numOprs is set to the number of operators read in
2477 OprInfo *
2478 getOperators(int *numOprs)
2480 PGresult *res;
2481 int ntups;
2482 int i;
2483 PQExpBuffer query = createPQExpBuffer();
2484 OprInfo *oprinfo;
2485 int i_tableoid;
2486 int i_oid;
2487 int i_oprname;
2488 int i_oprnamespace;
2489 int i_rolname;
2490 int i_oprcode;
2493 * find all operators, including builtin operators; we filter out
2494 * system-defined operators at dump-out time.
2497 /* Make sure we are in proper schema */
2498 selectSourceSchema("pg_catalog");
2500 if (g_fout->remoteVersion >= 70300)
2502 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
2503 "oprnamespace, "
2504 "(%s oprowner) AS rolname, "
2505 "oprcode::oid AS oprcode "
2506 "FROM pg_operator",
2507 username_subquery);
2509 else if (g_fout->remoteVersion >= 70100)
2511 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
2512 "0::oid AS oprnamespace, "
2513 "(%s oprowner) AS rolname, "
2514 "oprcode::oid AS oprcode "
2515 "FROM pg_operator",
2516 username_subquery);
2518 else
2520 appendPQExpBuffer(query, "SELECT "
2521 "(SELECT oid FROM pg_class WHERE relname = 'pg_operator') AS tableoid, "
2522 "oid, oprname, "
2523 "0::oid AS oprnamespace, "
2524 "(%s oprowner) AS rolname, "
2525 "oprcode::oid AS oprcode "
2526 "FROM pg_operator",
2527 username_subquery);
2530 res = PQexec(g_conn, query->data);
2531 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2533 ntups = PQntuples(res);
2534 *numOprs = ntups;
2536 oprinfo = (OprInfo *) malloc(ntups * sizeof(OprInfo));
2538 i_tableoid = PQfnumber(res, "tableoid");
2539 i_oid = PQfnumber(res, "oid");
2540 i_oprname = PQfnumber(res, "oprname");
2541 i_oprnamespace = PQfnumber(res, "oprnamespace");
2542 i_rolname = PQfnumber(res, "rolname");
2543 i_oprcode = PQfnumber(res, "oprcode");
2545 for (i = 0; i < ntups; i++)
2547 oprinfo[i].dobj.objType = DO_OPERATOR;
2548 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2549 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2550 AssignDumpId(&oprinfo[i].dobj);
2551 oprinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_oprname));
2552 oprinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)),
2553 oprinfo[i].dobj.catId.oid);
2554 oprinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2555 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
2557 /* Decide whether we want to dump it */
2558 selectDumpableObject(&(oprinfo[i].dobj));
2560 if (strlen(oprinfo[i].rolname) == 0)
2561 write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
2562 oprinfo[i].dobj.name);
2565 PQclear(res);
2567 destroyPQExpBuffer(query);
2569 return oprinfo;
2573 * getConversions:
2574 * read all conversions in the system catalogs and return them in the
2575 * ConvInfo* structure
2577 * numConversions is set to the number of conversions read in
2579 ConvInfo *
2580 getConversions(int *numConversions)
2582 PGresult *res;
2583 int ntups;
2584 int i;
2585 PQExpBuffer query = createPQExpBuffer();
2586 ConvInfo *convinfo;
2587 int i_tableoid;
2588 int i_oid;
2589 int i_conname;
2590 int i_connamespace;
2591 int i_rolname;
2593 /* Conversions didn't exist pre-7.3 */
2594 if (g_fout->remoteVersion < 70300)
2596 *numConversions = 0;
2597 return NULL;
2601 * find all conversions, including builtin conversions; we filter out
2602 * system-defined conversions at dump-out time.
2605 /* Make sure we are in proper schema */
2606 selectSourceSchema("pg_catalog");
2608 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
2609 "connamespace, "
2610 "(%s conowner) AS rolname "
2611 "FROM pg_conversion",
2612 username_subquery);
2614 res = PQexec(g_conn, query->data);
2615 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2617 ntups = PQntuples(res);
2618 *numConversions = ntups;
2620 convinfo = (ConvInfo *) malloc(ntups * sizeof(ConvInfo));
2622 i_tableoid = PQfnumber(res, "tableoid");
2623 i_oid = PQfnumber(res, "oid");
2624 i_conname = PQfnumber(res, "conname");
2625 i_connamespace = PQfnumber(res, "connamespace");
2626 i_rolname = PQfnumber(res, "rolname");
2628 for (i = 0; i < ntups; i++)
2630 convinfo[i].dobj.objType = DO_CONVERSION;
2631 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2632 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2633 AssignDumpId(&convinfo[i].dobj);
2634 convinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_conname));
2635 convinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_connamespace)),
2636 convinfo[i].dobj.catId.oid);
2637 convinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2639 /* Decide whether we want to dump it */
2640 selectDumpableObject(&(convinfo[i].dobj));
2643 PQclear(res);
2645 destroyPQExpBuffer(query);
2647 return convinfo;
2651 * getOpclasses:
2652 * read all opclasses in the system catalogs and return them in the
2653 * OpclassInfo* structure
2655 * numOpclasses is set to the number of opclasses read in
2657 OpclassInfo *
2658 getOpclasses(int *numOpclasses)
2660 PGresult *res;
2661 int ntups;
2662 int i;
2663 PQExpBuffer query = createPQExpBuffer();
2664 OpclassInfo *opcinfo;
2665 int i_tableoid;
2666 int i_oid;
2667 int i_opcname;
2668 int i_opcnamespace;
2669 int i_rolname;
2672 * find all opclasses, including builtin opclasses; we filter out
2673 * system-defined opclasses at dump-out time.
2676 /* Make sure we are in proper schema */
2677 selectSourceSchema("pg_catalog");
2679 if (g_fout->remoteVersion >= 70300)
2681 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
2682 "opcnamespace, "
2683 "(%s opcowner) AS rolname "
2684 "FROM pg_opclass",
2685 username_subquery);
2687 else if (g_fout->remoteVersion >= 70100)
2689 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
2690 "0::oid AS opcnamespace, "
2691 "''::name AS rolname "
2692 "FROM pg_opclass");
2694 else
2696 appendPQExpBuffer(query, "SELECT "
2697 "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, "
2698 "oid, opcname, "
2699 "0::oid AS opcnamespace, "
2700 "''::name AS rolname "
2701 "FROM pg_opclass");
2704 res = PQexec(g_conn, query->data);
2705 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2707 ntups = PQntuples(res);
2708 *numOpclasses = ntups;
2710 opcinfo = (OpclassInfo *) malloc(ntups * sizeof(OpclassInfo));
2712 i_tableoid = PQfnumber(res, "tableoid");
2713 i_oid = PQfnumber(res, "oid");
2714 i_opcname = PQfnumber(res, "opcname");
2715 i_opcnamespace = PQfnumber(res, "opcnamespace");
2716 i_rolname = PQfnumber(res, "rolname");
2718 for (i = 0; i < ntups; i++)
2720 opcinfo[i].dobj.objType = DO_OPCLASS;
2721 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2722 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2723 AssignDumpId(&opcinfo[i].dobj);
2724 opcinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_opcname));
2725 opcinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)),
2726 opcinfo[i].dobj.catId.oid);
2727 opcinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2729 /* Decide whether we want to dump it */
2730 selectDumpableObject(&(opcinfo[i].dobj));
2732 if (g_fout->remoteVersion >= 70300)
2734 if (strlen(opcinfo[i].rolname) == 0)
2735 write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
2736 opcinfo[i].dobj.name);
2740 PQclear(res);
2742 destroyPQExpBuffer(query);
2744 return opcinfo;
2748 * getOpfamilies:
2749 * read all opfamilies in the system catalogs and return them in the
2750 * OpfamilyInfo* structure
2752 * numOpfamilies is set to the number of opfamilies read in
2754 OpfamilyInfo *
2755 getOpfamilies(int *numOpfamilies)
2757 PGresult *res;
2758 int ntups;
2759 int i;
2760 PQExpBuffer query;
2761 OpfamilyInfo *opfinfo;
2762 int i_tableoid;
2763 int i_oid;
2764 int i_opfname;
2765 int i_opfnamespace;
2766 int i_rolname;
2768 /* Before 8.3, there is no separate concept of opfamilies */
2769 if (g_fout->remoteVersion < 80300)
2771 *numOpfamilies = 0;
2772 return NULL;
2775 query = createPQExpBuffer();
2778 * find all opfamilies, including builtin opfamilies; we filter out
2779 * system-defined opfamilies at dump-out time.
2782 /* Make sure we are in proper schema */
2783 selectSourceSchema("pg_catalog");
2785 appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
2786 "opfnamespace, "
2787 "(%s opfowner) AS rolname "
2788 "FROM pg_opfamily",
2789 username_subquery);
2791 res = PQexec(g_conn, query->data);
2792 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2794 ntups = PQntuples(res);
2795 *numOpfamilies = ntups;
2797 opfinfo = (OpfamilyInfo *) malloc(ntups * sizeof(OpfamilyInfo));
2799 i_tableoid = PQfnumber(res, "tableoid");
2800 i_oid = PQfnumber(res, "oid");
2801 i_opfname = PQfnumber(res, "opfname");
2802 i_opfnamespace = PQfnumber(res, "opfnamespace");
2803 i_rolname = PQfnumber(res, "rolname");
2805 for (i = 0; i < ntups; i++)
2807 opfinfo[i].dobj.objType = DO_OPFAMILY;
2808 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2809 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2810 AssignDumpId(&opfinfo[i].dobj);
2811 opfinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_opfname));
2812 opfinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)),
2813 opfinfo[i].dobj.catId.oid);
2814 opfinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2816 /* Decide whether we want to dump it */
2817 selectDumpableObject(&(opfinfo[i].dobj));
2819 if (g_fout->remoteVersion >= 70300)
2821 if (strlen(opfinfo[i].rolname) == 0)
2822 write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
2823 opfinfo[i].dobj.name);
2827 PQclear(res);
2829 destroyPQExpBuffer(query);
2831 return opfinfo;
2835 * getAggregates:
2836 * read all the user-defined aggregates in the system catalogs and
2837 * return them in the AggInfo* structure
2839 * numAggs is set to the number of aggregates read in
2841 AggInfo *
2842 getAggregates(int *numAggs)
2844 PGresult *res;
2845 int ntups;
2846 int i;
2847 PQExpBuffer query = createPQExpBuffer();
2848 AggInfo *agginfo;
2849 int i_tableoid;
2850 int i_oid;
2851 int i_aggname;
2852 int i_aggnamespace;
2853 int i_pronargs;
2854 int i_proargtypes;
2855 int i_rolname;
2856 int i_aggacl;
2858 /* Make sure we are in proper schema */
2859 selectSourceSchema("pg_catalog");
2861 /* find all user-defined aggregates */
2863 if (g_fout->remoteVersion >= 80200)
2865 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
2866 "pronamespace AS aggnamespace, "
2867 "pronargs, proargtypes, "
2868 "(%s proowner) AS rolname, "
2869 "proacl AS aggacl "
2870 "FROM pg_proc "
2871 "WHERE proisagg "
2872 "AND pronamespace != "
2873 "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
2874 username_subquery);
2876 else if (g_fout->remoteVersion >= 70300)
2878 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
2879 "pronamespace AS aggnamespace, "
2880 "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
2881 "proargtypes, "
2882 "(%s proowner) AS rolname, "
2883 "proacl AS aggacl "
2884 "FROM pg_proc "
2885 "WHERE proisagg "
2886 "AND pronamespace != "
2887 "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
2888 username_subquery);
2890 else if (g_fout->remoteVersion >= 70100)
2892 appendPQExpBuffer(query, "SELECT tableoid, oid, aggname, "
2893 "0::oid AS aggnamespace, "
2894 "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
2895 "aggbasetype AS proargtypes, "
2896 "(%s aggowner) AS rolname, "
2897 "'{=X}' AS aggacl "
2898 "FROM pg_aggregate "
2899 "where oid > '%u'::oid",
2900 username_subquery,
2901 g_last_builtin_oid);
2903 else
2905 appendPQExpBuffer(query, "SELECT "
2906 "(SELECT oid FROM pg_class WHERE relname = 'pg_aggregate') AS tableoid, "
2907 "oid, aggname, "
2908 "0::oid AS aggnamespace, "
2909 "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
2910 "aggbasetype AS proargtypes, "
2911 "(%s aggowner) AS rolname, "
2912 "'{=X}' AS aggacl "
2913 "FROM pg_aggregate "
2914 "where oid > '%u'::oid",
2915 username_subquery,
2916 g_last_builtin_oid);
2919 res = PQexec(g_conn, query->data);
2920 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2922 ntups = PQntuples(res);
2923 *numAggs = ntups;
2925 agginfo = (AggInfo *) malloc(ntups * sizeof(AggInfo));
2927 i_tableoid = PQfnumber(res, "tableoid");
2928 i_oid = PQfnumber(res, "oid");
2929 i_aggname = PQfnumber(res, "aggname");
2930 i_aggnamespace = PQfnumber(res, "aggnamespace");
2931 i_pronargs = PQfnumber(res, "pronargs");
2932 i_proargtypes = PQfnumber(res, "proargtypes");
2933 i_rolname = PQfnumber(res, "rolname");
2934 i_aggacl = PQfnumber(res, "aggacl");
2936 for (i = 0; i < ntups; i++)
2938 agginfo[i].aggfn.dobj.objType = DO_AGG;
2939 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2940 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2941 AssignDumpId(&agginfo[i].aggfn.dobj);
2942 agginfo[i].aggfn.dobj.name = strdup(PQgetvalue(res, i, i_aggname));
2943 agginfo[i].aggfn.dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)),
2944 agginfo[i].aggfn.dobj.catId.oid);
2945 agginfo[i].aggfn.rolname = strdup(PQgetvalue(res, i, i_rolname));
2946 if (strlen(agginfo[i].aggfn.rolname) == 0)
2947 write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
2948 agginfo[i].aggfn.dobj.name);
2949 agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
2950 agginfo[i].aggfn.prorettype = InvalidOid; /* not saved */
2951 agginfo[i].aggfn.proacl = strdup(PQgetvalue(res, i, i_aggacl));
2952 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
2953 if (agginfo[i].aggfn.nargs == 0)
2954 agginfo[i].aggfn.argtypes = NULL;
2955 else
2957 agginfo[i].aggfn.argtypes = (Oid *) malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
2958 if (g_fout->remoteVersion >= 70300)
2959 parseOidArray(PQgetvalue(res, i, i_proargtypes),
2960 agginfo[i].aggfn.argtypes,
2961 agginfo[i].aggfn.nargs);
2962 else
2963 /* it's just aggbasetype */
2964 agginfo[i].aggfn.argtypes[0] = atooid(PQgetvalue(res, i, i_proargtypes));
2967 /* Decide whether we want to dump it */
2968 selectDumpableObject(&(agginfo[i].aggfn.dobj));
2971 PQclear(res);
2973 destroyPQExpBuffer(query);
2975 return agginfo;
2979 * getFuncs:
2980 * read all the user-defined functions in the system catalogs and
2981 * return them in the FuncInfo* structure
2983 * numFuncs is set to the number of functions read in
2985 FuncInfo *
2986 getFuncs(int *numFuncs)
2988 PGresult *res;
2989 int ntups;
2990 int i;
2991 PQExpBuffer query = createPQExpBuffer();
2992 FuncInfo *finfo;
2993 int i_tableoid;
2994 int i_oid;
2995 int i_proname;
2996 int i_pronamespace;
2997 int i_rolname;
2998 int i_prolang;
2999 int i_pronargs;
3000 int i_proargtypes;
3001 int i_prorettype;
3002 int i_proacl;
3004 /* Make sure we are in proper schema */
3005 selectSourceSchema("pg_catalog");
3007 /* find all user-defined funcs */
3009 if (g_fout->remoteVersion >= 70300)
3011 appendPQExpBuffer(query,
3012 "SELECT tableoid, oid, proname, prolang, "
3013 "pronargs, proargtypes, prorettype, proacl, "
3014 "pronamespace, "
3015 "(%s proowner) AS rolname "
3016 "FROM pg_proc "
3017 "WHERE NOT proisagg "
3018 "AND pronamespace != "
3019 "(SELECT oid FROM pg_namespace "
3020 "WHERE nspname = 'pg_catalog')",
3021 username_subquery);
3023 else if (g_fout->remoteVersion >= 70100)
3025 appendPQExpBuffer(query,
3026 "SELECT tableoid, oid, proname, prolang, "
3027 "pronargs, proargtypes, prorettype, "
3028 "'{=X}' AS proacl, "
3029 "0::oid AS pronamespace, "
3030 "(%s proowner) AS rolname "
3031 "FROM pg_proc "
3032 "WHERE pg_proc.oid > '%u'::oid",
3033 username_subquery,
3034 g_last_builtin_oid);
3036 else
3038 appendPQExpBuffer(query,
3039 "SELECT "
3040 "(SELECT oid FROM pg_class "
3041 " WHERE relname = 'pg_proc') AS tableoid, "
3042 "oid, proname, prolang, "
3043 "pronargs, proargtypes, prorettype, "
3044 "'{=X}' AS proacl, "
3045 "0::oid AS pronamespace, "
3046 "(%s proowner) AS rolname "
3047 "FROM pg_proc "
3048 "where pg_proc.oid > '%u'::oid",
3049 username_subquery,
3050 g_last_builtin_oid);
3053 res = PQexec(g_conn, query->data);
3054 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3056 ntups = PQntuples(res);
3058 *numFuncs = ntups;
3060 finfo = (FuncInfo *) calloc(ntups, sizeof(FuncInfo));
3062 i_tableoid = PQfnumber(res, "tableoid");
3063 i_oid = PQfnumber(res, "oid");
3064 i_proname = PQfnumber(res, "proname");
3065 i_pronamespace = PQfnumber(res, "pronamespace");
3066 i_rolname = PQfnumber(res, "rolname");
3067 i_prolang = PQfnumber(res, "prolang");
3068 i_pronargs = PQfnumber(res, "pronargs");
3069 i_proargtypes = PQfnumber(res, "proargtypes");
3070 i_prorettype = PQfnumber(res, "prorettype");
3071 i_proacl = PQfnumber(res, "proacl");
3073 for (i = 0; i < ntups; i++)
3075 finfo[i].dobj.objType = DO_FUNC;
3076 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3077 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3078 AssignDumpId(&finfo[i].dobj);
3079 finfo[i].dobj.name = strdup(PQgetvalue(res, i, i_proname));
3080 finfo[i].dobj.namespace =
3081 findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)),
3082 finfo[i].dobj.catId.oid);
3083 finfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
3084 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
3085 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
3086 finfo[i].proacl = strdup(PQgetvalue(res, i, i_proacl));
3087 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
3088 if (finfo[i].nargs == 0)
3089 finfo[i].argtypes = NULL;
3090 else
3092 finfo[i].argtypes = (Oid *) malloc(finfo[i].nargs * sizeof(Oid));
3093 parseOidArray(PQgetvalue(res, i, i_proargtypes),
3094 finfo[i].argtypes, finfo[i].nargs);
3097 /* Decide whether we want to dump it */
3098 selectDumpableObject(&(finfo[i].dobj));
3100 if (strlen(finfo[i].rolname) == 0)
3101 write_msg(NULL,
3102 "WARNING: owner of function \"%s\" appears to be invalid\n",
3103 finfo[i].dobj.name);
3106 PQclear(res);
3108 destroyPQExpBuffer(query);
3110 return finfo;
3114 * getTables
3115 * read all the user-defined tables (no indexes, no catalogs)
3116 * in the system catalogs return them in the TableInfo* structure
3118 * numTables is set to the number of tables read in
3120 TableInfo *
3121 getTables(int *numTables)
3123 PGresult *res;
3124 int ntups;
3125 int i;
3126 PQExpBuffer query = createPQExpBuffer();
3127 TableInfo *tblinfo;
3128 int i_reltableoid;
3129 int i_reloid;
3130 int i_relname;
3131 int i_relnamespace;
3132 int i_relkind;
3133 int i_relacl;
3134 int i_rolname;
3135 int i_relchecks;
3136 int i_relhastriggers;
3137 int i_relhasindex;
3138 int i_relhasrules;
3139 int i_relhasoids;
3140 int i_relfrozenxid;
3141 int i_owning_tab;
3142 int i_owning_col;
3143 int i_reltablespace;
3144 int i_reloptions;
3145 int i_toastreloptions;
3147 /* Make sure we are in proper schema */
3148 selectSourceSchema("pg_catalog");
3151 * Find all the tables (including views and sequences).
3153 * We include system catalogs, so that we can work if a user table is
3154 * defined to inherit from a system catalog (pretty weird, but...)
3156 * We ignore tables that are not type 'r' (ordinary relation), 'S'
3157 * (sequence), 'v' (view), or 'c' (composite type).
3159 * Composite-type table entries won't be dumped as such, but we have to
3160 * make a DumpableObject for them so that we can track dependencies of the
3161 * composite type (pg_depend entries for columns of the composite type
3162 * link to the pg_class entry not the pg_type entry).
3164 * Note: in this phase we should collect only a minimal amount of
3165 * information about each table, basically just enough to decide if it is
3166 * interesting. We must fetch all tables in this phase because otherwise
3167 * we cannot correctly identify inherited columns, owned sequences, etc.
3170 if (g_fout->remoteVersion >= 80400)
3173 * Left join to pick up dependency info linking sequences to their
3174 * owning column, if any (note this dependency is AUTO as of 8.2)
3176 appendPQExpBuffer(query,
3177 "SELECT c.tableoid, c.oid, c.relname, "
3178 "c.relacl, c.relkind, c.relnamespace, "
3179 "(%s c.relowner) AS rolname, "
3180 "c.relchecks, c.relhastriggers, "
3181 "c.relhasindex, c.relhasrules, c.relhasoids, "
3182 "c.relfrozenxid, "
3183 "d.refobjid AS owning_tab, "
3184 "d.refobjsubid AS owning_col, "
3185 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
3186 "array_to_string(c.reloptions, ', ') AS reloptions, "
3187 "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
3188 "FROM pg_class c "
3189 "LEFT JOIN pg_depend d ON "
3190 "(c.relkind = '%c' AND "
3191 "d.classid = c.tableoid AND d.objid = c.oid AND "
3192 "d.objsubid = 0 AND "
3193 "d.refclassid = c.tableoid AND d.deptype = 'a') "
3194 "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
3195 "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
3196 "ORDER BY c.oid",
3197 username_subquery,
3198 RELKIND_SEQUENCE,
3199 RELKIND_RELATION, RELKIND_SEQUENCE,
3200 RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3202 else if (g_fout->remoteVersion >= 80200)
3205 * Left join to pick up dependency info linking sequences to their
3206 * owning column, if any (note this dependency is AUTO as of 8.2)
3208 appendPQExpBuffer(query,
3209 "SELECT c.tableoid, c.oid, relname, "
3210 "relacl, relkind, relnamespace, "
3211 "(%s relowner) AS rolname, "
3212 "relchecks, (reltriggers <> 0) AS relhastriggers, "
3213 "relhasindex, relhasrules, relhasoids, "
3214 "relfrozenxid, "
3215 "d.refobjid AS owning_tab, "
3216 "d.refobjsubid AS owning_col, "
3217 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
3218 "array_to_string(c.reloptions, ', ') AS reloptions, "
3219 "NULL AS toast_reloptions "
3220 "FROM pg_class c "
3221 "LEFT JOIN pg_depend d ON "
3222 "(c.relkind = '%c' AND "
3223 "d.classid = c.tableoid AND d.objid = c.oid AND "
3224 "d.objsubid = 0 AND "
3225 "d.refclassid = c.tableoid AND d.deptype = 'a') "
3226 "WHERE relkind in ('%c', '%c', '%c', '%c') "
3227 "ORDER BY c.oid",
3228 username_subquery,
3229 RELKIND_SEQUENCE,
3230 RELKIND_RELATION, RELKIND_SEQUENCE,
3231 RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3233 else if (g_fout->remoteVersion >= 80000)
3236 * Left join to pick up dependency info linking sequences to their
3237 * owning column, if any
3239 appendPQExpBuffer(query,
3240 "SELECT c.tableoid, c.oid, relname, "
3241 "relacl, relkind, relnamespace, "
3242 "(%s relowner) AS rolname, "
3243 "relchecks, (reltriggers <> 0) AS relhastriggers, "
3244 "relhasindex, relhasrules, relhasoids, "
3245 "0 AS relfrozenxid, "
3246 "d.refobjid AS owning_tab, "
3247 "d.refobjsubid AS owning_col, "
3248 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
3249 "NULL AS reloptions, "
3250 "NULL AS toast_reloptions "
3251 "FROM pg_class c "
3252 "LEFT JOIN pg_depend d ON "
3253 "(c.relkind = '%c' AND "
3254 "d.classid = c.tableoid AND d.objid = c.oid AND "
3255 "d.objsubid = 0 AND "
3256 "d.refclassid = c.tableoid AND d.deptype = 'i') "
3257 "WHERE relkind in ('%c', '%c', '%c', '%c') "
3258 "ORDER BY c.oid",
3259 username_subquery,
3260 RELKIND_SEQUENCE,
3261 RELKIND_RELATION, RELKIND_SEQUENCE,
3262 RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3264 else if (g_fout->remoteVersion >= 70300)
3267 * Left join to pick up dependency info linking sequences to their
3268 * owning column, if any
3270 appendPQExpBuffer(query,
3271 "SELECT c.tableoid, c.oid, relname, "
3272 "relacl, relkind, relnamespace, "
3273 "(%s relowner) AS rolname, "
3274 "relchecks, (reltriggers <> 0) AS relhastriggers, "
3275 "relhasindex, relhasrules, relhasoids, "
3276 "0 AS relfrozenxid, "
3277 "d.refobjid AS owning_tab, "
3278 "d.refobjsubid AS owning_col, "
3279 "NULL AS reltablespace, "
3280 "NULL AS reloptions, "
3281 "NULL AS toast_reloptions "
3282 "FROM pg_class c "
3283 "LEFT JOIN pg_depend d ON "
3284 "(c.relkind = '%c' AND "
3285 "d.classid = c.tableoid AND d.objid = c.oid AND "
3286 "d.objsubid = 0 AND "
3287 "d.refclassid = c.tableoid AND d.deptype = 'i') "
3288 "WHERE relkind IN ('%c', '%c', '%c', '%c') "
3289 "ORDER BY c.oid",
3290 username_subquery,
3291 RELKIND_SEQUENCE,
3292 RELKIND_RELATION, RELKIND_SEQUENCE,
3293 RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3295 else if (g_fout->remoteVersion >= 70200)
3297 appendPQExpBuffer(query,
3298 "SELECT tableoid, oid, relname, relacl, relkind, "
3299 "0::oid AS relnamespace, "
3300 "(%s relowner) AS rolname, "
3301 "relchecks, (reltriggers <> 0) AS relhastriggers, "
3302 "relhasindex, relhasrules, relhasoids, "
3303 "0 AS relfrozenxid, "
3304 "NULL::oid AS owning_tab, "
3305 "NULL::int4 AS owning_col, "
3306 "NULL AS reltablespace, "
3307 "NULL AS reloptions, "
3308 "NULL AS toast_reloptions "
3309 "FROM pg_class "
3310 "WHERE relkind IN ('%c', '%c', '%c') "
3311 "ORDER BY oid",
3312 username_subquery,
3313 RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
3315 else if (g_fout->remoteVersion >= 70100)
3317 /* all tables have oids in 7.1 */
3318 appendPQExpBuffer(query,
3319 "SELECT tableoid, oid, relname, relacl, relkind, "
3320 "0::oid AS relnamespace, "
3321 "(%s relowner) AS rolname, "
3322 "relchecks, (reltriggers <> 0) AS relhastriggers, "
3323 "relhasindex, relhasrules, "
3324 "'t'::bool AS relhasoids, "
3325 "0 AS relfrozenxid, "
3326 "NULL::oid AS owning_tab, "
3327 "NULL::int4 AS owning_col, "
3328 "NULL AS reltablespace, "
3329 "NULL AS reloptions, "
3330 "NULL AS toast_reloptions "
3331 "FROM pg_class "
3332 "WHERE relkind IN ('%c', '%c', '%c') "
3333 "ORDER BY oid",
3334 username_subquery,
3335 RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
3337 else
3340 * Before 7.1, view relkind was not set to 'v', so we must check if we
3341 * have a view by looking for a rule in pg_rewrite.
3343 appendPQExpBuffer(query,
3344 "SELECT "
3345 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
3346 "oid, relname, relacl, "
3347 "CASE WHEN relhasrules and relkind = 'r' "
3348 " and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
3349 " r.ev_class = c.oid AND r.ev_type = '1') "
3350 "THEN '%c'::\"char\" "
3351 "ELSE relkind END AS relkind,"
3352 "0::oid AS relnamespace, "
3353 "(%s relowner) AS rolname, "
3354 "relchecks, (reltriggers <> 0) AS relhastriggers, "
3355 "relhasindex, relhasrules, "
3356 "'t'::bool AS relhasoids, "
3357 "0 as relfrozenxid, "
3358 "NULL::oid AS owning_tab, "
3359 "NULL::int4 AS owning_col, "
3360 "NULL AS reltablespace, "
3361 "NULL AS reloptions, "
3362 "NULL AS toast_reloptions "
3363 "FROM pg_class c "
3364 "WHERE relkind IN ('%c', '%c') "
3365 "ORDER BY oid",
3366 RELKIND_VIEW,
3367 username_subquery,
3368 RELKIND_RELATION, RELKIND_SEQUENCE);
3371 res = PQexec(g_conn, query->data);
3372 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3374 ntups = PQntuples(res);
3376 *numTables = ntups;
3379 * Extract data from result and lock dumpable tables. We do the locking
3380 * before anything else, to minimize the window wherein a table could
3381 * disappear under us.
3383 * Note that we have to save info about all tables here, even when dumping
3384 * only one, because we don't yet know which tables might be inheritance
3385 * ancestors of the target table.
3387 tblinfo = (TableInfo *) calloc(ntups, sizeof(TableInfo));
3389 i_reltableoid = PQfnumber(res, "tableoid");
3390 i_reloid = PQfnumber(res, "oid");
3391 i_relname = PQfnumber(res, "relname");
3392 i_relnamespace = PQfnumber(res, "relnamespace");
3393 i_relacl = PQfnumber(res, "relacl");
3394 i_relkind = PQfnumber(res, "relkind");
3395 i_rolname = PQfnumber(res, "rolname");
3396 i_relchecks = PQfnumber(res, "relchecks");
3397 i_relhastriggers = PQfnumber(res, "relhastriggers");
3398 i_relhasindex = PQfnumber(res, "relhasindex");
3399 i_relhasrules = PQfnumber(res, "relhasrules");
3400 i_relhasoids = PQfnumber(res, "relhasoids");
3401 i_relfrozenxid = PQfnumber(res, "relfrozenxid");
3402 i_owning_tab = PQfnumber(res, "owning_tab");
3403 i_owning_col = PQfnumber(res, "owning_col");
3404 i_reltablespace = PQfnumber(res, "reltablespace");
3405 i_reloptions = PQfnumber(res, "reloptions");
3406 i_toastreloptions = PQfnumber(res, "toast_reloptions");
3408 if (lockWaitTimeout && g_fout->remoteVersion >= 70300)
3411 * Arrange to fail instead of waiting forever for a table lock.
3413 * NB: this coding assumes that the only queries issued within the
3414 * following loop are LOCK TABLEs; else the timeout may be undesirably
3415 * applied to other things too.
3417 resetPQExpBuffer(query);
3418 appendPQExpBuffer(query, "SET statement_timeout = ");
3419 appendStringLiteralConn(query, lockWaitTimeout, g_conn);
3420 do_sql_command(g_conn, query->data);
3423 for (i = 0; i < ntups; i++)
3425 tblinfo[i].dobj.objType = DO_TABLE;
3426 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
3427 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
3428 AssignDumpId(&tblinfo[i].dobj);
3429 tblinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_relname));
3430 tblinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)),
3431 tblinfo[i].dobj.catId.oid);
3432 tblinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
3433 tblinfo[i].relacl = strdup(PQgetvalue(res, i, i_relacl));
3434 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
3435 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
3436 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
3437 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
3438 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
3439 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
3440 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
3441 if (PQgetisnull(res, i, i_owning_tab))
3443 tblinfo[i].owning_tab = InvalidOid;
3444 tblinfo[i].owning_col = 0;
3446 else
3448 tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
3449 tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
3451 tblinfo[i].reltablespace = strdup(PQgetvalue(res, i, i_reltablespace));
3452 tblinfo[i].reloptions = strdup(PQgetvalue(res, i, i_reloptions));
3453 tblinfo[i].toast_reloptions = strdup(PQgetvalue(res, i, i_toastreloptions));
3455 /* other fields were zeroed above */
3458 * Decide whether we want to dump this table.
3460 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
3461 tblinfo[i].dobj.dump = false;
3462 else
3463 selectDumpableTable(&tblinfo[i]);
3464 tblinfo[i].interesting = tblinfo[i].dobj.dump;
3467 * Read-lock target tables to make sure they aren't DROPPED or altered
3468 * in schema before we get around to dumping them.
3470 * Note that we don't explicitly lock parents of the target tables; we
3471 * assume our lock on the child is enough to prevent schema
3472 * alterations to parent tables.
3474 * NOTE: it'd be kinda nice to lock views and sequences too, not only
3475 * plain tables, but the backend doesn't presently allow that.
3477 if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION)
3479 resetPQExpBuffer(query);
3480 appendPQExpBuffer(query,
3481 "LOCK TABLE %s IN ACCESS SHARE MODE",
3482 fmtQualifiedId(tblinfo[i].dobj.namespace->dobj.name,
3483 tblinfo[i].dobj.name));
3484 do_sql_command(g_conn, query->data);
3487 /* Emit notice if join for owner failed */
3488 if (strlen(tblinfo[i].rolname) == 0)
3489 write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
3490 tblinfo[i].dobj.name);
3493 if (lockWaitTimeout && g_fout->remoteVersion >= 70300)
3495 do_sql_command(g_conn, "SET statement_timeout = 0");
3498 PQclear(res);
3501 * Force sequences that are "owned" by table columns to be dumped whenever
3502 * their owning table is being dumped.
3504 for (i = 0; i < ntups; i++)
3506 TableInfo *seqinfo = &tblinfo[i];
3507 int j;
3509 if (!OidIsValid(seqinfo->owning_tab))
3510 continue; /* not an owned sequence */
3511 if (seqinfo->dobj.dump)
3512 continue; /* no need to search */
3514 /* can't use findTableByOid yet, unfortunately */
3515 for (j = 0; j < ntups; j++)
3517 if (tblinfo[j].dobj.catId.oid == seqinfo->owning_tab)
3519 if (tblinfo[j].dobj.dump)
3521 seqinfo->interesting = true;
3522 seqinfo->dobj.dump = true;
3524 break;
3529 destroyPQExpBuffer(query);
3531 return tblinfo;
3535 * getInherits
3536 * read all the inheritance information
3537 * from the system catalogs return them in the InhInfo* structure
3539 * numInherits is set to the number of pairs read in
3541 InhInfo *
3542 getInherits(int *numInherits)
3544 PGresult *res;
3545 int ntups;
3546 int i;
3547 PQExpBuffer query = createPQExpBuffer();
3548 InhInfo *inhinfo;
3550 int i_inhrelid;
3551 int i_inhparent;
3553 /* Make sure we are in proper schema */
3554 selectSourceSchema("pg_catalog");
3556 /* find all the inheritance information */
3558 appendPQExpBuffer(query, "SELECT inhrelid, inhparent FROM pg_inherits");
3560 res = PQexec(g_conn, query->data);
3561 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3563 ntups = PQntuples(res);
3565 *numInherits = ntups;
3567 inhinfo = (InhInfo *) malloc(ntups * sizeof(InhInfo));
3569 i_inhrelid = PQfnumber(res, "inhrelid");
3570 i_inhparent = PQfnumber(res, "inhparent");
3572 for (i = 0; i < ntups; i++)
3574 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
3575 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
3578 PQclear(res);
3580 destroyPQExpBuffer(query);
3582 return inhinfo;
3586 * getIndexes
3587 * get information about every index on a dumpable table
3589 * Note: index data is not returned directly to the caller, but it
3590 * does get entered into the DumpableObject tables.
3592 void
3593 getIndexes(TableInfo tblinfo[], int numTables)
3595 int i,
3597 PQExpBuffer query = createPQExpBuffer();
3598 PGresult *res;
3599 IndxInfo *indxinfo;
3600 ConstraintInfo *constrinfo;
3601 int i_tableoid,
3602 i_oid,
3603 i_indexname,
3604 i_indexdef,
3605 i_indnkeys,
3606 i_indkey,
3607 i_indisclustered,
3608 i_contype,
3609 i_conname,
3610 i_contableoid,
3611 i_conoid,
3612 i_tablespace,
3613 i_options;
3614 int ntups;
3616 for (i = 0; i < numTables; i++)
3618 TableInfo *tbinfo = &tblinfo[i];
3620 /* Only plain tables have indexes */
3621 if (tbinfo->relkind != RELKIND_RELATION || !tbinfo->hasindex)
3622 continue;
3624 /* Ignore indexes of tables not to be dumped */
3625 if (!tbinfo->dobj.dump)
3626 continue;
3628 if (g_verbose)
3629 write_msg(NULL, "reading indexes for table \"%s\"\n",
3630 tbinfo->dobj.name);
3632 /* Make sure we are in proper schema so indexdef is right */
3633 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
3636 * The point of the messy-looking outer join is to find a constraint
3637 * that is related by an internal dependency link to the index. If we
3638 * find one, create a CONSTRAINT entry linked to the INDEX entry. We
3639 * assume an index won't have more than one internal dependency.
3641 resetPQExpBuffer(query);
3642 if (g_fout->remoteVersion >= 80200)
3644 appendPQExpBuffer(query,
3645 "SELECT t.tableoid, t.oid, "
3646 "t.relname AS indexname, "
3647 "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
3648 "t.relnatts AS indnkeys, "
3649 "i.indkey, i.indisclustered, "
3650 "c.contype, c.conname, "
3651 "c.tableoid AS contableoid, "
3652 "c.oid AS conoid, "
3653 "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
3654 "array_to_string(t.reloptions, ', ') AS options "
3655 "FROM pg_catalog.pg_index i "
3656 "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
3657 "LEFT JOIN pg_catalog.pg_depend d "
3658 "ON (d.classid = t.tableoid "
3659 "AND d.objid = t.oid "
3660 "AND d.deptype = 'i') "
3661 "LEFT JOIN pg_catalog.pg_constraint c "
3662 "ON (d.refclassid = c.tableoid "
3663 "AND d.refobjid = c.oid) "
3664 "WHERE i.indrelid = '%u'::pg_catalog.oid "
3665 "ORDER BY indexname",
3666 tbinfo->dobj.catId.oid);
3668 else if (g_fout->remoteVersion >= 80000)
3670 appendPQExpBuffer(query,
3671 "SELECT t.tableoid, t.oid, "
3672 "t.relname AS indexname, "
3673 "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
3674 "t.relnatts AS indnkeys, "
3675 "i.indkey, i.indisclustered, "
3676 "c.contype, c.conname, "
3677 "c.tableoid AS contableoid, "
3678 "c.oid AS conoid, "
3679 "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
3680 "null AS options "
3681 "FROM pg_catalog.pg_index i "
3682 "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
3683 "LEFT JOIN pg_catalog.pg_depend d "
3684 "ON (d.classid = t.tableoid "
3685 "AND d.objid = t.oid "
3686 "AND d.deptype = 'i') "
3687 "LEFT JOIN pg_catalog.pg_constraint c "
3688 "ON (d.refclassid = c.tableoid "
3689 "AND d.refobjid = c.oid) "
3690 "WHERE i.indrelid = '%u'::pg_catalog.oid "
3691 "ORDER BY indexname",
3692 tbinfo->dobj.catId.oid);
3694 else if (g_fout->remoteVersion >= 70300)
3696 appendPQExpBuffer(query,
3697 "SELECT t.tableoid, t.oid, "
3698 "t.relname AS indexname, "
3699 "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
3700 "t.relnatts AS indnkeys, "
3701 "i.indkey, i.indisclustered, "
3702 "c.contype, c.conname, "
3703 "c.tableoid AS contableoid, "
3704 "c.oid AS conoid, "
3705 "NULL AS tablespace, "
3706 "null AS options "
3707 "FROM pg_catalog.pg_index i "
3708 "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
3709 "LEFT JOIN pg_catalog.pg_depend d "
3710 "ON (d.classid = t.tableoid "
3711 "AND d.objid = t.oid "
3712 "AND d.deptype = 'i') "
3713 "LEFT JOIN pg_catalog.pg_constraint c "
3714 "ON (d.refclassid = c.tableoid "
3715 "AND d.refobjid = c.oid) "
3716 "WHERE i.indrelid = '%u'::pg_catalog.oid "
3717 "ORDER BY indexname",
3718 tbinfo->dobj.catId.oid);
3720 else if (g_fout->remoteVersion >= 70100)
3722 appendPQExpBuffer(query,
3723 "SELECT t.tableoid, t.oid, "
3724 "t.relname AS indexname, "
3725 "pg_get_indexdef(i.indexrelid) AS indexdef, "
3726 "t.relnatts AS indnkeys, "
3727 "i.indkey, false AS indisclustered, "
3728 "CASE WHEN i.indisprimary THEN 'p'::char "
3729 "ELSE '0'::char END AS contype, "
3730 "t.relname AS conname, "
3731 "0::oid AS contableoid, "
3732 "t.oid AS conoid, "
3733 "NULL AS tablespace, "
3734 "null AS options "
3735 "FROM pg_index i, pg_class t "
3736 "WHERE t.oid = i.indexrelid "
3737 "AND i.indrelid = '%u'::oid "
3738 "ORDER BY indexname",
3739 tbinfo->dobj.catId.oid);
3741 else
3743 appendPQExpBuffer(query,
3744 "SELECT "
3745 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
3746 "t.oid, "
3747 "t.relname AS indexname, "
3748 "pg_get_indexdef(i.indexrelid) AS indexdef, "
3749 "t.relnatts AS indnkeys, "
3750 "i.indkey, false AS indisclustered, "
3751 "CASE WHEN i.indisprimary THEN 'p'::char "
3752 "ELSE '0'::char END AS contype, "
3753 "t.relname AS conname, "
3754 "0::oid AS contableoid, "
3755 "t.oid AS conoid, "
3756 "NULL AS tablespace, "
3757 "null AS options "
3758 "FROM pg_index i, pg_class t "
3759 "WHERE t.oid = i.indexrelid "
3760 "AND i.indrelid = '%u'::oid "
3761 "ORDER BY indexname",
3762 tbinfo->dobj.catId.oid);
3765 res = PQexec(g_conn, query->data);
3766 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3768 ntups = PQntuples(res);
3770 i_tableoid = PQfnumber(res, "tableoid");
3771 i_oid = PQfnumber(res, "oid");
3772 i_indexname = PQfnumber(res, "indexname");
3773 i_indexdef = PQfnumber(res, "indexdef");
3774 i_indnkeys = PQfnumber(res, "indnkeys");
3775 i_indkey = PQfnumber(res, "indkey");
3776 i_indisclustered = PQfnumber(res, "indisclustered");
3777 i_contype = PQfnumber(res, "contype");
3778 i_conname = PQfnumber(res, "conname");
3779 i_contableoid = PQfnumber(res, "contableoid");
3780 i_conoid = PQfnumber(res, "conoid");
3781 i_tablespace = PQfnumber(res, "tablespace");
3782 i_options = PQfnumber(res, "options");
3784 indxinfo = (IndxInfo *) malloc(ntups * sizeof(IndxInfo));
3785 constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
3787 for (j = 0; j < ntups; j++)
3789 char contype;
3791 indxinfo[j].dobj.objType = DO_INDEX;
3792 indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
3793 indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3794 AssignDumpId(&indxinfo[j].dobj);
3795 indxinfo[j].dobj.name = strdup(PQgetvalue(res, j, i_indexname));
3796 indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3797 indxinfo[j].indextable = tbinfo;
3798 indxinfo[j].indexdef = strdup(PQgetvalue(res, j, i_indexdef));
3799 indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
3800 indxinfo[j].tablespace = strdup(PQgetvalue(res, j, i_tablespace));
3801 indxinfo[j].options = strdup(PQgetvalue(res, j, i_options));
3804 * In pre-7.4 releases, indkeys may contain more entries than
3805 * indnkeys says (since indnkeys will be 1 for a functional
3806 * index). We don't actually care about this case since we don't
3807 * examine indkeys except for indexes associated with PRIMARY and
3808 * UNIQUE constraints, which are never functional indexes. But we
3809 * have to allocate enough space to keep parseOidArray from
3810 * complaining.
3812 indxinfo[j].indkeys = (Oid *) malloc(INDEX_MAX_KEYS * sizeof(Oid));
3813 parseOidArray(PQgetvalue(res, j, i_indkey),
3814 indxinfo[j].indkeys, INDEX_MAX_KEYS);
3815 indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
3816 contype = *(PQgetvalue(res, j, i_contype));
3818 if (contype == 'p' || contype == 'u')
3821 * If we found a constraint matching the index, create an
3822 * entry for it.
3824 * In a pre-7.3 database, we take this path iff the index was
3825 * marked indisprimary.
3827 constrinfo[j].dobj.objType = DO_CONSTRAINT;
3828 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
3829 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
3830 AssignDumpId(&constrinfo[j].dobj);
3831 constrinfo[j].dobj.name = strdup(PQgetvalue(res, j, i_conname));
3832 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3833 constrinfo[j].contable = tbinfo;
3834 constrinfo[j].condomain = NULL;
3835 constrinfo[j].contype = contype;
3836 constrinfo[j].condef = NULL;
3837 constrinfo[j].confrelid = InvalidOid;
3838 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
3839 constrinfo[j].conislocal = true;
3840 constrinfo[j].separate = true;
3842 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
3844 /* If pre-7.3 DB, better make sure table comes first */
3845 addObjectDependency(&constrinfo[j].dobj,
3846 tbinfo->dobj.dumpId);
3848 else
3850 /* Plain secondary index */
3851 indxinfo[j].indexconstraint = 0;
3855 PQclear(res);
3858 destroyPQExpBuffer(query);
3862 * getConstraints
3864 * Get info about constraints on dumpable tables.
3866 * Currently handles foreign keys only.
3867 * Unique and primary key constraints are handled with indexes,
3868 * while check constraints are processed in getTableAttrs().
3870 void
3871 getConstraints(TableInfo tblinfo[], int numTables)
3873 int i,
3875 ConstraintInfo *constrinfo;
3876 PQExpBuffer query;
3877 PGresult *res;
3878 int i_contableoid,
3879 i_conoid,
3880 i_conname,
3881 i_confrelid,
3882 i_condef;
3883 int ntups;
3885 /* pg_constraint was created in 7.3, so nothing to do if older */
3886 if (g_fout->remoteVersion < 70300)
3887 return;
3889 query = createPQExpBuffer();
3891 for (i = 0; i < numTables; i++)
3893 TableInfo *tbinfo = &tblinfo[i];
3895 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
3896 continue;
3898 if (g_verbose)
3899 write_msg(NULL, "reading foreign key constraints for table \"%s\"\n",
3900 tbinfo->dobj.name);
3903 * select table schema to ensure constraint expr is qualified if
3904 * needed
3906 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
3908 resetPQExpBuffer(query);
3909 appendPQExpBuffer(query,
3910 "SELECT tableoid, oid, conname, confrelid, "
3911 "pg_catalog.pg_get_constraintdef(oid) AS condef "
3912 "FROM pg_catalog.pg_constraint "
3913 "WHERE conrelid = '%u'::pg_catalog.oid "
3914 "AND contype = 'f'",
3915 tbinfo->dobj.catId.oid);
3916 res = PQexec(g_conn, query->data);
3917 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3919 ntups = PQntuples(res);
3921 i_contableoid = PQfnumber(res, "tableoid");
3922 i_conoid = PQfnumber(res, "oid");
3923 i_conname = PQfnumber(res, "conname");
3924 i_confrelid = PQfnumber(res, "confrelid");
3925 i_condef = PQfnumber(res, "condef");
3927 constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
3929 for (j = 0; j < ntups; j++)
3931 constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
3932 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
3933 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
3934 AssignDumpId(&constrinfo[j].dobj);
3935 constrinfo[j].dobj.name = strdup(PQgetvalue(res, j, i_conname));
3936 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3937 constrinfo[j].contable = tbinfo;
3938 constrinfo[j].condomain = NULL;
3939 constrinfo[j].contype = 'f';
3940 constrinfo[j].condef = strdup(PQgetvalue(res, j, i_condef));
3941 constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
3942 constrinfo[j].conindex = 0;
3943 constrinfo[j].conislocal = true;
3944 constrinfo[j].separate = true;
3947 PQclear(res);
3950 destroyPQExpBuffer(query);
3954 * getDomainConstraints
3956 * Get info about constraints on a domain.
3958 static void
3959 getDomainConstraints(TypeInfo *tinfo)
3961 int i;
3962 ConstraintInfo *constrinfo;
3963 PQExpBuffer query;
3964 PGresult *res;
3965 int i_tableoid,
3966 i_oid,
3967 i_conname,
3968 i_consrc;
3969 int ntups;
3971 /* pg_constraint was created in 7.3, so nothing to do if older */
3972 if (g_fout->remoteVersion < 70300)
3973 return;
3976 * select appropriate schema to ensure names in constraint are properly
3977 * qualified
3979 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
3981 query = createPQExpBuffer();
3983 if (g_fout->remoteVersion >= 70400)
3984 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
3985 "pg_catalog.pg_get_constraintdef(oid) AS consrc "
3986 "FROM pg_catalog.pg_constraint "
3987 "WHERE contypid = '%u'::pg_catalog.oid "
3988 "ORDER BY conname",
3989 tinfo->dobj.catId.oid);
3990 else
3991 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
3992 "'CHECK (' || consrc || ')' AS consrc "
3993 "FROM pg_catalog.pg_constraint "
3994 "WHERE contypid = '%u'::pg_catalog.oid "
3995 "ORDER BY conname",
3996 tinfo->dobj.catId.oid);
3998 res = PQexec(g_conn, query->data);
3999 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4001 ntups = PQntuples(res);
4003 i_tableoid = PQfnumber(res, "tableoid");
4004 i_oid = PQfnumber(res, "oid");
4005 i_conname = PQfnumber(res, "conname");
4006 i_consrc = PQfnumber(res, "consrc");
4008 constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
4010 tinfo->nDomChecks = ntups;
4011 tinfo->domChecks = constrinfo;
4013 for (i = 0; i < ntups; i++)
4015 constrinfo[i].dobj.objType = DO_CONSTRAINT;
4016 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4017 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4018 AssignDumpId(&constrinfo[i].dobj);
4019 constrinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_conname));
4020 constrinfo[i].dobj.namespace = tinfo->dobj.namespace;
4021 constrinfo[i].contable = NULL;
4022 constrinfo[i].condomain = tinfo;
4023 constrinfo[i].contype = 'c';
4024 constrinfo[i].condef = strdup(PQgetvalue(res, i, i_consrc));
4025 constrinfo[i].confrelid = InvalidOid;
4026 constrinfo[i].conindex = 0;
4027 constrinfo[i].conislocal = true;
4028 constrinfo[i].separate = false;
4031 * Make the domain depend on the constraint, ensuring it won't be
4032 * output till any constraint dependencies are OK.
4034 addObjectDependency(&tinfo->dobj,
4035 constrinfo[i].dobj.dumpId);
4038 PQclear(res);
4040 destroyPQExpBuffer(query);
4044 * getRules
4045 * get basic information about every rule in the system
4047 * numRules is set to the number of rules read in
4049 RuleInfo *
4050 getRules(int *numRules)
4052 PGresult *res;
4053 int ntups;
4054 int i;
4055 PQExpBuffer query = createPQExpBuffer();
4056 RuleInfo *ruleinfo;
4057 int i_tableoid;
4058 int i_oid;
4059 int i_rulename;
4060 int i_ruletable;
4061 int i_ev_type;
4062 int i_is_instead;
4063 int i_ev_enabled;
4065 /* Make sure we are in proper schema */
4066 selectSourceSchema("pg_catalog");
4068 if (g_fout->remoteVersion >= 80300)
4070 appendPQExpBuffer(query, "SELECT "
4071 "tableoid, oid, rulename, "
4072 "ev_class AS ruletable, ev_type, is_instead, "
4073 "ev_enabled "
4074 "FROM pg_rewrite "
4075 "ORDER BY oid");
4077 else if (g_fout->remoteVersion >= 70100)
4079 appendPQExpBuffer(query, "SELECT "
4080 "tableoid, oid, rulename, "
4081 "ev_class AS ruletable, ev_type, is_instead, "
4082 "'O'::char AS ev_enabled "
4083 "FROM pg_rewrite "
4084 "ORDER BY oid");
4086 else
4088 appendPQExpBuffer(query, "SELECT "
4089 "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
4090 "oid, rulename, "
4091 "ev_class AS ruletable, ev_type, is_instead, "
4092 "'O'::char AS ev_enabled "
4093 "FROM pg_rewrite "
4094 "ORDER BY oid");
4097 res = PQexec(g_conn, query->data);
4098 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4100 ntups = PQntuples(res);
4102 *numRules = ntups;
4104 ruleinfo = (RuleInfo *) malloc(ntups * sizeof(RuleInfo));
4106 i_tableoid = PQfnumber(res, "tableoid");
4107 i_oid = PQfnumber(res, "oid");
4108 i_rulename = PQfnumber(res, "rulename");
4109 i_ruletable = PQfnumber(res, "ruletable");
4110 i_ev_type = PQfnumber(res, "ev_type");
4111 i_is_instead = PQfnumber(res, "is_instead");
4112 i_ev_enabled = PQfnumber(res, "ev_enabled");
4114 for (i = 0; i < ntups; i++)
4116 Oid ruletableoid;
4118 ruleinfo[i].dobj.objType = DO_RULE;
4119 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4120 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4121 AssignDumpId(&ruleinfo[i].dobj);
4122 ruleinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_rulename));
4123 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
4124 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
4125 if (ruleinfo[i].ruletable == NULL)
4127 write_msg(NULL, "failed sanity check, parent table OID %u of pg_rewrite entry OID %u not found\n",
4128 ruletableoid,
4129 ruleinfo[i].dobj.catId.oid);
4130 exit_nicely();
4132 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
4133 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
4134 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
4135 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
4136 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
4137 if (ruleinfo[i].ruletable)
4140 * If the table is a view, force its ON SELECT rule to be sorted
4141 * before the view itself --- this ensures that any dependencies
4142 * for the rule affect the table's positioning. Other rules are
4143 * forced to appear after their table.
4145 if (ruleinfo[i].ruletable->relkind == RELKIND_VIEW &&
4146 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
4148 addObjectDependency(&ruleinfo[i].ruletable->dobj,
4149 ruleinfo[i].dobj.dumpId);
4150 /* We'll merge the rule into CREATE VIEW, if possible */
4151 ruleinfo[i].separate = false;
4153 else
4155 addObjectDependency(&ruleinfo[i].dobj,
4156 ruleinfo[i].ruletable->dobj.dumpId);
4157 ruleinfo[i].separate = true;
4160 else
4161 ruleinfo[i].separate = true;
4164 PQclear(res);
4166 destroyPQExpBuffer(query);
4168 return ruleinfo;
4172 * getTriggers
4173 * get information about every trigger on a dumpable table
4175 * Note: trigger data is not returned directly to the caller, but it
4176 * does get entered into the DumpableObject tables.
4178 void
4179 getTriggers(TableInfo tblinfo[], int numTables)
4181 int i,
4183 PQExpBuffer query = createPQExpBuffer();
4184 PGresult *res;
4185 TriggerInfo *tginfo;
4186 int i_tableoid,
4187 i_oid,
4188 i_tgname,
4189 i_tgfname,
4190 i_tgtype,
4191 i_tgnargs,
4192 i_tgargs,
4193 i_tgisconstraint,
4194 i_tgconstrname,
4195 i_tgconstrrelid,
4196 i_tgconstrrelname,
4197 i_tgenabled,
4198 i_tgdeferrable,
4199 i_tginitdeferred;
4200 int ntups;
4202 for (i = 0; i < numTables; i++)
4204 TableInfo *tbinfo = &tblinfo[i];
4206 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
4207 continue;
4209 if (g_verbose)
4210 write_msg(NULL, "reading triggers for table \"%s\"\n",
4211 tbinfo->dobj.name);
4214 * select table schema to ensure regproc name is qualified if needed
4216 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
4218 resetPQExpBuffer(query);
4219 if (g_fout->remoteVersion >= 80300)
4222 * We ignore triggers that are tied to a foreign-key constraint
4224 appendPQExpBuffer(query,
4225 "SELECT tgname, "
4226 "tgfoid::pg_catalog.regproc AS tgfname, "
4227 "tgtype, tgnargs, tgargs, tgenabled, "
4228 "tgisconstraint, tgconstrname, tgdeferrable, "
4229 "tgconstrrelid, tginitdeferred, tableoid, oid, "
4230 "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
4231 "FROM pg_catalog.pg_trigger t "
4232 "WHERE tgrelid = '%u'::pg_catalog.oid "
4233 "AND tgconstraint = 0",
4234 tbinfo->dobj.catId.oid);
4236 else if (g_fout->remoteVersion >= 70300)
4239 * We ignore triggers that are tied to a foreign-key constraint,
4240 * but in these versions we have to grovel through pg_constraint
4241 * to find out
4243 appendPQExpBuffer(query,
4244 "SELECT tgname, "
4245 "tgfoid::pg_catalog.regproc AS tgfname, "
4246 "tgtype, tgnargs, tgargs, tgenabled, "
4247 "tgisconstraint, tgconstrname, tgdeferrable, "
4248 "tgconstrrelid, tginitdeferred, tableoid, oid, "
4249 "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
4250 "FROM pg_catalog.pg_trigger t "
4251 "WHERE tgrelid = '%u'::pg_catalog.oid "
4252 "AND (NOT tgisconstraint "
4253 " OR NOT EXISTS"
4254 " (SELECT 1 FROM pg_catalog.pg_depend d "
4255 " JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
4256 " WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
4257 tbinfo->dobj.catId.oid);
4259 else if (g_fout->remoteVersion >= 70100)
4261 appendPQExpBuffer(query,
4262 "SELECT tgname, tgfoid::regproc AS tgfname, "
4263 "tgtype, tgnargs, tgargs, tgenabled, "
4264 "tgisconstraint, tgconstrname, tgdeferrable, "
4265 "tgconstrrelid, tginitdeferred, tableoid, oid, "
4266 "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
4267 " AS tgconstrrelname "
4268 "FROM pg_trigger "
4269 "WHERE tgrelid = '%u'::oid",
4270 tbinfo->dobj.catId.oid);
4272 else
4274 appendPQExpBuffer(query,
4275 "SELECT tgname, tgfoid::regproc AS tgfname, "
4276 "tgtype, tgnargs, tgargs, tgenabled, "
4277 "tgisconstraint, tgconstrname, tgdeferrable, "
4278 "tgconstrrelid, tginitdeferred, "
4279 "(SELECT oid FROM pg_class WHERE relname = 'pg_trigger') AS tableoid, "
4280 "oid, "
4281 "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
4282 " AS tgconstrrelname "
4283 "FROM pg_trigger "
4284 "WHERE tgrelid = '%u'::oid",
4285 tbinfo->dobj.catId.oid);
4287 res = PQexec(g_conn, query->data);
4288 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4290 ntups = PQntuples(res);
4292 i_tableoid = PQfnumber(res, "tableoid");
4293 i_oid = PQfnumber(res, "oid");
4294 i_tgname = PQfnumber(res, "tgname");
4295 i_tgfname = PQfnumber(res, "tgfname");
4296 i_tgtype = PQfnumber(res, "tgtype");
4297 i_tgnargs = PQfnumber(res, "tgnargs");
4298 i_tgargs = PQfnumber(res, "tgargs");
4299 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
4300 i_tgconstrname = PQfnumber(res, "tgconstrname");
4301 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
4302 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
4303 i_tgenabled = PQfnumber(res, "tgenabled");
4304 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
4305 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
4307 tginfo = (TriggerInfo *) malloc(ntups * sizeof(TriggerInfo));
4309 for (j = 0; j < ntups; j++)
4311 tginfo[j].dobj.objType = DO_TRIGGER;
4312 tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
4313 tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
4314 AssignDumpId(&tginfo[j].dobj);
4315 tginfo[j].dobj.name = strdup(PQgetvalue(res, j, i_tgname));
4316 tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
4317 tginfo[j].tgtable = tbinfo;
4318 tginfo[j].tgfname = strdup(PQgetvalue(res, j, i_tgfname));
4319 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
4320 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
4321 tginfo[j].tgargs = strdup(PQgetvalue(res, j, i_tgargs));
4322 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
4323 tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
4324 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
4325 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
4327 if (tginfo[j].tgisconstraint)
4329 tginfo[j].tgconstrname = strdup(PQgetvalue(res, j, i_tgconstrname));
4330 tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
4331 if (OidIsValid(tginfo[j].tgconstrrelid))
4333 if (PQgetisnull(res, j, i_tgconstrrelname))
4335 write_msg(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
4336 tginfo[j].dobj.name, tbinfo->dobj.name,
4337 tginfo[j].tgconstrrelid);
4338 exit_nicely();
4340 tginfo[j].tgconstrrelname = strdup(PQgetvalue(res, j, i_tgconstrrelname));
4342 else
4343 tginfo[j].tgconstrrelname = NULL;
4345 else
4347 tginfo[j].tgconstrname = NULL;
4348 tginfo[j].tgconstrrelid = InvalidOid;
4349 tginfo[j].tgconstrrelname = NULL;
4353 PQclear(res);
4356 destroyPQExpBuffer(query);
4360 * getProcLangs
4361 * get basic information about every procedural language in the system
4363 * numProcLangs is set to the number of langs read in
4365 * NB: this must run after getFuncs() because we assume we can do
4366 * findFuncByOid().
4368 ProcLangInfo *
4369 getProcLangs(int *numProcLangs)
4371 PGresult *res;
4372 int ntups;
4373 int i;
4374 PQExpBuffer query = createPQExpBuffer();
4375 ProcLangInfo *planginfo;
4376 int i_tableoid;
4377 int i_oid;
4378 int i_lanname;
4379 int i_lanpltrusted;
4380 int i_lanplcallfoid;
4381 int i_lanvalidator;
4382 int i_lanacl;
4383 int i_lanowner;
4385 /* Make sure we are in proper schema */
4386 selectSourceSchema("pg_catalog");
4388 if (g_fout->remoteVersion >= 80300)
4390 /* pg_language has a lanowner column */
4391 appendPQExpBuffer(query, "SELECT tableoid, oid, "
4392 "lanname, lanpltrusted, lanplcallfoid, "
4393 "lanvalidator, lanacl, "
4394 "(%s lanowner) AS lanowner "
4395 "FROM pg_language "
4396 "WHERE lanispl "
4397 "ORDER BY oid",
4398 username_subquery);
4400 else if (g_fout->remoteVersion >= 80100)
4402 /* Languages are owned by the bootstrap superuser, OID 10 */
4403 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
4404 "(%s '10') AS lanowner "
4405 "FROM pg_language "
4406 "WHERE lanispl "
4407 "ORDER BY oid",
4408 username_subquery);
4410 else if (g_fout->remoteVersion >= 70400)
4412 /* Languages are owned by the bootstrap superuser, sysid 1 */
4413 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
4414 "(%s '1') AS lanowner "
4415 "FROM pg_language "
4416 "WHERE lanispl "
4417 "ORDER BY oid",
4418 username_subquery);
4420 else if (g_fout->remoteVersion >= 70100)
4422 /* No clear notion of an owner at all before 7.4 ... */
4423 appendPQExpBuffer(query, "SELECT tableoid, oid, * FROM pg_language "
4424 "WHERE lanispl "
4425 "ORDER BY oid");
4427 else
4429 appendPQExpBuffer(query, "SELECT "
4430 "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, "
4431 "oid, * FROM pg_language "
4432 "WHERE lanispl "
4433 "ORDER BY oid");
4436 res = PQexec(g_conn, query->data);
4437 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4439 ntups = PQntuples(res);
4441 *numProcLangs = ntups;
4443 planginfo = (ProcLangInfo *) malloc(ntups * sizeof(ProcLangInfo));
4445 i_tableoid = PQfnumber(res, "tableoid");
4446 i_oid = PQfnumber(res, "oid");
4447 i_lanname = PQfnumber(res, "lanname");
4448 i_lanpltrusted = PQfnumber(res, "lanpltrusted");
4449 i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
4450 /* these may fail and return -1: */
4451 i_lanvalidator = PQfnumber(res, "lanvalidator");
4452 i_lanacl = PQfnumber(res, "lanacl");
4453 i_lanowner = PQfnumber(res, "lanowner");
4455 for (i = 0; i < ntups; i++)
4457 planginfo[i].dobj.objType = DO_PROCLANG;
4458 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4459 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4460 AssignDumpId(&planginfo[i].dobj);
4462 planginfo[i].dobj.name = strdup(PQgetvalue(res, i, i_lanname));
4463 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
4464 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
4465 if (i_lanvalidator >= 0)
4466 planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
4467 else
4468 planginfo[i].lanvalidator = InvalidOid;
4469 if (i_lanacl >= 0)
4470 planginfo[i].lanacl = strdup(PQgetvalue(res, i, i_lanacl));
4471 else
4472 planginfo[i].lanacl = strdup("{=U}");
4473 if (i_lanowner >= 0)
4474 planginfo[i].lanowner = strdup(PQgetvalue(res, i, i_lanowner));
4475 else
4476 planginfo[i].lanowner = strdup("");
4478 if (g_fout->remoteVersion < 70300)
4481 * We need to make a dependency to ensure the function will be
4482 * dumped first. (In 7.3 and later the regular dependency
4483 * mechanism will handle this for us.)
4485 FuncInfo *funcInfo = findFuncByOid(planginfo[i].lanplcallfoid);
4487 if (funcInfo)
4488 addObjectDependency(&planginfo[i].dobj,
4489 funcInfo->dobj.dumpId);
4493 PQclear(res);
4495 destroyPQExpBuffer(query);
4497 return planginfo;
4501 * getCasts
4502 * get basic information about every cast in the system
4504 * numCasts is set to the number of casts read in
4506 CastInfo *
4507 getCasts(int *numCasts)
4509 PGresult *res;
4510 int ntups;
4511 int i;
4512 PQExpBuffer query = createPQExpBuffer();
4513 CastInfo *castinfo;
4514 int i_tableoid;
4515 int i_oid;
4516 int i_castsource;
4517 int i_casttarget;
4518 int i_castfunc;
4519 int i_castcontext;
4520 int i_castmethod;
4522 /* Make sure we are in proper schema */
4523 selectSourceSchema("pg_catalog");
4525 if (g_fout->remoteVersion >= 80400)
4527 appendPQExpBuffer(query, "SELECT tableoid, oid, "
4528 "castsource, casttarget, castfunc, castcontext, "
4529 "castmethod "
4530 "FROM pg_cast ORDER BY 3,4");
4532 else if (g_fout->remoteVersion >= 70300)
4534 appendPQExpBuffer(query, "SELECT tableoid, oid, "
4535 "castsource, casttarget, castfunc, castcontext, "
4536 "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
4537 "FROM pg_cast ORDER BY 3,4");
4539 else
4541 appendPQExpBuffer(query, "SELECT 0 AS tableoid, p.oid, "
4542 "t1.oid AS castsource, t2.oid AS casttarget, "
4543 "p.oid AS castfunc, 'e' AS castcontext, "
4544 "'f' AS castmethod "
4545 "FROM pg_type t1, pg_type t2, pg_proc p "
4546 "WHERE p.pronargs = 1 AND "
4547 "p.proargtypes[0] = t1.oid AND "
4548 "p.prorettype = t2.oid AND p.proname = t2.typname "
4549 "ORDER BY 3,4");
4552 res = PQexec(g_conn, query->data);
4553 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4555 ntups = PQntuples(res);
4557 *numCasts = ntups;
4559 castinfo = (CastInfo *) malloc(ntups * sizeof(CastInfo));
4561 i_tableoid = PQfnumber(res, "tableoid");
4562 i_oid = PQfnumber(res, "oid");
4563 i_castsource = PQfnumber(res, "castsource");
4564 i_casttarget = PQfnumber(res, "casttarget");
4565 i_castfunc = PQfnumber(res, "castfunc");
4566 i_castcontext = PQfnumber(res, "castcontext");
4567 i_castmethod = PQfnumber(res, "castmethod");
4569 for (i = 0; i < ntups; i++)
4571 PQExpBufferData namebuf;
4572 TypeInfo *sTypeInfo;
4573 TypeInfo *tTypeInfo;
4575 castinfo[i].dobj.objType = DO_CAST;
4576 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4577 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4578 AssignDumpId(&castinfo[i].dobj);
4579 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
4580 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
4581 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
4582 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
4583 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
4586 * Try to name cast as concatenation of typnames. This is only used
4587 * for purposes of sorting. If we fail to find either type, the name
4588 * will be an empty string.
4590 initPQExpBuffer(&namebuf);
4591 sTypeInfo = findTypeByOid(castinfo[i].castsource);
4592 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
4593 if (sTypeInfo && tTypeInfo)
4594 appendPQExpBuffer(&namebuf, "%s %s",
4595 sTypeInfo->dobj.name, tTypeInfo->dobj.name);
4596 castinfo[i].dobj.name = namebuf.data;
4598 if (OidIsValid(castinfo[i].castfunc))
4601 * We need to make a dependency to ensure the function will be
4602 * dumped first. (In 7.3 and later the regular dependency
4603 * mechanism will handle this for us.)
4605 FuncInfo *funcInfo;
4607 funcInfo = findFuncByOid(castinfo[i].castfunc);
4608 if (funcInfo)
4609 addObjectDependency(&castinfo[i].dobj,
4610 funcInfo->dobj.dumpId);
4614 PQclear(res);
4616 destroyPQExpBuffer(query);
4618 return castinfo;
4622 * getTableAttrs -
4623 * for each interesting table, read info about its attributes
4624 * (names, types, default values, CHECK constraints, etc)
4626 * This is implemented in a very inefficient way right now, looping
4627 * through the tblinfo and doing a join per table to find the attrs and their
4628 * types. However, because we want type names and so forth to be named
4629 * relative to the schema of each table, we couldn't do it in just one
4630 * query. (Maybe one query per schema?)
4632 * modifies tblinfo
4634 void
4635 getTableAttrs(TableInfo *tblinfo, int numTables)
4637 int i,
4639 PQExpBuffer q = createPQExpBuffer();
4640 int i_attnum;
4641 int i_attname;
4642 int i_atttypname;
4643 int i_atttypmod;
4644 int i_attstattarget;
4645 int i_attstorage;
4646 int i_typstorage;
4647 int i_attnotnull;
4648 int i_atthasdef;
4649 int i_attisdropped;
4650 int i_attlen;
4651 int i_attalign;
4652 int i_attislocal;
4653 PGresult *res;
4654 int ntups;
4655 bool hasdefaults;
4657 for (i = 0; i < numTables; i++)
4659 TableInfo *tbinfo = &tblinfo[i];
4661 /* Don't bother to collect info for sequences */
4662 if (tbinfo->relkind == RELKIND_SEQUENCE)
4663 continue;
4665 /* Don't bother with uninteresting tables, either */
4666 if (!tbinfo->interesting)
4667 continue;
4670 * Make sure we are in proper schema for this table; this allows
4671 * correct retrieval of formatted type names and default exprs
4673 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
4675 /* find all the user attributes and their types */
4678 * we must read the attribute names in attribute number order! because
4679 * we will use the attnum to index into the attnames array later. We
4680 * actually ask to order by "attrelid, attnum" because (at least up to
4681 * 7.3) the planner is not smart enough to realize it needn't re-sort
4682 * the output of an indexscan on pg_attribute_relid_attnum_index.
4684 if (g_verbose)
4685 write_msg(NULL, "finding the columns and types of table \"%s\"\n",
4686 tbinfo->dobj.name);
4688 resetPQExpBuffer(q);
4690 if (g_fout->remoteVersion >= 70300)
4692 /* need left join here to not fail on dropped columns ... */
4693 appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
4694 "a.attstattarget, a.attstorage, t.typstorage, "
4695 "a.attnotnull, a.atthasdef, a.attisdropped, "
4696 "a.attlen, a.attalign, a.attislocal, "
4697 "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname "
4698 "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
4699 "ON a.atttypid = t.oid "
4700 "WHERE a.attrelid = '%u'::pg_catalog.oid "
4701 "AND a.attnum > 0::pg_catalog.int2 "
4702 "ORDER BY a.attrelid, a.attnum",
4703 tbinfo->dobj.catId.oid);
4705 else if (g_fout->remoteVersion >= 70100)
4708 * attstattarget doesn't exist in 7.1. It does exist in 7.2, but
4709 * we don't dump it because we can't tell whether it's been
4710 * explicitly set or was just a default.
4712 appendPQExpBuffer(q, "SELECT a.attnum, a.attname, "
4713 "a.atttypmod, -1 AS attstattarget, a.attstorage, "
4714 "t.typstorage, a.attnotnull, a.atthasdef, "
4715 "false AS attisdropped, 0 AS attlen, "
4716 "' ' AS attalign, false AS attislocal, "
4717 "format_type(t.oid,a.atttypmod) AS atttypname "
4718 "FROM pg_attribute a LEFT JOIN pg_type t "
4719 "ON a.atttypid = t.oid "
4720 "WHERE a.attrelid = '%u'::oid "
4721 "AND a.attnum > 0::int2 "
4722 "ORDER BY a.attrelid, a.attnum",
4723 tbinfo->dobj.catId.oid);
4725 else
4727 /* format_type not available before 7.1 */
4728 appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, "
4729 "-1 AS attstattarget, attstorage, "
4730 "attstorage AS typstorage, "
4731 "attnotnull, atthasdef, false AS attisdropped, "
4732 "0 AS attlen, ' ' AS attalign, "
4733 "false AS attislocal, "
4734 "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname "
4735 "FROM pg_attribute a "
4736 "WHERE attrelid = '%u'::oid "
4737 "AND attnum > 0::int2 "
4738 "ORDER BY attrelid, attnum",
4739 tbinfo->dobj.catId.oid);
4742 res = PQexec(g_conn, q->data);
4743 check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
4745 ntups = PQntuples(res);
4747 i_attnum = PQfnumber(res, "attnum");
4748 i_attname = PQfnumber(res, "attname");
4749 i_atttypname = PQfnumber(res, "atttypname");
4750 i_atttypmod = PQfnumber(res, "atttypmod");
4751 i_attstattarget = PQfnumber(res, "attstattarget");
4752 i_attstorage = PQfnumber(res, "attstorage");
4753 i_typstorage = PQfnumber(res, "typstorage");
4754 i_attnotnull = PQfnumber(res, "attnotnull");
4755 i_atthasdef = PQfnumber(res, "atthasdef");
4756 i_attisdropped = PQfnumber(res, "attisdropped");
4757 i_attlen = PQfnumber(res, "attlen");
4758 i_attalign = PQfnumber(res, "attalign");
4759 i_attislocal = PQfnumber(res, "attislocal");
4761 tbinfo->numatts = ntups;
4762 tbinfo->attnames = (char **) malloc(ntups * sizeof(char *));
4763 tbinfo->atttypnames = (char **) malloc(ntups * sizeof(char *));
4764 tbinfo->atttypmod = (int *) malloc(ntups * sizeof(int));
4765 tbinfo->attstattarget = (int *) malloc(ntups * sizeof(int));
4766 tbinfo->attstorage = (char *) malloc(ntups * sizeof(char));
4767 tbinfo->typstorage = (char *) malloc(ntups * sizeof(char));
4768 tbinfo->attisdropped = (bool *) malloc(ntups * sizeof(bool));
4769 tbinfo->attlen = (int *) malloc(ntups * sizeof(int));
4770 tbinfo->attalign = (char *) malloc(ntups * sizeof(char));
4771 tbinfo->attislocal = (bool *) malloc(ntups * sizeof(bool));
4772 tbinfo->notnull = (bool *) malloc(ntups * sizeof(bool));
4773 tbinfo->attrdefs = (AttrDefInfo **) malloc(ntups * sizeof(AttrDefInfo *));
4774 tbinfo->inhAttrs = (bool *) malloc(ntups * sizeof(bool));
4775 tbinfo->inhAttrDef = (bool *) malloc(ntups * sizeof(bool));
4776 tbinfo->inhNotNull = (bool *) malloc(ntups * sizeof(bool));
4777 hasdefaults = false;
4779 for (j = 0; j < ntups; j++)
4781 if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
4783 write_msg(NULL, "invalid column numbering in table \"%s\"\n",
4784 tbinfo->dobj.name);
4785 exit_nicely();
4787 tbinfo->attnames[j] = strdup(PQgetvalue(res, j, i_attname));
4788 tbinfo->atttypnames[j] = strdup(PQgetvalue(res, j, i_atttypname));
4789 tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
4790 tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
4791 tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
4792 tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
4793 tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
4794 tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
4795 tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
4796 tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
4797 tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
4798 tbinfo->attrdefs[j] = NULL; /* fix below */
4799 if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
4800 hasdefaults = true;
4801 /* these flags will be set in flagInhAttrs() */
4802 tbinfo->inhAttrs[j] = false;
4803 tbinfo->inhAttrDef[j] = false;
4804 tbinfo->inhNotNull[j] = false;
4807 PQclear(res);
4811 * ALTER TABLE DROP COLUMN clears pg_attribute.atttypid, so we set the
4812 * column data type to 'TEXT; we will later drop the column.
4814 if (binary_upgrade)
4816 for (j = 0; j < ntups; j++)
4818 if (tbinfo->attisdropped[j])
4819 tbinfo->atttypnames[j] = strdup("TEXT");
4824 * Get info about column defaults
4826 if (hasdefaults)
4828 AttrDefInfo *attrdefs;
4829 int numDefaults;
4831 if (g_verbose)
4832 write_msg(NULL, "finding default expressions of table \"%s\"\n",
4833 tbinfo->dobj.name);
4835 resetPQExpBuffer(q);
4836 if (g_fout->remoteVersion >= 70300)
4838 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
4839 "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
4840 "FROM pg_catalog.pg_attrdef "
4841 "WHERE adrelid = '%u'::pg_catalog.oid",
4842 tbinfo->dobj.catId.oid);
4844 else if (g_fout->remoteVersion >= 70200)
4846 /* 7.2 did not have OIDs in pg_attrdef */
4847 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, adnum, "
4848 "pg_get_expr(adbin, adrelid) AS adsrc "
4849 "FROM pg_attrdef "
4850 "WHERE adrelid = '%u'::oid",
4851 tbinfo->dobj.catId.oid);
4853 else if (g_fout->remoteVersion >= 70100)
4855 /* no pg_get_expr, so must rely on adsrc */
4856 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, adsrc "
4857 "FROM pg_attrdef "
4858 "WHERE adrelid = '%u'::oid",
4859 tbinfo->dobj.catId.oid);
4861 else
4863 /* no pg_get_expr, no tableoid either */
4864 appendPQExpBuffer(q, "SELECT "
4865 "(SELECT oid FROM pg_class WHERE relname = 'pg_attrdef') AS tableoid, "
4866 "oid, adnum, adsrc "
4867 "FROM pg_attrdef "
4868 "WHERE adrelid = '%u'::oid",
4869 tbinfo->dobj.catId.oid);
4871 res = PQexec(g_conn, q->data);
4872 check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
4874 numDefaults = PQntuples(res);
4875 attrdefs = (AttrDefInfo *) malloc(numDefaults * sizeof(AttrDefInfo));
4877 for (j = 0; j < numDefaults; j++)
4879 int adnum;
4881 attrdefs[j].dobj.objType = DO_ATTRDEF;
4882 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
4883 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
4884 AssignDumpId(&attrdefs[j].dobj);
4885 attrdefs[j].adtable = tbinfo;
4886 attrdefs[j].adnum = adnum = atoi(PQgetvalue(res, j, 2));
4887 attrdefs[j].adef_expr = strdup(PQgetvalue(res, j, 3));
4889 attrdefs[j].dobj.name = strdup(tbinfo->dobj.name);
4890 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
4892 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
4895 * Defaults on a VIEW must always be dumped as separate ALTER
4896 * TABLE commands. Defaults on regular tables are dumped as
4897 * part of the CREATE TABLE if possible. To check if it's
4898 * safe, we mark the default as needing to appear before the
4899 * CREATE.
4901 if (tbinfo->relkind == RELKIND_VIEW)
4903 attrdefs[j].separate = true;
4904 /* needed in case pre-7.3 DB: */
4905 addObjectDependency(&attrdefs[j].dobj,
4906 tbinfo->dobj.dumpId);
4908 else
4910 attrdefs[j].separate = false;
4911 addObjectDependency(&tbinfo->dobj,
4912 attrdefs[j].dobj.dumpId);
4915 if (adnum <= 0 || adnum > ntups)
4917 write_msg(NULL, "invalid adnum value %d for table \"%s\"\n",
4918 adnum, tbinfo->dobj.name);
4919 exit_nicely();
4921 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
4923 PQclear(res);
4927 * Get info about table CHECK constraints
4929 if (tbinfo->ncheck > 0)
4931 ConstraintInfo *constrs;
4932 int numConstrs;
4934 if (g_verbose)
4935 write_msg(NULL, "finding check constraints for table \"%s\"\n",
4936 tbinfo->dobj.name);
4938 resetPQExpBuffer(q);
4939 if (g_fout->remoteVersion >= 80400)
4941 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
4942 "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
4943 "conislocal "
4944 "FROM pg_catalog.pg_constraint "
4945 "WHERE conrelid = '%u'::pg_catalog.oid "
4946 " AND contype = 'c' "
4947 "ORDER BY conname",
4948 tbinfo->dobj.catId.oid);
4950 else if (g_fout->remoteVersion >= 70400)
4952 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
4953 "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
4954 "true AS conislocal "
4955 "FROM pg_catalog.pg_constraint "
4956 "WHERE conrelid = '%u'::pg_catalog.oid "
4957 " AND contype = 'c' "
4958 "ORDER BY conname",
4959 tbinfo->dobj.catId.oid);
4961 else if (g_fout->remoteVersion >= 70300)
4963 /* no pg_get_constraintdef, must use consrc */
4964 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
4965 "'CHECK (' || consrc || ')' AS consrc, "
4966 "true AS conislocal "
4967 "FROM pg_catalog.pg_constraint "
4968 "WHERE conrelid = '%u'::pg_catalog.oid "
4969 " AND contype = 'c' "
4970 "ORDER BY conname",
4971 tbinfo->dobj.catId.oid);
4973 else if (g_fout->remoteVersion >= 70200)
4975 /* 7.2 did not have OIDs in pg_relcheck */
4976 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, "
4977 "rcname AS conname, "
4978 "'CHECK (' || rcsrc || ')' AS consrc, "
4979 "true AS conislocal "
4980 "FROM pg_relcheck "
4981 "WHERE rcrelid = '%u'::oid "
4982 "ORDER BY rcname",
4983 tbinfo->dobj.catId.oid);
4985 else if (g_fout->remoteVersion >= 70100)
4987 appendPQExpBuffer(q, "SELECT tableoid, oid, "
4988 "rcname AS conname, "
4989 "'CHECK (' || rcsrc || ')' AS consrc, "
4990 "true AS conislocal "
4991 "FROM pg_relcheck "
4992 "WHERE rcrelid = '%u'::oid "
4993 "ORDER BY rcname",
4994 tbinfo->dobj.catId.oid);
4996 else
4998 /* no tableoid in 7.0 */
4999 appendPQExpBuffer(q, "SELECT "
5000 "(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
5001 "oid, rcname AS conname, "
5002 "'CHECK (' || rcsrc || ')' AS consrc, "
5003 "true AS conislocal "
5004 "FROM pg_relcheck "
5005 "WHERE rcrelid = '%u'::oid "
5006 "ORDER BY rcname",
5007 tbinfo->dobj.catId.oid);
5009 res = PQexec(g_conn, q->data);
5010 check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
5012 numConstrs = PQntuples(res);
5013 if (numConstrs != tbinfo->ncheck)
5015 write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
5016 "expected %d check constraints on table \"%s\" but found %d\n",
5017 tbinfo->ncheck),
5018 tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
5019 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
5020 exit_nicely();
5023 constrs = (ConstraintInfo *) malloc(numConstrs * sizeof(ConstraintInfo));
5024 tbinfo->checkexprs = constrs;
5026 for (j = 0; j < numConstrs; j++)
5028 constrs[j].dobj.objType = DO_CONSTRAINT;
5029 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
5030 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
5031 AssignDumpId(&constrs[j].dobj);
5032 constrs[j].dobj.name = strdup(PQgetvalue(res, j, 2));
5033 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
5034 constrs[j].contable = tbinfo;
5035 constrs[j].condomain = NULL;
5036 constrs[j].contype = 'c';
5037 constrs[j].condef = strdup(PQgetvalue(res, j, 3));
5038 constrs[j].confrelid = InvalidOid;
5039 constrs[j].conindex = 0;
5040 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
5041 constrs[j].separate = false;
5043 constrs[j].dobj.dump = tbinfo->dobj.dump;
5046 * Mark the constraint as needing to appear before the table
5047 * --- this is so that any other dependencies of the
5048 * constraint will be emitted before we try to create the
5049 * table.
5051 addObjectDependency(&tbinfo->dobj,
5052 constrs[j].dobj.dumpId);
5055 * If the constraint is inherited, this will be detected later
5056 * (in pre-8.4 databases). We also detect later if the
5057 * constraint must be split out from the table definition.
5060 PQclear(res);
5064 destroyPQExpBuffer(q);
5069 * getTSParsers:
5070 * read all text search parsers in the system catalogs and return them
5071 * in the TSParserInfo* structure
5073 * numTSParsers is set to the number of parsers read in
5075 TSParserInfo *
5076 getTSParsers(int *numTSParsers)
5078 PGresult *res;
5079 int ntups;
5080 int i;
5081 PQExpBuffer query = createPQExpBuffer();
5082 TSParserInfo *prsinfo;
5083 int i_tableoid;
5084 int i_oid;
5085 int i_prsname;
5086 int i_prsnamespace;
5087 int i_prsstart;
5088 int i_prstoken;
5089 int i_prsend;
5090 int i_prsheadline;
5091 int i_prslextype;
5093 /* Before 8.3, there is no built-in text search support */
5094 if (g_fout->remoteVersion < 80300)
5096 *numTSParsers = 0;
5097 return NULL;
5101 * find all text search objects, including builtin ones; we filter out
5102 * system-defined objects at dump-out time.
5105 /* Make sure we are in proper schema */
5106 selectSourceSchema("pg_catalog");
5108 appendPQExpBuffer(query, "SELECT tableoid, oid, prsname, prsnamespace, "
5109 "prsstart::oid, prstoken::oid, "
5110 "prsend::oid, prsheadline::oid, prslextype::oid "
5111 "FROM pg_ts_parser");
5113 res = PQexec(g_conn, query->data);
5114 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5116 ntups = PQntuples(res);
5117 *numTSParsers = ntups;
5119 prsinfo = (TSParserInfo *) malloc(ntups * sizeof(TSParserInfo));
5121 i_tableoid = PQfnumber(res, "tableoid");
5122 i_oid = PQfnumber(res, "oid");
5123 i_prsname = PQfnumber(res, "prsname");
5124 i_prsnamespace = PQfnumber(res, "prsnamespace");
5125 i_prsstart = PQfnumber(res, "prsstart");
5126 i_prstoken = PQfnumber(res, "prstoken");
5127 i_prsend = PQfnumber(res, "prsend");
5128 i_prsheadline = PQfnumber(res, "prsheadline");
5129 i_prslextype = PQfnumber(res, "prslextype");
5131 for (i = 0; i < ntups; i++)
5133 prsinfo[i].dobj.objType = DO_TSPARSER;
5134 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5135 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5136 AssignDumpId(&prsinfo[i].dobj);
5137 prsinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_prsname));
5138 prsinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)),
5139 prsinfo[i].dobj.catId.oid);
5140 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
5141 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
5142 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
5143 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
5144 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
5146 /* Decide whether we want to dump it */
5147 selectDumpableObject(&(prsinfo[i].dobj));
5150 PQclear(res);
5152 destroyPQExpBuffer(query);
5154 return prsinfo;
5158 * getTSDictionaries:
5159 * read all text search dictionaries in the system catalogs and return them
5160 * in the TSDictInfo* structure
5162 * numTSDicts is set to the number of dictionaries read in
5164 TSDictInfo *
5165 getTSDictionaries(int *numTSDicts)
5167 PGresult *res;
5168 int ntups;
5169 int i;
5170 PQExpBuffer query = createPQExpBuffer();
5171 TSDictInfo *dictinfo;
5172 int i_tableoid;
5173 int i_oid;
5174 int i_dictname;
5175 int i_dictnamespace;
5176 int i_rolname;
5177 int i_dicttemplate;
5178 int i_dictinitoption;
5180 /* Before 8.3, there is no built-in text search support */
5181 if (g_fout->remoteVersion < 80300)
5183 *numTSDicts = 0;
5184 return NULL;
5187 /* Make sure we are in proper schema */
5188 selectSourceSchema("pg_catalog");
5190 appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
5191 "dictnamespace, (%s dictowner) AS rolname, "
5192 "dicttemplate, dictinitoption "
5193 "FROM pg_ts_dict",
5194 username_subquery);
5196 res = PQexec(g_conn, query->data);
5197 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5199 ntups = PQntuples(res);
5200 *numTSDicts = ntups;
5202 dictinfo = (TSDictInfo *) malloc(ntups * sizeof(TSDictInfo));
5204 i_tableoid = PQfnumber(res, "tableoid");
5205 i_oid = PQfnumber(res, "oid");
5206 i_dictname = PQfnumber(res, "dictname");
5207 i_dictnamespace = PQfnumber(res, "dictnamespace");
5208 i_rolname = PQfnumber(res, "rolname");
5209 i_dictinitoption = PQfnumber(res, "dictinitoption");
5210 i_dicttemplate = PQfnumber(res, "dicttemplate");
5212 for (i = 0; i < ntups; i++)
5214 dictinfo[i].dobj.objType = DO_TSDICT;
5215 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5216 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5217 AssignDumpId(&dictinfo[i].dobj);
5218 dictinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_dictname));
5219 dictinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)),
5220 dictinfo[i].dobj.catId.oid);
5221 dictinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
5222 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
5223 if (PQgetisnull(res, i, i_dictinitoption))
5224 dictinfo[i].dictinitoption = NULL;
5225 else
5226 dictinfo[i].dictinitoption = strdup(PQgetvalue(res, i, i_dictinitoption));
5228 /* Decide whether we want to dump it */
5229 selectDumpableObject(&(dictinfo[i].dobj));
5232 PQclear(res);
5234 destroyPQExpBuffer(query);
5236 return dictinfo;
5240 * getTSTemplates:
5241 * read all text search templates in the system catalogs and return them
5242 * in the TSTemplateInfo* structure
5244 * numTSTemplates is set to the number of templates read in
5246 TSTemplateInfo *
5247 getTSTemplates(int *numTSTemplates)
5249 PGresult *res;
5250 int ntups;
5251 int i;
5252 PQExpBuffer query = createPQExpBuffer();
5253 TSTemplateInfo *tmplinfo;
5254 int i_tableoid;
5255 int i_oid;
5256 int i_tmplname;
5257 int i_tmplnamespace;
5258 int i_tmplinit;
5259 int i_tmpllexize;
5261 /* Before 8.3, there is no built-in text search support */
5262 if (g_fout->remoteVersion < 80300)
5264 *numTSTemplates = 0;
5265 return NULL;
5268 /* Make sure we are in proper schema */
5269 selectSourceSchema("pg_catalog");
5271 appendPQExpBuffer(query, "SELECT tableoid, oid, tmplname, "
5272 "tmplnamespace, tmplinit::oid, tmpllexize::oid "
5273 "FROM pg_ts_template");
5275 res = PQexec(g_conn, query->data);
5276 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5278 ntups = PQntuples(res);
5279 *numTSTemplates = ntups;
5281 tmplinfo = (TSTemplateInfo *) malloc(ntups * sizeof(TSTemplateInfo));
5283 i_tableoid = PQfnumber(res, "tableoid");
5284 i_oid = PQfnumber(res, "oid");
5285 i_tmplname = PQfnumber(res, "tmplname");
5286 i_tmplnamespace = PQfnumber(res, "tmplnamespace");
5287 i_tmplinit = PQfnumber(res, "tmplinit");
5288 i_tmpllexize = PQfnumber(res, "tmpllexize");
5290 for (i = 0; i < ntups; i++)
5292 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
5293 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5294 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5295 AssignDumpId(&tmplinfo[i].dobj);
5296 tmplinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_tmplname));
5297 tmplinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)),
5298 tmplinfo[i].dobj.catId.oid);
5299 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
5300 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
5302 /* Decide whether we want to dump it */
5303 selectDumpableObject(&(tmplinfo[i].dobj));
5306 PQclear(res);
5308 destroyPQExpBuffer(query);
5310 return tmplinfo;
5314 * getTSConfigurations:
5315 * read all text search configurations in the system catalogs and return
5316 * them in the TSConfigInfo* structure
5318 * numTSConfigs is set to the number of configurations read in
5320 TSConfigInfo *
5321 getTSConfigurations(int *numTSConfigs)
5323 PGresult *res;
5324 int ntups;
5325 int i;
5326 PQExpBuffer query = createPQExpBuffer();
5327 TSConfigInfo *cfginfo;
5328 int i_tableoid;
5329 int i_oid;
5330 int i_cfgname;
5331 int i_cfgnamespace;
5332 int i_rolname;
5333 int i_cfgparser;
5335 /* Before 8.3, there is no built-in text search support */
5336 if (g_fout->remoteVersion < 80300)
5338 *numTSConfigs = 0;
5339 return NULL;
5342 /* Make sure we are in proper schema */
5343 selectSourceSchema("pg_catalog");
5345 appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
5346 "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
5347 "FROM pg_ts_config",
5348 username_subquery);
5350 res = PQexec(g_conn, query->data);
5351 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5353 ntups = PQntuples(res);
5354 *numTSConfigs = ntups;
5356 cfginfo = (TSConfigInfo *) malloc(ntups * sizeof(TSConfigInfo));
5358 i_tableoid = PQfnumber(res, "tableoid");
5359 i_oid = PQfnumber(res, "oid");
5360 i_cfgname = PQfnumber(res, "cfgname");
5361 i_cfgnamespace = PQfnumber(res, "cfgnamespace");
5362 i_rolname = PQfnumber(res, "rolname");
5363 i_cfgparser = PQfnumber(res, "cfgparser");
5365 for (i = 0; i < ntups; i++)
5367 cfginfo[i].dobj.objType = DO_TSCONFIG;
5368 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5369 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5370 AssignDumpId(&cfginfo[i].dobj);
5371 cfginfo[i].dobj.name = strdup(PQgetvalue(res, i, i_cfgname));
5372 cfginfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)),
5373 cfginfo[i].dobj.catId.oid);
5374 cfginfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
5375 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
5377 /* Decide whether we want to dump it */
5378 selectDumpableObject(&(cfginfo[i].dobj));
5381 PQclear(res);
5383 destroyPQExpBuffer(query);
5385 return cfginfo;
5389 * getForeignDataWrappers:
5390 * read all foreign-data wrappers in the system catalogs and return
5391 * them in the FdwInfo* structure
5393 * numForeignDataWrappers is set to the number of fdws read in
5395 FdwInfo *
5396 getForeignDataWrappers(int *numForeignDataWrappers)
5398 PGresult *res;
5399 int ntups;
5400 int i;
5401 PQExpBuffer query = createPQExpBuffer();
5402 FdwInfo *fdwinfo;
5403 int i_oid;
5404 int i_fdwname;
5405 int i_rolname;
5406 int i_fdwvalidator;
5407 int i_fdwacl;
5408 int i_fdwoptions;
5410 /* Before 8.4, there are no foreign-data wrappers */
5411 if (g_fout->remoteVersion < 80400)
5413 *numForeignDataWrappers = 0;
5414 return NULL;
5417 /* Make sure we are in proper schema */
5418 selectSourceSchema("pg_catalog");
5420 appendPQExpBuffer(query, "SELECT oid, fdwname, "
5421 "(%s fdwowner) AS rolname, fdwvalidator::pg_catalog.regproc, fdwacl,"
5422 "array_to_string(ARRAY("
5423 " SELECT option_name || ' ' || quote_literal(option_value) "
5424 " FROM pg_options_to_table(fdwoptions)), ', ') AS fdwoptions "
5425 "FROM pg_foreign_data_wrapper",
5426 username_subquery);
5428 res = PQexec(g_conn, query->data);
5429 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5431 ntups = PQntuples(res);
5432 *numForeignDataWrappers = ntups;
5434 fdwinfo = (FdwInfo *) malloc(ntups * sizeof(FdwInfo));
5436 i_oid = PQfnumber(res, "oid");
5437 i_fdwname = PQfnumber(res, "fdwname");
5438 i_rolname = PQfnumber(res, "rolname");
5439 i_fdwvalidator = PQfnumber(res, "fdwvalidator");
5440 i_fdwacl = PQfnumber(res, "fdwacl");
5441 i_fdwoptions = PQfnumber(res, "fdwoptions");
5443 for (i = 0; i < ntups; i++)
5445 fdwinfo[i].dobj.objType = DO_FDW;
5446 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5447 AssignDumpId(&fdwinfo[i].dobj);
5448 fdwinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_fdwname));
5449 fdwinfo[i].dobj.namespace = NULL;
5450 fdwinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
5451 fdwinfo[i].fdwvalidator = strdup(PQgetvalue(res, i, i_fdwvalidator));
5452 fdwinfo[i].fdwoptions = strdup(PQgetvalue(res, i, i_fdwoptions));
5453 fdwinfo[i].fdwacl = strdup(PQgetvalue(res, i, i_fdwacl));
5456 /* Decide whether we want to dump it */
5457 selectDumpableObject(&(fdwinfo[i].dobj));
5460 PQclear(res);
5462 destroyPQExpBuffer(query);
5464 return fdwinfo;
5468 * getForeignServers:
5469 * read all foreign servers in the system catalogs and return
5470 * them in the ForeignServerInfo * structure
5472 * numForeignServers is set to the number of servers read in
5474 ForeignServerInfo *
5475 getForeignServers(int *numForeignServers)
5477 PGresult *res;
5478 int ntups;
5479 int i;
5480 PQExpBuffer query = createPQExpBuffer();
5481 ForeignServerInfo *srvinfo;
5482 int i_oid;
5483 int i_srvname;
5484 int i_rolname;
5485 int i_srvfdw;
5486 int i_srvtype;
5487 int i_srvversion;
5488 int i_srvacl;
5489 int i_srvoptions;
5491 /* Before 8.4, there are no foreign servers */
5492 if (g_fout->remoteVersion < 80400)
5494 *numForeignServers = 0;
5495 return NULL;
5498 /* Make sure we are in proper schema */
5499 selectSourceSchema("pg_catalog");
5501 appendPQExpBuffer(query, "SELECT oid, srvname, "
5502 "(%s srvowner) AS rolname, "
5503 "srvfdw, srvtype, srvversion, srvacl,"
5504 "array_to_string(ARRAY("
5505 " SELECT option_name || ' ' || quote_literal(option_value) "
5506 " FROM pg_options_to_table(srvoptions)), ', ') AS srvoptions "
5507 "FROM pg_foreign_server",
5508 username_subquery);
5510 res = PQexec(g_conn, query->data);
5511 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5513 ntups = PQntuples(res);
5514 *numForeignServers = ntups;
5516 srvinfo = (ForeignServerInfo *) malloc(ntups * sizeof(ForeignServerInfo));
5518 i_oid = PQfnumber(res, "oid");
5519 i_srvname = PQfnumber(res, "srvname");
5520 i_rolname = PQfnumber(res, "rolname");
5521 i_srvfdw = PQfnumber(res, "srvfdw");
5522 i_srvtype = PQfnumber(res, "srvtype");
5523 i_srvversion = PQfnumber(res, "srvversion");
5524 i_srvacl = PQfnumber(res, "srvacl");
5525 i_srvoptions = PQfnumber(res, "srvoptions");
5527 for (i = 0; i < ntups; i++)
5529 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
5530 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5531 AssignDumpId(&srvinfo[i].dobj);
5532 srvinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_srvname));
5533 srvinfo[i].dobj.namespace = NULL;
5534 srvinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
5535 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
5536 srvinfo[i].srvtype = strdup(PQgetvalue(res, i, i_srvtype));
5537 srvinfo[i].srvversion = strdup(PQgetvalue(res, i, i_srvversion));
5538 srvinfo[i].srvoptions = strdup(PQgetvalue(res, i, i_srvoptions));
5539 srvinfo[i].srvacl = strdup(PQgetvalue(res, i, i_srvacl));
5541 /* Decide whether we want to dump it */
5542 selectDumpableObject(&(srvinfo[i].dobj));
5545 PQclear(res);
5547 destroyPQExpBuffer(query);
5549 return srvinfo;
5553 * dumpComment --
5555 * This routine is used to dump any comments associated with the
5556 * object handed to this routine. The routine takes a constant character
5557 * string for the target part of the comment-creation command, plus
5558 * the namespace and owner of the object (for labeling the ArchiveEntry),
5559 * plus catalog ID and subid which are the lookup key for pg_description,
5560 * plus the dump ID for the object (for setting a dependency).
5561 * If a matching pg_description entry is found, it is dumped.
5563 * Note: although this routine takes a dumpId for dependency purposes,
5564 * that purpose is just to mark the dependency in the emitted dump file
5565 * for possible future use by pg_restore. We do NOT use it for determining
5566 * ordering of the comment in the dump file, because this routine is called
5567 * after dependency sorting occurs. This routine should be called just after
5568 * calling ArchiveEntry() for the specified object.
5570 static void
5571 dumpComment(Archive *fout, const char *target,
5572 const char *namespace, const char *owner,
5573 CatalogId catalogId, int subid, DumpId dumpId)
5575 CommentItem *comments;
5576 int ncomments;
5578 /* Comments are SCHEMA not data */
5579 if (dataOnly)
5580 return;
5582 /* Search for comments associated with catalogId, using table */
5583 ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
5584 &comments);
5586 /* Is there one matching the subid? */
5587 while (ncomments > 0)
5589 if (comments->objsubid == subid)
5590 break;
5591 comments++;
5592 ncomments--;
5595 /* If a comment exists, build COMMENT ON statement */
5596 if (ncomments > 0)
5598 PQExpBuffer query = createPQExpBuffer();
5600 appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
5601 appendStringLiteralAH(query, comments->descr, fout);
5602 appendPQExpBuffer(query, ";\n");
5605 * We mark comments as SECTION_NONE because they really belong in the
5606 * same section as their parent, whether that is pre-data or
5607 * post-data.
5609 ArchiveEntry(fout, nilCatalogId, createDumpId(),
5610 target, namespace, NULL, owner,
5611 false, "COMMENT", SECTION_NONE,
5612 query->data, "", NULL,
5613 &(dumpId), 1,
5614 NULL, NULL);
5616 destroyPQExpBuffer(query);
5621 * dumpTableComment --
5623 * As above, but dump comments for both the specified table (or view)
5624 * and its columns.
5626 static void
5627 dumpTableComment(Archive *fout, TableInfo *tbinfo,
5628 const char *reltypename)
5630 CommentItem *comments;
5631 int ncomments;
5632 PQExpBuffer query;
5633 PQExpBuffer target;
5635 /* Comments are SCHEMA not data */
5636 if (dataOnly)
5637 return;
5639 /* Search for comments associated with relation, using table */
5640 ncomments = findComments(fout,
5641 tbinfo->dobj.catId.tableoid,
5642 tbinfo->dobj.catId.oid,
5643 &comments);
5645 /* If comments exist, build COMMENT ON statements */
5646 if (ncomments <= 0)
5647 return;
5649 query = createPQExpBuffer();
5650 target = createPQExpBuffer();
5652 while (ncomments > 0)
5654 const char *descr = comments->descr;
5655 int objsubid = comments->objsubid;
5657 if (objsubid == 0)
5659 resetPQExpBuffer(target);
5660 appendPQExpBuffer(target, "%s %s", reltypename,
5661 fmtId(tbinfo->dobj.name));
5663 resetPQExpBuffer(query);
5664 appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
5665 appendStringLiteralAH(query, descr, fout);
5666 appendPQExpBuffer(query, ";\n");
5668 ArchiveEntry(fout, nilCatalogId, createDumpId(),
5669 target->data,
5670 tbinfo->dobj.namespace->dobj.name,
5671 NULL, tbinfo->rolname,
5672 false, "COMMENT", SECTION_NONE,
5673 query->data, "", NULL,
5674 &(tbinfo->dobj.dumpId), 1,
5675 NULL, NULL);
5677 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
5679 resetPQExpBuffer(target);
5680 appendPQExpBuffer(target, "COLUMN %s.",
5681 fmtId(tbinfo->dobj.name));
5682 appendPQExpBuffer(target, "%s",
5683 fmtId(tbinfo->attnames[objsubid - 1]));
5685 resetPQExpBuffer(query);
5686 appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
5687 appendStringLiteralAH(query, descr, fout);
5688 appendPQExpBuffer(query, ";\n");
5690 ArchiveEntry(fout, nilCatalogId, createDumpId(),
5691 target->data,
5692 tbinfo->dobj.namespace->dobj.name,
5693 NULL, tbinfo->rolname,
5694 false, "COMMENT", SECTION_NONE,
5695 query->data, "", NULL,
5696 &(tbinfo->dobj.dumpId), 1,
5697 NULL, NULL);
5700 comments++;
5701 ncomments--;
5704 destroyPQExpBuffer(query);
5705 destroyPQExpBuffer(target);
5709 * findComments --
5711 * Find the comment(s), if any, associated with the given object. All the
5712 * objsubid values associated with the given classoid/objoid are found with
5713 * one search.
5715 static int
5716 findComments(Archive *fout, Oid classoid, Oid objoid,
5717 CommentItem **items)
5719 /* static storage for table of comments */
5720 static CommentItem *comments = NULL;
5721 static int ncomments = -1;
5723 CommentItem *middle = NULL;
5724 CommentItem *low;
5725 CommentItem *high;
5726 int nmatch;
5728 /* Get comments if we didn't already */
5729 if (ncomments < 0)
5730 ncomments = collectComments(fout, &comments);
5733 * Pre-7.2, pg_description does not contain classoid, so collectComments
5734 * just stores a zero. If there's a collision on object OID, well, you
5735 * get duplicate comments.
5737 if (fout->remoteVersion < 70200)
5738 classoid = 0;
5741 * Do binary search to find some item matching the object.
5743 low = &comments[0];
5744 high = &comments[ncomments - 1];
5745 while (low <= high)
5747 middle = low + (high - low) / 2;
5749 if (classoid < middle->classoid)
5750 high = middle - 1;
5751 else if (classoid > middle->classoid)
5752 low = middle + 1;
5753 else if (objoid < middle->objoid)
5754 high = middle - 1;
5755 else if (objoid > middle->objoid)
5756 low = middle + 1;
5757 else
5758 break; /* found a match */
5761 if (low > high) /* no matches */
5763 *items = NULL;
5764 return 0;
5768 * Now determine how many items match the object. The search loop
5769 * invariant still holds: only items between low and high inclusive could
5770 * match.
5772 nmatch = 1;
5773 while (middle > low)
5775 if (classoid != middle[-1].classoid ||
5776 objoid != middle[-1].objoid)
5777 break;
5778 middle--;
5779 nmatch++;
5782 *items = middle;
5784 middle += nmatch;
5785 while (middle <= high)
5787 if (classoid != middle->classoid ||
5788 objoid != middle->objoid)
5789 break;
5790 middle++;
5791 nmatch++;
5794 return nmatch;
5798 * collectComments --
5800 * Construct a table of all comments available for database objects.
5801 * We used to do per-object queries for the comments, but it's much faster
5802 * to pull them all over at once, and on most databases the memory cost
5803 * isn't high.
5805 * The table is sorted by classoid/objid/objsubid for speed in lookup.
5807 static int
5808 collectComments(Archive *fout, CommentItem **items)
5810 PGresult *res;
5811 PQExpBuffer query;
5812 int i_description;
5813 int i_classoid;
5814 int i_objoid;
5815 int i_objsubid;
5816 int ntups;
5817 int i;
5818 CommentItem *comments;
5821 * Note we do NOT change source schema here; preserve the caller's
5822 * setting, instead.
5825 query = createPQExpBuffer();
5827 if (fout->remoteVersion >= 70300)
5829 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
5830 "FROM pg_catalog.pg_description "
5831 "ORDER BY classoid, objoid, objsubid");
5833 else if (fout->remoteVersion >= 70200)
5835 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
5836 "FROM pg_description "
5837 "ORDER BY classoid, objoid, objsubid");
5839 else
5841 /* Note: this will fail to find attribute comments in pre-7.2... */
5842 appendPQExpBuffer(query, "SELECT description, 0 AS classoid, objoid, 0 AS objsubid "
5843 "FROM pg_description "
5844 "ORDER BY objoid");
5847 res = PQexec(g_conn, query->data);
5848 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5850 /* Construct lookup table containing OIDs in numeric form */
5852 i_description = PQfnumber(res, "description");
5853 i_classoid = PQfnumber(res, "classoid");
5854 i_objoid = PQfnumber(res, "objoid");
5855 i_objsubid = PQfnumber(res, "objsubid");
5857 ntups = PQntuples(res);
5859 comments = (CommentItem *) malloc(ntups * sizeof(CommentItem));
5861 for (i = 0; i < ntups; i++)
5863 comments[i].descr = PQgetvalue(res, i, i_description);
5864 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
5865 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
5866 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
5869 /* Do NOT free the PGresult since we are keeping pointers into it */
5870 destroyPQExpBuffer(query);
5872 *items = comments;
5873 return ntups;
5877 * dumpDumpableObject
5879 * This routine and its subsidiaries are responsible for creating
5880 * ArchiveEntries (TOC objects) for each object to be dumped.
5882 static void
5883 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
5885 switch (dobj->objType)
5887 case DO_NAMESPACE:
5888 dumpNamespace(fout, (NamespaceInfo *) dobj);
5889 break;
5890 case DO_TYPE:
5891 dumpType(fout, (TypeInfo *) dobj);
5892 break;
5893 case DO_SHELL_TYPE:
5894 dumpShellType(fout, (ShellTypeInfo *) dobj);
5895 break;
5896 case DO_FUNC:
5897 dumpFunc(fout, (FuncInfo *) dobj);
5898 break;
5899 case DO_AGG:
5900 dumpAgg(fout, (AggInfo *) dobj);
5901 break;
5902 case DO_OPERATOR:
5903 dumpOpr(fout, (OprInfo *) dobj);
5904 break;
5905 case DO_OPCLASS:
5906 dumpOpclass(fout, (OpclassInfo *) dobj);
5907 break;
5908 case DO_OPFAMILY:
5909 dumpOpfamily(fout, (OpfamilyInfo *) dobj);
5910 break;
5911 case DO_CONVERSION:
5912 dumpConversion(fout, (ConvInfo *) dobj);
5913 break;
5914 case DO_TABLE:
5915 dumpTable(fout, (TableInfo *) dobj);
5916 break;
5917 case DO_ATTRDEF:
5918 dumpAttrDef(fout, (AttrDefInfo *) dobj);
5919 break;
5920 case DO_INDEX:
5921 dumpIndex(fout, (IndxInfo *) dobj);
5922 break;
5923 case DO_RULE:
5924 dumpRule(fout, (RuleInfo *) dobj);
5925 break;
5926 case DO_TRIGGER:
5927 dumpTrigger(fout, (TriggerInfo *) dobj);
5928 break;
5929 case DO_CONSTRAINT:
5930 dumpConstraint(fout, (ConstraintInfo *) dobj);
5931 break;
5932 case DO_FK_CONSTRAINT:
5933 dumpConstraint(fout, (ConstraintInfo *) dobj);
5934 break;
5935 case DO_PROCLANG:
5936 dumpProcLang(fout, (ProcLangInfo *) dobj);
5937 break;
5938 case DO_CAST:
5939 dumpCast(fout, (CastInfo *) dobj);
5940 break;
5941 case DO_TABLE_DATA:
5942 dumpTableData(fout, (TableDataInfo *) dobj);
5943 break;
5944 case DO_DUMMY_TYPE:
5945 /* table rowtypes and array types are never dumped separately */
5946 break;
5947 case DO_TSPARSER:
5948 dumpTSParser(fout, (TSParserInfo *) dobj);
5949 break;
5950 case DO_TSDICT:
5951 dumpTSDictionary(fout, (TSDictInfo *) dobj);
5952 break;
5953 case DO_TSTEMPLATE:
5954 dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
5955 break;
5956 case DO_TSCONFIG:
5957 dumpTSConfig(fout, (TSConfigInfo *) dobj);
5958 break;
5959 case DO_FDW:
5960 dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
5961 break;
5962 case DO_FOREIGN_SERVER:
5963 dumpForeignServer(fout, (ForeignServerInfo *) dobj);
5964 break;
5965 case DO_BLOBS:
5966 ArchiveEntry(fout, dobj->catId, dobj->dumpId,
5967 dobj->name, NULL, NULL, "",
5968 false, "BLOBS", SECTION_DATA,
5969 "", "", NULL,
5970 dobj->dependencies, dobj->nDeps,
5971 dumpBlobs, NULL);
5972 break;
5973 case DO_BLOB_COMMENTS:
5974 ArchiveEntry(fout, dobj->catId, dobj->dumpId,
5975 dobj->name, NULL, NULL, "",
5976 false, "BLOB COMMENTS", SECTION_DATA,
5977 "", "", NULL,
5978 dobj->dependencies, dobj->nDeps,
5979 dumpBlobComments, NULL);
5980 break;
5985 * dumpNamespace
5986 * writes out to fout the queries to recreate a user-defined namespace
5988 static void
5989 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
5991 PQExpBuffer q;
5992 PQExpBuffer delq;
5993 char *qnspname;
5995 /* Skip if not to be dumped */
5996 if (!nspinfo->dobj.dump || dataOnly)
5997 return;
5999 /* don't dump dummy namespace from pre-7.3 source */
6000 if (strlen(nspinfo->dobj.name) == 0)
6001 return;
6003 q = createPQExpBuffer();
6004 delq = createPQExpBuffer();
6006 qnspname = strdup(fmtId(nspinfo->dobj.name));
6008 appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
6010 appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
6012 ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
6013 nspinfo->dobj.name,
6014 NULL, NULL,
6015 nspinfo->rolname,
6016 false, "SCHEMA", SECTION_PRE_DATA,
6017 q->data, delq->data, NULL,
6018 nspinfo->dobj.dependencies, nspinfo->dobj.nDeps,
6019 NULL, NULL);
6021 /* Dump Schema Comments */
6022 resetPQExpBuffer(q);
6023 appendPQExpBuffer(q, "SCHEMA %s", qnspname);
6024 dumpComment(fout, q->data,
6025 NULL, nspinfo->rolname,
6026 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
6028 dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
6029 qnspname, NULL, nspinfo->dobj.name, NULL,
6030 nspinfo->rolname, nspinfo->nspacl);
6032 free(qnspname);
6034 destroyPQExpBuffer(q);
6035 destroyPQExpBuffer(delq);
6039 * dumpType
6040 * writes out to fout the queries to recreate a user-defined type
6042 static void
6043 dumpType(Archive *fout, TypeInfo *tinfo)
6045 /* Skip if not to be dumped */
6046 if (!tinfo->dobj.dump || dataOnly)
6047 return;
6049 /* Dump out in proper style */
6050 if (tinfo->typtype == TYPTYPE_BASE)
6051 dumpBaseType(fout, tinfo);
6052 else if (tinfo->typtype == TYPTYPE_DOMAIN)
6053 dumpDomain(fout, tinfo);
6054 else if (tinfo->typtype == TYPTYPE_COMPOSITE)
6055 dumpCompositeType(fout, tinfo);
6056 else if (tinfo->typtype == TYPTYPE_ENUM)
6057 dumpEnumType(fout, tinfo);
6061 * dumpEnumType
6062 * writes out to fout the queries to recreate a user-defined enum type
6064 static void
6065 dumpEnumType(Archive *fout, TypeInfo *tinfo)
6067 PQExpBuffer q = createPQExpBuffer();
6068 PQExpBuffer delq = createPQExpBuffer();
6069 PQExpBuffer query = createPQExpBuffer();
6070 PGresult *res;
6071 int num,
6073 char *label;
6075 /* Set proper schema search path so regproc references list correctly */
6076 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6078 appendPQExpBuffer(query, "SELECT enumlabel FROM pg_catalog.pg_enum "
6079 "WHERE enumtypid = '%u'"
6080 "ORDER BY oid",
6081 tinfo->dobj.catId.oid);
6083 res = PQexec(g_conn, query->data);
6084 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6086 num = PQntuples(res);
6087 /* should be at least 1 value */
6088 if (num == 0)
6090 write_msg(NULL, "no label definitions found for enum ID %u\n", tinfo->dobj.catId.oid);
6091 exit_nicely();
6095 * DROP must be fully qualified in case same name appears in pg_catalog.
6096 * CASCADE shouldn't be required here as for normal types since the I/O
6097 * functions are generic and do not get dropped.
6099 appendPQExpBuffer(delq, "DROP TYPE %s.",
6100 fmtId(tinfo->dobj.namespace->dobj.name));
6101 appendPQExpBuffer(delq, "%s;\n",
6102 fmtId(tinfo->dobj.name));
6103 appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (\n",
6104 fmtId(tinfo->dobj.name));
6105 for (i = 0; i < num; i++)
6107 label = PQgetvalue(res, i, 0);
6108 if (i > 0)
6109 appendPQExpBuffer(q, ",\n");
6110 appendPQExpBuffer(q, " ");
6111 appendStringLiteralAH(q, label, fout);
6113 appendPQExpBuffer(q, "\n);\n");
6115 ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
6116 tinfo->dobj.name,
6117 tinfo->dobj.namespace->dobj.name,
6118 NULL,
6119 tinfo->rolname, false,
6120 "TYPE", SECTION_PRE_DATA,
6121 q->data, delq->data, NULL,
6122 tinfo->dobj.dependencies, tinfo->dobj.nDeps,
6123 NULL, NULL);
6125 /* Dump Type Comments */
6126 resetPQExpBuffer(q);
6128 appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->dobj.name));
6129 dumpComment(fout, q->data,
6130 tinfo->dobj.namespace->dobj.name, tinfo->rolname,
6131 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
6133 PQclear(res);
6134 destroyPQExpBuffer(q);
6135 destroyPQExpBuffer(delq);
6136 destroyPQExpBuffer(query);
6140 * dumpBaseType
6141 * writes out to fout the queries to recreate a user-defined base type
6143 static void
6144 dumpBaseType(Archive *fout, TypeInfo *tinfo)
6146 PQExpBuffer q = createPQExpBuffer();
6147 PQExpBuffer delq = createPQExpBuffer();
6148 PQExpBuffer query = createPQExpBuffer();
6149 PGresult *res;
6150 int ntups;
6151 char *typlen;
6152 char *typinput;
6153 char *typoutput;
6154 char *typreceive;
6155 char *typsend;
6156 char *typmodin;
6157 char *typmodout;
6158 char *typanalyze;
6159 Oid typinputoid;
6160 Oid typoutputoid;
6161 Oid typreceiveoid;
6162 Oid typsendoid;
6163 Oid typmodinoid;
6164 Oid typmodoutoid;
6165 Oid typanalyzeoid;
6166 char *typcategory;
6167 char *typispreferred;
6168 char *typdelim;
6169 char *typbyval;
6170 char *typalign;
6171 char *typstorage;
6172 char *typdefault;
6173 bool typdefault_is_literal = false;
6175 /* Set proper schema search path so regproc references list correctly */
6176 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6178 /* Fetch type-specific details */
6179 if (fout->remoteVersion >= 80400)
6181 appendPQExpBuffer(query, "SELECT typlen, "
6182 "typinput, typoutput, typreceive, typsend, "
6183 "typmodin, typmodout, typanalyze, "
6184 "typinput::pg_catalog.oid AS typinputoid, "
6185 "typoutput::pg_catalog.oid AS typoutputoid, "
6186 "typreceive::pg_catalog.oid AS typreceiveoid, "
6187 "typsend::pg_catalog.oid AS typsendoid, "
6188 "typmodin::pg_catalog.oid AS typmodinoid, "
6189 "typmodout::pg_catalog.oid AS typmodoutoid, "
6190 "typanalyze::pg_catalog.oid AS typanalyzeoid, "
6191 "typcategory, typispreferred, "
6192 "typdelim, typbyval, typalign, typstorage, "
6193 "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
6194 "FROM pg_catalog.pg_type "
6195 "WHERE oid = '%u'::pg_catalog.oid",
6196 tinfo->dobj.catId.oid);
6198 else if (fout->remoteVersion >= 80300)
6200 /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
6201 appendPQExpBuffer(query, "SELECT typlen, "
6202 "typinput, typoutput, typreceive, typsend, "
6203 "typmodin, typmodout, typanalyze, "
6204 "typinput::pg_catalog.oid AS typinputoid, "
6205 "typoutput::pg_catalog.oid AS typoutputoid, "
6206 "typreceive::pg_catalog.oid AS typreceiveoid, "
6207 "typsend::pg_catalog.oid AS typsendoid, "
6208 "typmodin::pg_catalog.oid AS typmodinoid, "
6209 "typmodout::pg_catalog.oid AS typmodoutoid, "
6210 "typanalyze::pg_catalog.oid AS typanalyzeoid, "
6211 "'U' AS typcategory, false AS typispreferred, "
6212 "typdelim, typbyval, typalign, typstorage, "
6213 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6214 "FROM pg_catalog.pg_type "
6215 "WHERE oid = '%u'::pg_catalog.oid",
6216 tinfo->dobj.catId.oid);
6218 else if (fout->remoteVersion >= 80000)
6220 appendPQExpBuffer(query, "SELECT typlen, "
6221 "typinput, typoutput, typreceive, typsend, "
6222 "'-' AS typmodin, '-' AS typmodout, "
6223 "typanalyze, "
6224 "typinput::pg_catalog.oid AS typinputoid, "
6225 "typoutput::pg_catalog.oid AS typoutputoid, "
6226 "typreceive::pg_catalog.oid AS typreceiveoid, "
6227 "typsend::pg_catalog.oid AS typsendoid, "
6228 "0 AS typmodinoid, 0 AS typmodoutoid, "
6229 "typanalyze::pg_catalog.oid AS typanalyzeoid, "
6230 "'U' AS typcategory, false AS typispreferred, "
6231 "typdelim, typbyval, typalign, typstorage, "
6232 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6233 "FROM pg_catalog.pg_type "
6234 "WHERE oid = '%u'::pg_catalog.oid",
6235 tinfo->dobj.catId.oid);
6237 else if (fout->remoteVersion >= 70400)
6239 appendPQExpBuffer(query, "SELECT typlen, "
6240 "typinput, typoutput, typreceive, typsend, "
6241 "'-' AS typmodin, '-' AS typmodout, "
6242 "'-' AS typanalyze, "
6243 "typinput::pg_catalog.oid AS typinputoid, "
6244 "typoutput::pg_catalog.oid AS typoutputoid, "
6245 "typreceive::pg_catalog.oid AS typreceiveoid, "
6246 "typsend::pg_catalog.oid AS typsendoid, "
6247 "0 AS typmodinoid, 0 AS typmodoutoid, "
6248 "0 AS typanalyzeoid, "
6249 "'U' AS typcategory, false AS typispreferred, "
6250 "typdelim, typbyval, typalign, typstorage, "
6251 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6252 "FROM pg_catalog.pg_type "
6253 "WHERE oid = '%u'::pg_catalog.oid",
6254 tinfo->dobj.catId.oid);
6256 else if (fout->remoteVersion >= 70300)
6258 appendPQExpBuffer(query, "SELECT typlen, "
6259 "typinput, typoutput, "
6260 "'-' AS typreceive, '-' AS typsend, "
6261 "'-' AS typmodin, '-' AS typmodout, "
6262 "'-' AS typanalyze, "
6263 "typinput::pg_catalog.oid AS typinputoid, "
6264 "typoutput::pg_catalog.oid AS typoutputoid, "
6265 "0 AS typreceiveoid, 0 AS typsendoid, "
6266 "0 AS typmodinoid, 0 AS typmodoutoid, "
6267 "0 AS typanalyzeoid, "
6268 "'U' AS typcategory, false AS typispreferred, "
6269 "typdelim, typbyval, typalign, typstorage, "
6270 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6271 "FROM pg_catalog.pg_type "
6272 "WHERE oid = '%u'::pg_catalog.oid",
6273 tinfo->dobj.catId.oid);
6275 else if (fout->remoteVersion >= 70200)
6278 * Note: although pre-7.3 catalogs contain typreceive and typsend,
6279 * ignore them because they are not right.
6281 appendPQExpBuffer(query, "SELECT typlen, "
6282 "typinput, typoutput, "
6283 "'-' AS typreceive, '-' AS typsend, "
6284 "'-' AS typmodin, '-' AS typmodout, "
6285 "'-' AS typanalyze, "
6286 "typinput::oid AS typinputoid, "
6287 "typoutput::oid AS typoutputoid, "
6288 "0 AS typreceiveoid, 0 AS typsendoid, "
6289 "0 AS typmodinoid, 0 AS typmodoutoid, "
6290 "0 AS typanalyzeoid, "
6291 "'U' AS typcategory, false AS typispreferred, "
6292 "typdelim, typbyval, typalign, typstorage, "
6293 "NULL AS typdefaultbin, typdefault "
6294 "FROM pg_type "
6295 "WHERE oid = '%u'::oid",
6296 tinfo->dobj.catId.oid);
6298 else if (fout->remoteVersion >= 70100)
6301 * Ignore pre-7.2 typdefault; the field exists but has an unusable
6302 * representation.
6304 appendPQExpBuffer(query, "SELECT typlen, "
6305 "typinput, typoutput, "
6306 "'-' AS typreceive, '-' AS typsend, "
6307 "'-' AS typmodin, '-' AS typmodout, "
6308 "'-' AS typanalyze, "
6309 "typinput::oid AS typinputoid, "
6310 "typoutput::oid AS typoutputoid, "
6311 "0 AS typreceiveoid, 0 AS typsendoid, "
6312 "0 AS typmodinoid, 0 AS typmodoutoid, "
6313 "0 AS typanalyzeoid, "
6314 "'U' AS typcategory, false AS typispreferred, "
6315 "typdelim, typbyval, typalign, typstorage, "
6316 "NULL AS typdefaultbin, NULL AS typdefault "
6317 "FROM pg_type "
6318 "WHERE oid = '%u'::oid",
6319 tinfo->dobj.catId.oid);
6321 else
6323 appendPQExpBuffer(query, "SELECT typlen, "
6324 "typinput, typoutput, "
6325 "'-' AS typreceive, '-' AS typsend, "
6326 "'-' AS typmodin, '-' AS typmodout, "
6327 "'-' AS typanalyze, "
6328 "typinput::oid AS typinputoid, "
6329 "typoutput::oid AS typoutputoid, "
6330 "0 AS typreceiveoid, 0 AS typsendoid, "
6331 "0 AS typmodinoid, 0 AS typmodoutoid, "
6332 "0 AS typanalyzeoid, "
6333 "'U' AS typcategory, false AS typispreferred, "
6334 "typdelim, typbyval, typalign, "
6335 "'p'::char AS typstorage, "
6336 "NULL AS typdefaultbin, NULL AS typdefault "
6337 "FROM pg_type "
6338 "WHERE oid = '%u'::oid",
6339 tinfo->dobj.catId.oid);
6342 res = PQexec(g_conn, query->data);
6343 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6345 /* Expecting a single result only */
6346 ntups = PQntuples(res);
6347 if (ntups != 1)
6349 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
6350 "query returned %d rows instead of one: %s\n",
6351 ntups),
6352 ntups, query->data);
6353 exit_nicely();
6356 typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
6357 typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
6358 typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
6359 typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
6360 typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
6361 typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
6362 typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
6363 typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
6364 typinputoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typinputoid")));
6365 typoutputoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typoutputoid")));
6366 typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
6367 typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
6368 typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
6369 typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
6370 typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
6371 typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
6372 typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
6373 typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
6374 typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
6375 typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
6376 typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
6377 if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
6378 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
6379 else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
6381 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
6382 typdefault_is_literal = true; /* it needs quotes */
6384 else
6385 typdefault = NULL;
6388 * DROP must be fully qualified in case same name appears in pg_catalog.
6389 * The reason we include CASCADE is that the circular dependency between
6390 * the type and its I/O functions makes it impossible to drop the type any
6391 * other way.
6393 appendPQExpBuffer(delq, "DROP TYPE %s.",
6394 fmtId(tinfo->dobj.namespace->dobj.name));
6395 appendPQExpBuffer(delq, "%s CASCADE;\n",
6396 fmtId(tinfo->dobj.name));
6398 appendPQExpBuffer(q,
6399 "CREATE TYPE %s (\n"
6400 " INTERNALLENGTH = %s",
6401 fmtId(tinfo->dobj.name),
6402 (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
6404 if (fout->remoteVersion >= 70300)
6406 /* regproc result is correctly quoted as of 7.3 */
6407 appendPQExpBuffer(q, ",\n INPUT = %s", typinput);
6408 appendPQExpBuffer(q, ",\n OUTPUT = %s", typoutput);
6409 if (OidIsValid(typreceiveoid))
6410 appendPQExpBuffer(q, ",\n RECEIVE = %s", typreceive);
6411 if (OidIsValid(typsendoid))
6412 appendPQExpBuffer(q, ",\n SEND = %s", typsend);
6413 if (OidIsValid(typmodinoid))
6414 appendPQExpBuffer(q, ",\n TYPMOD_IN = %s", typmodin);
6415 if (OidIsValid(typmodoutoid))
6416 appendPQExpBuffer(q, ",\n TYPMOD_OUT = %s", typmodout);
6417 if (OidIsValid(typanalyzeoid))
6418 appendPQExpBuffer(q, ",\n ANALYZE = %s", typanalyze);
6420 else
6422 /* regproc delivers an unquoted name before 7.3 */
6423 /* cannot combine these because fmtId uses static result area */
6424 appendPQExpBuffer(q, ",\n INPUT = %s", fmtId(typinput));
6425 appendPQExpBuffer(q, ",\n OUTPUT = %s", fmtId(typoutput));
6426 /* receive/send/typmodin/typmodout/analyze need not be printed */
6429 if (typdefault != NULL)
6431 appendPQExpBuffer(q, ",\n DEFAULT = ");
6432 if (typdefault_is_literal)
6433 appendStringLiteralAH(q, typdefault, fout);
6434 else
6435 appendPQExpBufferStr(q, typdefault);
6438 if (OidIsValid(tinfo->typelem))
6440 char *elemType;
6442 /* reselect schema in case changed by function dump */
6443 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6444 elemType = getFormattedTypeName(tinfo->typelem, zeroAsOpaque);
6445 appendPQExpBuffer(q, ",\n ELEMENT = %s", elemType);
6446 free(elemType);
6449 if (strcmp(typcategory, "U") != 0)
6451 appendPQExpBuffer(q, ",\n CATEGORY = ");
6452 appendStringLiteralAH(q, typcategory, fout);
6455 if (strcmp(typispreferred, "t") == 0)
6456 appendPQExpBuffer(q, ",\n PREFERRED = true");
6458 if (typdelim && strcmp(typdelim, ",") != 0)
6460 appendPQExpBuffer(q, ",\n DELIMITER = ");
6461 appendStringLiteralAH(q, typdelim, fout);
6464 if (strcmp(typalign, "c") == 0)
6465 appendPQExpBuffer(q, ",\n ALIGNMENT = char");
6466 else if (strcmp(typalign, "s") == 0)
6467 appendPQExpBuffer(q, ",\n ALIGNMENT = int2");
6468 else if (strcmp(typalign, "i") == 0)
6469 appendPQExpBuffer(q, ",\n ALIGNMENT = int4");
6470 else if (strcmp(typalign, "d") == 0)
6471 appendPQExpBuffer(q, ",\n ALIGNMENT = double");
6473 if (strcmp(typstorage, "p") == 0)
6474 appendPQExpBuffer(q, ",\n STORAGE = plain");
6475 else if (strcmp(typstorage, "e") == 0)
6476 appendPQExpBuffer(q, ",\n STORAGE = external");
6477 else if (strcmp(typstorage, "x") == 0)
6478 appendPQExpBuffer(q, ",\n STORAGE = extended");
6479 else if (strcmp(typstorage, "m") == 0)
6480 appendPQExpBuffer(q, ",\n STORAGE = main");
6482 if (strcmp(typbyval, "t") == 0)
6483 appendPQExpBuffer(q, ",\n PASSEDBYVALUE");
6485 appendPQExpBuffer(q, "\n);\n");
6487 ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
6488 tinfo->dobj.name,
6489 tinfo->dobj.namespace->dobj.name,
6490 NULL,
6491 tinfo->rolname, false,
6492 "TYPE", SECTION_PRE_DATA,
6493 q->data, delq->data, NULL,
6494 tinfo->dobj.dependencies, tinfo->dobj.nDeps,
6495 NULL, NULL);
6497 /* Dump Type Comments */
6498 resetPQExpBuffer(q);
6500 appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->dobj.name));
6501 dumpComment(fout, q->data,
6502 tinfo->dobj.namespace->dobj.name, tinfo->rolname,
6503 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
6505 PQclear(res);
6506 destroyPQExpBuffer(q);
6507 destroyPQExpBuffer(delq);
6508 destroyPQExpBuffer(query);
6512 * dumpDomain
6513 * writes out to fout the queries to recreate a user-defined domain
6515 static void
6516 dumpDomain(Archive *fout, TypeInfo *tinfo)
6518 PQExpBuffer q = createPQExpBuffer();
6519 PQExpBuffer delq = createPQExpBuffer();
6520 PQExpBuffer query = createPQExpBuffer();
6521 PGresult *res;
6522 int ntups;
6523 int i;
6524 char *typnotnull;
6525 char *typdefn;
6526 char *typdefault;
6527 bool typdefault_is_literal = false;
6529 /* Set proper schema search path so type references list correctly */
6530 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6532 /* Fetch domain specific details */
6533 /* We assume here that remoteVersion must be at least 70300 */
6534 appendPQExpBuffer(query, "SELECT typnotnull, "
6535 "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
6536 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6537 "FROM pg_catalog.pg_type "
6538 "WHERE oid = '%u'::pg_catalog.oid",
6539 tinfo->dobj.catId.oid);
6541 res = PQexec(g_conn, query->data);
6542 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6544 /* Expecting a single result only */
6545 ntups = PQntuples(res);
6546 if (ntups != 1)
6548 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
6549 "query returned %d rows instead of one: %s\n",
6550 ntups),
6551 ntups, query->data);
6552 exit_nicely();
6555 typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
6556 typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
6557 if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
6558 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
6559 else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
6561 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
6562 typdefault_is_literal = true; /* it needs quotes */
6564 else
6565 typdefault = NULL;
6567 appendPQExpBuffer(q,
6568 "CREATE DOMAIN %s AS %s",
6569 fmtId(tinfo->dobj.name),
6570 typdefn);
6572 if (typnotnull[0] == 't')
6573 appendPQExpBuffer(q, " NOT NULL");
6575 if (typdefault != NULL)
6577 appendPQExpBuffer(q, " DEFAULT ");
6578 if (typdefault_is_literal)
6579 appendStringLiteralAH(q, typdefault, fout);
6580 else
6581 appendPQExpBufferStr(q, typdefault);
6584 PQclear(res);
6587 * Add any CHECK constraints for the domain
6589 for (i = 0; i < tinfo->nDomChecks; i++)
6591 ConstraintInfo *domcheck = &(tinfo->domChecks[i]);
6593 if (!domcheck->separate)
6594 appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
6595 fmtId(domcheck->dobj.name), domcheck->condef);
6598 appendPQExpBuffer(q, ";\n");
6601 * DROP must be fully qualified in case same name appears in pg_catalog
6603 appendPQExpBuffer(delq, "DROP DOMAIN %s.",
6604 fmtId(tinfo->dobj.namespace->dobj.name));
6605 appendPQExpBuffer(delq, "%s;\n",
6606 fmtId(tinfo->dobj.name));
6608 ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
6609 tinfo->dobj.name,
6610 tinfo->dobj.namespace->dobj.name,
6611 NULL,
6612 tinfo->rolname, false,
6613 "DOMAIN", SECTION_PRE_DATA,
6614 q->data, delq->data, NULL,
6615 tinfo->dobj.dependencies, tinfo->dobj.nDeps,
6616 NULL, NULL);
6618 /* Dump Domain Comments */
6619 resetPQExpBuffer(q);
6621 appendPQExpBuffer(q, "DOMAIN %s", fmtId(tinfo->dobj.name));
6622 dumpComment(fout, q->data,
6623 tinfo->dobj.namespace->dobj.name, tinfo->rolname,
6624 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
6626 destroyPQExpBuffer(q);
6627 destroyPQExpBuffer(delq);
6628 destroyPQExpBuffer(query);
6632 * dumpCompositeType
6633 * writes out to fout the queries to recreate a user-defined stand-alone
6634 * composite type
6636 static void
6637 dumpCompositeType(Archive *fout, TypeInfo *tinfo)
6639 PQExpBuffer q = createPQExpBuffer();
6640 PQExpBuffer delq = createPQExpBuffer();
6641 PQExpBuffer query = createPQExpBuffer();
6642 PGresult *res;
6643 int ntups;
6644 int i_attname;
6645 int i_atttypdefn;
6646 int i;
6648 /* Set proper schema search path so type references list correctly */
6649 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6651 /* Fetch type specific details */
6652 /* We assume here that remoteVersion must be at least 70300 */
6654 appendPQExpBuffer(query, "SELECT a.attname, "
6655 "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn "
6656 "FROM pg_catalog.pg_type t, pg_catalog.pg_attribute a "
6657 "WHERE t.oid = '%u'::pg_catalog.oid "
6658 "AND a.attrelid = t.typrelid "
6659 "AND NOT a.attisdropped "
6660 "ORDER BY a.attnum ",
6661 tinfo->dobj.catId.oid);
6663 res = PQexec(g_conn, query->data);
6664 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6666 /* Expecting at least a single result */
6667 ntups = PQntuples(res);
6668 if (ntups < 1)
6670 write_msg(NULL, "query returned no rows: %s\n", query->data);
6671 exit_nicely();
6674 i_attname = PQfnumber(res, "attname");
6675 i_atttypdefn = PQfnumber(res, "atttypdefn");
6677 appendPQExpBuffer(q, "CREATE TYPE %s AS (",
6678 fmtId(tinfo->dobj.name));
6680 for (i = 0; i < ntups; i++)
6682 char *attname;
6683 char *atttypdefn;
6685 attname = PQgetvalue(res, i, i_attname);
6686 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
6688 appendPQExpBuffer(q, "\n\t%s %s", fmtId(attname), atttypdefn);
6689 if (i < ntups - 1)
6690 appendPQExpBuffer(q, ",");
6692 appendPQExpBuffer(q, "\n);\n");
6695 * DROP must be fully qualified in case same name appears in pg_catalog
6697 appendPQExpBuffer(delq, "DROP TYPE %s.",
6698 fmtId(tinfo->dobj.namespace->dobj.name));
6699 appendPQExpBuffer(delq, "%s;\n",
6700 fmtId(tinfo->dobj.name));
6702 ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
6703 tinfo->dobj.name,
6704 tinfo->dobj.namespace->dobj.name,
6705 NULL,
6706 tinfo->rolname, false,
6707 "TYPE", SECTION_PRE_DATA,
6708 q->data, delq->data, NULL,
6709 tinfo->dobj.dependencies, tinfo->dobj.nDeps,
6710 NULL, NULL);
6713 /* Dump Type Comments */
6714 resetPQExpBuffer(q);
6716 appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->dobj.name));
6717 dumpComment(fout, q->data,
6718 tinfo->dobj.namespace->dobj.name, tinfo->rolname,
6719 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
6721 PQclear(res);
6722 destroyPQExpBuffer(q);
6723 destroyPQExpBuffer(delq);
6724 destroyPQExpBuffer(query);
6728 * dumpShellType
6729 * writes out to fout the queries to create a shell type
6731 * We dump a shell definition in advance of the I/O functions for the type.
6733 static void
6734 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
6736 PQExpBuffer q;
6738 /* Skip if not to be dumped */
6739 if (!stinfo->dobj.dump || dataOnly)
6740 return;
6742 q = createPQExpBuffer();
6745 * Note the lack of a DROP command for the shell type; any required DROP
6746 * is driven off the base type entry, instead. This interacts with
6747 * _printTocEntry()'s use of the presence of a DROP command to decide
6748 * whether an entry needs an ALTER OWNER command. We don't want to alter
6749 * the shell type's owner immediately on creation; that should happen only
6750 * after it's filled in, otherwise the backend complains.
6753 appendPQExpBuffer(q, "CREATE TYPE %s;\n",
6754 fmtId(stinfo->dobj.name));
6756 ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
6757 stinfo->dobj.name,
6758 stinfo->dobj.namespace->dobj.name,
6759 NULL,
6760 stinfo->baseType->rolname, false,
6761 "SHELL TYPE", SECTION_PRE_DATA,
6762 q->data, "", NULL,
6763 stinfo->dobj.dependencies, stinfo->dobj.nDeps,
6764 NULL, NULL);
6766 destroyPQExpBuffer(q);
6770 * Determine whether we want to dump definitions for procedural languages.
6771 * Since the languages themselves don't have schemas, we can't rely on
6772 * the normal schema-based selection mechanism. We choose to dump them
6773 * whenever neither --schema nor --table was given. (Before 8.1, we used
6774 * the dump flag of the PL's call handler function, but in 8.1 this will
6775 * probably always be false since call handlers are created in pg_catalog.)
6777 * For some backwards compatibility with the older behavior, we forcibly
6778 * dump a PL if its handler function (and validator if any) are in a
6779 * dumpable namespace. That case is not checked here.
6781 static bool
6782 shouldDumpProcLangs(void)
6784 if (!include_everything)
6785 return false;
6786 /* And they're schema not data */
6787 if (dataOnly)
6788 return false;
6789 return true;
6793 * dumpProcLang
6794 * writes out to fout the queries to recreate a user-defined
6795 * procedural language
6797 static void
6798 dumpProcLang(Archive *fout, ProcLangInfo *plang)
6800 PQExpBuffer defqry;
6801 PQExpBuffer delqry;
6802 bool useParams;
6803 char *qlanname;
6804 char *lanschema;
6805 FuncInfo *funcInfo;
6806 FuncInfo *validatorInfo = NULL;
6808 if (dataOnly)
6809 return;
6812 * Try to find the support function(s). It is not an error if we don't
6813 * find them --- if the functions are in the pg_catalog schema, as is
6814 * standard in 8.1 and up, then we won't have loaded them. (In this case
6815 * we will emit a parameterless CREATE LANGUAGE command, which will
6816 * require PL template knowledge in the backend to reload.)
6819 funcInfo = findFuncByOid(plang->lanplcallfoid);
6820 if (funcInfo != NULL && !funcInfo->dobj.dump)
6821 funcInfo = NULL; /* treat not-dumped same as not-found */
6823 if (OidIsValid(plang->lanvalidator))
6825 validatorInfo = findFuncByOid(plang->lanvalidator);
6826 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
6827 validatorInfo = NULL;
6831 * If the functions are dumpable then emit a traditional CREATE LANGUAGE
6832 * with parameters. Otherwise, dump only if shouldDumpProcLangs() says to
6833 * dump it.
6835 useParams = (funcInfo != NULL &&
6836 (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
6838 if (!useParams && !shouldDumpProcLangs())
6839 return;
6841 defqry = createPQExpBuffer();
6842 delqry = createPQExpBuffer();
6844 qlanname = strdup(fmtId(plang->dobj.name));
6847 * If dumping a HANDLER clause, treat the language as being in the handler
6848 * function's schema; this avoids cluttering the HANDLER clause. Otherwise
6849 * it doesn't really have a schema.
6851 if (useParams)
6852 lanschema = funcInfo->dobj.namespace->dobj.name;
6853 else
6854 lanschema = NULL;
6856 appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
6857 qlanname);
6859 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
6860 (useParams && plang->lanpltrusted) ? "TRUSTED " : "",
6861 qlanname);
6862 if (useParams)
6864 appendPQExpBuffer(defqry, " HANDLER %s",
6865 fmtId(funcInfo->dobj.name));
6866 if (OidIsValid(plang->lanvalidator))
6868 appendPQExpBuffer(defqry, " VALIDATOR ");
6869 /* Cope with possibility that validator is in different schema */
6870 if (validatorInfo->dobj.namespace != funcInfo->dobj.namespace)
6871 appendPQExpBuffer(defqry, "%s.",
6872 fmtId(validatorInfo->dobj.namespace->dobj.name));
6873 appendPQExpBuffer(defqry, "%s",
6874 fmtId(validatorInfo->dobj.name));
6877 appendPQExpBuffer(defqry, ";\n");
6879 ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
6880 plang->dobj.name,
6881 lanschema, NULL, plang->lanowner,
6882 false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
6883 defqry->data, delqry->data, NULL,
6884 plang->dobj.dependencies, plang->dobj.nDeps,
6885 NULL, NULL);
6887 /* Dump Proc Lang Comments */
6888 resetPQExpBuffer(defqry);
6889 appendPQExpBuffer(defqry, "LANGUAGE %s", qlanname);
6890 dumpComment(fout, defqry->data,
6891 NULL, "",
6892 plang->dobj.catId, 0, plang->dobj.dumpId);
6894 if (plang->lanpltrusted)
6895 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
6896 qlanname, NULL, plang->dobj.name,
6897 lanschema,
6898 plang->lanowner, plang->lanacl);
6900 free(qlanname);
6902 destroyPQExpBuffer(defqry);
6903 destroyPQExpBuffer(delqry);
6907 * format_function_arguments: generate function name and argument list
6909 * This is used when we can rely on pg_get_function_arguments to format
6910 * the argument list.
6912 static char *
6913 format_function_arguments(FuncInfo *finfo, char *funcargs)
6915 PQExpBufferData fn;
6917 initPQExpBuffer(&fn);
6918 appendPQExpBuffer(&fn, "%s(%s)", fmtId(finfo->dobj.name), funcargs);
6919 return fn.data;
6923 * format_function_arguments_old: generate function name and argument list
6925 * The argument type names are qualified if needed. The function name
6926 * is never qualified.
6928 * This is used only with pre-8.4 servers, so we aren't expecting to see
6929 * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
6931 * Any or all of allargtypes, argmodes, argnames may be NULL.
6933 static char *
6934 format_function_arguments_old(FuncInfo *finfo, int nallargs,
6935 char **allargtypes,
6936 char **argmodes,
6937 char **argnames)
6939 PQExpBufferData fn;
6940 int j;
6942 initPQExpBuffer(&fn);
6943 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
6944 for (j = 0; j < nallargs; j++)
6946 Oid typid;
6947 char *typname;
6948 const char *argmode;
6949 const char *argname;
6951 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
6952 typname = getFormattedTypeName(typid, zeroAsOpaque);
6954 if (argmodes)
6956 switch (argmodes[j][0])
6958 case PROARGMODE_IN:
6959 argmode = "";
6960 break;
6961 case PROARGMODE_OUT:
6962 argmode = "OUT ";
6963 break;
6964 case PROARGMODE_INOUT:
6965 argmode = "INOUT ";
6966 break;
6967 default:
6968 write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
6969 argmode = "";
6970 break;
6973 else
6974 argmode = "";
6976 argname = argnames ? argnames[j] : (char *) NULL;
6977 if (argname && argname[0] == '\0')
6978 argname = NULL;
6980 appendPQExpBuffer(&fn, "%s%s%s%s%s",
6981 (j > 0) ? ", " : "",
6982 argmode,
6983 argname ? fmtId(argname) : "",
6984 argname ? " " : "",
6985 typname);
6986 free(typname);
6988 appendPQExpBuffer(&fn, ")");
6989 return fn.data;
6993 * format_function_signature: generate function name and argument list
6995 * This is like format_function_arguments_old except that only a minimal
6996 * list of input argument types is generated; this is sufficient to
6997 * reference the function, but not to define it.
6999 * If honor_quotes is false then the function name is never quoted.
7000 * This is appropriate for use in TOC tags, but not in SQL commands.
7002 static char *
7003 format_function_signature(FuncInfo *finfo, bool honor_quotes)
7005 PQExpBufferData fn;
7006 int j;
7008 initPQExpBuffer(&fn);
7009 if (honor_quotes)
7010 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
7011 else
7012 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
7013 for (j = 0; j < finfo->nargs; j++)
7015 char *typname;
7017 typname = getFormattedTypeName(finfo->argtypes[j], zeroAsOpaque);
7019 appendPQExpBuffer(&fn, "%s%s",
7020 (j > 0) ? ", " : "",
7021 typname);
7022 free(typname);
7024 appendPQExpBuffer(&fn, ")");
7025 return fn.data;
7030 * dumpFunc:
7031 * dump out one function
7033 static void
7034 dumpFunc(Archive *fout, FuncInfo *finfo)
7036 PQExpBuffer query;
7037 PQExpBuffer q;
7038 PQExpBuffer delqry;
7039 PQExpBuffer asPart;
7040 PGresult *res;
7041 char *funcsig; /* identity signature */
7042 char *funcfullsig; /* full signature */
7043 char *funcsig_tag;
7044 int ntups;
7045 char *proretset;
7046 char *prosrc;
7047 char *probin;
7048 char *funcargs;
7049 char *funciargs;
7050 char *funcresult;
7051 char *proallargtypes;
7052 char *proargmodes;
7053 char *proargnames;
7054 char *proiswindow;
7055 char *provolatile;
7056 char *proisstrict;
7057 char *prosecdef;
7058 char *proconfig;
7059 char *procost;
7060 char *prorows;
7061 char *lanname;
7062 char *rettypename;
7063 int nallargs;
7064 char **allargtypes = NULL;
7065 char **argmodes = NULL;
7066 char **argnames = NULL;
7067 char **configitems = NULL;
7068 int nconfigitems = 0;
7069 int i;
7071 /* Skip if not to be dumped */
7072 if (!finfo->dobj.dump || dataOnly)
7073 return;
7075 query = createPQExpBuffer();
7076 q = createPQExpBuffer();
7077 delqry = createPQExpBuffer();
7078 asPart = createPQExpBuffer();
7080 /* Set proper schema search path so type references list correctly */
7081 selectSourceSchema(finfo->dobj.namespace->dobj.name);
7083 /* Fetch function-specific details */
7084 if (g_fout->remoteVersion >= 80400)
7087 * In 8.4 and up we rely on pg_get_function_arguments and
7088 * pg_get_function_result instead of examining proallargtypes etc.
7090 appendPQExpBuffer(query,
7091 "SELECT proretset, prosrc, probin, "
7092 "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
7093 "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
7094 "pg_catalog.pg_get_function_result(oid) AS funcresult, "
7095 "proiswindow, provolatile, proisstrict, prosecdef, "
7096 "proconfig, procost, prorows, "
7097 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7098 "FROM pg_catalog.pg_proc "
7099 "WHERE oid = '%u'::pg_catalog.oid",
7100 finfo->dobj.catId.oid);
7102 else if (g_fout->remoteVersion >= 80300)
7104 appendPQExpBuffer(query,
7105 "SELECT proretset, prosrc, probin, "
7106 "proallargtypes, proargmodes, proargnames, "
7107 "false AS proiswindow, "
7108 "provolatile, proisstrict, prosecdef, "
7109 "proconfig, procost, prorows, "
7110 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7111 "FROM pg_catalog.pg_proc "
7112 "WHERE oid = '%u'::pg_catalog.oid",
7113 finfo->dobj.catId.oid);
7115 else if (g_fout->remoteVersion >= 80100)
7117 appendPQExpBuffer(query,
7118 "SELECT proretset, prosrc, probin, "
7119 "proallargtypes, proargmodes, proargnames, "
7120 "false AS proiswindow, "
7121 "provolatile, proisstrict, prosecdef, "
7122 "null AS proconfig, 0 AS procost, 0 AS prorows, "
7123 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7124 "FROM pg_catalog.pg_proc "
7125 "WHERE oid = '%u'::pg_catalog.oid",
7126 finfo->dobj.catId.oid);
7128 else if (g_fout->remoteVersion >= 80000)
7130 appendPQExpBuffer(query,
7131 "SELECT proretset, prosrc, probin, "
7132 "null AS proallargtypes, "
7133 "null AS proargmodes, "
7134 "proargnames, "
7135 "false AS proiswindow, "
7136 "provolatile, proisstrict, prosecdef, "
7137 "null AS proconfig, 0 AS procost, 0 AS prorows, "
7138 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7139 "FROM pg_catalog.pg_proc "
7140 "WHERE oid = '%u'::pg_catalog.oid",
7141 finfo->dobj.catId.oid);
7143 else if (g_fout->remoteVersion >= 70300)
7145 appendPQExpBuffer(query,
7146 "SELECT proretset, prosrc, probin, "
7147 "null AS proallargtypes, "
7148 "null AS proargmodes, "
7149 "null AS proargnames, "
7150 "false AS proiswindow, "
7151 "provolatile, proisstrict, prosecdef, "
7152 "null AS proconfig, 0 AS procost, 0 AS prorows, "
7153 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7154 "FROM pg_catalog.pg_proc "
7155 "WHERE oid = '%u'::pg_catalog.oid",
7156 finfo->dobj.catId.oid);
7158 else if (g_fout->remoteVersion >= 70100)
7160 appendPQExpBuffer(query,
7161 "SELECT proretset, prosrc, probin, "
7162 "null AS proallargtypes, "
7163 "null AS proargmodes, "
7164 "null AS proargnames, "
7165 "false AS proiswindow, "
7166 "case when proiscachable then 'i' else 'v' end AS provolatile, "
7167 "proisstrict, "
7168 "false AS prosecdef, "
7169 "null AS proconfig, 0 AS procost, 0 AS prorows, "
7170 "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
7171 "FROM pg_proc "
7172 "WHERE oid = '%u'::oid",
7173 finfo->dobj.catId.oid);
7175 else
7177 appendPQExpBuffer(query,
7178 "SELECT proretset, prosrc, probin, "
7179 "null AS proallargtypes, "
7180 "null AS proargmodes, "
7181 "null AS proargnames, "
7182 "false AS proiswindow, "
7183 "CASE WHEN proiscachable THEN 'i' ELSE 'v' END AS provolatile, "
7184 "false AS proisstrict, "
7185 "false AS prosecdef, "
7186 "NULL AS proconfig, 0 AS procost, 0 AS prorows, "
7187 "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
7188 "FROM pg_proc "
7189 "WHERE oid = '%u'::oid",
7190 finfo->dobj.catId.oid);
7193 res = PQexec(g_conn, query->data);
7194 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7196 /* Expecting a single result only */
7197 ntups = PQntuples(res);
7198 if (ntups != 1)
7200 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
7201 "query returned %d rows instead of one: %s\n",
7202 ntups),
7203 ntups, query->data);
7204 exit_nicely();
7207 proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
7208 prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
7209 probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
7210 if (g_fout->remoteVersion >= 80400)
7212 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
7213 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
7214 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
7215 proallargtypes = proargmodes = proargnames = NULL;
7217 else
7219 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
7220 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
7221 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
7222 funcargs = funciargs = funcresult = NULL;
7224 proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow"));
7225 provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
7226 proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
7227 prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
7228 proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
7229 procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
7230 prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
7231 lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
7234 * See backend/commands/functioncmds.c for details of how the 'AS' clause
7235 * is used. In 8.4 and up, an unused probin is NULL (here ""); previous
7236 * versions would set it to "-". There are no known cases in which prosrc
7237 * is unused, so the tests below for "-" are probably useless.
7239 if (probin[0] != '\0' && strcmp(probin, "-") != 0)
7241 appendPQExpBuffer(asPart, "AS ");
7242 appendStringLiteralAH(asPart, probin, fout);
7243 if (strcmp(prosrc, "-") != 0)
7245 appendPQExpBuffer(asPart, ", ");
7248 * where we have bin, use dollar quoting if allowed and src
7249 * contains quote or backslash; else use regular quoting.
7251 if (disable_dollar_quoting ||
7252 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
7253 appendStringLiteralAH(asPart, prosrc, fout);
7254 else
7255 appendStringLiteralDQ(asPart, prosrc, NULL);
7258 else
7260 if (strcmp(prosrc, "-") != 0)
7262 appendPQExpBuffer(asPart, "AS ");
7263 /* with no bin, dollar quote src unconditionally if allowed */
7264 if (disable_dollar_quoting)
7265 appendStringLiteralAH(asPart, prosrc, fout);
7266 else
7267 appendStringLiteralDQ(asPart, prosrc, NULL);
7271 nallargs = finfo->nargs; /* unless we learn different from allargs */
7273 if (proallargtypes && *proallargtypes)
7275 int nitems = 0;
7277 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
7278 nitems < finfo->nargs)
7280 write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
7281 if (allargtypes)
7282 free(allargtypes);
7283 allargtypes = NULL;
7285 else
7286 nallargs = nitems;
7289 if (proargmodes && *proargmodes)
7291 int nitems = 0;
7293 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
7294 nitems != nallargs)
7296 write_msg(NULL, "WARNING: could not parse proargmodes array\n");
7297 if (argmodes)
7298 free(argmodes);
7299 argmodes = NULL;
7303 if (proargnames && *proargnames)
7305 int nitems = 0;
7307 if (!parsePGArray(proargnames, &argnames, &nitems) ||
7308 nitems != nallargs)
7310 write_msg(NULL, "WARNING: could not parse proargnames array\n");
7311 if (argnames)
7312 free(argnames);
7313 argnames = NULL;
7317 if (proconfig && *proconfig)
7319 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
7321 write_msg(NULL, "WARNING: could not parse proconfig array\n");
7322 if (configitems)
7323 free(configitems);
7324 configitems = NULL;
7325 nconfigitems = 0;
7329 if (funcargs)
7331 /* 8.4 or later; we rely on server-side code for most of the work */
7332 funcfullsig = format_function_arguments(finfo, funcargs);
7333 funcsig = format_function_arguments(finfo, funciargs);
7335 else
7337 /* pre-8.4, do it ourselves */
7338 funcsig = format_function_arguments_old(finfo, nallargs, allargtypes,
7339 argmodes, argnames);
7340 funcfullsig = funcsig;
7343 funcsig_tag = format_function_signature(finfo, false);
7346 * DROP must be fully qualified in case same name appears in pg_catalog
7348 appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
7349 fmtId(finfo->dobj.namespace->dobj.name),
7350 funcsig);
7352 appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig);
7353 if (funcresult)
7354 appendPQExpBuffer(q, "RETURNS %s", funcresult);
7355 else
7357 rettypename = getFormattedTypeName(finfo->prorettype, zeroAsOpaque);
7358 appendPQExpBuffer(q, "RETURNS %s%s",
7359 (proretset[0] == 't') ? "SETOF " : "",
7360 rettypename);
7361 free(rettypename);
7364 appendPQExpBuffer(q, "\n LANGUAGE %s", fmtId(lanname));
7366 if (proiswindow[0] == 't')
7367 appendPQExpBuffer(q, " WINDOW");
7369 if (provolatile[0] != PROVOLATILE_VOLATILE)
7371 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
7372 appendPQExpBuffer(q, " IMMUTABLE");
7373 else if (provolatile[0] == PROVOLATILE_STABLE)
7374 appendPQExpBuffer(q, " STABLE");
7375 else if (provolatile[0] != PROVOLATILE_VOLATILE)
7377 write_msg(NULL, "unrecognized provolatile value for function \"%s\"\n",
7378 finfo->dobj.name);
7379 exit_nicely();
7383 if (proisstrict[0] == 't')
7384 appendPQExpBuffer(q, " STRICT");
7386 if (prosecdef[0] == 't')
7387 appendPQExpBuffer(q, " SECURITY DEFINER");
7390 * COST and ROWS are emitted only if present and not default, so as not to
7391 * break backwards-compatibility of the dump without need. Keep this code
7392 * in sync with the defaults in functioncmds.c.
7394 if (strcmp(procost, "0") != 0)
7396 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
7398 /* default cost is 1 */
7399 if (strcmp(procost, "1") != 0)
7400 appendPQExpBuffer(q, " COST %s", procost);
7402 else
7404 /* default cost is 100 */
7405 if (strcmp(procost, "100") != 0)
7406 appendPQExpBuffer(q, " COST %s", procost);
7409 if (proretset[0] == 't' &&
7410 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
7411 appendPQExpBuffer(q, " ROWS %s", prorows);
7413 for (i = 0; i < nconfigitems; i++)
7415 /* we feel free to scribble on configitems[] here */
7416 char *configitem = configitems[i];
7417 char *pos;
7419 pos = strchr(configitem, '=');
7420 if (pos == NULL)
7421 continue;
7422 *pos++ = '\0';
7423 appendPQExpBuffer(q, "\n SET %s TO ", fmtId(configitem));
7426 * Some GUC variable names are 'LIST' type and hence must not be
7427 * quoted.
7429 if (pg_strcasecmp(configitem, "DateStyle") == 0
7430 || pg_strcasecmp(configitem, "search_path") == 0)
7431 appendPQExpBuffer(q, "%s", pos);
7432 else
7433 appendStringLiteralAH(q, pos, fout);
7436 appendPQExpBuffer(q, "\n %s;\n", asPart->data);
7438 ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
7439 funcsig_tag,
7440 finfo->dobj.namespace->dobj.name,
7441 NULL,
7442 finfo->rolname, false,
7443 "FUNCTION", SECTION_PRE_DATA,
7444 q->data, delqry->data, NULL,
7445 finfo->dobj.dependencies, finfo->dobj.nDeps,
7446 NULL, NULL);
7448 /* Dump Function Comments */
7449 resetPQExpBuffer(q);
7450 appendPQExpBuffer(q, "FUNCTION %s", funcsig);
7451 dumpComment(fout, q->data,
7452 finfo->dobj.namespace->dobj.name, finfo->rolname,
7453 finfo->dobj.catId, 0, finfo->dobj.dumpId);
7455 dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
7456 funcsig, NULL, funcsig_tag,
7457 finfo->dobj.namespace->dobj.name,
7458 finfo->rolname, finfo->proacl);
7460 PQclear(res);
7462 destroyPQExpBuffer(query);
7463 destroyPQExpBuffer(q);
7464 destroyPQExpBuffer(delqry);
7465 destroyPQExpBuffer(asPart);
7466 free(funcsig);
7467 free(funcsig_tag);
7468 if (allargtypes)
7469 free(allargtypes);
7470 if (argmodes)
7471 free(argmodes);
7472 if (argnames)
7473 free(argnames);
7474 if (configitems)
7475 free(configitems);
7480 * Dump a user-defined cast
7482 static void
7483 dumpCast(Archive *fout, CastInfo *cast)
7485 PQExpBuffer defqry;
7486 PQExpBuffer delqry;
7487 PQExpBuffer castsig;
7488 FuncInfo *funcInfo = NULL;
7489 TypeInfo *sourceInfo;
7490 TypeInfo *targetInfo;
7492 if (dataOnly)
7493 return;
7495 if (OidIsValid(cast->castfunc))
7497 funcInfo = findFuncByOid(cast->castfunc);
7498 if (funcInfo == NULL)
7499 return;
7503 * As per discussion we dump casts if one or more of the underlying
7504 * objects (the conversion function and the two data types) are not
7505 * builtin AND if all of the non-builtin objects are included in the dump.
7506 * Builtin meaning, the namespace name does not start with "pg_".
7508 sourceInfo = findTypeByOid(cast->castsource);
7509 targetInfo = findTypeByOid(cast->casttarget);
7511 if (sourceInfo == NULL || targetInfo == NULL)
7512 return;
7515 * Skip this cast if all objects are from pg_
7517 if ((funcInfo == NULL ||
7518 strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
7519 strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) == 0 &&
7520 strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) == 0)
7521 return;
7524 * Skip cast if function isn't from pg_ and is not to be dumped.
7526 if (funcInfo &&
7527 strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
7528 !funcInfo->dobj.dump)
7529 return;
7532 * Same for the source type
7534 if (strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
7535 !sourceInfo->dobj.dump)
7536 return;
7539 * and the target type.
7541 if (strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
7542 !targetInfo->dobj.dump)
7543 return;
7545 /* Make sure we are in proper schema (needed for getFormattedTypeName) */
7546 selectSourceSchema("pg_catalog");
7548 defqry = createPQExpBuffer();
7549 delqry = createPQExpBuffer();
7550 castsig = createPQExpBuffer();
7552 appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
7553 getFormattedTypeName(cast->castsource, zeroAsNone),
7554 getFormattedTypeName(cast->casttarget, zeroAsNone));
7556 appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
7557 getFormattedTypeName(cast->castsource, zeroAsNone),
7558 getFormattedTypeName(cast->casttarget, zeroAsNone));
7560 switch (cast->castmethod)
7562 case COERCION_METHOD_BINARY:
7563 appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
7564 break;
7565 case COERCION_METHOD_INOUT:
7566 appendPQExpBuffer(defqry, "WITH INOUT");
7567 break;
7568 case COERCION_METHOD_FUNCTION:
7571 * Always qualify the function name, in case it is not in
7572 * pg_catalog schema (format_function_signature won't qualify it).
7574 appendPQExpBuffer(defqry, "WITH FUNCTION %s.",
7575 fmtId(funcInfo->dobj.namespace->dobj.name));
7576 appendPQExpBuffer(defqry, "%s",
7577 format_function_signature(funcInfo, true));
7578 break;
7579 default:
7580 write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
7583 if (cast->castcontext == 'a')
7584 appendPQExpBuffer(defqry, " AS ASSIGNMENT");
7585 else if (cast->castcontext == 'i')
7586 appendPQExpBuffer(defqry, " AS IMPLICIT");
7587 appendPQExpBuffer(defqry, ";\n");
7589 appendPQExpBuffer(castsig, "CAST (%s AS %s)",
7590 getFormattedTypeName(cast->castsource, zeroAsNone),
7591 getFormattedTypeName(cast->casttarget, zeroAsNone));
7593 ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
7594 castsig->data,
7595 "pg_catalog", NULL, "",
7596 false, "CAST", SECTION_PRE_DATA,
7597 defqry->data, delqry->data, NULL,
7598 cast->dobj.dependencies, cast->dobj.nDeps,
7599 NULL, NULL);
7601 /* Dump Cast Comments */
7602 resetPQExpBuffer(defqry);
7603 appendPQExpBuffer(defqry, "CAST (%s AS %s)",
7604 getFormattedTypeName(cast->castsource, zeroAsNone),
7605 getFormattedTypeName(cast->casttarget, zeroAsNone));
7606 dumpComment(fout, defqry->data,
7607 NULL, "",
7608 cast->dobj.catId, 0, cast->dobj.dumpId);
7610 destroyPQExpBuffer(defqry);
7611 destroyPQExpBuffer(delqry);
7612 destroyPQExpBuffer(castsig);
7616 * dumpOpr
7617 * write out a single operator definition
7619 static void
7620 dumpOpr(Archive *fout, OprInfo *oprinfo)
7622 PQExpBuffer query;
7623 PQExpBuffer q;
7624 PQExpBuffer delq;
7625 PQExpBuffer oprid;
7626 PQExpBuffer details;
7627 const char *name;
7628 PGresult *res;
7629 int ntups;
7630 int i_oprkind;
7631 int i_oprcode;
7632 int i_oprleft;
7633 int i_oprright;
7634 int i_oprcom;
7635 int i_oprnegate;
7636 int i_oprrest;
7637 int i_oprjoin;
7638 int i_oprcanmerge;
7639 int i_oprcanhash;
7640 char *oprkind;
7641 char *oprcode;
7642 char *oprleft;
7643 char *oprright;
7644 char *oprcom;
7645 char *oprnegate;
7646 char *oprrest;
7647 char *oprjoin;
7648 char *oprcanmerge;
7649 char *oprcanhash;
7651 /* Skip if not to be dumped */
7652 if (!oprinfo->dobj.dump || dataOnly)
7653 return;
7656 * some operators are invalid because they were the result of user
7657 * defining operators before commutators exist
7659 if (!OidIsValid(oprinfo->oprcode))
7660 return;
7662 query = createPQExpBuffer();
7663 q = createPQExpBuffer();
7664 delq = createPQExpBuffer();
7665 oprid = createPQExpBuffer();
7666 details = createPQExpBuffer();
7668 /* Make sure we are in proper schema so regoperator works correctly */
7669 selectSourceSchema(oprinfo->dobj.namespace->dobj.name);
7671 if (g_fout->remoteVersion >= 80300)
7673 appendPQExpBuffer(query, "SELECT oprkind, "
7674 "oprcode::pg_catalog.regprocedure, "
7675 "oprleft::pg_catalog.regtype, "
7676 "oprright::pg_catalog.regtype, "
7677 "oprcom::pg_catalog.regoperator, "
7678 "oprnegate::pg_catalog.regoperator, "
7679 "oprrest::pg_catalog.regprocedure, "
7680 "oprjoin::pg_catalog.regprocedure, "
7681 "oprcanmerge, oprcanhash "
7682 "FROM pg_catalog.pg_operator "
7683 "WHERE oid = '%u'::pg_catalog.oid",
7684 oprinfo->dobj.catId.oid);
7686 else if (g_fout->remoteVersion >= 70300)
7688 appendPQExpBuffer(query, "SELECT oprkind, "
7689 "oprcode::pg_catalog.regprocedure, "
7690 "oprleft::pg_catalog.regtype, "
7691 "oprright::pg_catalog.regtype, "
7692 "oprcom::pg_catalog.regoperator, "
7693 "oprnegate::pg_catalog.regoperator, "
7694 "oprrest::pg_catalog.regprocedure, "
7695 "oprjoin::pg_catalog.regprocedure, "
7696 "(oprlsortop != 0) AS oprcanmerge, "
7697 "oprcanhash "
7698 "FROM pg_catalog.pg_operator "
7699 "WHERE oid = '%u'::pg_catalog.oid",
7700 oprinfo->dobj.catId.oid);
7702 else if (g_fout->remoteVersion >= 70100)
7704 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
7705 "CASE WHEN oprleft = 0 THEN '-' "
7706 "ELSE format_type(oprleft, NULL) END AS oprleft, "
7707 "CASE WHEN oprright = 0 THEN '-' "
7708 "ELSE format_type(oprright, NULL) END AS oprright, "
7709 "oprcom, oprnegate, oprrest, oprjoin, "
7710 "(oprlsortop != 0) AS oprcanmerge, "
7711 "oprcanhash "
7712 "FROM pg_operator "
7713 "WHERE oid = '%u'::oid",
7714 oprinfo->dobj.catId.oid);
7716 else
7718 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
7719 "CASE WHEN oprleft = 0 THEN '-'::name "
7720 "ELSE (SELECT typname FROM pg_type WHERE oid = oprleft) END AS oprleft, "
7721 "CASE WHEN oprright = 0 THEN '-'::name "
7722 "ELSE (SELECT typname FROM pg_type WHERE oid = oprright) END AS oprright, "
7723 "oprcom, oprnegate, oprrest, oprjoin, "
7724 "(oprlsortop != 0) AS oprcanmerge, "
7725 "oprcanhash "
7726 "FROM pg_operator "
7727 "WHERE oid = '%u'::oid",
7728 oprinfo->dobj.catId.oid);
7731 res = PQexec(g_conn, query->data);
7732 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7734 /* Expecting a single result only */
7735 ntups = PQntuples(res);
7736 if (ntups != 1)
7738 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
7739 "query returned %d rows instead of one: %s\n",
7740 ntups),
7741 ntups, query->data);
7742 exit_nicely();
7745 i_oprkind = PQfnumber(res, "oprkind");
7746 i_oprcode = PQfnumber(res, "oprcode");
7747 i_oprleft = PQfnumber(res, "oprleft");
7748 i_oprright = PQfnumber(res, "oprright");
7749 i_oprcom = PQfnumber(res, "oprcom");
7750 i_oprnegate = PQfnumber(res, "oprnegate");
7751 i_oprrest = PQfnumber(res, "oprrest");
7752 i_oprjoin = PQfnumber(res, "oprjoin");
7753 i_oprcanmerge = PQfnumber(res, "oprcanmerge");
7754 i_oprcanhash = PQfnumber(res, "oprcanhash");
7756 oprkind = PQgetvalue(res, 0, i_oprkind);
7757 oprcode = PQgetvalue(res, 0, i_oprcode);
7758 oprleft = PQgetvalue(res, 0, i_oprleft);
7759 oprright = PQgetvalue(res, 0, i_oprright);
7760 oprcom = PQgetvalue(res, 0, i_oprcom);
7761 oprnegate = PQgetvalue(res, 0, i_oprnegate);
7762 oprrest = PQgetvalue(res, 0, i_oprrest);
7763 oprjoin = PQgetvalue(res, 0, i_oprjoin);
7764 oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
7765 oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
7767 appendPQExpBuffer(details, " PROCEDURE = %s",
7768 convertRegProcReference(oprcode));
7770 appendPQExpBuffer(oprid, "%s (",
7771 oprinfo->dobj.name);
7774 * right unary means there's a left arg and left unary means there's a
7775 * right arg
7777 if (strcmp(oprkind, "r") == 0 ||
7778 strcmp(oprkind, "b") == 0)
7780 if (g_fout->remoteVersion >= 70100)
7781 name = oprleft;
7782 else
7783 name = fmtId(oprleft);
7784 appendPQExpBuffer(details, ",\n LEFTARG = %s", name);
7785 appendPQExpBuffer(oprid, "%s", name);
7787 else
7788 appendPQExpBuffer(oprid, "NONE");
7790 if (strcmp(oprkind, "l") == 0 ||
7791 strcmp(oprkind, "b") == 0)
7793 if (g_fout->remoteVersion >= 70100)
7794 name = oprright;
7795 else
7796 name = fmtId(oprright);
7797 appendPQExpBuffer(details, ",\n RIGHTARG = %s", name);
7798 appendPQExpBuffer(oprid, ", %s)", name);
7800 else
7801 appendPQExpBuffer(oprid, ", NONE)");
7803 name = convertOperatorReference(oprcom);
7804 if (name)
7805 appendPQExpBuffer(details, ",\n COMMUTATOR = %s", name);
7807 name = convertOperatorReference(oprnegate);
7808 if (name)
7809 appendPQExpBuffer(details, ",\n NEGATOR = %s", name);
7811 if (strcmp(oprcanmerge, "t") == 0)
7812 appendPQExpBuffer(details, ",\n MERGES");
7814 if (strcmp(oprcanhash, "t") == 0)
7815 appendPQExpBuffer(details, ",\n HASHES");
7817 name = convertRegProcReference(oprrest);
7818 if (name)
7819 appendPQExpBuffer(details, ",\n RESTRICT = %s", name);
7821 name = convertRegProcReference(oprjoin);
7822 if (name)
7823 appendPQExpBuffer(details, ",\n JOIN = %s", name);
7826 * DROP must be fully qualified in case same name appears in pg_catalog
7828 appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
7829 fmtId(oprinfo->dobj.namespace->dobj.name),
7830 oprid->data);
7832 appendPQExpBuffer(q, "CREATE OPERATOR %s (\n%s\n);\n",
7833 oprinfo->dobj.name, details->data);
7835 ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
7836 oprinfo->dobj.name,
7837 oprinfo->dobj.namespace->dobj.name,
7838 NULL,
7839 oprinfo->rolname,
7840 false, "OPERATOR", SECTION_PRE_DATA,
7841 q->data, delq->data, NULL,
7842 oprinfo->dobj.dependencies, oprinfo->dobj.nDeps,
7843 NULL, NULL);
7845 /* Dump Operator Comments */
7846 resetPQExpBuffer(q);
7847 appendPQExpBuffer(q, "OPERATOR %s", oprid->data);
7848 dumpComment(fout, q->data,
7849 oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
7850 oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
7852 PQclear(res);
7854 destroyPQExpBuffer(query);
7855 destroyPQExpBuffer(q);
7856 destroyPQExpBuffer(delq);
7857 destroyPQExpBuffer(oprid);
7858 destroyPQExpBuffer(details);
7862 * Convert a function reference obtained from pg_operator
7864 * Returns what to print, or NULL if function references is InvalidOid
7866 * In 7.3 the input is a REGPROCEDURE display; we have to strip the
7867 * argument-types part. In prior versions, the input is a REGPROC display.
7869 static const char *
7870 convertRegProcReference(const char *proc)
7872 /* In all cases "-" means a null reference */
7873 if (strcmp(proc, "-") == 0)
7874 return NULL;
7876 if (g_fout->remoteVersion >= 70300)
7878 char *name;
7879 char *paren;
7880 bool inquote;
7882 name = strdup(proc);
7883 /* find non-double-quoted left paren */
7884 inquote = false;
7885 for (paren = name; *paren; paren++)
7887 if (*paren == '(' && !inquote)
7889 *paren = '\0';
7890 break;
7892 if (*paren == '"')
7893 inquote = !inquote;
7895 return name;
7898 /* REGPROC before 7.3 does not quote its result */
7899 return fmtId(proc);
7903 * Convert an operator cross-reference obtained from pg_operator
7905 * Returns what to print, or NULL to print nothing
7907 * In 7.3 and up the input is a REGOPERATOR display; we have to strip the
7908 * argument-types part, and add OPERATOR() decoration if the name is
7909 * schema-qualified. In older versions, the input is just a numeric OID,
7910 * which we search our operator list for.
7912 static const char *
7913 convertOperatorReference(const char *opr)
7915 OprInfo *oprInfo;
7917 /* In all cases "0" means a null reference */
7918 if (strcmp(opr, "0") == 0)
7919 return NULL;
7921 if (g_fout->remoteVersion >= 70300)
7923 char *name;
7924 char *oname;
7925 char *ptr;
7926 bool inquote;
7927 bool sawdot;
7929 name = strdup(opr);
7930 /* find non-double-quoted left paren, and check for non-quoted dot */
7931 inquote = false;
7932 sawdot = false;
7933 for (ptr = name; *ptr; ptr++)
7935 if (*ptr == '"')
7936 inquote = !inquote;
7937 else if (*ptr == '.' && !inquote)
7938 sawdot = true;
7939 else if (*ptr == '(' && !inquote)
7941 *ptr = '\0';
7942 break;
7945 /* If not schema-qualified, don't need to add OPERATOR() */
7946 if (!sawdot)
7947 return name;
7948 oname = malloc(strlen(name) + 11);
7949 sprintf(oname, "OPERATOR(%s)", name);
7950 free(name);
7951 return oname;
7954 oprInfo = findOprByOid(atooid(opr));
7955 if (oprInfo == NULL)
7957 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
7958 opr);
7959 return NULL;
7961 return oprInfo->dobj.name;
7965 * Convert a function OID obtained from pg_ts_parser or pg_ts_template
7967 * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
7968 * argument lists of these functions are predetermined. Note that the
7969 * caller should ensure we are in the proper schema, because the results
7970 * are search path dependent!
7972 static const char *
7973 convertTSFunction(Oid funcOid)
7975 char *result;
7976 char query[128];
7977 PGresult *res;
7978 int ntups;
7980 snprintf(query, sizeof(query),
7981 "SELECT '%u'::pg_catalog.regproc", funcOid);
7982 res = PQexec(g_conn, query);
7983 check_sql_result(res, g_conn, query, PGRES_TUPLES_OK);
7985 ntups = PQntuples(res);
7986 if (ntups != 1)
7988 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
7989 "query returned %d rows instead of one: %s\n",
7990 ntups),
7991 ntups, query);
7992 exit_nicely();
7995 result = strdup(PQgetvalue(res, 0, 0));
7997 PQclear(res);
7999 return result;
8004 * dumpOpclass
8005 * write out a single operator class definition
8007 static void
8008 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
8010 PQExpBuffer query;
8011 PQExpBuffer q;
8012 PQExpBuffer delq;
8013 PGresult *res;
8014 int ntups;
8015 int i_opcintype;
8016 int i_opckeytype;
8017 int i_opcdefault;
8018 int i_opcfamily;
8019 int i_opcfamilynsp;
8020 int i_amname;
8021 int i_amopstrategy;
8022 int i_amopreqcheck;
8023 int i_amopopr;
8024 int i_amprocnum;
8025 int i_amproc;
8026 char *opcintype;
8027 char *opckeytype;
8028 char *opcdefault;
8029 char *opcfamily;
8030 char *opcfamilynsp;
8031 char *amname;
8032 char *amopstrategy;
8033 char *amopreqcheck;
8034 char *amopopr;
8035 char *amprocnum;
8036 char *amproc;
8037 bool needComma;
8038 int i;
8040 /* Skip if not to be dumped */
8041 if (!opcinfo->dobj.dump || dataOnly)
8042 return;
8045 * XXX currently we do not implement dumping of operator classes from
8046 * pre-7.3 databases. This could be done but it seems not worth the
8047 * trouble.
8049 if (g_fout->remoteVersion < 70300)
8050 return;
8052 query = createPQExpBuffer();
8053 q = createPQExpBuffer();
8054 delq = createPQExpBuffer();
8056 /* Make sure we are in proper schema so regoperator works correctly */
8057 selectSourceSchema(opcinfo->dobj.namespace->dobj.name);
8059 /* Get additional fields from the pg_opclass row */
8060 if (g_fout->remoteVersion >= 80300)
8062 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
8063 "opckeytype::pg_catalog.regtype, "
8064 "opcdefault, "
8065 "opfname AS opcfamily, "
8066 "nspname AS opcfamilynsp, "
8067 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
8068 "FROM pg_catalog.pg_opclass c "
8069 "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
8070 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
8071 "WHERE c.oid = '%u'::pg_catalog.oid",
8072 opcinfo->dobj.catId.oid);
8074 else
8076 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
8077 "opckeytype::pg_catalog.regtype, "
8078 "opcdefault, "
8079 "NULL AS opcfamily, "
8080 "NULL AS opcfamilynsp, "
8081 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
8082 "FROM pg_catalog.pg_opclass "
8083 "WHERE oid = '%u'::pg_catalog.oid",
8084 opcinfo->dobj.catId.oid);
8087 res = PQexec(g_conn, query->data);
8088 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8090 /* Expecting a single result only */
8091 ntups = PQntuples(res);
8092 if (ntups != 1)
8094 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
8095 "query returned %d rows instead of one: %s\n",
8096 ntups),
8097 ntups, query->data);
8098 exit_nicely();
8101 i_opcintype = PQfnumber(res, "opcintype");
8102 i_opckeytype = PQfnumber(res, "opckeytype");
8103 i_opcdefault = PQfnumber(res, "opcdefault");
8104 i_opcfamily = PQfnumber(res, "opcfamily");
8105 i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
8106 i_amname = PQfnumber(res, "amname");
8108 opcintype = PQgetvalue(res, 0, i_opcintype);
8109 opckeytype = PQgetvalue(res, 0, i_opckeytype);
8110 opcdefault = PQgetvalue(res, 0, i_opcdefault);
8111 opcfamily = PQgetvalue(res, 0, i_opcfamily);
8112 opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
8113 /* amname will still be needed after we PQclear res */
8114 amname = strdup(PQgetvalue(res, 0, i_amname));
8117 * DROP must be fully qualified in case same name appears in pg_catalog
8119 appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
8120 fmtId(opcinfo->dobj.namespace->dobj.name));
8121 appendPQExpBuffer(delq, ".%s",
8122 fmtId(opcinfo->dobj.name));
8123 appendPQExpBuffer(delq, " USING %s;\n",
8124 fmtId(amname));
8126 /* Build the fixed portion of the CREATE command */
8127 appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n ",
8128 fmtId(opcinfo->dobj.name));
8129 if (strcmp(opcdefault, "t") == 0)
8130 appendPQExpBuffer(q, "DEFAULT ");
8131 appendPQExpBuffer(q, "FOR TYPE %s USING %s",
8132 opcintype,
8133 fmtId(amname));
8134 if (strlen(opcfamily) > 0 &&
8135 (strcmp(opcfamily, opcinfo->dobj.name) != 0 ||
8136 strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
8138 appendPQExpBuffer(q, " FAMILY ");
8139 if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
8140 appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
8141 appendPQExpBuffer(q, "%s", fmtId(opcfamily));
8143 appendPQExpBuffer(q, " AS\n ");
8145 needComma = false;
8147 if (strcmp(opckeytype, "-") != 0)
8149 appendPQExpBuffer(q, "STORAGE %s",
8150 opckeytype);
8151 needComma = true;
8154 PQclear(res);
8157 * Now fetch and print the OPERATOR entries (pg_amop rows).
8159 resetPQExpBuffer(query);
8161 if (g_fout->remoteVersion >= 80400)
8164 * Print only those opfamily members that are tied to the opclass by
8165 * pg_depend entries.
8167 * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping
8168 * an older server's opclass in which it is used. This is to avoid
8169 * hard-to-detect breakage if a newer pg_dump is used to dump from an
8170 * older server and then reload into that old version. This can go
8171 * away once 8.3 is so old as to not be of interest to anyone.
8173 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
8174 "amopopr::pg_catalog.regoperator "
8175 "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
8176 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
8177 "AND refobjid = '%u'::pg_catalog.oid "
8178 "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
8179 "AND objid = ao.oid "
8180 "ORDER BY amopstrategy",
8181 opcinfo->dobj.catId.oid);
8183 else if (g_fout->remoteVersion >= 80300)
8186 * Print only those opfamily members that are tied to the opclass by
8187 * pg_depend entries.
8189 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
8190 "amopopr::pg_catalog.regoperator "
8191 "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
8192 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
8193 "AND refobjid = '%u'::pg_catalog.oid "
8194 "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
8195 "AND objid = ao.oid "
8196 "ORDER BY amopstrategy",
8197 opcinfo->dobj.catId.oid);
8199 else
8201 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
8202 "amopopr::pg_catalog.regoperator "
8203 "FROM pg_catalog.pg_amop "
8204 "WHERE amopclaid = '%u'::pg_catalog.oid "
8205 "ORDER BY amopstrategy",
8206 opcinfo->dobj.catId.oid);
8209 res = PQexec(g_conn, query->data);
8210 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8212 ntups = PQntuples(res);
8214 i_amopstrategy = PQfnumber(res, "amopstrategy");
8215 i_amopreqcheck = PQfnumber(res, "amopreqcheck");
8216 i_amopopr = PQfnumber(res, "amopopr");
8218 for (i = 0; i < ntups; i++)
8220 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
8221 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
8222 amopopr = PQgetvalue(res, i, i_amopopr);
8224 if (needComma)
8225 appendPQExpBuffer(q, " ,\n ");
8227 appendPQExpBuffer(q, "OPERATOR %s %s",
8228 amopstrategy, amopopr);
8229 if (strcmp(amopreqcheck, "t") == 0)
8230 appendPQExpBuffer(q, " RECHECK");
8232 needComma = true;
8235 PQclear(res);
8238 * Now fetch and print the FUNCTION entries (pg_amproc rows).
8240 resetPQExpBuffer(query);
8242 if (g_fout->remoteVersion >= 80300)
8245 * Print only those opfamily members that are tied to the opclass by
8246 * pg_depend entries.
8248 appendPQExpBuffer(query, "SELECT amprocnum, "
8249 "amproc::pg_catalog.regprocedure "
8250 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
8251 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
8252 "AND refobjid = '%u'::pg_catalog.oid "
8253 "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
8254 "AND objid = ap.oid "
8255 "ORDER BY amprocnum",
8256 opcinfo->dobj.catId.oid);
8258 else
8260 appendPQExpBuffer(query, "SELECT amprocnum, "
8261 "amproc::pg_catalog.regprocedure "
8262 "FROM pg_catalog.pg_amproc "
8263 "WHERE amopclaid = '%u'::pg_catalog.oid "
8264 "ORDER BY amprocnum",
8265 opcinfo->dobj.catId.oid);
8268 res = PQexec(g_conn, query->data);
8269 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8271 ntups = PQntuples(res);
8273 i_amprocnum = PQfnumber(res, "amprocnum");
8274 i_amproc = PQfnumber(res, "amproc");
8276 for (i = 0; i < ntups; i++)
8278 amprocnum = PQgetvalue(res, i, i_amprocnum);
8279 amproc = PQgetvalue(res, i, i_amproc);
8281 if (needComma)
8282 appendPQExpBuffer(q, " ,\n ");
8284 appendPQExpBuffer(q, "FUNCTION %s %s",
8285 amprocnum, amproc);
8287 needComma = true;
8290 PQclear(res);
8292 appendPQExpBuffer(q, ";\n");
8294 ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
8295 opcinfo->dobj.name,
8296 opcinfo->dobj.namespace->dobj.name,
8297 NULL,
8298 opcinfo->rolname,
8299 false, "OPERATOR CLASS", SECTION_PRE_DATA,
8300 q->data, delq->data, NULL,
8301 opcinfo->dobj.dependencies, opcinfo->dobj.nDeps,
8302 NULL, NULL);
8304 /* Dump Operator Class Comments */
8305 resetPQExpBuffer(q);
8306 appendPQExpBuffer(q, "OPERATOR CLASS %s",
8307 fmtId(opcinfo->dobj.name));
8308 appendPQExpBuffer(q, " USING %s",
8309 fmtId(amname));
8310 dumpComment(fout, q->data,
8311 NULL, opcinfo->rolname,
8312 opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
8314 free(amname);
8315 destroyPQExpBuffer(query);
8316 destroyPQExpBuffer(q);
8317 destroyPQExpBuffer(delq);
8321 * dumpOpfamily
8322 * write out a single operator family definition
8324 static void
8325 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
8327 PQExpBuffer query;
8328 PQExpBuffer q;
8329 PQExpBuffer delq;
8330 PGresult *res;
8331 PGresult *res_ops;
8332 PGresult *res_procs;
8333 int ntups;
8334 int i_amname;
8335 int i_amopstrategy;
8336 int i_amopreqcheck;
8337 int i_amopopr;
8338 int i_amprocnum;
8339 int i_amproc;
8340 int i_amproclefttype;
8341 int i_amprocrighttype;
8342 char *amname;
8343 char *amopstrategy;
8344 char *amopreqcheck;
8345 char *amopopr;
8346 char *amprocnum;
8347 char *amproc;
8348 char *amproclefttype;
8349 char *amprocrighttype;
8350 bool needComma;
8351 int i;
8353 /* Skip if not to be dumped */
8354 if (!opfinfo->dobj.dump || dataOnly)
8355 return;
8358 * We want to dump the opfamily only if (1) it contains "loose" operators
8359 * or functions, or (2) it contains an opclass with a different name or
8360 * owner. Otherwise it's sufficient to let it be created during creation
8361 * of the contained opclass, and not dumping it improves portability of
8362 * the dump. Since we have to fetch the loose operators/funcs anyway, do
8363 * that first.
8366 query = createPQExpBuffer();
8367 q = createPQExpBuffer();
8368 delq = createPQExpBuffer();
8370 /* Make sure we are in proper schema so regoperator works correctly */
8371 selectSourceSchema(opfinfo->dobj.namespace->dobj.name);
8374 * Fetch only those opfamily members that are tied directly to the
8375 * opfamily by pg_depend entries.
8377 if (g_fout->remoteVersion >= 80400)
8380 * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping
8381 * an older server's opclass in which it is used. This is to avoid
8382 * hard-to-detect breakage if a newer pg_dump is used to dump from an
8383 * older server and then reload into that old version. This can go
8384 * away once 8.3 is so old as to not be of interest to anyone.
8386 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
8387 "amopopr::pg_catalog.regoperator "
8388 "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
8389 "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8390 "AND refobjid = '%u'::pg_catalog.oid "
8391 "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
8392 "AND objid = ao.oid "
8393 "ORDER BY amopstrategy",
8394 opfinfo->dobj.catId.oid);
8396 else
8398 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
8399 "amopopr::pg_catalog.regoperator "
8400 "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
8401 "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8402 "AND refobjid = '%u'::pg_catalog.oid "
8403 "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
8404 "AND objid = ao.oid "
8405 "ORDER BY amopstrategy",
8406 opfinfo->dobj.catId.oid);
8409 res_ops = PQexec(g_conn, query->data);
8410 check_sql_result(res_ops, g_conn, query->data, PGRES_TUPLES_OK);
8412 resetPQExpBuffer(query);
8414 appendPQExpBuffer(query, "SELECT amprocnum, "
8415 "amproc::pg_catalog.regprocedure, "
8416 "amproclefttype::pg_catalog.regtype, "
8417 "amprocrighttype::pg_catalog.regtype "
8418 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
8419 "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8420 "AND refobjid = '%u'::pg_catalog.oid "
8421 "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
8422 "AND objid = ap.oid "
8423 "ORDER BY amprocnum",
8424 opfinfo->dobj.catId.oid);
8426 res_procs = PQexec(g_conn, query->data);
8427 check_sql_result(res_procs, g_conn, query->data, PGRES_TUPLES_OK);
8429 if (PQntuples(res_ops) == 0 && PQntuples(res_procs) == 0)
8431 /* No loose members, so check contained opclasses */
8432 resetPQExpBuffer(query);
8434 appendPQExpBuffer(query, "SELECT 1 "
8435 "FROM pg_catalog.pg_opclass c, pg_catalog.pg_opfamily f, pg_catalog.pg_depend "
8436 "WHERE f.oid = '%u'::pg_catalog.oid "
8437 "AND refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8438 "AND refobjid = f.oid "
8439 "AND classid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
8440 "AND objid = c.oid "
8441 "AND (opcname != opfname OR opcnamespace != opfnamespace OR opcowner != opfowner) "
8442 "LIMIT 1",
8443 opfinfo->dobj.catId.oid);
8445 res = PQexec(g_conn, query->data);
8446 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8448 if (PQntuples(res) == 0)
8450 /* no need to dump it, so bail out */
8451 PQclear(res);
8452 PQclear(res_ops);
8453 PQclear(res_procs);
8454 destroyPQExpBuffer(query);
8455 destroyPQExpBuffer(q);
8456 destroyPQExpBuffer(delq);
8457 return;
8460 PQclear(res);
8463 /* Get additional fields from the pg_opfamily row */
8464 resetPQExpBuffer(query);
8466 appendPQExpBuffer(query, "SELECT "
8467 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
8468 "FROM pg_catalog.pg_opfamily "
8469 "WHERE oid = '%u'::pg_catalog.oid",
8470 opfinfo->dobj.catId.oid);
8472 res = PQexec(g_conn, query->data);
8473 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8475 /* Expecting a single result only */
8476 ntups = PQntuples(res);
8477 if (ntups != 1)
8479 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
8480 "query returned %d rows instead of one: %s\n",
8481 ntups),
8482 ntups, query->data);
8483 exit_nicely();
8486 i_amname = PQfnumber(res, "amname");
8488 /* amname will still be needed after we PQclear res */
8489 amname = strdup(PQgetvalue(res, 0, i_amname));
8492 * DROP must be fully qualified in case same name appears in pg_catalog
8494 appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
8495 fmtId(opfinfo->dobj.namespace->dobj.name));
8496 appendPQExpBuffer(delq, ".%s",
8497 fmtId(opfinfo->dobj.name));
8498 appendPQExpBuffer(delq, " USING %s;\n",
8499 fmtId(amname));
8501 /* Build the fixed portion of the CREATE command */
8502 appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
8503 fmtId(opfinfo->dobj.name));
8504 appendPQExpBuffer(q, " USING %s;\n",
8505 fmtId(amname));
8507 PQclear(res);
8509 /* Do we need an ALTER to add loose members? */
8510 if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
8512 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
8513 fmtId(opfinfo->dobj.name));
8514 appendPQExpBuffer(q, " USING %s ADD\n ",
8515 fmtId(amname));
8517 needComma = false;
8520 * Now fetch and print the OPERATOR entries (pg_amop rows).
8522 ntups = PQntuples(res_ops);
8524 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
8525 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
8526 i_amopopr = PQfnumber(res_ops, "amopopr");
8528 for (i = 0; i < ntups; i++)
8530 amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
8531 amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
8532 amopopr = PQgetvalue(res_ops, i, i_amopopr);
8534 if (needComma)
8535 appendPQExpBuffer(q, " ,\n ");
8537 appendPQExpBuffer(q, "OPERATOR %s %s",
8538 amopstrategy, amopopr);
8539 if (strcmp(amopreqcheck, "t") == 0)
8540 appendPQExpBuffer(q, " RECHECK");
8542 needComma = true;
8546 * Now fetch and print the FUNCTION entries (pg_amproc rows).
8548 ntups = PQntuples(res_procs);
8550 i_amprocnum = PQfnumber(res_procs, "amprocnum");
8551 i_amproc = PQfnumber(res_procs, "amproc");
8552 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
8553 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
8555 for (i = 0; i < ntups; i++)
8557 amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
8558 amproc = PQgetvalue(res_procs, i, i_amproc);
8559 amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
8560 amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
8562 if (needComma)
8563 appendPQExpBuffer(q, " ,\n ");
8565 appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
8566 amprocnum, amproclefttype, amprocrighttype,
8567 amproc);
8569 needComma = true;
8572 appendPQExpBuffer(q, ";\n");
8575 ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
8576 opfinfo->dobj.name,
8577 opfinfo->dobj.namespace->dobj.name,
8578 NULL,
8579 opfinfo->rolname,
8580 false, "OPERATOR FAMILY", SECTION_PRE_DATA,
8581 q->data, delq->data, NULL,
8582 opfinfo->dobj.dependencies, opfinfo->dobj.nDeps,
8583 NULL, NULL);
8585 /* Dump Operator Family Comments */
8586 resetPQExpBuffer(q);
8587 appendPQExpBuffer(q, "OPERATOR FAMILY %s",
8588 fmtId(opfinfo->dobj.name));
8589 appendPQExpBuffer(q, " USING %s",
8590 fmtId(amname));
8591 dumpComment(fout, q->data,
8592 NULL, opfinfo->rolname,
8593 opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
8595 free(amname);
8596 PQclear(res_ops);
8597 PQclear(res_procs);
8598 destroyPQExpBuffer(query);
8599 destroyPQExpBuffer(q);
8600 destroyPQExpBuffer(delq);
8604 * dumpConversion
8605 * write out a single conversion definition
8607 static void
8608 dumpConversion(Archive *fout, ConvInfo *convinfo)
8610 PQExpBuffer query;
8611 PQExpBuffer q;
8612 PQExpBuffer delq;
8613 PQExpBuffer details;
8614 PGresult *res;
8615 int ntups;
8616 int i_conname;
8617 int i_conforencoding;
8618 int i_contoencoding;
8619 int i_conproc;
8620 int i_condefault;
8621 const char *conname;
8622 const char *conforencoding;
8623 const char *contoencoding;
8624 const char *conproc;
8625 bool condefault;
8627 /* Skip if not to be dumped */
8628 if (!convinfo->dobj.dump || dataOnly)
8629 return;
8631 query = createPQExpBuffer();
8632 q = createPQExpBuffer();
8633 delq = createPQExpBuffer();
8634 details = createPQExpBuffer();
8636 /* Make sure we are in proper schema */
8637 selectSourceSchema(convinfo->dobj.namespace->dobj.name);
8639 /* Get conversion-specific details */
8640 appendPQExpBuffer(query, "SELECT conname, "
8641 "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
8642 "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
8643 "conproc, condefault "
8644 "FROM pg_catalog.pg_conversion c "
8645 "WHERE c.oid = '%u'::pg_catalog.oid",
8646 convinfo->dobj.catId.oid);
8648 res = PQexec(g_conn, query->data);
8649 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8651 /* Expecting a single result only */
8652 ntups = PQntuples(res);
8653 if (ntups != 1)
8655 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
8656 "query returned %d rows instead of one: %s\n",
8657 ntups),
8658 ntups, query->data);
8659 exit_nicely();
8662 i_conname = PQfnumber(res, "conname");
8663 i_conforencoding = PQfnumber(res, "conforencoding");
8664 i_contoencoding = PQfnumber(res, "contoencoding");
8665 i_conproc = PQfnumber(res, "conproc");
8666 i_condefault = PQfnumber(res, "condefault");
8668 conname = PQgetvalue(res, 0, i_conname);
8669 conforencoding = PQgetvalue(res, 0, i_conforencoding);
8670 contoencoding = PQgetvalue(res, 0, i_contoencoding);
8671 conproc = PQgetvalue(res, 0, i_conproc);
8672 condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
8675 * DROP must be fully qualified in case same name appears in pg_catalog
8677 appendPQExpBuffer(delq, "DROP CONVERSION %s",
8678 fmtId(convinfo->dobj.namespace->dobj.name));
8679 appendPQExpBuffer(delq, ".%s;\n",
8680 fmtId(convinfo->dobj.name));
8682 appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
8683 (condefault) ? "DEFAULT " : "",
8684 fmtId(convinfo->dobj.name));
8685 appendStringLiteralAH(q, conforencoding, fout);
8686 appendPQExpBuffer(q, " TO ");
8687 appendStringLiteralAH(q, contoencoding, fout);
8688 /* regproc is automatically quoted in 7.3 and above */
8689 appendPQExpBuffer(q, " FROM %s;\n", conproc);
8691 ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
8692 convinfo->dobj.name,
8693 convinfo->dobj.namespace->dobj.name,
8694 NULL,
8695 convinfo->rolname,
8696 false, "CONVERSION", SECTION_PRE_DATA,
8697 q->data, delq->data, NULL,
8698 convinfo->dobj.dependencies, convinfo->dobj.nDeps,
8699 NULL, NULL);
8701 /* Dump Conversion Comments */
8702 resetPQExpBuffer(q);
8703 appendPQExpBuffer(q, "CONVERSION %s", fmtId(convinfo->dobj.name));
8704 dumpComment(fout, q->data,
8705 convinfo->dobj.namespace->dobj.name, convinfo->rolname,
8706 convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
8708 PQclear(res);
8710 destroyPQExpBuffer(query);
8711 destroyPQExpBuffer(q);
8712 destroyPQExpBuffer(delq);
8713 destroyPQExpBuffer(details);
8717 * format_aggregate_signature: generate aggregate name and argument list
8719 * The argument type names are qualified if needed. The aggregate name
8720 * is never qualified.
8722 static char *
8723 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
8725 PQExpBufferData buf;
8726 int j;
8728 initPQExpBuffer(&buf);
8729 if (honor_quotes)
8730 appendPQExpBuffer(&buf, "%s",
8731 fmtId(agginfo->aggfn.dobj.name));
8732 else
8733 appendPQExpBuffer(&buf, "%s", agginfo->aggfn.dobj.name);
8735 if (agginfo->aggfn.nargs == 0)
8736 appendPQExpBuffer(&buf, "(*)");
8737 else
8739 appendPQExpBuffer(&buf, "(");
8740 for (j = 0; j < agginfo->aggfn.nargs; j++)
8742 char *typname;
8744 typname = getFormattedTypeName(agginfo->aggfn.argtypes[j], zeroAsOpaque);
8746 appendPQExpBuffer(&buf, "%s%s",
8747 (j > 0) ? ", " : "",
8748 typname);
8749 free(typname);
8751 appendPQExpBuffer(&buf, ")");
8753 return buf.data;
8757 * dumpAgg
8758 * write out a single aggregate definition
8760 static void
8761 dumpAgg(Archive *fout, AggInfo *agginfo)
8763 PQExpBuffer query;
8764 PQExpBuffer q;
8765 PQExpBuffer delq;
8766 PQExpBuffer details;
8767 char *aggsig;
8768 char *aggsig_tag;
8769 PGresult *res;
8770 int ntups;
8771 int i_aggtransfn;
8772 int i_aggfinalfn;
8773 int i_aggsortop;
8774 int i_aggtranstype;
8775 int i_agginitval;
8776 int i_convertok;
8777 const char *aggtransfn;
8778 const char *aggfinalfn;
8779 const char *aggsortop;
8780 const char *aggtranstype;
8781 const char *agginitval;
8782 bool convertok;
8784 /* Skip if not to be dumped */
8785 if (!agginfo->aggfn.dobj.dump || dataOnly)
8786 return;
8788 query = createPQExpBuffer();
8789 q = createPQExpBuffer();
8790 delq = createPQExpBuffer();
8791 details = createPQExpBuffer();
8793 /* Make sure we are in proper schema */
8794 selectSourceSchema(agginfo->aggfn.dobj.namespace->dobj.name);
8796 /* Get aggregate-specific details */
8797 if (g_fout->remoteVersion >= 80100)
8799 appendPQExpBuffer(query, "SELECT aggtransfn, "
8800 "aggfinalfn, aggtranstype::pg_catalog.regtype, "
8801 "aggsortop::pg_catalog.regoperator, "
8802 "agginitval, "
8803 "'t'::boolean AS convertok "
8804 "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
8805 "WHERE a.aggfnoid = p.oid "
8806 "AND p.oid = '%u'::pg_catalog.oid",
8807 agginfo->aggfn.dobj.catId.oid);
8809 else if (g_fout->remoteVersion >= 70300)
8811 appendPQExpBuffer(query, "SELECT aggtransfn, "
8812 "aggfinalfn, aggtranstype::pg_catalog.regtype, "
8813 "0 AS aggsortop, "
8814 "agginitval, "
8815 "'t'::boolean AS convertok "
8816 "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
8817 "WHERE a.aggfnoid = p.oid "
8818 "AND p.oid = '%u'::pg_catalog.oid",
8819 agginfo->aggfn.dobj.catId.oid);
8821 else if (g_fout->remoteVersion >= 70100)
8823 appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
8824 "format_type(aggtranstype, NULL) AS aggtranstype, "
8825 "0 AS aggsortop, "
8826 "agginitval, "
8827 "'t'::boolean AS convertok "
8828 "FROM pg_aggregate "
8829 "WHERE oid = '%u'::oid",
8830 agginfo->aggfn.dobj.catId.oid);
8832 else
8834 appendPQExpBuffer(query, "SELECT aggtransfn1 AS aggtransfn, "
8835 "aggfinalfn, "
8836 "(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
8837 "0 AS aggsortop, "
8838 "agginitval1 AS agginitval, "
8839 "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
8840 "FROM pg_aggregate "
8841 "WHERE oid = '%u'::oid",
8842 agginfo->aggfn.dobj.catId.oid);
8845 res = PQexec(g_conn, query->data);
8846 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8848 /* Expecting a single result only */
8849 ntups = PQntuples(res);
8850 if (ntups != 1)
8852 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
8853 "query returned %d rows instead of one: %s\n",
8854 ntups),
8855 ntups, query->data);
8856 exit_nicely();
8859 i_aggtransfn = PQfnumber(res, "aggtransfn");
8860 i_aggfinalfn = PQfnumber(res, "aggfinalfn");
8861 i_aggsortop = PQfnumber(res, "aggsortop");
8862 i_aggtranstype = PQfnumber(res, "aggtranstype");
8863 i_agginitval = PQfnumber(res, "agginitval");
8864 i_convertok = PQfnumber(res, "convertok");
8866 aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
8867 aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
8868 aggsortop = PQgetvalue(res, 0, i_aggsortop);
8869 aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
8870 agginitval = PQgetvalue(res, 0, i_agginitval);
8871 convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
8873 aggsig = format_aggregate_signature(agginfo, fout, true);
8874 aggsig_tag = format_aggregate_signature(agginfo, fout, false);
8876 if (!convertok)
8878 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
8879 aggsig);
8880 return;
8883 if (g_fout->remoteVersion >= 70300)
8885 /* If using 7.3's regproc or regtype, data is already quoted */
8886 appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
8887 aggtransfn,
8888 aggtranstype);
8890 else if (g_fout->remoteVersion >= 70100)
8892 /* format_type quotes, regproc does not */
8893 appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
8894 fmtId(aggtransfn),
8895 aggtranstype);
8897 else
8899 /* need quotes all around */
8900 appendPQExpBuffer(details, " SFUNC = %s,\n",
8901 fmtId(aggtransfn));
8902 appendPQExpBuffer(details, " STYPE = %s",
8903 fmtId(aggtranstype));
8906 if (!PQgetisnull(res, 0, i_agginitval))
8908 appendPQExpBuffer(details, ",\n INITCOND = ");
8909 appendStringLiteralAH(details, agginitval, fout);
8912 if (strcmp(aggfinalfn, "-") != 0)
8914 appendPQExpBuffer(details, ",\n FINALFUNC = %s",
8915 aggfinalfn);
8918 aggsortop = convertOperatorReference(aggsortop);
8919 if (aggsortop)
8921 appendPQExpBuffer(details, ",\n SORTOP = %s",
8922 aggsortop);
8926 * DROP must be fully qualified in case same name appears in pg_catalog
8928 appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
8929 fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
8930 aggsig);
8932 appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
8933 aggsig, details->data);
8935 ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
8936 aggsig_tag,
8937 agginfo->aggfn.dobj.namespace->dobj.name,
8938 NULL,
8939 agginfo->aggfn.rolname,
8940 false, "AGGREGATE", SECTION_PRE_DATA,
8941 q->data, delq->data, NULL,
8942 agginfo->aggfn.dobj.dependencies, agginfo->aggfn.dobj.nDeps,
8943 NULL, NULL);
8945 /* Dump Aggregate Comments */
8946 resetPQExpBuffer(q);
8947 appendPQExpBuffer(q, "AGGREGATE %s", aggsig);
8948 dumpComment(fout, q->data,
8949 agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
8950 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
8953 * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
8954 * command look like a function's GRANT; in particular this affects the
8955 * syntax for zero-argument aggregates.
8957 free(aggsig);
8958 free(aggsig_tag);
8960 aggsig = format_function_signature(&agginfo->aggfn, true);
8961 aggsig_tag = format_function_signature(&agginfo->aggfn, false);
8963 dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
8964 "FUNCTION",
8965 aggsig, NULL, aggsig_tag,
8966 agginfo->aggfn.dobj.namespace->dobj.name,
8967 agginfo->aggfn.rolname, agginfo->aggfn.proacl);
8969 free(aggsig);
8970 free(aggsig_tag);
8972 PQclear(res);
8974 destroyPQExpBuffer(query);
8975 destroyPQExpBuffer(q);
8976 destroyPQExpBuffer(delq);
8977 destroyPQExpBuffer(details);
8981 * dumpTSParser
8982 * write out a single text search parser
8984 static void
8985 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
8987 PQExpBuffer q;
8988 PQExpBuffer delq;
8990 /* Skip if not to be dumped */
8991 if (!prsinfo->dobj.dump || dataOnly)
8992 return;
8994 q = createPQExpBuffer();
8995 delq = createPQExpBuffer();
8997 /* Make sure we are in proper schema */
8998 selectSourceSchema(prsinfo->dobj.namespace->dobj.name);
9000 appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
9001 fmtId(prsinfo->dobj.name));
9003 appendPQExpBuffer(q, " START = %s,\n",
9004 convertTSFunction(prsinfo->prsstart));
9005 appendPQExpBuffer(q, " GETTOKEN = %s,\n",
9006 convertTSFunction(prsinfo->prstoken));
9007 appendPQExpBuffer(q, " END = %s,\n",
9008 convertTSFunction(prsinfo->prsend));
9009 if (prsinfo->prsheadline != InvalidOid)
9010 appendPQExpBuffer(q, " HEADLINE = %s,\n",
9011 convertTSFunction(prsinfo->prsheadline));
9012 appendPQExpBuffer(q, " LEXTYPES = %s );\n",
9013 convertTSFunction(prsinfo->prslextype));
9016 * DROP must be fully qualified in case same name appears in pg_catalog
9018 appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s",
9019 fmtId(prsinfo->dobj.namespace->dobj.name));
9020 appendPQExpBuffer(delq, ".%s;\n",
9021 fmtId(prsinfo->dobj.name));
9023 ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
9024 prsinfo->dobj.name,
9025 prsinfo->dobj.namespace->dobj.name,
9026 NULL,
9028 false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
9029 q->data, delq->data, NULL,
9030 prsinfo->dobj.dependencies, prsinfo->dobj.nDeps,
9031 NULL, NULL);
9033 /* Dump Parser Comments */
9034 resetPQExpBuffer(q);
9035 appendPQExpBuffer(q, "TEXT SEARCH PARSER %s",
9036 fmtId(prsinfo->dobj.name));
9037 dumpComment(fout, q->data,
9038 NULL, "",
9039 prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
9041 destroyPQExpBuffer(q);
9042 destroyPQExpBuffer(delq);
9046 * dumpTSDictionary
9047 * write out a single text search dictionary
9049 static void
9050 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
9052 PQExpBuffer q;
9053 PQExpBuffer delq;
9054 PQExpBuffer query;
9055 PGresult *res;
9056 int ntups;
9057 char *nspname;
9058 char *tmplname;
9060 /* Skip if not to be dumped */
9061 if (!dictinfo->dobj.dump || dataOnly)
9062 return;
9064 q = createPQExpBuffer();
9065 delq = createPQExpBuffer();
9066 query = createPQExpBuffer();
9068 /* Fetch name and namespace of the dictionary's template */
9069 selectSourceSchema("pg_catalog");
9070 appendPQExpBuffer(query, "SELECT nspname, tmplname "
9071 "FROM pg_ts_template p, pg_namespace n "
9072 "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
9073 dictinfo->dicttemplate);
9074 res = PQexec(g_conn, query->data);
9075 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9076 ntups = PQntuples(res);
9077 if (ntups != 1)
9079 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9080 "query returned %d rows instead of one: %s\n",
9081 ntups),
9082 ntups, query->data);
9083 exit_nicely();
9085 nspname = PQgetvalue(res, 0, 0);
9086 tmplname = PQgetvalue(res, 0, 1);
9088 /* Make sure we are in proper schema */
9089 selectSourceSchema(dictinfo->dobj.namespace->dobj.name);
9091 appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
9092 fmtId(dictinfo->dobj.name));
9094 appendPQExpBuffer(q, " TEMPLATE = ");
9095 if (strcmp(nspname, dictinfo->dobj.namespace->dobj.name) != 0)
9096 appendPQExpBuffer(q, "%s.", fmtId(nspname));
9097 appendPQExpBuffer(q, "%s", fmtId(tmplname));
9099 PQclear(res);
9101 /* the dictinitoption can be dumped straight into the command */
9102 if (dictinfo->dictinitoption)
9103 appendPQExpBuffer(q, ",\n %s", dictinfo->dictinitoption);
9105 appendPQExpBuffer(q, " );\n");
9108 * DROP must be fully qualified in case same name appears in pg_catalog
9110 appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s",
9111 fmtId(dictinfo->dobj.namespace->dobj.name));
9112 appendPQExpBuffer(delq, ".%s;\n",
9113 fmtId(dictinfo->dobj.name));
9115 ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
9116 dictinfo->dobj.name,
9117 dictinfo->dobj.namespace->dobj.name,
9118 NULL,
9119 dictinfo->rolname,
9120 false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
9121 q->data, delq->data, NULL,
9122 dictinfo->dobj.dependencies, dictinfo->dobj.nDeps,
9123 NULL, NULL);
9125 /* Dump Dictionary Comments */
9126 resetPQExpBuffer(q);
9127 appendPQExpBuffer(q, "TEXT SEARCH DICTIONARY %s",
9128 fmtId(dictinfo->dobj.name));
9129 dumpComment(fout, q->data,
9130 NULL, dictinfo->rolname,
9131 dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
9133 destroyPQExpBuffer(q);
9134 destroyPQExpBuffer(delq);
9135 destroyPQExpBuffer(query);
9139 * dumpTSTemplate
9140 * write out a single text search template
9142 static void
9143 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
9145 PQExpBuffer q;
9146 PQExpBuffer delq;
9148 /* Skip if not to be dumped */
9149 if (!tmplinfo->dobj.dump || dataOnly)
9150 return;
9152 q = createPQExpBuffer();
9153 delq = createPQExpBuffer();
9155 /* Make sure we are in proper schema */
9156 selectSourceSchema(tmplinfo->dobj.namespace->dobj.name);
9158 appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
9159 fmtId(tmplinfo->dobj.name));
9161 if (tmplinfo->tmplinit != InvalidOid)
9162 appendPQExpBuffer(q, " INIT = %s,\n",
9163 convertTSFunction(tmplinfo->tmplinit));
9164 appendPQExpBuffer(q, " LEXIZE = %s );\n",
9165 convertTSFunction(tmplinfo->tmpllexize));
9168 * DROP must be fully qualified in case same name appears in pg_catalog
9170 appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s",
9171 fmtId(tmplinfo->dobj.namespace->dobj.name));
9172 appendPQExpBuffer(delq, ".%s;\n",
9173 fmtId(tmplinfo->dobj.name));
9175 ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
9176 tmplinfo->dobj.name,
9177 tmplinfo->dobj.namespace->dobj.name,
9178 NULL,
9180 false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
9181 q->data, delq->data, NULL,
9182 tmplinfo->dobj.dependencies, tmplinfo->dobj.nDeps,
9183 NULL, NULL);
9185 /* Dump Template Comments */
9186 resetPQExpBuffer(q);
9187 appendPQExpBuffer(q, "TEXT SEARCH TEMPLATE %s",
9188 fmtId(tmplinfo->dobj.name));
9189 dumpComment(fout, q->data,
9190 NULL, "",
9191 tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
9193 destroyPQExpBuffer(q);
9194 destroyPQExpBuffer(delq);
9198 * dumpTSConfig
9199 * write out a single text search configuration
9201 static void
9202 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
9204 PQExpBuffer q;
9205 PQExpBuffer delq;
9206 PQExpBuffer query;
9207 PGresult *res;
9208 char *nspname;
9209 char *prsname;
9210 int ntups,
9212 int i_tokenname;
9213 int i_dictname;
9215 /* Skip if not to be dumped */
9216 if (!cfginfo->dobj.dump || dataOnly)
9217 return;
9219 q = createPQExpBuffer();
9220 delq = createPQExpBuffer();
9221 query = createPQExpBuffer();
9223 /* Fetch name and namespace of the config's parser */
9224 selectSourceSchema("pg_catalog");
9225 appendPQExpBuffer(query, "SELECT nspname, prsname "
9226 "FROM pg_ts_parser p, pg_namespace n "
9227 "WHERE p.oid = '%u' AND n.oid = prsnamespace",
9228 cfginfo->cfgparser);
9229 res = PQexec(g_conn, query->data);
9230 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9231 ntups = PQntuples(res);
9232 if (ntups != 1)
9234 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9235 "query returned %d rows instead of one: %s\n",
9236 ntups),
9237 ntups, query->data);
9238 exit_nicely();
9240 nspname = PQgetvalue(res, 0, 0);
9241 prsname = PQgetvalue(res, 0, 1);
9243 /* Make sure we are in proper schema */
9244 selectSourceSchema(cfginfo->dobj.namespace->dobj.name);
9246 appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
9247 fmtId(cfginfo->dobj.name));
9249 appendPQExpBuffer(q, " PARSER = ");
9250 if (strcmp(nspname, cfginfo->dobj.namespace->dobj.name) != 0)
9251 appendPQExpBuffer(q, "%s.", fmtId(nspname));
9252 appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
9254 PQclear(res);
9256 resetPQExpBuffer(query);
9257 appendPQExpBuffer(query,
9258 "SELECT \n"
9259 " ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t \n"
9260 " WHERE t.tokid = m.maptokentype ) AS tokenname, \n"
9261 " m.mapdict::pg_catalog.regdictionary AS dictname \n"
9262 "FROM pg_catalog.pg_ts_config_map AS m \n"
9263 "WHERE m.mapcfg = '%u' \n"
9264 "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
9265 cfginfo->cfgparser, cfginfo->dobj.catId.oid);
9267 res = PQexec(g_conn, query->data);
9268 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9269 ntups = PQntuples(res);
9271 i_tokenname = PQfnumber(res, "tokenname");
9272 i_dictname = PQfnumber(res, "dictname");
9274 for (i = 0; i < ntups; i++)
9276 char *tokenname = PQgetvalue(res, i, i_tokenname);
9277 char *dictname = PQgetvalue(res, i, i_dictname);
9279 if (i == 0 ||
9280 strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
9282 /* starting a new token type, so start a new command */
9283 if (i > 0)
9284 appendPQExpBuffer(q, ";\n");
9285 appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
9286 fmtId(cfginfo->dobj.name));
9287 /* tokenname needs quoting, dictname does NOT */
9288 appendPQExpBuffer(q, " ADD MAPPING FOR %s WITH %s",
9289 fmtId(tokenname), dictname);
9291 else
9292 appendPQExpBuffer(q, ", %s", dictname);
9295 if (ntups > 0)
9296 appendPQExpBuffer(q, ";\n");
9298 PQclear(res);
9301 * DROP must be fully qualified in case same name appears in pg_catalog
9303 appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s",
9304 fmtId(cfginfo->dobj.namespace->dobj.name));
9305 appendPQExpBuffer(delq, ".%s;\n",
9306 fmtId(cfginfo->dobj.name));
9308 ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
9309 cfginfo->dobj.name,
9310 cfginfo->dobj.namespace->dobj.name,
9311 NULL,
9312 cfginfo->rolname,
9313 false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
9314 q->data, delq->data, NULL,
9315 cfginfo->dobj.dependencies, cfginfo->dobj.nDeps,
9316 NULL, NULL);
9318 /* Dump Configuration Comments */
9319 resetPQExpBuffer(q);
9320 appendPQExpBuffer(q, "TEXT SEARCH CONFIGURATION %s",
9321 fmtId(cfginfo->dobj.name));
9322 dumpComment(fout, q->data,
9323 NULL, cfginfo->rolname,
9324 cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
9326 destroyPQExpBuffer(q);
9327 destroyPQExpBuffer(delq);
9328 destroyPQExpBuffer(query);
9332 * dumpForeignDataWrapper
9333 * write out a single foreign-data wrapper definition
9335 static void
9336 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
9338 PQExpBuffer q;
9339 PQExpBuffer delq;
9340 char *namecopy;
9342 /* Skip if not to be dumped */
9343 if (!fdwinfo->dobj.dump || dataOnly)
9344 return;
9346 q = createPQExpBuffer();
9347 delq = createPQExpBuffer();
9349 appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
9350 fmtId(fdwinfo->dobj.name));
9352 if (fdwinfo->fdwvalidator && strcmp(fdwinfo->fdwvalidator, "-") != 0)
9353 appendPQExpBuffer(q, " VALIDATOR %s",
9354 fdwinfo->fdwvalidator);
9356 if (fdwinfo->fdwoptions && strlen(fdwinfo->fdwoptions) > 0)
9357 appendPQExpBuffer(q, " OPTIONS (%s)", fdwinfo->fdwoptions);
9359 appendPQExpBuffer(q, ";\n");
9361 appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
9362 fmtId(fdwinfo->dobj.name));
9364 ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
9365 fdwinfo->dobj.name,
9366 NULL,
9367 NULL,
9368 fdwinfo->rolname,
9369 false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
9370 q->data, delq->data, NULL,
9371 fdwinfo->dobj.dependencies, fdwinfo->dobj.nDeps,
9372 NULL, NULL);
9374 /* Handle the ACL */
9375 namecopy = strdup(fmtId(fdwinfo->dobj.name));
9376 dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
9377 "FOREIGN DATA WRAPPER",
9378 namecopy, NULL, fdwinfo->dobj.name,
9379 NULL, fdwinfo->rolname,
9380 fdwinfo->fdwacl);
9381 free(namecopy);
9383 destroyPQExpBuffer(q);
9384 destroyPQExpBuffer(delq);
9388 * dumpForeignServer
9389 * write out a foreign server definition
9391 static void
9392 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
9394 PQExpBuffer q;
9395 PQExpBuffer delq;
9396 PQExpBuffer query;
9397 PGresult *res;
9398 int ntups;
9399 char *namecopy;
9400 char *fdwname;
9402 /* Skip if not to be dumped */
9403 if (!srvinfo->dobj.dump || dataOnly)
9404 return;
9406 q = createPQExpBuffer();
9407 delq = createPQExpBuffer();
9408 query = createPQExpBuffer();
9410 /* look up the foreign-data wrapper */
9411 appendPQExpBuffer(query, "SELECT fdwname "
9412 "FROM pg_foreign_data_wrapper w "
9413 "WHERE w.oid = '%u'",
9414 srvinfo->srvfdw);
9415 res = PQexec(g_conn, query->data);
9416 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9417 ntups = PQntuples(res);
9418 if (ntups != 1)
9420 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9421 "query returned %d rows instead of one: %s\n",
9422 ntups),
9423 ntups, query->data);
9424 exit_nicely();
9426 fdwname = PQgetvalue(res, 0, 0);
9428 appendPQExpBuffer(q, "CREATE SERVER %s", fmtId(srvinfo->dobj.name));
9429 if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
9431 appendPQExpBuffer(q, " TYPE ");
9432 appendStringLiteralAH(q, srvinfo->srvtype, fout);
9434 if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
9436 appendPQExpBuffer(q, " VERSION ");
9437 appendStringLiteralAH(q, srvinfo->srvversion, fout);
9440 appendPQExpBuffer(q, " FOREIGN DATA WRAPPER ");
9441 appendPQExpBuffer(q, "%s", fmtId(fdwname));
9443 if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
9444 appendPQExpBuffer(q, " OPTIONS (%s)", srvinfo->srvoptions);
9446 appendPQExpBuffer(q, ";\n");
9448 appendPQExpBuffer(delq, "DROP SERVER %s;\n",
9449 fmtId(srvinfo->dobj.name));
9451 ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
9452 srvinfo->dobj.name,
9453 NULL,
9454 NULL,
9455 srvinfo->rolname,
9456 false, "SERVER", SECTION_PRE_DATA,
9457 q->data, delq->data, NULL,
9458 srvinfo->dobj.dependencies, srvinfo->dobj.nDeps,
9459 NULL, NULL);
9461 /* Handle the ACL */
9462 namecopy = strdup(fmtId(srvinfo->dobj.name));
9463 dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
9464 "SERVER",
9465 namecopy, NULL, srvinfo->dobj.name,
9466 NULL, srvinfo->rolname,
9467 srvinfo->srvacl);
9468 free(namecopy);
9470 /* Dump user mappings */
9471 resetPQExpBuffer(q);
9472 appendPQExpBuffer(q, "SERVER %s", fmtId(srvinfo->dobj.name));
9473 dumpUserMappings(fout, q->data,
9474 srvinfo->dobj.name, NULL,
9475 srvinfo->rolname,
9476 srvinfo->dobj.catId, srvinfo->dobj.dumpId);
9478 destroyPQExpBuffer(q);
9479 destroyPQExpBuffer(delq);
9483 * dumpUserMappings
9485 * This routine is used to dump any user mappings associated with the
9486 * server handed to this routine. Should be called after ArchiveEntry()
9487 * for the server.
9489 static void
9490 dumpUserMappings(Archive *fout, const char *target,
9491 const char *servername, const char *namespace,
9492 const char *owner,
9493 CatalogId catalogId, DumpId dumpId)
9495 PQExpBuffer q;
9496 PQExpBuffer delq;
9497 PQExpBuffer query;
9498 PQExpBuffer tag;
9499 PGresult *res;
9500 int ntups;
9501 int i_umuser;
9502 int i_umoptions;
9503 int i;
9505 q = createPQExpBuffer();
9506 tag = createPQExpBuffer();
9507 delq = createPQExpBuffer();
9508 query = createPQExpBuffer();
9510 appendPQExpBuffer(query,
9511 "SELECT (%s umuser) AS umuser, "
9512 "array_to_string(ARRAY(SELECT option_name || ' ' || quote_literal(option_value) FROM pg_options_to_table(umoptions)), ', ') AS umoptions\n"
9513 "FROM pg_user_mapping "
9514 "WHERE umserver=%u",
9515 username_subquery,
9516 catalogId.oid);
9518 res = PQexec(g_conn, query->data);
9519 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9521 ntups = PQntuples(res);
9522 i_umuser = PQfnumber(res, "umuser");
9523 i_umoptions = PQfnumber(res, "umoptions");
9525 for (i = 0; i < ntups; i++)
9527 char *umuser;
9528 char *umoptions;
9530 umuser = PQgetvalue(res, i, i_umuser);
9531 umoptions = PQgetvalue(res, i, i_umoptions);
9533 resetPQExpBuffer(q);
9534 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(umuser));
9535 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
9537 if (umoptions && strlen(umoptions) > 0)
9538 appendPQExpBuffer(q, " OPTIONS (%s)", umoptions);
9540 appendPQExpBuffer(q, ";\n");
9542 resetPQExpBuffer(delq);
9543 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s SERVER %s;\n", fmtId(umuser), fmtId(servername));
9545 resetPQExpBuffer(tag);
9546 appendPQExpBuffer(tag, "USER MAPPING %s %s", fmtId(umuser), target);
9548 ArchiveEntry(fout, nilCatalogId, createDumpId(),
9549 tag->data,
9550 namespace,
9551 NULL,
9552 owner, false,
9553 "USER MAPPING", SECTION_PRE_DATA,
9554 q->data, delq->data, NULL,
9555 &dumpId, 1,
9556 NULL, NULL);
9559 PQclear(res);
9561 destroyPQExpBuffer(query);
9562 destroyPQExpBuffer(delq);
9563 destroyPQExpBuffer(q);
9566 /*----------
9567 * Write out grant/revoke information
9569 * 'objCatId' is the catalog ID of the underlying object.
9570 * 'objDumpId' is the dump ID of the underlying object.
9571 * 'type' must be TABLE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, or TABLESPACE.
9572 * 'name' is the formatted name of the object. Must be quoted etc. already.
9573 * 'subname' is the formatted name of the sub-object, if any. Must be quoted.
9574 * 'tag' is the tag for the archive entry (typ. unquoted name of object).
9575 * 'nspname' is the namespace the object is in (NULL if none).
9576 * 'owner' is the owner, NULL if there is no owner (for languages).
9577 * 'acls' is the string read out of the fooacl system catalog field;
9578 * it will be parsed here.
9579 *----------
9581 static void
9582 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
9583 const char *type, const char *name, const char *subname,
9584 const char *tag, const char *nspname, const char *owner,
9585 const char *acls)
9587 PQExpBuffer sql;
9589 /* Do nothing if ACL dump is not enabled */
9590 if (dataOnly || aclsSkip)
9591 return;
9593 sql = createPQExpBuffer();
9595 if (!buildACLCommands(name, subname, type, acls, owner, fout->remoteVersion, sql))
9597 write_msg(NULL, "could not parse ACL list (%s) for object \"%s\" (%s)\n",
9598 acls, name, type);
9599 exit_nicely();
9602 if (sql->len > 0)
9603 ArchiveEntry(fout, nilCatalogId, createDumpId(),
9604 tag, nspname,
9605 NULL,
9606 owner ? owner : "",
9607 false, "ACL", SECTION_NONE,
9608 sql->data, "", NULL,
9609 &(objDumpId), 1,
9610 NULL, NULL);
9612 destroyPQExpBuffer(sql);
9616 * dumpTable
9617 * write out to fout the declarations (not data) of a user-defined table
9619 static void
9620 dumpTable(Archive *fout, TableInfo *tbinfo)
9622 if (tbinfo->dobj.dump)
9624 char *namecopy;
9626 if (tbinfo->relkind == RELKIND_SEQUENCE)
9627 dumpSequence(fout, tbinfo);
9628 else if (!dataOnly)
9629 dumpTableSchema(fout, tbinfo);
9631 /* Handle the ACL here */
9632 namecopy = strdup(fmtId(tbinfo->dobj.name));
9633 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
9634 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE",
9635 namecopy, NULL, tbinfo->dobj.name,
9636 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
9637 tbinfo->relacl);
9640 * Handle column ACLs, if any. Note: we pull these with a separate
9641 * query rather than trying to fetch them during getTableAttrs, so
9642 * that we won't miss ACLs on system columns.
9644 if (g_fout->remoteVersion >= 80400)
9646 PQExpBuffer query = createPQExpBuffer();
9647 PGresult *res;
9648 int i;
9650 appendPQExpBuffer(query,
9651 "SELECT attname, attacl FROM pg_catalog.pg_attribute "
9652 "WHERE attrelid = '%u' AND NOT attisdropped AND attacl IS NOT NULL "
9653 "ORDER BY attnum",
9654 tbinfo->dobj.catId.oid);
9655 res = PQexec(g_conn, query->data);
9656 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9658 for (i = 0; i < PQntuples(res); i++)
9660 char *attname = PQgetvalue(res, i, 0);
9661 char *attacl = PQgetvalue(res, i, 1);
9662 char *attnamecopy;
9663 char *acltag;
9665 attnamecopy = strdup(fmtId(attname));
9666 acltag = malloc(strlen(tbinfo->dobj.name) + strlen(attname) + 2);
9667 sprintf(acltag, "%s.%s", tbinfo->dobj.name, attname);
9668 /* Column's GRANT type is always TABLE */
9669 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
9670 namecopy, attnamecopy, acltag,
9671 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
9672 attacl);
9673 free(attnamecopy);
9674 free(acltag);
9676 PQclear(res);
9677 destroyPQExpBuffer(query);
9680 free(namecopy);
9685 * dumpTableSchema
9686 * write the declaration (not data) of one user-defined table or view
9688 static void
9689 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
9691 PQExpBuffer query = createPQExpBuffer();
9692 PQExpBuffer q = createPQExpBuffer();
9693 PQExpBuffer delq = createPQExpBuffer();
9694 PGresult *res;
9695 int numParents;
9696 TableInfo **parents;
9697 int actual_atts; /* number of attrs in this CREATE statment */
9698 char *reltypename;
9699 char *storage;
9700 int j,
9703 /* Make sure we are in proper schema */
9704 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
9706 /* Is it a table or a view? */
9707 if (tbinfo->relkind == RELKIND_VIEW)
9709 char *viewdef;
9711 reltypename = "VIEW";
9713 /* Fetch the view definition */
9714 if (g_fout->remoteVersion >= 70300)
9716 /* Beginning in 7.3, viewname is not unique; rely on OID */
9717 appendPQExpBuffer(query,
9718 "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
9719 tbinfo->dobj.catId.oid);
9721 else
9723 appendPQExpBuffer(query, "SELECT definition AS viewdef "
9724 "FROM pg_views WHERE viewname = ");
9725 appendStringLiteralAH(query, tbinfo->dobj.name, fout);
9726 appendPQExpBuffer(query, ";");
9729 res = PQexec(g_conn, query->data);
9730 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9732 if (PQntuples(res) != 1)
9734 if (PQntuples(res) < 1)
9735 write_msg(NULL, "query to obtain definition of view \"%s\" returned no data\n",
9736 tbinfo->dobj.name);
9737 else
9738 write_msg(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
9739 tbinfo->dobj.name);
9740 exit_nicely();
9743 viewdef = PQgetvalue(res, 0, 0);
9745 if (strlen(viewdef) == 0)
9747 write_msg(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
9748 tbinfo->dobj.name);
9749 exit_nicely();
9753 * DROP must be fully qualified in case same name appears in
9754 * pg_catalog
9756 appendPQExpBuffer(delq, "DROP VIEW %s.",
9757 fmtId(tbinfo->dobj.namespace->dobj.name));
9758 appendPQExpBuffer(delq, "%s;\n",
9759 fmtId(tbinfo->dobj.name));
9761 appendPQExpBuffer(q, "CREATE VIEW %s AS\n %s\n",
9762 fmtId(tbinfo->dobj.name), viewdef);
9764 PQclear(res);
9766 else
9768 reltypename = "TABLE";
9769 numParents = tbinfo->numParents;
9770 parents = tbinfo->parents;
9773 * DROP must be fully qualified in case same name appears in
9774 * pg_catalog
9776 appendPQExpBuffer(delq, "DROP TABLE %s.",
9777 fmtId(tbinfo->dobj.namespace->dobj.name));
9778 appendPQExpBuffer(delq, "%s;\n",
9779 fmtId(tbinfo->dobj.name));
9781 appendPQExpBuffer(q, "CREATE TABLE %s (",
9782 fmtId(tbinfo->dobj.name));
9783 actual_atts = 0;
9784 for (j = 0; j < tbinfo->numatts; j++)
9786 /* Is this one of the table's own attrs, and not dropped ? */
9787 if (!tbinfo->inhAttrs[j] &&
9788 (!tbinfo->attisdropped[j] || binary_upgrade))
9790 /* Format properly if not first attr */
9791 if (actual_atts > 0)
9792 appendPQExpBuffer(q, ",");
9793 appendPQExpBuffer(q, "\n ");
9795 /* Attribute name */
9796 appendPQExpBuffer(q, "%s ",
9797 fmtId(tbinfo->attnames[j]));
9799 /* Attribute type */
9800 if (g_fout->remoteVersion >= 70100)
9802 appendPQExpBuffer(q, "%s",
9803 tbinfo->atttypnames[j]);
9805 else
9807 /* If no format_type, fake it */
9808 appendPQExpBuffer(q, "%s",
9809 myFormatType(tbinfo->atttypnames[j],
9810 tbinfo->atttypmod[j]));
9814 * Default value --- suppress if inherited or to be printed
9815 * separately.
9817 if (tbinfo->attrdefs[j] != NULL &&
9818 !tbinfo->inhAttrDef[j] &&
9819 !tbinfo->attrdefs[j]->separate)
9820 appendPQExpBuffer(q, " DEFAULT %s",
9821 tbinfo->attrdefs[j]->adef_expr);
9824 * Not Null constraint --- suppress if inherited
9826 if (tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
9827 appendPQExpBuffer(q, " NOT NULL");
9829 actual_atts++;
9834 * Add non-inherited CHECK constraints, if any.
9836 for (j = 0; j < tbinfo->ncheck; j++)
9838 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
9840 if (constr->separate || !constr->conislocal)
9841 continue;
9843 if (actual_atts > 0)
9844 appendPQExpBuffer(q, ",\n ");
9846 appendPQExpBuffer(q, "CONSTRAINT %s ",
9847 fmtId(constr->dobj.name));
9848 appendPQExpBuffer(q, "%s", constr->condef);
9850 actual_atts++;
9853 appendPQExpBuffer(q, "\n)");
9855 if (numParents > 0)
9857 appendPQExpBuffer(q, "\nINHERITS (");
9858 for (k = 0; k < numParents; k++)
9860 TableInfo *parentRel = parents[k];
9862 if (k > 0)
9863 appendPQExpBuffer(q, ", ");
9864 if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
9865 appendPQExpBuffer(q, "%s.",
9866 fmtId(parentRel->dobj.namespace->dobj.name));
9867 appendPQExpBuffer(q, "%s",
9868 fmtId(parentRel->dobj.name));
9870 appendPQExpBuffer(q, ")");
9873 if ((tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) ||
9874 (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0))
9876 bool addcomma = false;
9878 appendPQExpBuffer(q, "\nWITH (");
9879 if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
9881 addcomma = true;
9882 appendPQExpBuffer(q, "%s", tbinfo->reloptions);
9884 if (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0)
9886 appendPQExpBuffer(q, "%s%s", addcomma ? ", " : "",
9887 tbinfo->toast_reloptions);
9889 appendPQExpBuffer(q, ")");
9892 appendPQExpBuffer(q, ";\n");
9895 * For binary-compatible heap files, we create dropped columns above
9896 * and drop them here.
9898 if (binary_upgrade)
9900 for (j = 0; j < tbinfo->numatts; j++)
9902 if (tbinfo->attisdropped[j])
9904 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
9905 fmtId(tbinfo->dobj.name));
9906 appendPQExpBuffer(q, "DROP COLUMN %s;\n",
9907 fmtId(tbinfo->attnames[j]));
9910 * ALTER TABLE DROP COLUMN clears pg_attribute.atttypid,
9911 * so we have to set pg_attribute.attlen and
9912 * pg_attribute.attalign values because that is what is
9913 * used to skip over dropped columns in the heap tuples.
9914 * We have atttypmod, but it seems impossible to know the
9915 * correct data type that will yield pg_attribute values
9916 * that match the old installation. See comment in
9917 * backend/catalog/heap.c::RemoveAttributeById()
9919 appendPQExpBuffer(q, "\n-- For binary upgrade, recreate dropped column's length and alignment.\n");
9920 appendPQExpBuffer(q, "UPDATE pg_attribute\n"
9921 "SET attlen = %d, "
9922 "attalign = '%c'\n"
9923 "WHERE attname = '%s'\n"
9924 " AND attrelid = \n"
9925 " (\n"
9926 " SELECT oid\n"
9927 " FROM pg_class\n"
9928 " WHERE relnamespace = "
9929 "(SELECT oid FROM pg_namespace "
9930 "WHERE nspname = CURRENT_SCHEMA)\n"
9931 " AND relname = ",
9932 tbinfo->attlen[j],
9933 tbinfo->attalign[j],
9934 tbinfo->attnames[j]);
9935 appendStringLiteralAH(q, tbinfo->dobj.name, fout);
9936 appendPQExpBuffer(q, "\n );\n");
9939 appendPQExpBuffer(q, "\n-- For binary upgrade, set relfrozenxid.\n");
9940 appendPQExpBuffer(q, "UPDATE pg_class\n"
9941 "SET relfrozenxid = '%u'\n"
9942 "WHERE relname = ",
9943 tbinfo->frozenxid);
9944 appendStringLiteralAH(q, tbinfo->dobj.name, fout);
9945 appendPQExpBuffer(q, "\n AND relnamespace = "
9946 "(SELECT oid FROM pg_namespace "
9947 "WHERE nspname = CURRENT_SCHEMA);\n");
9950 /* Loop dumping statistics and storage statements */
9951 for (j = 0; j < tbinfo->numatts; j++)
9954 * Dump per-column statistics information. We only issue an ALTER
9955 * TABLE statement if the attstattarget entry for this column is
9956 * non-negative (i.e. it's not the default value)
9958 if (tbinfo->attstattarget[j] >= 0 &&
9959 !tbinfo->attisdropped[j])
9961 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
9962 fmtId(tbinfo->dobj.name));
9963 appendPQExpBuffer(q, "ALTER COLUMN %s ",
9964 fmtId(tbinfo->attnames[j]));
9965 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
9966 tbinfo->attstattarget[j]);
9970 * Dump per-column storage information. The statement is only
9971 * dumped if the storage has been changed from the type's default.
9973 if (!tbinfo->attisdropped[j] && tbinfo->attstorage[j] != tbinfo->typstorage[j])
9975 switch (tbinfo->attstorage[j])
9977 case 'p':
9978 storage = "PLAIN";
9979 break;
9980 case 'e':
9981 storage = "EXTERNAL";
9982 break;
9983 case 'm':
9984 storage = "MAIN";
9985 break;
9986 case 'x':
9987 storage = "EXTENDED";
9988 break;
9989 default:
9990 storage = NULL;
9994 * Only dump the statement if it's a storage type we recognize
9996 if (storage != NULL)
9998 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
9999 fmtId(tbinfo->dobj.name));
10000 appendPQExpBuffer(q, "ALTER COLUMN %s ",
10001 fmtId(tbinfo->attnames[j]));
10002 appendPQExpBuffer(q, "SET STORAGE %s;\n",
10003 storage);
10009 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
10010 tbinfo->dobj.name,
10011 tbinfo->dobj.namespace->dobj.name,
10012 (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
10013 tbinfo->rolname,
10014 (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
10015 reltypename, SECTION_PRE_DATA,
10016 q->data, delq->data, NULL,
10017 tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
10018 NULL, NULL);
10020 /* Dump Table Comments */
10021 dumpTableComment(fout, tbinfo, reltypename);
10023 /* Dump comments on inlined table constraints */
10024 for (j = 0; j < tbinfo->ncheck; j++)
10026 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
10028 if (constr->separate || !constr->conislocal)
10029 continue;
10031 dumpTableConstraintComment(fout, constr);
10034 destroyPQExpBuffer(query);
10035 destroyPQExpBuffer(q);
10036 destroyPQExpBuffer(delq);
10040 * dumpAttrDef --- dump an attribute's default-value declaration
10042 static void
10043 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
10045 TableInfo *tbinfo = adinfo->adtable;
10046 int adnum = adinfo->adnum;
10047 PQExpBuffer q;
10048 PQExpBuffer delq;
10050 /* Only print it if "separate" mode is selected */
10051 if (!tbinfo->dobj.dump || !adinfo->separate || dataOnly)
10052 return;
10054 /* Don't print inherited defaults, either */
10055 if (tbinfo->inhAttrDef[adnum - 1])
10056 return;
10058 q = createPQExpBuffer();
10059 delq = createPQExpBuffer();
10061 appendPQExpBuffer(q, "ALTER TABLE %s ",
10062 fmtId(tbinfo->dobj.name));
10063 appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
10064 fmtId(tbinfo->attnames[adnum - 1]),
10065 adinfo->adef_expr);
10068 * DROP must be fully qualified in case same name appears in pg_catalog
10070 appendPQExpBuffer(delq, "ALTER TABLE %s.",
10071 fmtId(tbinfo->dobj.namespace->dobj.name));
10072 appendPQExpBuffer(delq, "%s ",
10073 fmtId(tbinfo->dobj.name));
10074 appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
10075 fmtId(tbinfo->attnames[adnum - 1]));
10077 ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
10078 tbinfo->attnames[adnum - 1],
10079 tbinfo->dobj.namespace->dobj.name,
10080 NULL,
10081 tbinfo->rolname,
10082 false, "DEFAULT", SECTION_PRE_DATA,
10083 q->data, delq->data, NULL,
10084 adinfo->dobj.dependencies, adinfo->dobj.nDeps,
10085 NULL, NULL);
10087 destroyPQExpBuffer(q);
10088 destroyPQExpBuffer(delq);
10092 * getAttrName: extract the correct name for an attribute
10094 * The array tblInfo->attnames[] only provides names of user attributes;
10095 * if a system attribute number is supplied, we have to fake it.
10096 * We also do a little bit of bounds checking for safety's sake.
10098 static const char *
10099 getAttrName(int attrnum, TableInfo *tblInfo)
10101 if (attrnum > 0 && attrnum <= tblInfo->numatts)
10102 return tblInfo->attnames[attrnum - 1];
10103 switch (attrnum)
10105 case SelfItemPointerAttributeNumber:
10106 return "ctid";
10107 case ObjectIdAttributeNumber:
10108 return "oid";
10109 case MinTransactionIdAttributeNumber:
10110 return "xmin";
10111 case MinCommandIdAttributeNumber:
10112 return "cmin";
10113 case MaxTransactionIdAttributeNumber:
10114 return "xmax";
10115 case MaxCommandIdAttributeNumber:
10116 return "cmax";
10117 case TableOidAttributeNumber:
10118 return "tableoid";
10120 write_msg(NULL, "invalid column number %d for table \"%s\"\n",
10121 attrnum, tblInfo->dobj.name);
10122 exit_nicely();
10123 return NULL; /* keep compiler quiet */
10127 * dumpIndex
10128 * write out to fout a user-defined index
10130 static void
10131 dumpIndex(Archive *fout, IndxInfo *indxinfo)
10133 TableInfo *tbinfo = indxinfo->indextable;
10134 PQExpBuffer q;
10135 PQExpBuffer delq;
10137 if (dataOnly)
10138 return;
10140 q = createPQExpBuffer();
10141 delq = createPQExpBuffer();
10144 * If there's an associated constraint, don't dump the index per se, but
10145 * do dump any comment for it. (This is safe because dependency ordering
10146 * will have ensured the constraint is emitted first.)
10148 if (indxinfo->indexconstraint == 0)
10150 /* Plain secondary index */
10151 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
10153 /* If the index is clustered, we need to record that. */
10154 if (indxinfo->indisclustered)
10156 appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
10157 fmtId(tbinfo->dobj.name));
10158 appendPQExpBuffer(q, " ON %s;\n",
10159 fmtId(indxinfo->dobj.name));
10163 * DROP must be fully qualified in case same name appears in
10164 * pg_catalog
10166 appendPQExpBuffer(delq, "DROP INDEX %s.",
10167 fmtId(tbinfo->dobj.namespace->dobj.name));
10168 appendPQExpBuffer(delq, "%s;\n",
10169 fmtId(indxinfo->dobj.name));
10171 ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
10172 indxinfo->dobj.name,
10173 tbinfo->dobj.namespace->dobj.name,
10174 indxinfo->tablespace,
10175 tbinfo->rolname, false,
10176 "INDEX", SECTION_POST_DATA,
10177 q->data, delq->data, NULL,
10178 indxinfo->dobj.dependencies, indxinfo->dobj.nDeps,
10179 NULL, NULL);
10182 /* Dump Index Comments */
10183 resetPQExpBuffer(q);
10184 appendPQExpBuffer(q, "INDEX %s",
10185 fmtId(indxinfo->dobj.name));
10186 dumpComment(fout, q->data,
10187 tbinfo->dobj.namespace->dobj.name,
10188 tbinfo->rolname,
10189 indxinfo->dobj.catId, 0, indxinfo->dobj.dumpId);
10191 destroyPQExpBuffer(q);
10192 destroyPQExpBuffer(delq);
10196 * dumpConstraint
10197 * write out to fout a user-defined constraint
10199 static void
10200 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
10202 TableInfo *tbinfo = coninfo->contable;
10203 PQExpBuffer q;
10204 PQExpBuffer delq;
10206 /* Skip if not to be dumped */
10207 if (!coninfo->dobj.dump || dataOnly)
10208 return;
10210 q = createPQExpBuffer();
10211 delq = createPQExpBuffer();
10213 if (coninfo->contype == 'p' || coninfo->contype == 'u')
10215 /* Index-related constraint */
10216 IndxInfo *indxinfo;
10217 int k;
10219 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
10221 if (indxinfo == NULL)
10223 write_msg(NULL, "missing index for constraint \"%s\"\n",
10224 coninfo->dobj.name);
10225 exit_nicely();
10228 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
10229 fmtId(tbinfo->dobj.name));
10230 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s (",
10231 fmtId(coninfo->dobj.name),
10232 coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
10234 for (k = 0; k < indxinfo->indnkeys; k++)
10236 int indkey = (int) indxinfo->indkeys[k];
10237 const char *attname;
10239 if (indkey == InvalidAttrNumber)
10240 break;
10241 attname = getAttrName(indkey, tbinfo);
10243 appendPQExpBuffer(q, "%s%s",
10244 (k == 0) ? "" : ", ",
10245 fmtId(attname));
10248 appendPQExpBuffer(q, ")");
10250 if (indxinfo->options && strlen(indxinfo->options) > 0)
10251 appendPQExpBuffer(q, " WITH (%s)", indxinfo->options);
10253 appendPQExpBuffer(q, ";\n");
10255 /* If the index is clustered, we need to record that. */
10256 if (indxinfo->indisclustered)
10258 appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
10259 fmtId(tbinfo->dobj.name));
10260 appendPQExpBuffer(q, " ON %s;\n",
10261 fmtId(indxinfo->dobj.name));
10265 * DROP must be fully qualified in case same name appears in
10266 * pg_catalog
10268 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
10269 fmtId(tbinfo->dobj.namespace->dobj.name));
10270 appendPQExpBuffer(delq, "%s ",
10271 fmtId(tbinfo->dobj.name));
10272 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
10273 fmtId(coninfo->dobj.name));
10275 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
10276 coninfo->dobj.name,
10277 tbinfo->dobj.namespace->dobj.name,
10278 indxinfo->tablespace,
10279 tbinfo->rolname, false,
10280 "CONSTRAINT", SECTION_POST_DATA,
10281 q->data, delq->data, NULL,
10282 coninfo->dobj.dependencies, coninfo->dobj.nDeps,
10283 NULL, NULL);
10285 else if (coninfo->contype == 'f')
10288 * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
10289 * current table data is not processed
10291 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
10292 fmtId(tbinfo->dobj.name));
10293 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
10294 fmtId(coninfo->dobj.name),
10295 coninfo->condef);
10298 * DROP must be fully qualified in case same name appears in
10299 * pg_catalog
10301 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
10302 fmtId(tbinfo->dobj.namespace->dobj.name));
10303 appendPQExpBuffer(delq, "%s ",
10304 fmtId(tbinfo->dobj.name));
10305 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
10306 fmtId(coninfo->dobj.name));
10308 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
10309 coninfo->dobj.name,
10310 tbinfo->dobj.namespace->dobj.name,
10311 NULL,
10312 tbinfo->rolname, false,
10313 "FK CONSTRAINT", SECTION_POST_DATA,
10314 q->data, delq->data, NULL,
10315 coninfo->dobj.dependencies, coninfo->dobj.nDeps,
10316 NULL, NULL);
10318 else if (coninfo->contype == 'c' && tbinfo)
10320 /* CHECK constraint on a table */
10322 /* Ignore if not to be dumped separately */
10323 if (coninfo->separate)
10325 /* not ONLY since we want it to propagate to children */
10326 appendPQExpBuffer(q, "ALTER TABLE %s\n",
10327 fmtId(tbinfo->dobj.name));
10328 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
10329 fmtId(coninfo->dobj.name),
10330 coninfo->condef);
10333 * DROP must be fully qualified in case same name appears in
10334 * pg_catalog
10336 appendPQExpBuffer(delq, "ALTER TABLE %s.",
10337 fmtId(tbinfo->dobj.namespace->dobj.name));
10338 appendPQExpBuffer(delq, "%s ",
10339 fmtId(tbinfo->dobj.name));
10340 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
10341 fmtId(coninfo->dobj.name));
10343 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
10344 coninfo->dobj.name,
10345 tbinfo->dobj.namespace->dobj.name,
10346 NULL,
10347 tbinfo->rolname, false,
10348 "CHECK CONSTRAINT", SECTION_POST_DATA,
10349 q->data, delq->data, NULL,
10350 coninfo->dobj.dependencies, coninfo->dobj.nDeps,
10351 NULL, NULL);
10354 else if (coninfo->contype == 'c' && tbinfo == NULL)
10356 /* CHECK constraint on a domain */
10357 TypeInfo *tinfo = coninfo->condomain;
10359 /* Ignore if not to be dumped separately */
10360 if (coninfo->separate)
10362 appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
10363 fmtId(tinfo->dobj.name));
10364 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
10365 fmtId(coninfo->dobj.name),
10366 coninfo->condef);
10369 * DROP must be fully qualified in case same name appears in
10370 * pg_catalog
10372 appendPQExpBuffer(delq, "ALTER DOMAIN %s.",
10373 fmtId(tinfo->dobj.namespace->dobj.name));
10374 appendPQExpBuffer(delq, "%s ",
10375 fmtId(tinfo->dobj.name));
10376 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
10377 fmtId(coninfo->dobj.name));
10379 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
10380 coninfo->dobj.name,
10381 tinfo->dobj.namespace->dobj.name,
10382 NULL,
10383 tinfo->rolname, false,
10384 "CHECK CONSTRAINT", SECTION_POST_DATA,
10385 q->data, delq->data, NULL,
10386 coninfo->dobj.dependencies, coninfo->dobj.nDeps,
10387 NULL, NULL);
10390 else
10392 write_msg(NULL, "unrecognized constraint type: %c\n", coninfo->contype);
10393 exit_nicely();
10396 /* Dump Constraint Comments --- only works for table constraints */
10397 if (tbinfo && coninfo->separate)
10398 dumpTableConstraintComment(fout, coninfo);
10400 destroyPQExpBuffer(q);
10401 destroyPQExpBuffer(delq);
10405 * dumpTableConstraintComment --- dump a constraint's comment if any
10407 * This is split out because we need the function in two different places
10408 * depending on whether the constraint is dumped as part of CREATE TABLE
10409 * or as a separate ALTER command.
10411 static void
10412 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
10414 TableInfo *tbinfo = coninfo->contable;
10415 PQExpBuffer q = createPQExpBuffer();
10417 appendPQExpBuffer(q, "CONSTRAINT %s ",
10418 fmtId(coninfo->dobj.name));
10419 appendPQExpBuffer(q, "ON %s",
10420 fmtId(tbinfo->dobj.name));
10421 dumpComment(fout, q->data,
10422 tbinfo->dobj.namespace->dobj.name,
10423 tbinfo->rolname,
10424 coninfo->dobj.catId, 0,
10425 coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
10427 destroyPQExpBuffer(q);
10431 * findLastBuiltInOid -
10432 * find the last built in oid
10434 * For 7.1 and 7.2, we do this by retrieving datlastsysoid from the
10435 * pg_database entry for the current database
10437 static Oid
10438 findLastBuiltinOid_V71(const char *dbname)
10440 PGresult *res;
10441 int ntups;
10442 Oid last_oid;
10443 PQExpBuffer query = createPQExpBuffer();
10445 resetPQExpBuffer(query);
10446 appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
10447 appendStringLiteralAH(query, dbname, g_fout);
10449 res = PQexec(g_conn, query->data);
10450 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10452 ntups = PQntuples(res);
10453 if (ntups < 1)
10455 write_msg(NULL, "missing pg_database entry for this database\n");
10456 exit_nicely();
10458 if (ntups > 1)
10460 write_msg(NULL, "found more than one pg_database entry for this database\n");
10461 exit_nicely();
10463 last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
10464 PQclear(res);
10465 destroyPQExpBuffer(query);
10466 return last_oid;
10470 * findLastBuiltInOid -
10471 * find the last built in oid
10473 * For 7.0, we do this by assuming that the last thing that initdb does is to
10474 * create the pg_indexes view. This sucks in general, but seeing that 7.0.x
10475 * initdb won't be changing anymore, it'll do.
10477 static Oid
10478 findLastBuiltinOid_V70(void)
10480 PGresult *res;
10481 int ntups;
10482 int last_oid;
10484 res = PQexec(g_conn,
10485 "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'");
10486 check_sql_result(res, g_conn,
10487 "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'",
10488 PGRES_TUPLES_OK);
10489 ntups = PQntuples(res);
10490 if (ntups < 1)
10492 write_msg(NULL, "could not find entry for pg_indexes in pg_class\n");
10493 exit_nicely();
10495 if (ntups > 1)
10497 write_msg(NULL, "found more than one entry for pg_indexes in pg_class\n");
10498 exit_nicely();
10500 last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
10501 PQclear(res);
10502 return last_oid;
10505 static void
10506 dumpSequence(Archive *fout, TableInfo *tbinfo)
10508 PGresult *res;
10509 char *startv,
10510 *last,
10511 *incby,
10512 *maxv = NULL,
10513 *minv = NULL,
10514 *cache;
10515 char bufm[100],
10516 bufx[100];
10517 bool cycled,
10518 called;
10519 PQExpBuffer query = createPQExpBuffer();
10520 PQExpBuffer delqry = createPQExpBuffer();
10522 /* Make sure we are in proper schema */
10523 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
10525 snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
10526 snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
10528 if (g_fout->remoteVersion >= 80400)
10530 appendPQExpBuffer(query,
10531 "SELECT sequence_name, "
10532 "start_value, last_value, increment_by, "
10533 "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
10534 " WHEN increment_by < 0 AND max_value = -1 THEN NULL "
10535 " ELSE max_value "
10536 "END AS max_value, "
10537 "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
10538 " WHEN increment_by < 0 AND min_value = %s THEN NULL "
10539 " ELSE min_value "
10540 "END AS min_value, "
10541 "cache_value, is_cycled, is_called from %s",
10542 bufx, bufm,
10543 fmtId(tbinfo->dobj.name));
10545 else
10547 appendPQExpBuffer(query,
10548 "SELECT sequence_name, "
10549 "0 AS start_value, last_value, increment_by, "
10550 "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
10551 " WHEN increment_by < 0 AND max_value = -1 THEN NULL "
10552 " ELSE max_value "
10553 "END AS max_value, "
10554 "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
10555 " WHEN increment_by < 0 AND min_value = %s THEN NULL "
10556 " ELSE min_value "
10557 "END AS min_value, "
10558 "cache_value, is_cycled, is_called from %s",
10559 bufx, bufm,
10560 fmtId(tbinfo->dobj.name));
10563 res = PQexec(g_conn, query->data);
10564 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10566 if (PQntuples(res) != 1)
10568 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
10569 "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
10570 PQntuples(res)),
10571 tbinfo->dobj.name, PQntuples(res));
10572 exit_nicely();
10575 /* Disable this check: it fails if sequence has been renamed */
10576 #ifdef NOT_USED
10577 if (strcmp(PQgetvalue(res, 0, 0), tbinfo->dobj.name) != 0)
10579 write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
10580 tbinfo->dobj.name, PQgetvalue(res, 0, 0));
10581 exit_nicely();
10583 #endif
10585 startv = PQgetvalue(res, 0, 1);
10586 last = PQgetvalue(res, 0, 2);
10587 incby = PQgetvalue(res, 0, 3);
10588 if (!PQgetisnull(res, 0, 4))
10589 maxv = PQgetvalue(res, 0, 4);
10590 if (!PQgetisnull(res, 0, 5))
10591 minv = PQgetvalue(res, 0, 5);
10592 cache = PQgetvalue(res, 0, 6);
10593 cycled = (strcmp(PQgetvalue(res, 0, 7), "t") == 0);
10594 called = (strcmp(PQgetvalue(res, 0, 8), "t") == 0);
10597 * The logic we use for restoring sequences is as follows:
10599 * Add a CREATE SEQUENCE statement as part of a "schema" dump (use
10600 * last_val for start if called is false, else use min_val for start_val).
10601 * Also, if the sequence is owned by a column, add an ALTER SEQUENCE OWNED
10602 * BY command for it.
10604 * Add a 'SETVAL(seq, last_val, iscalled)' as part of a "data" dump.
10606 if (!dataOnly)
10608 resetPQExpBuffer(delqry);
10611 * DROP must be fully qualified in case same name appears in
10612 * pg_catalog
10614 appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
10615 fmtId(tbinfo->dobj.namespace->dobj.name));
10616 appendPQExpBuffer(delqry, "%s;\n",
10617 fmtId(tbinfo->dobj.name));
10619 resetPQExpBuffer(query);
10620 appendPQExpBuffer(query,
10621 "CREATE SEQUENCE %s\n",
10622 fmtId(tbinfo->dobj.name));
10624 if (g_fout->remoteVersion >= 80400)
10625 appendPQExpBuffer(query, " START WITH %s\n", startv);
10626 else
10629 * Versions before 8.4 did not remember the true start value. If
10630 * is_called is false then the sequence has never been incremented
10631 * so we can use last_val. Otherwise punt and let it default.
10633 if (!called)
10634 appendPQExpBuffer(query, " START WITH %s\n", last);
10637 appendPQExpBuffer(query, " INCREMENT BY %s\n", incby);
10639 if (maxv)
10640 appendPQExpBuffer(query, " MAXVALUE %s\n", maxv);
10641 else
10642 appendPQExpBuffer(query, " NO MAXVALUE\n");
10644 if (minv)
10645 appendPQExpBuffer(query, " MINVALUE %s\n", minv);
10646 else
10647 appendPQExpBuffer(query, " NO MINVALUE\n");
10649 appendPQExpBuffer(query,
10650 " CACHE %s%s",
10651 cache, (cycled ? "\n CYCLE" : ""));
10653 appendPQExpBuffer(query, ";\n");
10655 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
10656 tbinfo->dobj.name,
10657 tbinfo->dobj.namespace->dobj.name,
10658 NULL,
10659 tbinfo->rolname,
10660 false, "SEQUENCE", SECTION_PRE_DATA,
10661 query->data, delqry->data, NULL,
10662 tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
10663 NULL, NULL);
10666 * If the sequence is owned by a table column, emit the ALTER for it
10667 * as a separate TOC entry immediately following the sequence's own
10668 * entry. It's OK to do this rather than using full sorting logic,
10669 * because the dependency that tells us it's owned will have forced
10670 * the table to be created first. We can't just include the ALTER in
10671 * the TOC entry because it will fail if we haven't reassigned the
10672 * sequence owner to match the table's owner.
10674 * We need not schema-qualify the table reference because both
10675 * sequence and table must be in the same schema.
10677 if (OidIsValid(tbinfo->owning_tab))
10679 TableInfo *owning_tab = findTableByOid(tbinfo->owning_tab);
10681 if (owning_tab && owning_tab->dobj.dump)
10683 resetPQExpBuffer(query);
10684 appendPQExpBuffer(query, "ALTER SEQUENCE %s",
10685 fmtId(tbinfo->dobj.name));
10686 appendPQExpBuffer(query, " OWNED BY %s",
10687 fmtId(owning_tab->dobj.name));
10688 appendPQExpBuffer(query, ".%s;\n",
10689 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
10691 ArchiveEntry(fout, nilCatalogId, createDumpId(),
10692 tbinfo->dobj.name,
10693 tbinfo->dobj.namespace->dobj.name,
10694 NULL,
10695 tbinfo->rolname,
10696 false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
10697 query->data, "", NULL,
10698 &(tbinfo->dobj.dumpId), 1,
10699 NULL, NULL);
10703 /* Dump Sequence Comments */
10704 resetPQExpBuffer(query);
10705 appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
10706 dumpComment(fout, query->data,
10707 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
10708 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
10711 if (!schemaOnly)
10713 resetPQExpBuffer(query);
10714 appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
10715 appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
10716 appendPQExpBuffer(query, ", %s, %s);\n",
10717 last, (called ? "true" : "false"));
10719 ArchiveEntry(fout, nilCatalogId, createDumpId(),
10720 tbinfo->dobj.name,
10721 tbinfo->dobj.namespace->dobj.name,
10722 NULL,
10723 tbinfo->rolname,
10724 false, "SEQUENCE SET", SECTION_PRE_DATA,
10725 query->data, "", NULL,
10726 &(tbinfo->dobj.dumpId), 1,
10727 NULL, NULL);
10730 PQclear(res);
10732 destroyPQExpBuffer(query);
10733 destroyPQExpBuffer(delqry);
10736 static void
10737 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
10739 TableInfo *tbinfo = tginfo->tgtable;
10740 PQExpBuffer query;
10741 PQExpBuffer delqry;
10742 const char *p;
10743 int findx;
10745 if (dataOnly)
10746 return;
10748 query = createPQExpBuffer();
10749 delqry = createPQExpBuffer();
10752 * DROP must be fully qualified in case same name appears in pg_catalog
10754 appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
10755 fmtId(tginfo->dobj.name));
10756 appendPQExpBuffer(delqry, "ON %s.",
10757 fmtId(tbinfo->dobj.namespace->dobj.name));
10758 appendPQExpBuffer(delqry, "%s;\n",
10759 fmtId(tbinfo->dobj.name));
10761 if (tginfo->tgisconstraint)
10763 appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
10764 appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
10766 else
10768 appendPQExpBuffer(query, "CREATE TRIGGER ");
10769 appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
10771 appendPQExpBuffer(query, "\n ");
10773 /* Trigger type */
10774 findx = 0;
10775 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
10776 appendPQExpBuffer(query, "BEFORE");
10777 else
10778 appendPQExpBuffer(query, "AFTER");
10779 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
10781 appendPQExpBuffer(query, " INSERT");
10782 findx++;
10784 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
10786 if (findx > 0)
10787 appendPQExpBuffer(query, " OR DELETE");
10788 else
10789 appendPQExpBuffer(query, " DELETE");
10790 findx++;
10792 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
10794 if (findx > 0)
10795 appendPQExpBuffer(query, " OR UPDATE");
10796 else
10797 appendPQExpBuffer(query, " UPDATE");
10799 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
10801 if (findx > 0)
10802 appendPQExpBuffer(query, " OR TRUNCATE");
10803 else
10804 appendPQExpBuffer(query, " TRUNCATE");
10806 appendPQExpBuffer(query, " ON %s\n",
10807 fmtId(tbinfo->dobj.name));
10809 if (tginfo->tgisconstraint)
10811 if (OidIsValid(tginfo->tgconstrrelid))
10813 /* If we are using regclass, name is already quoted */
10814 if (g_fout->remoteVersion >= 70300)
10815 appendPQExpBuffer(query, " FROM %s\n ",
10816 tginfo->tgconstrrelname);
10817 else
10818 appendPQExpBuffer(query, " FROM %s\n ",
10819 fmtId(tginfo->tgconstrrelname));
10821 if (!tginfo->tgdeferrable)
10822 appendPQExpBuffer(query, "NOT ");
10823 appendPQExpBuffer(query, "DEFERRABLE INITIALLY ");
10824 if (tginfo->tginitdeferred)
10825 appendPQExpBuffer(query, "DEFERRED\n");
10826 else
10827 appendPQExpBuffer(query, "IMMEDIATE\n");
10830 if (TRIGGER_FOR_ROW(tginfo->tgtype))
10831 appendPQExpBuffer(query, " FOR EACH ROW\n ");
10832 else
10833 appendPQExpBuffer(query, " FOR EACH STATEMENT\n ");
10835 /* In 7.3, result of regproc is already quoted */
10836 if (g_fout->remoteVersion >= 70300)
10837 appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
10838 tginfo->tgfname);
10839 else
10840 appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
10841 fmtId(tginfo->tgfname));
10843 p = tginfo->tgargs;
10844 for (findx = 0; findx < tginfo->tgnargs; findx++)
10846 const char *s = p;
10848 /* Set 'p' to end of arg string. marked by '\000' */
10849 for (;;)
10851 p = strchr(p, '\\');
10852 if (p == NULL)
10854 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
10855 tginfo->tgargs,
10856 tginfo->dobj.name,
10857 tbinfo->dobj.name);
10858 exit_nicely();
10860 p++;
10861 if (*p == '\\') /* is it '\\'? */
10863 p++;
10864 continue;
10866 if (p[0] == '0' && p[1] == '0' && p[2] == '0') /* is it '\000'? */
10867 break;
10869 p--;
10871 appendPQExpBufferChar(query, '\'');
10872 while (s < p)
10874 if (*s == '\'')
10875 appendPQExpBufferChar(query, '\'');
10878 * bytea unconditionally doubles backslashes, so we suppress the
10879 * doubling for standard_conforming_strings.
10881 if (fout->std_strings && *s == '\\' && s[1] == '\\')
10882 s++;
10883 appendPQExpBufferChar(query, *s++);
10885 appendPQExpBufferChar(query, '\'');
10886 appendPQExpBuffer(query,
10887 (findx < tginfo->tgnargs - 1) ? ", " : "");
10888 p = p + 4;
10890 appendPQExpBuffer(query, ");\n");
10892 if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
10894 appendPQExpBuffer(query, "\nALTER TABLE %s ",
10895 fmtId(tbinfo->dobj.name));
10896 switch (tginfo->tgenabled)
10898 case 'D':
10899 case 'f':
10900 appendPQExpBuffer(query, "DISABLE");
10901 break;
10902 case 'A':
10903 appendPQExpBuffer(query, "ENABLE ALWAYS");
10904 break;
10905 case 'R':
10906 appendPQExpBuffer(query, "ENABLE REPLICA");
10907 break;
10908 default:
10909 appendPQExpBuffer(query, "ENABLE");
10910 break;
10912 appendPQExpBuffer(query, " TRIGGER %s;\n",
10913 fmtId(tginfo->dobj.name));
10916 ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
10917 tginfo->dobj.name,
10918 tbinfo->dobj.namespace->dobj.name,
10919 NULL,
10920 tbinfo->rolname, false,
10921 "TRIGGER", SECTION_POST_DATA,
10922 query->data, delqry->data, NULL,
10923 tginfo->dobj.dependencies, tginfo->dobj.nDeps,
10924 NULL, NULL);
10926 resetPQExpBuffer(query);
10927 appendPQExpBuffer(query, "TRIGGER %s ",
10928 fmtId(tginfo->dobj.name));
10929 appendPQExpBuffer(query, "ON %s",
10930 fmtId(tbinfo->dobj.name));
10932 dumpComment(fout, query->data,
10933 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
10934 tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
10936 destroyPQExpBuffer(query);
10937 destroyPQExpBuffer(delqry);
10941 * dumpRule
10942 * Dump a rule
10944 static void
10945 dumpRule(Archive *fout, RuleInfo *rinfo)
10947 TableInfo *tbinfo = rinfo->ruletable;
10948 PQExpBuffer query;
10949 PQExpBuffer cmd;
10950 PQExpBuffer delcmd;
10951 PGresult *res;
10953 /* Skip if not to be dumped */
10954 if (!rinfo->dobj.dump || dataOnly)
10955 return;
10958 * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
10959 * we do not want to dump it as a separate object.
10961 if (!rinfo->separate)
10962 return;
10965 * Make sure we are in proper schema.
10967 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
10969 query = createPQExpBuffer();
10970 cmd = createPQExpBuffer();
10971 delcmd = createPQExpBuffer();
10973 if (g_fout->remoteVersion >= 70300)
10975 appendPQExpBuffer(query,
10976 "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid) AS definition",
10977 rinfo->dobj.catId.oid);
10979 else
10981 /* Rule name was unique before 7.3 ... */
10982 appendPQExpBuffer(query,
10983 "SELECT pg_get_ruledef('%s') AS definition",
10984 rinfo->dobj.name);
10987 res = PQexec(g_conn, query->data);
10988 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10990 if (PQntuples(res) != 1)
10992 write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
10993 rinfo->dobj.name, tbinfo->dobj.name);
10994 exit_nicely();
10997 printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
11000 * Add the command to alter the rules replication firing semantics if it
11001 * differs from the default.
11003 if (rinfo->ev_enabled != 'O')
11005 appendPQExpBuffer(cmd, "ALTER TABLE %s.",
11006 fmtId(tbinfo->dobj.namespace->dobj.name));
11007 appendPQExpBuffer(cmd, "%s ",
11008 fmtId(tbinfo->dobj.name));
11009 switch (rinfo->ev_enabled)
11011 case 'A':
11012 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
11013 fmtId(rinfo->dobj.name));
11014 break;
11015 case 'R':
11016 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
11017 fmtId(rinfo->dobj.name));
11018 break;
11019 case 'D':
11020 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
11021 fmtId(rinfo->dobj.name));
11022 break;
11027 * DROP must be fully qualified in case same name appears in pg_catalog
11029 appendPQExpBuffer(delcmd, "DROP RULE %s ",
11030 fmtId(rinfo->dobj.name));
11031 appendPQExpBuffer(delcmd, "ON %s.",
11032 fmtId(tbinfo->dobj.namespace->dobj.name));
11033 appendPQExpBuffer(delcmd, "%s;\n",
11034 fmtId(tbinfo->dobj.name));
11036 ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
11037 rinfo->dobj.name,
11038 tbinfo->dobj.namespace->dobj.name,
11039 NULL,
11040 tbinfo->rolname, false,
11041 "RULE", SECTION_POST_DATA,
11042 cmd->data, delcmd->data, NULL,
11043 rinfo->dobj.dependencies, rinfo->dobj.nDeps,
11044 NULL, NULL);
11046 /* Dump rule comments */
11047 resetPQExpBuffer(query);
11048 appendPQExpBuffer(query, "RULE %s",
11049 fmtId(rinfo->dobj.name));
11050 appendPQExpBuffer(query, " ON %s",
11051 fmtId(tbinfo->dobj.name));
11052 dumpComment(fout, query->data,
11053 tbinfo->dobj.namespace->dobj.name,
11054 tbinfo->rolname,
11055 rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
11057 PQclear(res);
11059 destroyPQExpBuffer(query);
11060 destroyPQExpBuffer(cmd);
11061 destroyPQExpBuffer(delcmd);
11065 * getDependencies --- obtain available dependency data
11067 static void
11068 getDependencies(void)
11070 PQExpBuffer query;
11071 PGresult *res;
11072 int ntups,
11074 int i_classid,
11075 i_objid,
11076 i_refclassid,
11077 i_refobjid,
11078 i_deptype;
11079 DumpableObject *dobj,
11080 *refdobj;
11082 /* No dependency info available before 7.3 */
11083 if (g_fout->remoteVersion < 70300)
11084 return;
11086 if (g_verbose)
11087 write_msg(NULL, "reading dependency data\n");
11089 /* Make sure we are in proper schema */
11090 selectSourceSchema("pg_catalog");
11092 query = createPQExpBuffer();
11094 appendPQExpBuffer(query, "SELECT "
11095 "classid, objid, refclassid, refobjid, deptype "
11096 "FROM pg_depend "
11097 "WHERE deptype != 'p' "
11098 "ORDER BY 1,2");
11100 res = PQexec(g_conn, query->data);
11101 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11103 ntups = PQntuples(res);
11105 i_classid = PQfnumber(res, "classid");
11106 i_objid = PQfnumber(res, "objid");
11107 i_refclassid = PQfnumber(res, "refclassid");
11108 i_refobjid = PQfnumber(res, "refobjid");
11109 i_deptype = PQfnumber(res, "deptype");
11112 * Since we ordered the SELECT by referencing ID, we can expect that
11113 * multiple entries for the same object will appear together; this saves
11114 * on searches.
11116 dobj = NULL;
11118 for (i = 0; i < ntups; i++)
11120 CatalogId objId;
11121 CatalogId refobjId;
11122 char deptype;
11124 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
11125 objId.oid = atooid(PQgetvalue(res, i, i_objid));
11126 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
11127 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
11128 deptype = *(PQgetvalue(res, i, i_deptype));
11130 if (dobj == NULL ||
11131 dobj->catId.tableoid != objId.tableoid ||
11132 dobj->catId.oid != objId.oid)
11133 dobj = findObjectByCatalogId(objId);
11136 * Failure to find objects mentioned in pg_depend is not unexpected,
11137 * since for example we don't collect info about TOAST tables.
11139 if (dobj == NULL)
11141 #ifdef NOT_USED
11142 fprintf(stderr, "no referencing object %u %u\n",
11143 objId.tableoid, objId.oid);
11144 #endif
11145 continue;
11148 refdobj = findObjectByCatalogId(refobjId);
11150 if (refdobj == NULL)
11152 #ifdef NOT_USED
11153 fprintf(stderr, "no referenced object %u %u\n",
11154 refobjId.tableoid, refobjId.oid);
11155 #endif
11156 continue;
11160 * Ordinarily, table rowtypes have implicit dependencies on their
11161 * tables. However, for a composite type the implicit dependency goes
11162 * the other way in pg_depend; which is the right thing for DROP but
11163 * it doesn't produce the dependency ordering we need. So in that one
11164 * case, we reverse the direction of the dependency.
11166 if (deptype == 'i' &&
11167 dobj->objType == DO_TABLE &&
11168 refdobj->objType == DO_TYPE)
11169 addObjectDependency(refdobj, dobj->dumpId);
11170 else
11171 /* normal case */
11172 addObjectDependency(dobj, refdobj->dumpId);
11175 PQclear(res);
11177 destroyPQExpBuffer(query);
11182 * selectSourceSchema - make the specified schema the active search path
11183 * in the source database.
11185 * NB: pg_catalog is explicitly searched after the specified schema;
11186 * so user names are only qualified if they are cross-schema references,
11187 * and system names are only qualified if they conflict with a user name
11188 * in the current schema.
11190 * Whenever the selected schema is not pg_catalog, be careful to qualify
11191 * references to system catalogs and types in our emitted commands!
11193 static void
11194 selectSourceSchema(const char *schemaName)
11196 static char *curSchemaName = NULL;
11197 PQExpBuffer query;
11199 /* Not relevant if fetching from pre-7.3 DB */
11200 if (g_fout->remoteVersion < 70300)
11201 return;
11202 /* Ignore null schema names */
11203 if (schemaName == NULL || *schemaName == '\0')
11204 return;
11205 /* Optimize away repeated selection of same schema */
11206 if (curSchemaName && strcmp(curSchemaName, schemaName) == 0)
11207 return;
11209 query = createPQExpBuffer();
11210 appendPQExpBuffer(query, "SET search_path = %s",
11211 fmtId(schemaName));
11212 if (strcmp(schemaName, "pg_catalog") != 0)
11213 appendPQExpBuffer(query, ", pg_catalog");
11215 do_sql_command(g_conn, query->data);
11217 destroyPQExpBuffer(query);
11218 if (curSchemaName)
11219 free(curSchemaName);
11220 curSchemaName = strdup(schemaName);
11224 * getFormattedTypeName - retrieve a nicely-formatted type name for the
11225 * given type name.
11227 * NB: in 7.3 and up the result may depend on the currently-selected
11228 * schema; this is why we don't try to cache the names.
11230 static char *
11231 getFormattedTypeName(Oid oid, OidOptions opts)
11233 char *result;
11234 PQExpBuffer query;
11235 PGresult *res;
11236 int ntups;
11238 if (oid == 0)
11240 if ((opts & zeroAsOpaque) != 0)
11241 return strdup(g_opaque_type);
11242 else if ((opts & zeroAsAny) != 0)
11243 return strdup("'any'");
11244 else if ((opts & zeroAsStar) != 0)
11245 return strdup("*");
11246 else if ((opts & zeroAsNone) != 0)
11247 return strdup("NONE");
11250 query = createPQExpBuffer();
11251 if (g_fout->remoteVersion >= 70300)
11253 appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
11254 oid);
11256 else if (g_fout->remoteVersion >= 70100)
11258 appendPQExpBuffer(query, "SELECT format_type('%u'::oid, NULL)",
11259 oid);
11261 else
11263 appendPQExpBuffer(query, "SELECT typname "
11264 "FROM pg_type "
11265 "WHERE oid = '%u'::oid",
11266 oid);
11269 res = PQexec(g_conn, query->data);
11270 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11272 /* Expecting a single result only */
11273 ntups = PQntuples(res);
11274 if (ntups != 1)
11276 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
11277 "query returned %d rows instead of one: %s\n",
11278 ntups),
11279 ntups, query->data);
11280 exit_nicely();
11283 if (g_fout->remoteVersion >= 70100)
11285 /* already quoted */
11286 result = strdup(PQgetvalue(res, 0, 0));
11288 else
11290 /* may need to quote it */
11291 result = strdup(fmtId(PQgetvalue(res, 0, 0)));
11294 PQclear(res);
11295 destroyPQExpBuffer(query);
11297 return result;
11301 * myFormatType --- local implementation of format_type for use with 7.0.
11303 static char *
11304 myFormatType(const char *typname, int32 typmod)
11306 char *result;
11307 bool isarray = false;
11308 PQExpBuffer buf = createPQExpBuffer();
11310 /* Handle array types */
11311 if (typname[0] == '_')
11313 isarray = true;
11314 typname++;
11317 /* Show lengths on bpchar and varchar */
11318 if (!strcmp(typname, "bpchar"))
11320 int len = (typmod - VARHDRSZ);
11322 appendPQExpBuffer(buf, "character");
11323 if (len > 1)
11324 appendPQExpBuffer(buf, "(%d)",
11325 typmod - VARHDRSZ);
11327 else if (!strcmp(typname, "varchar"))
11329 appendPQExpBuffer(buf, "character varying");
11330 if (typmod != -1)
11331 appendPQExpBuffer(buf, "(%d)",
11332 typmod - VARHDRSZ);
11334 else if (!strcmp(typname, "numeric"))
11336 appendPQExpBuffer(buf, "numeric");
11337 if (typmod != -1)
11339 int32 tmp_typmod;
11340 int precision;
11341 int scale;
11343 tmp_typmod = typmod - VARHDRSZ;
11344 precision = (tmp_typmod >> 16) & 0xffff;
11345 scale = tmp_typmod & 0xffff;
11346 appendPQExpBuffer(buf, "(%d,%d)",
11347 precision, scale);
11352 * char is an internal single-byte data type; Let's make sure we force it
11353 * through with quotes. - thomas 1998-12-13
11355 else if (strcmp(typname, "char") == 0)
11356 appendPQExpBuffer(buf, "\"char\"");
11357 else
11358 appendPQExpBuffer(buf, "%s", fmtId(typname));
11360 /* Append array qualifier for array types */
11361 if (isarray)
11362 appendPQExpBuffer(buf, "[]");
11364 result = strdup(buf->data);
11365 destroyPQExpBuffer(buf);
11367 return result;
11371 * fmtQualifiedId - convert a qualified name to the proper format for
11372 * the source database.
11374 * Like fmtId, use the result before calling again.
11376 static const char *
11377 fmtQualifiedId(const char *schema, const char *id)
11379 static PQExpBuffer id_return = NULL;
11381 if (id_return) /* first time through? */
11382 resetPQExpBuffer(id_return);
11383 else
11384 id_return = createPQExpBuffer();
11386 /* Suppress schema name if fetching from pre-7.3 DB */
11387 if (g_fout->remoteVersion >= 70300 && schema && *schema)
11389 appendPQExpBuffer(id_return, "%s.",
11390 fmtId(schema));
11392 appendPQExpBuffer(id_return, "%s",
11393 fmtId(id));
11395 return id_return->data;
11399 * Return a column list clause for the given relation.
11401 * Special case: if there are no undropped columns in the relation, return
11402 * "", not an invalid "()" column list.
11404 static const char *
11405 fmtCopyColumnList(const TableInfo *ti)
11407 static PQExpBuffer q = NULL;
11408 int numatts = ti->numatts;
11409 char **attnames = ti->attnames;
11410 bool *attisdropped = ti->attisdropped;
11411 bool needComma;
11412 int i;
11414 if (q) /* first time through? */
11415 resetPQExpBuffer(q);
11416 else
11417 q = createPQExpBuffer();
11419 appendPQExpBuffer(q, "(");
11420 needComma = false;
11421 for (i = 0; i < numatts; i++)
11423 if (attisdropped[i])
11424 continue;
11425 if (needComma)
11426 appendPQExpBuffer(q, ", ");
11427 appendPQExpBuffer(q, "%s", fmtId(attnames[i]));
11428 needComma = true;
11431 if (!needComma)
11432 return ""; /* no undropped columns */
11434 appendPQExpBuffer(q, ")");
11435 return q->data;
11439 * Convenience subroutine to execute a SQL command and check for
11440 * COMMAND_OK status.
11442 static void
11443 do_sql_command(PGconn *conn, const char *query)
11445 PGresult *res;
11447 res = PQexec(conn, query);
11448 check_sql_result(res, conn, query, PGRES_COMMAND_OK);
11449 PQclear(res);
11453 * Convenience subroutine to verify a SQL command succeeded,
11454 * and exit with a useful error message if not.
11456 static void
11457 check_sql_result(PGresult *res, PGconn *conn, const char *query,
11458 ExecStatusType expected)
11460 const char *err;
11462 if (res && PQresultStatus(res) == expected)
11463 return; /* A-OK */
11465 write_msg(NULL, "SQL command failed\n");
11466 if (res)
11467 err = PQresultErrorMessage(res);
11468 else
11469 err = PQerrorMessage(conn);
11470 write_msg(NULL, "Error message from server: %s", err);
11471 write_msg(NULL, "The command was: %s\n", query);
11472 exit_nicely();