Fix xslt_process() to ensure that it inserts a NULL terminator after the
[PostgreSQL.git] / src / bin / pg_dump / pg_dump.c
blob304967b91cb122a97d8ec8c4a89c99b6fff96f83
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 static 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_catalog.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, a.attlen, "
4716 "a.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 "attlen, 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);
4810 * Get info about column defaults
4812 if (hasdefaults)
4814 AttrDefInfo *attrdefs;
4815 int numDefaults;
4817 if (g_verbose)
4818 write_msg(NULL, "finding default expressions of table \"%s\"\n",
4819 tbinfo->dobj.name);
4821 resetPQExpBuffer(q);
4822 if (g_fout->remoteVersion >= 70300)
4824 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
4825 "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
4826 "FROM pg_catalog.pg_attrdef "
4827 "WHERE adrelid = '%u'::pg_catalog.oid",
4828 tbinfo->dobj.catId.oid);
4830 else if (g_fout->remoteVersion >= 70200)
4832 /* 7.2 did not have OIDs in pg_attrdef */
4833 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, adnum, "
4834 "pg_get_expr(adbin, adrelid) AS adsrc "
4835 "FROM pg_attrdef "
4836 "WHERE adrelid = '%u'::oid",
4837 tbinfo->dobj.catId.oid);
4839 else if (g_fout->remoteVersion >= 70100)
4841 /* no pg_get_expr, so must rely on adsrc */
4842 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, adsrc "
4843 "FROM pg_attrdef "
4844 "WHERE adrelid = '%u'::oid",
4845 tbinfo->dobj.catId.oid);
4847 else
4849 /* no pg_get_expr, no tableoid either */
4850 appendPQExpBuffer(q, "SELECT "
4851 "(SELECT oid FROM pg_class WHERE relname = 'pg_attrdef') AS tableoid, "
4852 "oid, adnum, adsrc "
4853 "FROM pg_attrdef "
4854 "WHERE adrelid = '%u'::oid",
4855 tbinfo->dobj.catId.oid);
4857 res = PQexec(g_conn, q->data);
4858 check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
4860 numDefaults = PQntuples(res);
4861 attrdefs = (AttrDefInfo *) malloc(numDefaults * sizeof(AttrDefInfo));
4863 for (j = 0; j < numDefaults; j++)
4865 int adnum;
4867 attrdefs[j].dobj.objType = DO_ATTRDEF;
4868 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
4869 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
4870 AssignDumpId(&attrdefs[j].dobj);
4871 attrdefs[j].adtable = tbinfo;
4872 attrdefs[j].adnum = adnum = atoi(PQgetvalue(res, j, 2));
4873 attrdefs[j].adef_expr = strdup(PQgetvalue(res, j, 3));
4875 attrdefs[j].dobj.name = strdup(tbinfo->dobj.name);
4876 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
4878 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
4881 * Defaults on a VIEW must always be dumped as separate ALTER
4882 * TABLE commands. Defaults on regular tables are dumped as
4883 * part of the CREATE TABLE if possible. To check if it's
4884 * safe, we mark the default as needing to appear before the
4885 * CREATE.
4887 if (tbinfo->relkind == RELKIND_VIEW)
4889 attrdefs[j].separate = true;
4890 /* needed in case pre-7.3 DB: */
4891 addObjectDependency(&attrdefs[j].dobj,
4892 tbinfo->dobj.dumpId);
4894 else
4896 attrdefs[j].separate = false;
4897 addObjectDependency(&tbinfo->dobj,
4898 attrdefs[j].dobj.dumpId);
4901 if (adnum <= 0 || adnum > ntups)
4903 write_msg(NULL, "invalid adnum value %d for table \"%s\"\n",
4904 adnum, tbinfo->dobj.name);
4905 exit_nicely();
4907 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
4909 PQclear(res);
4913 * Get info about table CHECK constraints
4915 if (tbinfo->ncheck > 0)
4917 ConstraintInfo *constrs;
4918 int numConstrs;
4920 if (g_verbose)
4921 write_msg(NULL, "finding check constraints for table \"%s\"\n",
4922 tbinfo->dobj.name);
4924 resetPQExpBuffer(q);
4925 if (g_fout->remoteVersion >= 80400)
4927 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
4928 "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
4929 "conislocal "
4930 "FROM pg_catalog.pg_constraint "
4931 "WHERE conrelid = '%u'::pg_catalog.oid "
4932 " AND contype = 'c' "
4933 "ORDER BY conname",
4934 tbinfo->dobj.catId.oid);
4936 else if (g_fout->remoteVersion >= 70400)
4938 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
4939 "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
4940 "true AS conislocal "
4941 "FROM pg_catalog.pg_constraint "
4942 "WHERE conrelid = '%u'::pg_catalog.oid "
4943 " AND contype = 'c' "
4944 "ORDER BY conname",
4945 tbinfo->dobj.catId.oid);
4947 else if (g_fout->remoteVersion >= 70300)
4949 /* no pg_get_constraintdef, must use consrc */
4950 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
4951 "'CHECK (' || consrc || ')' AS consrc, "
4952 "true AS conislocal "
4953 "FROM pg_catalog.pg_constraint "
4954 "WHERE conrelid = '%u'::pg_catalog.oid "
4955 " AND contype = 'c' "
4956 "ORDER BY conname",
4957 tbinfo->dobj.catId.oid);
4959 else if (g_fout->remoteVersion >= 70200)
4961 /* 7.2 did not have OIDs in pg_relcheck */
4962 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, "
4963 "rcname AS conname, "
4964 "'CHECK (' || rcsrc || ')' AS consrc, "
4965 "true AS conislocal "
4966 "FROM pg_relcheck "
4967 "WHERE rcrelid = '%u'::oid "
4968 "ORDER BY rcname",
4969 tbinfo->dobj.catId.oid);
4971 else if (g_fout->remoteVersion >= 70100)
4973 appendPQExpBuffer(q, "SELECT tableoid, oid, "
4974 "rcname AS conname, "
4975 "'CHECK (' || rcsrc || ')' AS consrc, "
4976 "true AS conislocal "
4977 "FROM pg_relcheck "
4978 "WHERE rcrelid = '%u'::oid "
4979 "ORDER BY rcname",
4980 tbinfo->dobj.catId.oid);
4982 else
4984 /* no tableoid in 7.0 */
4985 appendPQExpBuffer(q, "SELECT "
4986 "(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
4987 "oid, rcname AS conname, "
4988 "'CHECK (' || rcsrc || ')' AS consrc, "
4989 "true AS conislocal "
4990 "FROM pg_relcheck "
4991 "WHERE rcrelid = '%u'::oid "
4992 "ORDER BY rcname",
4993 tbinfo->dobj.catId.oid);
4995 res = PQexec(g_conn, q->data);
4996 check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
4998 numConstrs = PQntuples(res);
4999 if (numConstrs != tbinfo->ncheck)
5001 write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
5002 "expected %d check constraints on table \"%s\" but found %d\n",
5003 tbinfo->ncheck),
5004 tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
5005 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
5006 exit_nicely();
5009 constrs = (ConstraintInfo *) malloc(numConstrs * sizeof(ConstraintInfo));
5010 tbinfo->checkexprs = constrs;
5012 for (j = 0; j < numConstrs; j++)
5014 constrs[j].dobj.objType = DO_CONSTRAINT;
5015 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
5016 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
5017 AssignDumpId(&constrs[j].dobj);
5018 constrs[j].dobj.name = strdup(PQgetvalue(res, j, 2));
5019 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
5020 constrs[j].contable = tbinfo;
5021 constrs[j].condomain = NULL;
5022 constrs[j].contype = 'c';
5023 constrs[j].condef = strdup(PQgetvalue(res, j, 3));
5024 constrs[j].confrelid = InvalidOid;
5025 constrs[j].conindex = 0;
5026 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
5027 constrs[j].separate = false;
5029 constrs[j].dobj.dump = tbinfo->dobj.dump;
5032 * Mark the constraint as needing to appear before the table
5033 * --- this is so that any other dependencies of the
5034 * constraint will be emitted before we try to create the
5035 * table.
5037 addObjectDependency(&tbinfo->dobj,
5038 constrs[j].dobj.dumpId);
5041 * If the constraint is inherited, this will be detected later
5042 * (in pre-8.4 databases). We also detect later if the
5043 * constraint must be split out from the table definition.
5046 PQclear(res);
5050 destroyPQExpBuffer(q);
5055 * getTSParsers:
5056 * read all text search parsers in the system catalogs and return them
5057 * in the TSParserInfo* structure
5059 * numTSParsers is set to the number of parsers read in
5061 TSParserInfo *
5062 getTSParsers(int *numTSParsers)
5064 PGresult *res;
5065 int ntups;
5066 int i;
5067 PQExpBuffer query = createPQExpBuffer();
5068 TSParserInfo *prsinfo;
5069 int i_tableoid;
5070 int i_oid;
5071 int i_prsname;
5072 int i_prsnamespace;
5073 int i_prsstart;
5074 int i_prstoken;
5075 int i_prsend;
5076 int i_prsheadline;
5077 int i_prslextype;
5079 /* Before 8.3, there is no built-in text search support */
5080 if (g_fout->remoteVersion < 80300)
5082 *numTSParsers = 0;
5083 return NULL;
5087 * find all text search objects, including builtin ones; we filter out
5088 * system-defined objects at dump-out time.
5091 /* Make sure we are in proper schema */
5092 selectSourceSchema("pg_catalog");
5094 appendPQExpBuffer(query, "SELECT tableoid, oid, prsname, prsnamespace, "
5095 "prsstart::oid, prstoken::oid, "
5096 "prsend::oid, prsheadline::oid, prslextype::oid "
5097 "FROM pg_ts_parser");
5099 res = PQexec(g_conn, query->data);
5100 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5102 ntups = PQntuples(res);
5103 *numTSParsers = ntups;
5105 prsinfo = (TSParserInfo *) malloc(ntups * sizeof(TSParserInfo));
5107 i_tableoid = PQfnumber(res, "tableoid");
5108 i_oid = PQfnumber(res, "oid");
5109 i_prsname = PQfnumber(res, "prsname");
5110 i_prsnamespace = PQfnumber(res, "prsnamespace");
5111 i_prsstart = PQfnumber(res, "prsstart");
5112 i_prstoken = PQfnumber(res, "prstoken");
5113 i_prsend = PQfnumber(res, "prsend");
5114 i_prsheadline = PQfnumber(res, "prsheadline");
5115 i_prslextype = PQfnumber(res, "prslextype");
5117 for (i = 0; i < ntups; i++)
5119 prsinfo[i].dobj.objType = DO_TSPARSER;
5120 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5121 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5122 AssignDumpId(&prsinfo[i].dobj);
5123 prsinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_prsname));
5124 prsinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)),
5125 prsinfo[i].dobj.catId.oid);
5126 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
5127 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
5128 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
5129 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
5130 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
5132 /* Decide whether we want to dump it */
5133 selectDumpableObject(&(prsinfo[i].dobj));
5136 PQclear(res);
5138 destroyPQExpBuffer(query);
5140 return prsinfo;
5144 * getTSDictionaries:
5145 * read all text search dictionaries in the system catalogs and return them
5146 * in the TSDictInfo* structure
5148 * numTSDicts is set to the number of dictionaries read in
5150 TSDictInfo *
5151 getTSDictionaries(int *numTSDicts)
5153 PGresult *res;
5154 int ntups;
5155 int i;
5156 PQExpBuffer query = createPQExpBuffer();
5157 TSDictInfo *dictinfo;
5158 int i_tableoid;
5159 int i_oid;
5160 int i_dictname;
5161 int i_dictnamespace;
5162 int i_rolname;
5163 int i_dicttemplate;
5164 int i_dictinitoption;
5166 /* Before 8.3, there is no built-in text search support */
5167 if (g_fout->remoteVersion < 80300)
5169 *numTSDicts = 0;
5170 return NULL;
5173 /* Make sure we are in proper schema */
5174 selectSourceSchema("pg_catalog");
5176 appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
5177 "dictnamespace, (%s dictowner) AS rolname, "
5178 "dicttemplate, dictinitoption "
5179 "FROM pg_ts_dict",
5180 username_subquery);
5182 res = PQexec(g_conn, query->data);
5183 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5185 ntups = PQntuples(res);
5186 *numTSDicts = ntups;
5188 dictinfo = (TSDictInfo *) malloc(ntups * sizeof(TSDictInfo));
5190 i_tableoid = PQfnumber(res, "tableoid");
5191 i_oid = PQfnumber(res, "oid");
5192 i_dictname = PQfnumber(res, "dictname");
5193 i_dictnamespace = PQfnumber(res, "dictnamespace");
5194 i_rolname = PQfnumber(res, "rolname");
5195 i_dictinitoption = PQfnumber(res, "dictinitoption");
5196 i_dicttemplate = PQfnumber(res, "dicttemplate");
5198 for (i = 0; i < ntups; i++)
5200 dictinfo[i].dobj.objType = DO_TSDICT;
5201 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5202 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5203 AssignDumpId(&dictinfo[i].dobj);
5204 dictinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_dictname));
5205 dictinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)),
5206 dictinfo[i].dobj.catId.oid);
5207 dictinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
5208 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
5209 if (PQgetisnull(res, i, i_dictinitoption))
5210 dictinfo[i].dictinitoption = NULL;
5211 else
5212 dictinfo[i].dictinitoption = strdup(PQgetvalue(res, i, i_dictinitoption));
5214 /* Decide whether we want to dump it */
5215 selectDumpableObject(&(dictinfo[i].dobj));
5218 PQclear(res);
5220 destroyPQExpBuffer(query);
5222 return dictinfo;
5226 * getTSTemplates:
5227 * read all text search templates in the system catalogs and return them
5228 * in the TSTemplateInfo* structure
5230 * numTSTemplates is set to the number of templates read in
5232 TSTemplateInfo *
5233 getTSTemplates(int *numTSTemplates)
5235 PGresult *res;
5236 int ntups;
5237 int i;
5238 PQExpBuffer query = createPQExpBuffer();
5239 TSTemplateInfo *tmplinfo;
5240 int i_tableoid;
5241 int i_oid;
5242 int i_tmplname;
5243 int i_tmplnamespace;
5244 int i_tmplinit;
5245 int i_tmpllexize;
5247 /* Before 8.3, there is no built-in text search support */
5248 if (g_fout->remoteVersion < 80300)
5250 *numTSTemplates = 0;
5251 return NULL;
5254 /* Make sure we are in proper schema */
5255 selectSourceSchema("pg_catalog");
5257 appendPQExpBuffer(query, "SELECT tableoid, oid, tmplname, "
5258 "tmplnamespace, tmplinit::oid, tmpllexize::oid "
5259 "FROM pg_ts_template");
5261 res = PQexec(g_conn, query->data);
5262 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5264 ntups = PQntuples(res);
5265 *numTSTemplates = ntups;
5267 tmplinfo = (TSTemplateInfo *) malloc(ntups * sizeof(TSTemplateInfo));
5269 i_tableoid = PQfnumber(res, "tableoid");
5270 i_oid = PQfnumber(res, "oid");
5271 i_tmplname = PQfnumber(res, "tmplname");
5272 i_tmplnamespace = PQfnumber(res, "tmplnamespace");
5273 i_tmplinit = PQfnumber(res, "tmplinit");
5274 i_tmpllexize = PQfnumber(res, "tmpllexize");
5276 for (i = 0; i < ntups; i++)
5278 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
5279 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5280 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5281 AssignDumpId(&tmplinfo[i].dobj);
5282 tmplinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_tmplname));
5283 tmplinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)),
5284 tmplinfo[i].dobj.catId.oid);
5285 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
5286 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
5288 /* Decide whether we want to dump it */
5289 selectDumpableObject(&(tmplinfo[i].dobj));
5292 PQclear(res);
5294 destroyPQExpBuffer(query);
5296 return tmplinfo;
5300 * getTSConfigurations:
5301 * read all text search configurations in the system catalogs and return
5302 * them in the TSConfigInfo* structure
5304 * numTSConfigs is set to the number of configurations read in
5306 TSConfigInfo *
5307 getTSConfigurations(int *numTSConfigs)
5309 PGresult *res;
5310 int ntups;
5311 int i;
5312 PQExpBuffer query = createPQExpBuffer();
5313 TSConfigInfo *cfginfo;
5314 int i_tableoid;
5315 int i_oid;
5316 int i_cfgname;
5317 int i_cfgnamespace;
5318 int i_rolname;
5319 int i_cfgparser;
5321 /* Before 8.3, there is no built-in text search support */
5322 if (g_fout->remoteVersion < 80300)
5324 *numTSConfigs = 0;
5325 return NULL;
5328 /* Make sure we are in proper schema */
5329 selectSourceSchema("pg_catalog");
5331 appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
5332 "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
5333 "FROM pg_ts_config",
5334 username_subquery);
5336 res = PQexec(g_conn, query->data);
5337 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5339 ntups = PQntuples(res);
5340 *numTSConfigs = ntups;
5342 cfginfo = (TSConfigInfo *) malloc(ntups * sizeof(TSConfigInfo));
5344 i_tableoid = PQfnumber(res, "tableoid");
5345 i_oid = PQfnumber(res, "oid");
5346 i_cfgname = PQfnumber(res, "cfgname");
5347 i_cfgnamespace = PQfnumber(res, "cfgnamespace");
5348 i_rolname = PQfnumber(res, "rolname");
5349 i_cfgparser = PQfnumber(res, "cfgparser");
5351 for (i = 0; i < ntups; i++)
5353 cfginfo[i].dobj.objType = DO_TSCONFIG;
5354 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5355 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5356 AssignDumpId(&cfginfo[i].dobj);
5357 cfginfo[i].dobj.name = strdup(PQgetvalue(res, i, i_cfgname));
5358 cfginfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)),
5359 cfginfo[i].dobj.catId.oid);
5360 cfginfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
5361 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
5363 /* Decide whether we want to dump it */
5364 selectDumpableObject(&(cfginfo[i].dobj));
5367 PQclear(res);
5369 destroyPQExpBuffer(query);
5371 return cfginfo;
5375 * getForeignDataWrappers:
5376 * read all foreign-data wrappers in the system catalogs and return
5377 * them in the FdwInfo* structure
5379 * numForeignDataWrappers is set to the number of fdws read in
5381 FdwInfo *
5382 getForeignDataWrappers(int *numForeignDataWrappers)
5384 PGresult *res;
5385 int ntups;
5386 int i;
5387 PQExpBuffer query = createPQExpBuffer();
5388 FdwInfo *fdwinfo;
5389 int i_oid;
5390 int i_fdwname;
5391 int i_rolname;
5392 int i_fdwvalidator;
5393 int i_fdwacl;
5394 int i_fdwoptions;
5396 /* Before 8.4, there are no foreign-data wrappers */
5397 if (g_fout->remoteVersion < 80400)
5399 *numForeignDataWrappers = 0;
5400 return NULL;
5403 /* Make sure we are in proper schema */
5404 selectSourceSchema("pg_catalog");
5406 appendPQExpBuffer(query, "SELECT oid, fdwname, "
5407 "(%s fdwowner) AS rolname, fdwvalidator::pg_catalog.regproc, fdwacl,"
5408 "array_to_string(ARRAY("
5409 " SELECT option_name || ' ' || quote_literal(option_value) "
5410 " FROM pg_options_to_table(fdwoptions)), ', ') AS fdwoptions "
5411 "FROM pg_foreign_data_wrapper",
5412 username_subquery);
5414 res = PQexec(g_conn, query->data);
5415 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5417 ntups = PQntuples(res);
5418 *numForeignDataWrappers = ntups;
5420 fdwinfo = (FdwInfo *) malloc(ntups * sizeof(FdwInfo));
5422 i_oid = PQfnumber(res, "oid");
5423 i_fdwname = PQfnumber(res, "fdwname");
5424 i_rolname = PQfnumber(res, "rolname");
5425 i_fdwvalidator = PQfnumber(res, "fdwvalidator");
5426 i_fdwacl = PQfnumber(res, "fdwacl");
5427 i_fdwoptions = PQfnumber(res, "fdwoptions");
5429 for (i = 0; i < ntups; i++)
5431 fdwinfo[i].dobj.objType = DO_FDW;
5432 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5433 AssignDumpId(&fdwinfo[i].dobj);
5434 fdwinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_fdwname));
5435 fdwinfo[i].dobj.namespace = NULL;
5436 fdwinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
5437 fdwinfo[i].fdwvalidator = strdup(PQgetvalue(res, i, i_fdwvalidator));
5438 fdwinfo[i].fdwoptions = strdup(PQgetvalue(res, i, i_fdwoptions));
5439 fdwinfo[i].fdwacl = strdup(PQgetvalue(res, i, i_fdwacl));
5442 /* Decide whether we want to dump it */
5443 selectDumpableObject(&(fdwinfo[i].dobj));
5446 PQclear(res);
5448 destroyPQExpBuffer(query);
5450 return fdwinfo;
5454 * getForeignServers:
5455 * read all foreign servers in the system catalogs and return
5456 * them in the ForeignServerInfo * structure
5458 * numForeignServers is set to the number of servers read in
5460 ForeignServerInfo *
5461 getForeignServers(int *numForeignServers)
5463 PGresult *res;
5464 int ntups;
5465 int i;
5466 PQExpBuffer query = createPQExpBuffer();
5467 ForeignServerInfo *srvinfo;
5468 int i_oid;
5469 int i_srvname;
5470 int i_rolname;
5471 int i_srvfdw;
5472 int i_srvtype;
5473 int i_srvversion;
5474 int i_srvacl;
5475 int i_srvoptions;
5477 /* Before 8.4, there are no foreign servers */
5478 if (g_fout->remoteVersion < 80400)
5480 *numForeignServers = 0;
5481 return NULL;
5484 /* Make sure we are in proper schema */
5485 selectSourceSchema("pg_catalog");
5487 appendPQExpBuffer(query, "SELECT oid, srvname, "
5488 "(%s srvowner) AS rolname, "
5489 "srvfdw, srvtype, srvversion, srvacl,"
5490 "array_to_string(ARRAY("
5491 " SELECT option_name || ' ' || quote_literal(option_value) "
5492 " FROM pg_options_to_table(srvoptions)), ', ') AS srvoptions "
5493 "FROM pg_foreign_server",
5494 username_subquery);
5496 res = PQexec(g_conn, query->data);
5497 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5499 ntups = PQntuples(res);
5500 *numForeignServers = ntups;
5502 srvinfo = (ForeignServerInfo *) malloc(ntups * sizeof(ForeignServerInfo));
5504 i_oid = PQfnumber(res, "oid");
5505 i_srvname = PQfnumber(res, "srvname");
5506 i_rolname = PQfnumber(res, "rolname");
5507 i_srvfdw = PQfnumber(res, "srvfdw");
5508 i_srvtype = PQfnumber(res, "srvtype");
5509 i_srvversion = PQfnumber(res, "srvversion");
5510 i_srvacl = PQfnumber(res, "srvacl");
5511 i_srvoptions = PQfnumber(res, "srvoptions");
5513 for (i = 0; i < ntups; i++)
5515 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
5516 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5517 AssignDumpId(&srvinfo[i].dobj);
5518 srvinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_srvname));
5519 srvinfo[i].dobj.namespace = NULL;
5520 srvinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
5521 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
5522 srvinfo[i].srvtype = strdup(PQgetvalue(res, i, i_srvtype));
5523 srvinfo[i].srvversion = strdup(PQgetvalue(res, i, i_srvversion));
5524 srvinfo[i].srvoptions = strdup(PQgetvalue(res, i, i_srvoptions));
5525 srvinfo[i].srvacl = strdup(PQgetvalue(res, i, i_srvacl));
5527 /* Decide whether we want to dump it */
5528 selectDumpableObject(&(srvinfo[i].dobj));
5531 PQclear(res);
5533 destroyPQExpBuffer(query);
5535 return srvinfo;
5539 * dumpComment --
5541 * This routine is used to dump any comments associated with the
5542 * object handed to this routine. The routine takes a constant character
5543 * string for the target part of the comment-creation command, plus
5544 * the namespace and owner of the object (for labeling the ArchiveEntry),
5545 * plus catalog ID and subid which are the lookup key for pg_description,
5546 * plus the dump ID for the object (for setting a dependency).
5547 * If a matching pg_description entry is found, it is dumped.
5549 * Note: although this routine takes a dumpId for dependency purposes,
5550 * that purpose is just to mark the dependency in the emitted dump file
5551 * for possible future use by pg_restore. We do NOT use it for determining
5552 * ordering of the comment in the dump file, because this routine is called
5553 * after dependency sorting occurs. This routine should be called just after
5554 * calling ArchiveEntry() for the specified object.
5556 static void
5557 dumpComment(Archive *fout, const char *target,
5558 const char *namespace, const char *owner,
5559 CatalogId catalogId, int subid, DumpId dumpId)
5561 CommentItem *comments;
5562 int ncomments;
5564 /* Comments are SCHEMA not data */
5565 if (dataOnly)
5566 return;
5568 /* Search for comments associated with catalogId, using table */
5569 ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
5570 &comments);
5572 /* Is there one matching the subid? */
5573 while (ncomments > 0)
5575 if (comments->objsubid == subid)
5576 break;
5577 comments++;
5578 ncomments--;
5581 /* If a comment exists, build COMMENT ON statement */
5582 if (ncomments > 0)
5584 PQExpBuffer query = createPQExpBuffer();
5586 appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
5587 appendStringLiteralAH(query, comments->descr, fout);
5588 appendPQExpBuffer(query, ";\n");
5591 * We mark comments as SECTION_NONE because they really belong in the
5592 * same section as their parent, whether that is pre-data or
5593 * post-data.
5595 ArchiveEntry(fout, nilCatalogId, createDumpId(),
5596 target, namespace, NULL, owner,
5597 false, "COMMENT", SECTION_NONE,
5598 query->data, "", NULL,
5599 &(dumpId), 1,
5600 NULL, NULL);
5602 destroyPQExpBuffer(query);
5607 * dumpTableComment --
5609 * As above, but dump comments for both the specified table (or view)
5610 * and its columns.
5612 static void
5613 dumpTableComment(Archive *fout, TableInfo *tbinfo,
5614 const char *reltypename)
5616 CommentItem *comments;
5617 int ncomments;
5618 PQExpBuffer query;
5619 PQExpBuffer target;
5621 /* Comments are SCHEMA not data */
5622 if (dataOnly)
5623 return;
5625 /* Search for comments associated with relation, using table */
5626 ncomments = findComments(fout,
5627 tbinfo->dobj.catId.tableoid,
5628 tbinfo->dobj.catId.oid,
5629 &comments);
5631 /* If comments exist, build COMMENT ON statements */
5632 if (ncomments <= 0)
5633 return;
5635 query = createPQExpBuffer();
5636 target = createPQExpBuffer();
5638 while (ncomments > 0)
5640 const char *descr = comments->descr;
5641 int objsubid = comments->objsubid;
5643 if (objsubid == 0)
5645 resetPQExpBuffer(target);
5646 appendPQExpBuffer(target, "%s %s", reltypename,
5647 fmtId(tbinfo->dobj.name));
5649 resetPQExpBuffer(query);
5650 appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
5651 appendStringLiteralAH(query, descr, fout);
5652 appendPQExpBuffer(query, ";\n");
5654 ArchiveEntry(fout, nilCatalogId, createDumpId(),
5655 target->data,
5656 tbinfo->dobj.namespace->dobj.name,
5657 NULL, tbinfo->rolname,
5658 false, "COMMENT", SECTION_NONE,
5659 query->data, "", NULL,
5660 &(tbinfo->dobj.dumpId), 1,
5661 NULL, NULL);
5663 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
5665 resetPQExpBuffer(target);
5666 appendPQExpBuffer(target, "COLUMN %s.",
5667 fmtId(tbinfo->dobj.name));
5668 appendPQExpBuffer(target, "%s",
5669 fmtId(tbinfo->attnames[objsubid - 1]));
5671 resetPQExpBuffer(query);
5672 appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
5673 appendStringLiteralAH(query, descr, fout);
5674 appendPQExpBuffer(query, ";\n");
5676 ArchiveEntry(fout, nilCatalogId, createDumpId(),
5677 target->data,
5678 tbinfo->dobj.namespace->dobj.name,
5679 NULL, tbinfo->rolname,
5680 false, "COMMENT", SECTION_NONE,
5681 query->data, "", NULL,
5682 &(tbinfo->dobj.dumpId), 1,
5683 NULL, NULL);
5686 comments++;
5687 ncomments--;
5690 destroyPQExpBuffer(query);
5691 destroyPQExpBuffer(target);
5695 * findComments --
5697 * Find the comment(s), if any, associated with the given object. All the
5698 * objsubid values associated with the given classoid/objoid are found with
5699 * one search.
5701 static int
5702 findComments(Archive *fout, Oid classoid, Oid objoid,
5703 CommentItem **items)
5705 /* static storage for table of comments */
5706 static CommentItem *comments = NULL;
5707 static int ncomments = -1;
5709 CommentItem *middle = NULL;
5710 CommentItem *low;
5711 CommentItem *high;
5712 int nmatch;
5714 /* Get comments if we didn't already */
5715 if (ncomments < 0)
5716 ncomments = collectComments(fout, &comments);
5719 * Pre-7.2, pg_description does not contain classoid, so collectComments
5720 * just stores a zero. If there's a collision on object OID, well, you
5721 * get duplicate comments.
5723 if (fout->remoteVersion < 70200)
5724 classoid = 0;
5727 * Do binary search to find some item matching the object.
5729 low = &comments[0];
5730 high = &comments[ncomments - 1];
5731 while (low <= high)
5733 middle = low + (high - low) / 2;
5735 if (classoid < middle->classoid)
5736 high = middle - 1;
5737 else if (classoid > middle->classoid)
5738 low = middle + 1;
5739 else if (objoid < middle->objoid)
5740 high = middle - 1;
5741 else if (objoid > middle->objoid)
5742 low = middle + 1;
5743 else
5744 break; /* found a match */
5747 if (low > high) /* no matches */
5749 *items = NULL;
5750 return 0;
5754 * Now determine how many items match the object. The search loop
5755 * invariant still holds: only items between low and high inclusive could
5756 * match.
5758 nmatch = 1;
5759 while (middle > low)
5761 if (classoid != middle[-1].classoid ||
5762 objoid != middle[-1].objoid)
5763 break;
5764 middle--;
5765 nmatch++;
5768 *items = middle;
5770 middle += nmatch;
5771 while (middle <= high)
5773 if (classoid != middle->classoid ||
5774 objoid != middle->objoid)
5775 break;
5776 middle++;
5777 nmatch++;
5780 return nmatch;
5784 * collectComments --
5786 * Construct a table of all comments available for database objects.
5787 * We used to do per-object queries for the comments, but it's much faster
5788 * to pull them all over at once, and on most databases the memory cost
5789 * isn't high.
5791 * The table is sorted by classoid/objid/objsubid for speed in lookup.
5793 static int
5794 collectComments(Archive *fout, CommentItem **items)
5796 PGresult *res;
5797 PQExpBuffer query;
5798 int i_description;
5799 int i_classoid;
5800 int i_objoid;
5801 int i_objsubid;
5802 int ntups;
5803 int i;
5804 CommentItem *comments;
5807 * Note we do NOT change source schema here; preserve the caller's
5808 * setting, instead.
5811 query = createPQExpBuffer();
5813 if (fout->remoteVersion >= 70300)
5815 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
5816 "FROM pg_catalog.pg_description "
5817 "ORDER BY classoid, objoid, objsubid");
5819 else if (fout->remoteVersion >= 70200)
5821 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
5822 "FROM pg_description "
5823 "ORDER BY classoid, objoid, objsubid");
5825 else
5827 /* Note: this will fail to find attribute comments in pre-7.2... */
5828 appendPQExpBuffer(query, "SELECT description, 0 AS classoid, objoid, 0 AS objsubid "
5829 "FROM pg_description "
5830 "ORDER BY objoid");
5833 res = PQexec(g_conn, query->data);
5834 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5836 /* Construct lookup table containing OIDs in numeric form */
5838 i_description = PQfnumber(res, "description");
5839 i_classoid = PQfnumber(res, "classoid");
5840 i_objoid = PQfnumber(res, "objoid");
5841 i_objsubid = PQfnumber(res, "objsubid");
5843 ntups = PQntuples(res);
5845 comments = (CommentItem *) malloc(ntups * sizeof(CommentItem));
5847 for (i = 0; i < ntups; i++)
5849 comments[i].descr = PQgetvalue(res, i, i_description);
5850 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
5851 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
5852 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
5855 /* Do NOT free the PGresult since we are keeping pointers into it */
5856 destroyPQExpBuffer(query);
5858 *items = comments;
5859 return ntups;
5863 * dumpDumpableObject
5865 * This routine and its subsidiaries are responsible for creating
5866 * ArchiveEntries (TOC objects) for each object to be dumped.
5868 static void
5869 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
5871 switch (dobj->objType)
5873 case DO_NAMESPACE:
5874 dumpNamespace(fout, (NamespaceInfo *) dobj);
5875 break;
5876 case DO_TYPE:
5877 dumpType(fout, (TypeInfo *) dobj);
5878 break;
5879 case DO_SHELL_TYPE:
5880 dumpShellType(fout, (ShellTypeInfo *) dobj);
5881 break;
5882 case DO_FUNC:
5883 dumpFunc(fout, (FuncInfo *) dobj);
5884 break;
5885 case DO_AGG:
5886 dumpAgg(fout, (AggInfo *) dobj);
5887 break;
5888 case DO_OPERATOR:
5889 dumpOpr(fout, (OprInfo *) dobj);
5890 break;
5891 case DO_OPCLASS:
5892 dumpOpclass(fout, (OpclassInfo *) dobj);
5893 break;
5894 case DO_OPFAMILY:
5895 dumpOpfamily(fout, (OpfamilyInfo *) dobj);
5896 break;
5897 case DO_CONVERSION:
5898 dumpConversion(fout, (ConvInfo *) dobj);
5899 break;
5900 case DO_TABLE:
5901 dumpTable(fout, (TableInfo *) dobj);
5902 break;
5903 case DO_ATTRDEF:
5904 dumpAttrDef(fout, (AttrDefInfo *) dobj);
5905 break;
5906 case DO_INDEX:
5907 dumpIndex(fout, (IndxInfo *) dobj);
5908 break;
5909 case DO_RULE:
5910 dumpRule(fout, (RuleInfo *) dobj);
5911 break;
5912 case DO_TRIGGER:
5913 dumpTrigger(fout, (TriggerInfo *) dobj);
5914 break;
5915 case DO_CONSTRAINT:
5916 dumpConstraint(fout, (ConstraintInfo *) dobj);
5917 break;
5918 case DO_FK_CONSTRAINT:
5919 dumpConstraint(fout, (ConstraintInfo *) dobj);
5920 break;
5921 case DO_PROCLANG:
5922 dumpProcLang(fout, (ProcLangInfo *) dobj);
5923 break;
5924 case DO_CAST:
5925 dumpCast(fout, (CastInfo *) dobj);
5926 break;
5927 case DO_TABLE_DATA:
5928 dumpTableData(fout, (TableDataInfo *) dobj);
5929 break;
5930 case DO_DUMMY_TYPE:
5931 /* table rowtypes and array types are never dumped separately */
5932 break;
5933 case DO_TSPARSER:
5934 dumpTSParser(fout, (TSParserInfo *) dobj);
5935 break;
5936 case DO_TSDICT:
5937 dumpTSDictionary(fout, (TSDictInfo *) dobj);
5938 break;
5939 case DO_TSTEMPLATE:
5940 dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
5941 break;
5942 case DO_TSCONFIG:
5943 dumpTSConfig(fout, (TSConfigInfo *) dobj);
5944 break;
5945 case DO_FDW:
5946 dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
5947 break;
5948 case DO_FOREIGN_SERVER:
5949 dumpForeignServer(fout, (ForeignServerInfo *) dobj);
5950 break;
5951 case DO_BLOBS:
5952 ArchiveEntry(fout, dobj->catId, dobj->dumpId,
5953 dobj->name, NULL, NULL, "",
5954 false, "BLOBS", SECTION_DATA,
5955 "", "", NULL,
5956 dobj->dependencies, dobj->nDeps,
5957 dumpBlobs, NULL);
5958 break;
5959 case DO_BLOB_COMMENTS:
5960 ArchiveEntry(fout, dobj->catId, dobj->dumpId,
5961 dobj->name, NULL, NULL, "",
5962 false, "BLOB COMMENTS", SECTION_DATA,
5963 "", "", NULL,
5964 dobj->dependencies, dobj->nDeps,
5965 dumpBlobComments, NULL);
5966 break;
5971 * dumpNamespace
5972 * writes out to fout the queries to recreate a user-defined namespace
5974 static void
5975 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
5977 PQExpBuffer q;
5978 PQExpBuffer delq;
5979 char *qnspname;
5981 /* Skip if not to be dumped */
5982 if (!nspinfo->dobj.dump || dataOnly)
5983 return;
5985 /* don't dump dummy namespace from pre-7.3 source */
5986 if (strlen(nspinfo->dobj.name) == 0)
5987 return;
5989 q = createPQExpBuffer();
5990 delq = createPQExpBuffer();
5992 qnspname = strdup(fmtId(nspinfo->dobj.name));
5994 appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
5996 appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
5998 ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
5999 nspinfo->dobj.name,
6000 NULL, NULL,
6001 nspinfo->rolname,
6002 false, "SCHEMA", SECTION_PRE_DATA,
6003 q->data, delq->data, NULL,
6004 nspinfo->dobj.dependencies, nspinfo->dobj.nDeps,
6005 NULL, NULL);
6007 /* Dump Schema Comments */
6008 resetPQExpBuffer(q);
6009 appendPQExpBuffer(q, "SCHEMA %s", qnspname);
6010 dumpComment(fout, q->data,
6011 NULL, nspinfo->rolname,
6012 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
6014 dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
6015 qnspname, NULL, nspinfo->dobj.name, NULL,
6016 nspinfo->rolname, nspinfo->nspacl);
6018 free(qnspname);
6020 destroyPQExpBuffer(q);
6021 destroyPQExpBuffer(delq);
6025 * dumpType
6026 * writes out to fout the queries to recreate a user-defined type
6028 static void
6029 dumpType(Archive *fout, TypeInfo *tinfo)
6031 /* Skip if not to be dumped */
6032 if (!tinfo->dobj.dump || dataOnly)
6033 return;
6035 /* Dump out in proper style */
6036 if (tinfo->typtype == TYPTYPE_BASE)
6037 dumpBaseType(fout, tinfo);
6038 else if (tinfo->typtype == TYPTYPE_DOMAIN)
6039 dumpDomain(fout, tinfo);
6040 else if (tinfo->typtype == TYPTYPE_COMPOSITE)
6041 dumpCompositeType(fout, tinfo);
6042 else if (tinfo->typtype == TYPTYPE_ENUM)
6043 dumpEnumType(fout, tinfo);
6047 * dumpEnumType
6048 * writes out to fout the queries to recreate a user-defined enum type
6050 static void
6051 dumpEnumType(Archive *fout, TypeInfo *tinfo)
6053 PQExpBuffer q = createPQExpBuffer();
6054 PQExpBuffer delq = createPQExpBuffer();
6055 PQExpBuffer query = createPQExpBuffer();
6056 PGresult *res;
6057 int num,
6059 char *label;
6061 /* Set proper schema search path so regproc references list correctly */
6062 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6064 appendPQExpBuffer(query, "SELECT enumlabel FROM pg_catalog.pg_enum "
6065 "WHERE enumtypid = '%u'"
6066 "ORDER BY oid",
6067 tinfo->dobj.catId.oid);
6069 res = PQexec(g_conn, query->data);
6070 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6072 num = PQntuples(res);
6073 /* should be at least 1 value */
6074 if (num == 0)
6076 write_msg(NULL, "no label definitions found for enum ID %u\n", tinfo->dobj.catId.oid);
6077 exit_nicely();
6081 * DROP must be fully qualified in case same name appears in pg_catalog.
6082 * CASCADE shouldn't be required here as for normal types since the I/O
6083 * functions are generic and do not get dropped.
6085 appendPQExpBuffer(delq, "DROP TYPE %s.",
6086 fmtId(tinfo->dobj.namespace->dobj.name));
6087 appendPQExpBuffer(delq, "%s;\n",
6088 fmtId(tinfo->dobj.name));
6089 appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (\n",
6090 fmtId(tinfo->dobj.name));
6091 for (i = 0; i < num; i++)
6093 label = PQgetvalue(res, i, 0);
6094 if (i > 0)
6095 appendPQExpBuffer(q, ",\n");
6096 appendPQExpBuffer(q, " ");
6097 appendStringLiteralAH(q, label, fout);
6099 appendPQExpBuffer(q, "\n);\n");
6101 ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
6102 tinfo->dobj.name,
6103 tinfo->dobj.namespace->dobj.name,
6104 NULL,
6105 tinfo->rolname, false,
6106 "TYPE", SECTION_PRE_DATA,
6107 q->data, delq->data, NULL,
6108 tinfo->dobj.dependencies, tinfo->dobj.nDeps,
6109 NULL, NULL);
6111 /* Dump Type Comments */
6112 resetPQExpBuffer(q);
6114 appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->dobj.name));
6115 dumpComment(fout, q->data,
6116 tinfo->dobj.namespace->dobj.name, tinfo->rolname,
6117 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
6119 PQclear(res);
6120 destroyPQExpBuffer(q);
6121 destroyPQExpBuffer(delq);
6122 destroyPQExpBuffer(query);
6126 * dumpBaseType
6127 * writes out to fout the queries to recreate a user-defined base type
6129 static void
6130 dumpBaseType(Archive *fout, TypeInfo *tinfo)
6132 PQExpBuffer q = createPQExpBuffer();
6133 PQExpBuffer delq = createPQExpBuffer();
6134 PQExpBuffer query = createPQExpBuffer();
6135 PGresult *res;
6136 int ntups;
6137 char *typlen;
6138 char *typinput;
6139 char *typoutput;
6140 char *typreceive;
6141 char *typsend;
6142 char *typmodin;
6143 char *typmodout;
6144 char *typanalyze;
6145 Oid typinputoid;
6146 Oid typoutputoid;
6147 Oid typreceiveoid;
6148 Oid typsendoid;
6149 Oid typmodinoid;
6150 Oid typmodoutoid;
6151 Oid typanalyzeoid;
6152 char *typcategory;
6153 char *typispreferred;
6154 char *typdelim;
6155 char *typbyval;
6156 char *typalign;
6157 char *typstorage;
6158 char *typdefault;
6159 bool typdefault_is_literal = false;
6161 /* Set proper schema search path so regproc references list correctly */
6162 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6164 /* Fetch type-specific details */
6165 if (fout->remoteVersion >= 80400)
6167 appendPQExpBuffer(query, "SELECT typlen, "
6168 "typinput, typoutput, typreceive, typsend, "
6169 "typmodin, typmodout, typanalyze, "
6170 "typinput::pg_catalog.oid AS typinputoid, "
6171 "typoutput::pg_catalog.oid AS typoutputoid, "
6172 "typreceive::pg_catalog.oid AS typreceiveoid, "
6173 "typsend::pg_catalog.oid AS typsendoid, "
6174 "typmodin::pg_catalog.oid AS typmodinoid, "
6175 "typmodout::pg_catalog.oid AS typmodoutoid, "
6176 "typanalyze::pg_catalog.oid AS typanalyzeoid, "
6177 "typcategory, typispreferred, "
6178 "typdelim, typbyval, typalign, typstorage, "
6179 "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
6180 "FROM pg_catalog.pg_type "
6181 "WHERE oid = '%u'::pg_catalog.oid",
6182 tinfo->dobj.catId.oid);
6184 else if (fout->remoteVersion >= 80300)
6186 /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
6187 appendPQExpBuffer(query, "SELECT typlen, "
6188 "typinput, typoutput, typreceive, typsend, "
6189 "typmodin, typmodout, typanalyze, "
6190 "typinput::pg_catalog.oid AS typinputoid, "
6191 "typoutput::pg_catalog.oid AS typoutputoid, "
6192 "typreceive::pg_catalog.oid AS typreceiveoid, "
6193 "typsend::pg_catalog.oid AS typsendoid, "
6194 "typmodin::pg_catalog.oid AS typmodinoid, "
6195 "typmodout::pg_catalog.oid AS typmodoutoid, "
6196 "typanalyze::pg_catalog.oid AS typanalyzeoid, "
6197 "'U' AS typcategory, false AS typispreferred, "
6198 "typdelim, typbyval, typalign, typstorage, "
6199 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6200 "FROM pg_catalog.pg_type "
6201 "WHERE oid = '%u'::pg_catalog.oid",
6202 tinfo->dobj.catId.oid);
6204 else if (fout->remoteVersion >= 80000)
6206 appendPQExpBuffer(query, "SELECT typlen, "
6207 "typinput, typoutput, typreceive, typsend, "
6208 "'-' AS typmodin, '-' AS typmodout, "
6209 "typanalyze, "
6210 "typinput::pg_catalog.oid AS typinputoid, "
6211 "typoutput::pg_catalog.oid AS typoutputoid, "
6212 "typreceive::pg_catalog.oid AS typreceiveoid, "
6213 "typsend::pg_catalog.oid AS typsendoid, "
6214 "0 AS typmodinoid, 0 AS typmodoutoid, "
6215 "typanalyze::pg_catalog.oid AS typanalyzeoid, "
6216 "'U' AS typcategory, false AS typispreferred, "
6217 "typdelim, typbyval, typalign, typstorage, "
6218 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6219 "FROM pg_catalog.pg_type "
6220 "WHERE oid = '%u'::pg_catalog.oid",
6221 tinfo->dobj.catId.oid);
6223 else if (fout->remoteVersion >= 70400)
6225 appendPQExpBuffer(query, "SELECT typlen, "
6226 "typinput, typoutput, typreceive, typsend, "
6227 "'-' AS typmodin, '-' AS typmodout, "
6228 "'-' AS typanalyze, "
6229 "typinput::pg_catalog.oid AS typinputoid, "
6230 "typoutput::pg_catalog.oid AS typoutputoid, "
6231 "typreceive::pg_catalog.oid AS typreceiveoid, "
6232 "typsend::pg_catalog.oid AS typsendoid, "
6233 "0 AS typmodinoid, 0 AS typmodoutoid, "
6234 "0 AS typanalyzeoid, "
6235 "'U' AS typcategory, false AS typispreferred, "
6236 "typdelim, typbyval, typalign, typstorage, "
6237 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6238 "FROM pg_catalog.pg_type "
6239 "WHERE oid = '%u'::pg_catalog.oid",
6240 tinfo->dobj.catId.oid);
6242 else if (fout->remoteVersion >= 70300)
6244 appendPQExpBuffer(query, "SELECT typlen, "
6245 "typinput, typoutput, "
6246 "'-' AS typreceive, '-' AS typsend, "
6247 "'-' AS typmodin, '-' AS typmodout, "
6248 "'-' AS typanalyze, "
6249 "typinput::pg_catalog.oid AS typinputoid, "
6250 "typoutput::pg_catalog.oid AS typoutputoid, "
6251 "0 AS typreceiveoid, 0 AS typsendoid, "
6252 "0 AS typmodinoid, 0 AS typmodoutoid, "
6253 "0 AS typanalyzeoid, "
6254 "'U' AS typcategory, false AS typispreferred, "
6255 "typdelim, typbyval, typalign, typstorage, "
6256 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6257 "FROM pg_catalog.pg_type "
6258 "WHERE oid = '%u'::pg_catalog.oid",
6259 tinfo->dobj.catId.oid);
6261 else if (fout->remoteVersion >= 70200)
6264 * Note: although pre-7.3 catalogs contain typreceive and typsend,
6265 * ignore them because they are not right.
6267 appendPQExpBuffer(query, "SELECT typlen, "
6268 "typinput, typoutput, "
6269 "'-' AS typreceive, '-' AS typsend, "
6270 "'-' AS typmodin, '-' AS typmodout, "
6271 "'-' AS typanalyze, "
6272 "typinput::oid AS typinputoid, "
6273 "typoutput::oid AS typoutputoid, "
6274 "0 AS typreceiveoid, 0 AS typsendoid, "
6275 "0 AS typmodinoid, 0 AS typmodoutoid, "
6276 "0 AS typanalyzeoid, "
6277 "'U' AS typcategory, false AS typispreferred, "
6278 "typdelim, typbyval, typalign, typstorage, "
6279 "NULL AS typdefaultbin, typdefault "
6280 "FROM pg_type "
6281 "WHERE oid = '%u'::oid",
6282 tinfo->dobj.catId.oid);
6284 else if (fout->remoteVersion >= 70100)
6287 * Ignore pre-7.2 typdefault; the field exists but has an unusable
6288 * representation.
6290 appendPQExpBuffer(query, "SELECT typlen, "
6291 "typinput, typoutput, "
6292 "'-' AS typreceive, '-' AS typsend, "
6293 "'-' AS typmodin, '-' AS typmodout, "
6294 "'-' AS typanalyze, "
6295 "typinput::oid AS typinputoid, "
6296 "typoutput::oid AS typoutputoid, "
6297 "0 AS typreceiveoid, 0 AS typsendoid, "
6298 "0 AS typmodinoid, 0 AS typmodoutoid, "
6299 "0 AS typanalyzeoid, "
6300 "'U' AS typcategory, false AS typispreferred, "
6301 "typdelim, typbyval, typalign, typstorage, "
6302 "NULL AS typdefaultbin, NULL AS typdefault "
6303 "FROM pg_type "
6304 "WHERE oid = '%u'::oid",
6305 tinfo->dobj.catId.oid);
6307 else
6309 appendPQExpBuffer(query, "SELECT typlen, "
6310 "typinput, typoutput, "
6311 "'-' AS typreceive, '-' AS typsend, "
6312 "'-' AS typmodin, '-' AS typmodout, "
6313 "'-' AS typanalyze, "
6314 "typinput::oid AS typinputoid, "
6315 "typoutput::oid AS typoutputoid, "
6316 "0 AS typreceiveoid, 0 AS typsendoid, "
6317 "0 AS typmodinoid, 0 AS typmodoutoid, "
6318 "0 AS typanalyzeoid, "
6319 "'U' AS typcategory, false AS typispreferred, "
6320 "typdelim, typbyval, typalign, "
6321 "'p'::char AS typstorage, "
6322 "NULL AS typdefaultbin, NULL AS typdefault "
6323 "FROM pg_type "
6324 "WHERE oid = '%u'::oid",
6325 tinfo->dobj.catId.oid);
6328 res = PQexec(g_conn, query->data);
6329 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6331 /* Expecting a single result only */
6332 ntups = PQntuples(res);
6333 if (ntups != 1)
6335 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
6336 "query returned %d rows instead of one: %s\n",
6337 ntups),
6338 ntups, query->data);
6339 exit_nicely();
6342 typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
6343 typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
6344 typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
6345 typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
6346 typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
6347 typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
6348 typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
6349 typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
6350 typinputoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typinputoid")));
6351 typoutputoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typoutputoid")));
6352 typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
6353 typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
6354 typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
6355 typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
6356 typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
6357 typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
6358 typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
6359 typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
6360 typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
6361 typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
6362 typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
6363 if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
6364 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
6365 else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
6367 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
6368 typdefault_is_literal = true; /* it needs quotes */
6370 else
6371 typdefault = NULL;
6374 * DROP must be fully qualified in case same name appears in pg_catalog.
6375 * The reason we include CASCADE is that the circular dependency between
6376 * the type and its I/O functions makes it impossible to drop the type any
6377 * other way.
6379 appendPQExpBuffer(delq, "DROP TYPE %s.",
6380 fmtId(tinfo->dobj.namespace->dobj.name));
6381 appendPQExpBuffer(delq, "%s CASCADE;\n",
6382 fmtId(tinfo->dobj.name));
6384 appendPQExpBuffer(q,
6385 "CREATE TYPE %s (\n"
6386 " INTERNALLENGTH = %s",
6387 fmtId(tinfo->dobj.name),
6388 (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
6390 if (fout->remoteVersion >= 70300)
6392 /* regproc result is correctly quoted as of 7.3 */
6393 appendPQExpBuffer(q, ",\n INPUT = %s", typinput);
6394 appendPQExpBuffer(q, ",\n OUTPUT = %s", typoutput);
6395 if (OidIsValid(typreceiveoid))
6396 appendPQExpBuffer(q, ",\n RECEIVE = %s", typreceive);
6397 if (OidIsValid(typsendoid))
6398 appendPQExpBuffer(q, ",\n SEND = %s", typsend);
6399 if (OidIsValid(typmodinoid))
6400 appendPQExpBuffer(q, ",\n TYPMOD_IN = %s", typmodin);
6401 if (OidIsValid(typmodoutoid))
6402 appendPQExpBuffer(q, ",\n TYPMOD_OUT = %s", typmodout);
6403 if (OidIsValid(typanalyzeoid))
6404 appendPQExpBuffer(q, ",\n ANALYZE = %s", typanalyze);
6406 else
6408 /* regproc delivers an unquoted name before 7.3 */
6409 /* cannot combine these because fmtId uses static result area */
6410 appendPQExpBuffer(q, ",\n INPUT = %s", fmtId(typinput));
6411 appendPQExpBuffer(q, ",\n OUTPUT = %s", fmtId(typoutput));
6412 /* receive/send/typmodin/typmodout/analyze need not be printed */
6415 if (typdefault != NULL)
6417 appendPQExpBuffer(q, ",\n DEFAULT = ");
6418 if (typdefault_is_literal)
6419 appendStringLiteralAH(q, typdefault, fout);
6420 else
6421 appendPQExpBufferStr(q, typdefault);
6424 if (OidIsValid(tinfo->typelem))
6426 char *elemType;
6428 /* reselect schema in case changed by function dump */
6429 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6430 elemType = getFormattedTypeName(tinfo->typelem, zeroAsOpaque);
6431 appendPQExpBuffer(q, ",\n ELEMENT = %s", elemType);
6432 free(elemType);
6435 if (strcmp(typcategory, "U") != 0)
6437 appendPQExpBuffer(q, ",\n CATEGORY = ");
6438 appendStringLiteralAH(q, typcategory, fout);
6441 if (strcmp(typispreferred, "t") == 0)
6442 appendPQExpBuffer(q, ",\n PREFERRED = true");
6444 if (typdelim && strcmp(typdelim, ",") != 0)
6446 appendPQExpBuffer(q, ",\n DELIMITER = ");
6447 appendStringLiteralAH(q, typdelim, fout);
6450 if (strcmp(typalign, "c") == 0)
6451 appendPQExpBuffer(q, ",\n ALIGNMENT = char");
6452 else if (strcmp(typalign, "s") == 0)
6453 appendPQExpBuffer(q, ",\n ALIGNMENT = int2");
6454 else if (strcmp(typalign, "i") == 0)
6455 appendPQExpBuffer(q, ",\n ALIGNMENT = int4");
6456 else if (strcmp(typalign, "d") == 0)
6457 appendPQExpBuffer(q, ",\n ALIGNMENT = double");
6459 if (strcmp(typstorage, "p") == 0)
6460 appendPQExpBuffer(q, ",\n STORAGE = plain");
6461 else if (strcmp(typstorage, "e") == 0)
6462 appendPQExpBuffer(q, ",\n STORAGE = external");
6463 else if (strcmp(typstorage, "x") == 0)
6464 appendPQExpBuffer(q, ",\n STORAGE = extended");
6465 else if (strcmp(typstorage, "m") == 0)
6466 appendPQExpBuffer(q, ",\n STORAGE = main");
6468 if (strcmp(typbyval, "t") == 0)
6469 appendPQExpBuffer(q, ",\n PASSEDBYVALUE");
6471 appendPQExpBuffer(q, "\n);\n");
6473 ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
6474 tinfo->dobj.name,
6475 tinfo->dobj.namespace->dobj.name,
6476 NULL,
6477 tinfo->rolname, false,
6478 "TYPE", SECTION_PRE_DATA,
6479 q->data, delq->data, NULL,
6480 tinfo->dobj.dependencies, tinfo->dobj.nDeps,
6481 NULL, NULL);
6483 /* Dump Type Comments */
6484 resetPQExpBuffer(q);
6486 appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->dobj.name));
6487 dumpComment(fout, q->data,
6488 tinfo->dobj.namespace->dobj.name, tinfo->rolname,
6489 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
6491 PQclear(res);
6492 destroyPQExpBuffer(q);
6493 destroyPQExpBuffer(delq);
6494 destroyPQExpBuffer(query);
6498 * dumpDomain
6499 * writes out to fout the queries to recreate a user-defined domain
6501 static void
6502 dumpDomain(Archive *fout, TypeInfo *tinfo)
6504 PQExpBuffer q = createPQExpBuffer();
6505 PQExpBuffer delq = createPQExpBuffer();
6506 PQExpBuffer query = createPQExpBuffer();
6507 PGresult *res;
6508 int ntups;
6509 int i;
6510 char *typnotnull;
6511 char *typdefn;
6512 char *typdefault;
6513 bool typdefault_is_literal = false;
6515 /* Set proper schema search path so type references list correctly */
6516 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6518 /* Fetch domain specific details */
6519 /* We assume here that remoteVersion must be at least 70300 */
6520 appendPQExpBuffer(query, "SELECT typnotnull, "
6521 "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
6522 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6523 "FROM pg_catalog.pg_type "
6524 "WHERE oid = '%u'::pg_catalog.oid",
6525 tinfo->dobj.catId.oid);
6527 res = PQexec(g_conn, query->data);
6528 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6530 /* Expecting a single result only */
6531 ntups = PQntuples(res);
6532 if (ntups != 1)
6534 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
6535 "query returned %d rows instead of one: %s\n",
6536 ntups),
6537 ntups, query->data);
6538 exit_nicely();
6541 typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
6542 typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
6543 if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
6544 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
6545 else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
6547 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
6548 typdefault_is_literal = true; /* it needs quotes */
6550 else
6551 typdefault = NULL;
6553 appendPQExpBuffer(q,
6554 "CREATE DOMAIN %s AS %s",
6555 fmtId(tinfo->dobj.name),
6556 typdefn);
6558 if (typnotnull[0] == 't')
6559 appendPQExpBuffer(q, " NOT NULL");
6561 if (typdefault != NULL)
6563 appendPQExpBuffer(q, " DEFAULT ");
6564 if (typdefault_is_literal)
6565 appendStringLiteralAH(q, typdefault, fout);
6566 else
6567 appendPQExpBufferStr(q, typdefault);
6570 PQclear(res);
6573 * Add any CHECK constraints for the domain
6575 for (i = 0; i < tinfo->nDomChecks; i++)
6577 ConstraintInfo *domcheck = &(tinfo->domChecks[i]);
6579 if (!domcheck->separate)
6580 appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
6581 fmtId(domcheck->dobj.name), domcheck->condef);
6584 appendPQExpBuffer(q, ";\n");
6587 * DROP must be fully qualified in case same name appears in pg_catalog
6589 appendPQExpBuffer(delq, "DROP DOMAIN %s.",
6590 fmtId(tinfo->dobj.namespace->dobj.name));
6591 appendPQExpBuffer(delq, "%s;\n",
6592 fmtId(tinfo->dobj.name));
6594 ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
6595 tinfo->dobj.name,
6596 tinfo->dobj.namespace->dobj.name,
6597 NULL,
6598 tinfo->rolname, false,
6599 "DOMAIN", SECTION_PRE_DATA,
6600 q->data, delq->data, NULL,
6601 tinfo->dobj.dependencies, tinfo->dobj.nDeps,
6602 NULL, NULL);
6604 /* Dump Domain Comments */
6605 resetPQExpBuffer(q);
6607 appendPQExpBuffer(q, "DOMAIN %s", fmtId(tinfo->dobj.name));
6608 dumpComment(fout, q->data,
6609 tinfo->dobj.namespace->dobj.name, tinfo->rolname,
6610 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
6612 destroyPQExpBuffer(q);
6613 destroyPQExpBuffer(delq);
6614 destroyPQExpBuffer(query);
6618 * dumpCompositeType
6619 * writes out to fout the queries to recreate a user-defined stand-alone
6620 * composite type
6622 static void
6623 dumpCompositeType(Archive *fout, TypeInfo *tinfo)
6625 PQExpBuffer q = createPQExpBuffer();
6626 PQExpBuffer delq = createPQExpBuffer();
6627 PQExpBuffer query = createPQExpBuffer();
6628 PGresult *res;
6629 int ntups;
6630 int i_attname;
6631 int i_atttypdefn;
6632 int i;
6634 /* Set proper schema search path so type references list correctly */
6635 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6637 /* Fetch type specific details */
6638 /* We assume here that remoteVersion must be at least 70300 */
6640 appendPQExpBuffer(query, "SELECT a.attname, "
6641 "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn "
6642 "FROM pg_catalog.pg_type t, pg_catalog.pg_attribute a "
6643 "WHERE t.oid = '%u'::pg_catalog.oid "
6644 "AND a.attrelid = t.typrelid "
6645 "AND NOT a.attisdropped "
6646 "ORDER BY a.attnum ",
6647 tinfo->dobj.catId.oid);
6649 res = PQexec(g_conn, query->data);
6650 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6652 /* Expecting at least a single result */
6653 ntups = PQntuples(res);
6654 if (ntups < 1)
6656 write_msg(NULL, "query returned no rows: %s\n", query->data);
6657 exit_nicely();
6660 i_attname = PQfnumber(res, "attname");
6661 i_atttypdefn = PQfnumber(res, "atttypdefn");
6663 appendPQExpBuffer(q, "CREATE TYPE %s AS (",
6664 fmtId(tinfo->dobj.name));
6666 for (i = 0; i < ntups; i++)
6668 char *attname;
6669 char *atttypdefn;
6671 attname = PQgetvalue(res, i, i_attname);
6672 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
6674 appendPQExpBuffer(q, "\n\t%s %s", fmtId(attname), atttypdefn);
6675 if (i < ntups - 1)
6676 appendPQExpBuffer(q, ",");
6678 appendPQExpBuffer(q, "\n);\n");
6681 * DROP must be fully qualified in case same name appears in pg_catalog
6683 appendPQExpBuffer(delq, "DROP TYPE %s.",
6684 fmtId(tinfo->dobj.namespace->dobj.name));
6685 appendPQExpBuffer(delq, "%s;\n",
6686 fmtId(tinfo->dobj.name));
6688 ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
6689 tinfo->dobj.name,
6690 tinfo->dobj.namespace->dobj.name,
6691 NULL,
6692 tinfo->rolname, false,
6693 "TYPE", SECTION_PRE_DATA,
6694 q->data, delq->data, NULL,
6695 tinfo->dobj.dependencies, tinfo->dobj.nDeps,
6696 NULL, NULL);
6699 /* Dump Type Comments */
6700 resetPQExpBuffer(q);
6702 appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->dobj.name));
6703 dumpComment(fout, q->data,
6704 tinfo->dobj.namespace->dobj.name, tinfo->rolname,
6705 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
6707 PQclear(res);
6708 destroyPQExpBuffer(q);
6709 destroyPQExpBuffer(delq);
6710 destroyPQExpBuffer(query);
6714 * dumpShellType
6715 * writes out to fout the queries to create a shell type
6717 * We dump a shell definition in advance of the I/O functions for the type.
6719 static void
6720 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
6722 PQExpBuffer q;
6724 /* Skip if not to be dumped */
6725 if (!stinfo->dobj.dump || dataOnly)
6726 return;
6728 q = createPQExpBuffer();
6731 * Note the lack of a DROP command for the shell type; any required DROP
6732 * is driven off the base type entry, instead. This interacts with
6733 * _printTocEntry()'s use of the presence of a DROP command to decide
6734 * whether an entry needs an ALTER OWNER command. We don't want to alter
6735 * the shell type's owner immediately on creation; that should happen only
6736 * after it's filled in, otherwise the backend complains.
6739 appendPQExpBuffer(q, "CREATE TYPE %s;\n",
6740 fmtId(stinfo->dobj.name));
6742 ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
6743 stinfo->dobj.name,
6744 stinfo->dobj.namespace->dobj.name,
6745 NULL,
6746 stinfo->baseType->rolname, false,
6747 "SHELL TYPE", SECTION_PRE_DATA,
6748 q->data, "", NULL,
6749 stinfo->dobj.dependencies, stinfo->dobj.nDeps,
6750 NULL, NULL);
6752 destroyPQExpBuffer(q);
6756 * Determine whether we want to dump definitions for procedural languages.
6757 * Since the languages themselves don't have schemas, we can't rely on
6758 * the normal schema-based selection mechanism. We choose to dump them
6759 * whenever neither --schema nor --table was given. (Before 8.1, we used
6760 * the dump flag of the PL's call handler function, but in 8.1 this will
6761 * probably always be false since call handlers are created in pg_catalog.)
6763 * For some backwards compatibility with the older behavior, we forcibly
6764 * dump a PL if its handler function (and validator if any) are in a
6765 * dumpable namespace. That case is not checked here.
6767 static bool
6768 shouldDumpProcLangs(void)
6770 if (!include_everything)
6771 return false;
6772 /* And they're schema not data */
6773 if (dataOnly)
6774 return false;
6775 return true;
6779 * dumpProcLang
6780 * writes out to fout the queries to recreate a user-defined
6781 * procedural language
6783 static void
6784 dumpProcLang(Archive *fout, ProcLangInfo *plang)
6786 PQExpBuffer defqry;
6787 PQExpBuffer delqry;
6788 bool useParams;
6789 char *qlanname;
6790 char *lanschema;
6791 FuncInfo *funcInfo;
6792 FuncInfo *validatorInfo = NULL;
6794 if (dataOnly)
6795 return;
6798 * Try to find the support function(s). It is not an error if we don't
6799 * find them --- if the functions are in the pg_catalog schema, as is
6800 * standard in 8.1 and up, then we won't have loaded them. (In this case
6801 * we will emit a parameterless CREATE LANGUAGE command, which will
6802 * require PL template knowledge in the backend to reload.)
6805 funcInfo = findFuncByOid(plang->lanplcallfoid);
6806 if (funcInfo != NULL && !funcInfo->dobj.dump)
6807 funcInfo = NULL; /* treat not-dumped same as not-found */
6809 if (OidIsValid(plang->lanvalidator))
6811 validatorInfo = findFuncByOid(plang->lanvalidator);
6812 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
6813 validatorInfo = NULL;
6817 * If the functions are dumpable then emit a traditional CREATE LANGUAGE
6818 * with parameters. Otherwise, dump only if shouldDumpProcLangs() says to
6819 * dump it.
6821 useParams = (funcInfo != NULL &&
6822 (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
6824 if (!useParams && !shouldDumpProcLangs())
6825 return;
6827 defqry = createPQExpBuffer();
6828 delqry = createPQExpBuffer();
6830 qlanname = strdup(fmtId(plang->dobj.name));
6833 * If dumping a HANDLER clause, treat the language as being in the handler
6834 * function's schema; this avoids cluttering the HANDLER clause. Otherwise
6835 * it doesn't really have a schema.
6837 if (useParams)
6838 lanschema = funcInfo->dobj.namespace->dobj.name;
6839 else
6840 lanschema = NULL;
6842 appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
6843 qlanname);
6845 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
6846 (useParams && plang->lanpltrusted) ? "TRUSTED " : "",
6847 qlanname);
6848 if (useParams)
6850 appendPQExpBuffer(defqry, " HANDLER %s",
6851 fmtId(funcInfo->dobj.name));
6852 if (OidIsValid(plang->lanvalidator))
6854 appendPQExpBuffer(defqry, " VALIDATOR ");
6855 /* Cope with possibility that validator is in different schema */
6856 if (validatorInfo->dobj.namespace != funcInfo->dobj.namespace)
6857 appendPQExpBuffer(defqry, "%s.",
6858 fmtId(validatorInfo->dobj.namespace->dobj.name));
6859 appendPQExpBuffer(defqry, "%s",
6860 fmtId(validatorInfo->dobj.name));
6863 appendPQExpBuffer(defqry, ";\n");
6865 ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
6866 plang->dobj.name,
6867 lanschema, NULL, plang->lanowner,
6868 false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
6869 defqry->data, delqry->data, NULL,
6870 plang->dobj.dependencies, plang->dobj.nDeps,
6871 NULL, NULL);
6873 /* Dump Proc Lang Comments */
6874 resetPQExpBuffer(defqry);
6875 appendPQExpBuffer(defqry, "LANGUAGE %s", qlanname);
6876 dumpComment(fout, defqry->data,
6877 NULL, "",
6878 plang->dobj.catId, 0, plang->dobj.dumpId);
6880 if (plang->lanpltrusted)
6881 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
6882 qlanname, NULL, plang->dobj.name,
6883 lanschema,
6884 plang->lanowner, plang->lanacl);
6886 free(qlanname);
6888 destroyPQExpBuffer(defqry);
6889 destroyPQExpBuffer(delqry);
6893 * format_function_arguments: generate function name and argument list
6895 * This is used when we can rely on pg_get_function_arguments to format
6896 * the argument list.
6898 static char *
6899 format_function_arguments(FuncInfo *finfo, char *funcargs)
6901 PQExpBufferData fn;
6903 initPQExpBuffer(&fn);
6904 appendPQExpBuffer(&fn, "%s(%s)", fmtId(finfo->dobj.name), funcargs);
6905 return fn.data;
6909 * format_function_arguments_old: generate function name and argument list
6911 * The argument type names are qualified if needed. The function name
6912 * is never qualified.
6914 * This is used only with pre-8.4 servers, so we aren't expecting to see
6915 * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
6917 * Any or all of allargtypes, argmodes, argnames may be NULL.
6919 static char *
6920 format_function_arguments_old(FuncInfo *finfo, int nallargs,
6921 char **allargtypes,
6922 char **argmodes,
6923 char **argnames)
6925 PQExpBufferData fn;
6926 int j;
6928 initPQExpBuffer(&fn);
6929 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
6930 for (j = 0; j < nallargs; j++)
6932 Oid typid;
6933 char *typname;
6934 const char *argmode;
6935 const char *argname;
6937 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
6938 typname = getFormattedTypeName(typid, zeroAsOpaque);
6940 if (argmodes)
6942 switch (argmodes[j][0])
6944 case PROARGMODE_IN:
6945 argmode = "";
6946 break;
6947 case PROARGMODE_OUT:
6948 argmode = "OUT ";
6949 break;
6950 case PROARGMODE_INOUT:
6951 argmode = "INOUT ";
6952 break;
6953 default:
6954 write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
6955 argmode = "";
6956 break;
6959 else
6960 argmode = "";
6962 argname = argnames ? argnames[j] : (char *) NULL;
6963 if (argname && argname[0] == '\0')
6964 argname = NULL;
6966 appendPQExpBuffer(&fn, "%s%s%s%s%s",
6967 (j > 0) ? ", " : "",
6968 argmode,
6969 argname ? fmtId(argname) : "",
6970 argname ? " " : "",
6971 typname);
6972 free(typname);
6974 appendPQExpBuffer(&fn, ")");
6975 return fn.data;
6979 * format_function_signature: generate function name and argument list
6981 * This is like format_function_arguments_old except that only a minimal
6982 * list of input argument types is generated; this is sufficient to
6983 * reference the function, but not to define it.
6985 * If honor_quotes is false then the function name is never quoted.
6986 * This is appropriate for use in TOC tags, but not in SQL commands.
6988 static char *
6989 format_function_signature(FuncInfo *finfo, bool honor_quotes)
6991 PQExpBufferData fn;
6992 int j;
6994 initPQExpBuffer(&fn);
6995 if (honor_quotes)
6996 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
6997 else
6998 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
6999 for (j = 0; j < finfo->nargs; j++)
7001 char *typname;
7003 typname = getFormattedTypeName(finfo->argtypes[j], zeroAsOpaque);
7005 appendPQExpBuffer(&fn, "%s%s",
7006 (j > 0) ? ", " : "",
7007 typname);
7008 free(typname);
7010 appendPQExpBuffer(&fn, ")");
7011 return fn.data;
7016 * dumpFunc:
7017 * dump out one function
7019 static void
7020 dumpFunc(Archive *fout, FuncInfo *finfo)
7022 PQExpBuffer query;
7023 PQExpBuffer q;
7024 PQExpBuffer delqry;
7025 PQExpBuffer asPart;
7026 PGresult *res;
7027 char *funcsig; /* identity signature */
7028 char *funcfullsig; /* full signature */
7029 char *funcsig_tag;
7030 int ntups;
7031 char *proretset;
7032 char *prosrc;
7033 char *probin;
7034 char *funcargs;
7035 char *funciargs;
7036 char *funcresult;
7037 char *proallargtypes;
7038 char *proargmodes;
7039 char *proargnames;
7040 char *proiswindow;
7041 char *provolatile;
7042 char *proisstrict;
7043 char *prosecdef;
7044 char *proconfig;
7045 char *procost;
7046 char *prorows;
7047 char *lanname;
7048 char *rettypename;
7049 int nallargs;
7050 char **allargtypes = NULL;
7051 char **argmodes = NULL;
7052 char **argnames = NULL;
7053 char **configitems = NULL;
7054 int nconfigitems = 0;
7055 int i;
7057 /* Skip if not to be dumped */
7058 if (!finfo->dobj.dump || dataOnly)
7059 return;
7061 query = createPQExpBuffer();
7062 q = createPQExpBuffer();
7063 delqry = createPQExpBuffer();
7064 asPart = createPQExpBuffer();
7066 /* Set proper schema search path so type references list correctly */
7067 selectSourceSchema(finfo->dobj.namespace->dobj.name);
7069 /* Fetch function-specific details */
7070 if (g_fout->remoteVersion >= 80400)
7073 * In 8.4 and up we rely on pg_get_function_arguments and
7074 * pg_get_function_result instead of examining proallargtypes etc.
7076 appendPQExpBuffer(query,
7077 "SELECT proretset, prosrc, probin, "
7078 "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
7079 "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
7080 "pg_catalog.pg_get_function_result(oid) AS funcresult, "
7081 "proiswindow, provolatile, proisstrict, prosecdef, "
7082 "proconfig, procost, prorows, "
7083 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7084 "FROM pg_catalog.pg_proc "
7085 "WHERE oid = '%u'::pg_catalog.oid",
7086 finfo->dobj.catId.oid);
7088 else if (g_fout->remoteVersion >= 80300)
7090 appendPQExpBuffer(query,
7091 "SELECT proretset, prosrc, probin, "
7092 "proallargtypes, proargmodes, proargnames, "
7093 "false AS proiswindow, "
7094 "provolatile, proisstrict, prosecdef, "
7095 "proconfig, procost, prorows, "
7096 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7097 "FROM pg_catalog.pg_proc "
7098 "WHERE oid = '%u'::pg_catalog.oid",
7099 finfo->dobj.catId.oid);
7101 else if (g_fout->remoteVersion >= 80100)
7103 appendPQExpBuffer(query,
7104 "SELECT proretset, prosrc, probin, "
7105 "proallargtypes, proargmodes, proargnames, "
7106 "false AS proiswindow, "
7107 "provolatile, proisstrict, prosecdef, "
7108 "null AS proconfig, 0 AS procost, 0 AS prorows, "
7109 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7110 "FROM pg_catalog.pg_proc "
7111 "WHERE oid = '%u'::pg_catalog.oid",
7112 finfo->dobj.catId.oid);
7114 else if (g_fout->remoteVersion >= 80000)
7116 appendPQExpBuffer(query,
7117 "SELECT proretset, prosrc, probin, "
7118 "null AS proallargtypes, "
7119 "null AS proargmodes, "
7120 "proargnames, "
7121 "false AS proiswindow, "
7122 "provolatile, proisstrict, prosecdef, "
7123 "null AS proconfig, 0 AS procost, 0 AS prorows, "
7124 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7125 "FROM pg_catalog.pg_proc "
7126 "WHERE oid = '%u'::pg_catalog.oid",
7127 finfo->dobj.catId.oid);
7129 else if (g_fout->remoteVersion >= 70300)
7131 appendPQExpBuffer(query,
7132 "SELECT proretset, prosrc, probin, "
7133 "null AS proallargtypes, "
7134 "null AS proargmodes, "
7135 "null AS proargnames, "
7136 "false AS proiswindow, "
7137 "provolatile, proisstrict, prosecdef, "
7138 "null AS proconfig, 0 AS procost, 0 AS prorows, "
7139 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7140 "FROM pg_catalog.pg_proc "
7141 "WHERE oid = '%u'::pg_catalog.oid",
7142 finfo->dobj.catId.oid);
7144 else if (g_fout->remoteVersion >= 70100)
7146 appendPQExpBuffer(query,
7147 "SELECT proretset, prosrc, probin, "
7148 "null AS proallargtypes, "
7149 "null AS proargmodes, "
7150 "null AS proargnames, "
7151 "false AS proiswindow, "
7152 "case when proiscachable then 'i' else 'v' end AS provolatile, "
7153 "proisstrict, "
7154 "false AS prosecdef, "
7155 "null AS proconfig, 0 AS procost, 0 AS prorows, "
7156 "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
7157 "FROM pg_proc "
7158 "WHERE oid = '%u'::oid",
7159 finfo->dobj.catId.oid);
7161 else
7163 appendPQExpBuffer(query,
7164 "SELECT proretset, prosrc, probin, "
7165 "null AS proallargtypes, "
7166 "null AS proargmodes, "
7167 "null AS proargnames, "
7168 "false AS proiswindow, "
7169 "CASE WHEN proiscachable THEN 'i' ELSE 'v' END AS provolatile, "
7170 "false AS proisstrict, "
7171 "false AS prosecdef, "
7172 "NULL AS proconfig, 0 AS procost, 0 AS prorows, "
7173 "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
7174 "FROM pg_proc "
7175 "WHERE oid = '%u'::oid",
7176 finfo->dobj.catId.oid);
7179 res = PQexec(g_conn, query->data);
7180 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7182 /* Expecting a single result only */
7183 ntups = PQntuples(res);
7184 if (ntups != 1)
7186 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
7187 "query returned %d rows instead of one: %s\n",
7188 ntups),
7189 ntups, query->data);
7190 exit_nicely();
7193 proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
7194 prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
7195 probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
7196 if (g_fout->remoteVersion >= 80400)
7198 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
7199 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
7200 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
7201 proallargtypes = proargmodes = proargnames = NULL;
7203 else
7205 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
7206 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
7207 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
7208 funcargs = funciargs = funcresult = NULL;
7210 proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow"));
7211 provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
7212 proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
7213 prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
7214 proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
7215 procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
7216 prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
7217 lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
7220 * See backend/commands/functioncmds.c for details of how the 'AS' clause
7221 * is used. In 8.4 and up, an unused probin is NULL (here ""); previous
7222 * versions would set it to "-". There are no known cases in which prosrc
7223 * is unused, so the tests below for "-" are probably useless.
7225 if (probin[0] != '\0' && strcmp(probin, "-") != 0)
7227 appendPQExpBuffer(asPart, "AS ");
7228 appendStringLiteralAH(asPart, probin, fout);
7229 if (strcmp(prosrc, "-") != 0)
7231 appendPQExpBuffer(asPart, ", ");
7234 * where we have bin, use dollar quoting if allowed and src
7235 * contains quote or backslash; else use regular quoting.
7237 if (disable_dollar_quoting ||
7238 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
7239 appendStringLiteralAH(asPart, prosrc, fout);
7240 else
7241 appendStringLiteralDQ(asPart, prosrc, NULL);
7244 else
7246 if (strcmp(prosrc, "-") != 0)
7248 appendPQExpBuffer(asPart, "AS ");
7249 /* with no bin, dollar quote src unconditionally if allowed */
7250 if (disable_dollar_quoting)
7251 appendStringLiteralAH(asPart, prosrc, fout);
7252 else
7253 appendStringLiteralDQ(asPart, prosrc, NULL);
7257 nallargs = finfo->nargs; /* unless we learn different from allargs */
7259 if (proallargtypes && *proallargtypes)
7261 int nitems = 0;
7263 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
7264 nitems < finfo->nargs)
7266 write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
7267 if (allargtypes)
7268 free(allargtypes);
7269 allargtypes = NULL;
7271 else
7272 nallargs = nitems;
7275 if (proargmodes && *proargmodes)
7277 int nitems = 0;
7279 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
7280 nitems != nallargs)
7282 write_msg(NULL, "WARNING: could not parse proargmodes array\n");
7283 if (argmodes)
7284 free(argmodes);
7285 argmodes = NULL;
7289 if (proargnames && *proargnames)
7291 int nitems = 0;
7293 if (!parsePGArray(proargnames, &argnames, &nitems) ||
7294 nitems != nallargs)
7296 write_msg(NULL, "WARNING: could not parse proargnames array\n");
7297 if (argnames)
7298 free(argnames);
7299 argnames = NULL;
7303 if (proconfig && *proconfig)
7305 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
7307 write_msg(NULL, "WARNING: could not parse proconfig array\n");
7308 if (configitems)
7309 free(configitems);
7310 configitems = NULL;
7311 nconfigitems = 0;
7315 if (funcargs)
7317 /* 8.4 or later; we rely on server-side code for most of the work */
7318 funcfullsig = format_function_arguments(finfo, funcargs);
7319 funcsig = format_function_arguments(finfo, funciargs);
7321 else
7323 /* pre-8.4, do it ourselves */
7324 funcsig = format_function_arguments_old(finfo, nallargs, allargtypes,
7325 argmodes, argnames);
7326 funcfullsig = funcsig;
7329 funcsig_tag = format_function_signature(finfo, false);
7332 * DROP must be fully qualified in case same name appears in pg_catalog
7334 appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
7335 fmtId(finfo->dobj.namespace->dobj.name),
7336 funcsig);
7338 appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig);
7339 if (funcresult)
7340 appendPQExpBuffer(q, "RETURNS %s", funcresult);
7341 else
7343 rettypename = getFormattedTypeName(finfo->prorettype, zeroAsOpaque);
7344 appendPQExpBuffer(q, "RETURNS %s%s",
7345 (proretset[0] == 't') ? "SETOF " : "",
7346 rettypename);
7347 free(rettypename);
7350 appendPQExpBuffer(q, "\n LANGUAGE %s", fmtId(lanname));
7352 if (proiswindow[0] == 't')
7353 appendPQExpBuffer(q, " WINDOW");
7355 if (provolatile[0] != PROVOLATILE_VOLATILE)
7357 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
7358 appendPQExpBuffer(q, " IMMUTABLE");
7359 else if (provolatile[0] == PROVOLATILE_STABLE)
7360 appendPQExpBuffer(q, " STABLE");
7361 else if (provolatile[0] != PROVOLATILE_VOLATILE)
7363 write_msg(NULL, "unrecognized provolatile value for function \"%s\"\n",
7364 finfo->dobj.name);
7365 exit_nicely();
7369 if (proisstrict[0] == 't')
7370 appendPQExpBuffer(q, " STRICT");
7372 if (prosecdef[0] == 't')
7373 appendPQExpBuffer(q, " SECURITY DEFINER");
7376 * COST and ROWS are emitted only if present and not default, so as not to
7377 * break backwards-compatibility of the dump without need. Keep this code
7378 * in sync with the defaults in functioncmds.c.
7380 if (strcmp(procost, "0") != 0)
7382 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
7384 /* default cost is 1 */
7385 if (strcmp(procost, "1") != 0)
7386 appendPQExpBuffer(q, " COST %s", procost);
7388 else
7390 /* default cost is 100 */
7391 if (strcmp(procost, "100") != 0)
7392 appendPQExpBuffer(q, " COST %s", procost);
7395 if (proretset[0] == 't' &&
7396 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
7397 appendPQExpBuffer(q, " ROWS %s", prorows);
7399 for (i = 0; i < nconfigitems; i++)
7401 /* we feel free to scribble on configitems[] here */
7402 char *configitem = configitems[i];
7403 char *pos;
7405 pos = strchr(configitem, '=');
7406 if (pos == NULL)
7407 continue;
7408 *pos++ = '\0';
7409 appendPQExpBuffer(q, "\n SET %s TO ", fmtId(configitem));
7412 * Some GUC variable names are 'LIST' type and hence must not be
7413 * quoted.
7415 if (pg_strcasecmp(configitem, "DateStyle") == 0
7416 || pg_strcasecmp(configitem, "search_path") == 0)
7417 appendPQExpBuffer(q, "%s", pos);
7418 else
7419 appendStringLiteralAH(q, pos, fout);
7422 appendPQExpBuffer(q, "\n %s;\n", asPart->data);
7424 ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
7425 funcsig_tag,
7426 finfo->dobj.namespace->dobj.name,
7427 NULL,
7428 finfo->rolname, false,
7429 "FUNCTION", SECTION_PRE_DATA,
7430 q->data, delqry->data, NULL,
7431 finfo->dobj.dependencies, finfo->dobj.nDeps,
7432 NULL, NULL);
7434 /* Dump Function Comments */
7435 resetPQExpBuffer(q);
7436 appendPQExpBuffer(q, "FUNCTION %s", funcsig);
7437 dumpComment(fout, q->data,
7438 finfo->dobj.namespace->dobj.name, finfo->rolname,
7439 finfo->dobj.catId, 0, finfo->dobj.dumpId);
7441 dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
7442 funcsig, NULL, funcsig_tag,
7443 finfo->dobj.namespace->dobj.name,
7444 finfo->rolname, finfo->proacl);
7446 PQclear(res);
7448 destroyPQExpBuffer(query);
7449 destroyPQExpBuffer(q);
7450 destroyPQExpBuffer(delqry);
7451 destroyPQExpBuffer(asPart);
7452 free(funcsig);
7453 free(funcsig_tag);
7454 if (allargtypes)
7455 free(allargtypes);
7456 if (argmodes)
7457 free(argmodes);
7458 if (argnames)
7459 free(argnames);
7460 if (configitems)
7461 free(configitems);
7466 * Dump a user-defined cast
7468 static void
7469 dumpCast(Archive *fout, CastInfo *cast)
7471 PQExpBuffer defqry;
7472 PQExpBuffer delqry;
7473 PQExpBuffer castsig;
7474 FuncInfo *funcInfo = NULL;
7475 TypeInfo *sourceInfo;
7476 TypeInfo *targetInfo;
7478 if (dataOnly)
7479 return;
7481 if (OidIsValid(cast->castfunc))
7483 funcInfo = findFuncByOid(cast->castfunc);
7484 if (funcInfo == NULL)
7485 return;
7489 * As per discussion we dump casts if one or more of the underlying
7490 * objects (the conversion function and the two data types) are not
7491 * builtin AND if all of the non-builtin objects are included in the dump.
7492 * Builtin meaning, the namespace name does not start with "pg_".
7494 sourceInfo = findTypeByOid(cast->castsource);
7495 targetInfo = findTypeByOid(cast->casttarget);
7497 if (sourceInfo == NULL || targetInfo == NULL)
7498 return;
7501 * Skip this cast if all objects are from pg_
7503 if ((funcInfo == NULL ||
7504 strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
7505 strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) == 0 &&
7506 strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) == 0)
7507 return;
7510 * Skip cast if function isn't from pg_ and is not to be dumped.
7512 if (funcInfo &&
7513 strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
7514 !funcInfo->dobj.dump)
7515 return;
7518 * Same for the source type
7520 if (strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
7521 !sourceInfo->dobj.dump)
7522 return;
7525 * and the target type.
7527 if (strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
7528 !targetInfo->dobj.dump)
7529 return;
7531 /* Make sure we are in proper schema (needed for getFormattedTypeName) */
7532 selectSourceSchema("pg_catalog");
7534 defqry = createPQExpBuffer();
7535 delqry = createPQExpBuffer();
7536 castsig = createPQExpBuffer();
7538 appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
7539 getFormattedTypeName(cast->castsource, zeroAsNone),
7540 getFormattedTypeName(cast->casttarget, zeroAsNone));
7542 appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
7543 getFormattedTypeName(cast->castsource, zeroAsNone),
7544 getFormattedTypeName(cast->casttarget, zeroAsNone));
7546 switch (cast->castmethod)
7548 case COERCION_METHOD_BINARY:
7549 appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
7550 break;
7551 case COERCION_METHOD_INOUT:
7552 appendPQExpBuffer(defqry, "WITH INOUT");
7553 break;
7554 case COERCION_METHOD_FUNCTION:
7557 * Always qualify the function name, in case it is not in
7558 * pg_catalog schema (format_function_signature won't qualify it).
7560 appendPQExpBuffer(defqry, "WITH FUNCTION %s.",
7561 fmtId(funcInfo->dobj.namespace->dobj.name));
7562 appendPQExpBuffer(defqry, "%s",
7563 format_function_signature(funcInfo, true));
7564 break;
7565 default:
7566 write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
7569 if (cast->castcontext == 'a')
7570 appendPQExpBuffer(defqry, " AS ASSIGNMENT");
7571 else if (cast->castcontext == 'i')
7572 appendPQExpBuffer(defqry, " AS IMPLICIT");
7573 appendPQExpBuffer(defqry, ";\n");
7575 appendPQExpBuffer(castsig, "CAST (%s AS %s)",
7576 getFormattedTypeName(cast->castsource, zeroAsNone),
7577 getFormattedTypeName(cast->casttarget, zeroAsNone));
7579 ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
7580 castsig->data,
7581 "pg_catalog", NULL, "",
7582 false, "CAST", SECTION_PRE_DATA,
7583 defqry->data, delqry->data, NULL,
7584 cast->dobj.dependencies, cast->dobj.nDeps,
7585 NULL, NULL);
7587 /* Dump Cast Comments */
7588 resetPQExpBuffer(defqry);
7589 appendPQExpBuffer(defqry, "CAST (%s AS %s)",
7590 getFormattedTypeName(cast->castsource, zeroAsNone),
7591 getFormattedTypeName(cast->casttarget, zeroAsNone));
7592 dumpComment(fout, defqry->data,
7593 NULL, "",
7594 cast->dobj.catId, 0, cast->dobj.dumpId);
7596 destroyPQExpBuffer(defqry);
7597 destroyPQExpBuffer(delqry);
7598 destroyPQExpBuffer(castsig);
7602 * dumpOpr
7603 * write out a single operator definition
7605 static void
7606 dumpOpr(Archive *fout, OprInfo *oprinfo)
7608 PQExpBuffer query;
7609 PQExpBuffer q;
7610 PQExpBuffer delq;
7611 PQExpBuffer oprid;
7612 PQExpBuffer details;
7613 const char *name;
7614 PGresult *res;
7615 int ntups;
7616 int i_oprkind;
7617 int i_oprcode;
7618 int i_oprleft;
7619 int i_oprright;
7620 int i_oprcom;
7621 int i_oprnegate;
7622 int i_oprrest;
7623 int i_oprjoin;
7624 int i_oprcanmerge;
7625 int i_oprcanhash;
7626 char *oprkind;
7627 char *oprcode;
7628 char *oprleft;
7629 char *oprright;
7630 char *oprcom;
7631 char *oprnegate;
7632 char *oprrest;
7633 char *oprjoin;
7634 char *oprcanmerge;
7635 char *oprcanhash;
7637 /* Skip if not to be dumped */
7638 if (!oprinfo->dobj.dump || dataOnly)
7639 return;
7642 * some operators are invalid because they were the result of user
7643 * defining operators before commutators exist
7645 if (!OidIsValid(oprinfo->oprcode))
7646 return;
7648 query = createPQExpBuffer();
7649 q = createPQExpBuffer();
7650 delq = createPQExpBuffer();
7651 oprid = createPQExpBuffer();
7652 details = createPQExpBuffer();
7654 /* Make sure we are in proper schema so regoperator works correctly */
7655 selectSourceSchema(oprinfo->dobj.namespace->dobj.name);
7657 if (g_fout->remoteVersion >= 80300)
7659 appendPQExpBuffer(query, "SELECT oprkind, "
7660 "oprcode::pg_catalog.regprocedure, "
7661 "oprleft::pg_catalog.regtype, "
7662 "oprright::pg_catalog.regtype, "
7663 "oprcom::pg_catalog.regoperator, "
7664 "oprnegate::pg_catalog.regoperator, "
7665 "oprrest::pg_catalog.regprocedure, "
7666 "oprjoin::pg_catalog.regprocedure, "
7667 "oprcanmerge, oprcanhash "
7668 "FROM pg_catalog.pg_operator "
7669 "WHERE oid = '%u'::pg_catalog.oid",
7670 oprinfo->dobj.catId.oid);
7672 else if (g_fout->remoteVersion >= 70300)
7674 appendPQExpBuffer(query, "SELECT oprkind, "
7675 "oprcode::pg_catalog.regprocedure, "
7676 "oprleft::pg_catalog.regtype, "
7677 "oprright::pg_catalog.regtype, "
7678 "oprcom::pg_catalog.regoperator, "
7679 "oprnegate::pg_catalog.regoperator, "
7680 "oprrest::pg_catalog.regprocedure, "
7681 "oprjoin::pg_catalog.regprocedure, "
7682 "(oprlsortop != 0) AS oprcanmerge, "
7683 "oprcanhash "
7684 "FROM pg_catalog.pg_operator "
7685 "WHERE oid = '%u'::pg_catalog.oid",
7686 oprinfo->dobj.catId.oid);
7688 else if (g_fout->remoteVersion >= 70100)
7690 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
7691 "CASE WHEN oprleft = 0 THEN '-' "
7692 "ELSE format_type(oprleft, NULL) END AS oprleft, "
7693 "CASE WHEN oprright = 0 THEN '-' "
7694 "ELSE format_type(oprright, NULL) END AS oprright, "
7695 "oprcom, oprnegate, oprrest, oprjoin, "
7696 "(oprlsortop != 0) AS oprcanmerge, "
7697 "oprcanhash "
7698 "FROM pg_operator "
7699 "WHERE oid = '%u'::oid",
7700 oprinfo->dobj.catId.oid);
7702 else
7704 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
7705 "CASE WHEN oprleft = 0 THEN '-'::name "
7706 "ELSE (SELECT typname FROM pg_type WHERE oid = oprleft) END AS oprleft, "
7707 "CASE WHEN oprright = 0 THEN '-'::name "
7708 "ELSE (SELECT typname FROM pg_type WHERE oid = oprright) 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);
7717 res = PQexec(g_conn, query->data);
7718 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7720 /* Expecting a single result only */
7721 ntups = PQntuples(res);
7722 if (ntups != 1)
7724 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
7725 "query returned %d rows instead of one: %s\n",
7726 ntups),
7727 ntups, query->data);
7728 exit_nicely();
7731 i_oprkind = PQfnumber(res, "oprkind");
7732 i_oprcode = PQfnumber(res, "oprcode");
7733 i_oprleft = PQfnumber(res, "oprleft");
7734 i_oprright = PQfnumber(res, "oprright");
7735 i_oprcom = PQfnumber(res, "oprcom");
7736 i_oprnegate = PQfnumber(res, "oprnegate");
7737 i_oprrest = PQfnumber(res, "oprrest");
7738 i_oprjoin = PQfnumber(res, "oprjoin");
7739 i_oprcanmerge = PQfnumber(res, "oprcanmerge");
7740 i_oprcanhash = PQfnumber(res, "oprcanhash");
7742 oprkind = PQgetvalue(res, 0, i_oprkind);
7743 oprcode = PQgetvalue(res, 0, i_oprcode);
7744 oprleft = PQgetvalue(res, 0, i_oprleft);
7745 oprright = PQgetvalue(res, 0, i_oprright);
7746 oprcom = PQgetvalue(res, 0, i_oprcom);
7747 oprnegate = PQgetvalue(res, 0, i_oprnegate);
7748 oprrest = PQgetvalue(res, 0, i_oprrest);
7749 oprjoin = PQgetvalue(res, 0, i_oprjoin);
7750 oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
7751 oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
7753 appendPQExpBuffer(details, " PROCEDURE = %s",
7754 convertRegProcReference(oprcode));
7756 appendPQExpBuffer(oprid, "%s (",
7757 oprinfo->dobj.name);
7760 * right unary means there's a left arg and left unary means there's a
7761 * right arg
7763 if (strcmp(oprkind, "r") == 0 ||
7764 strcmp(oprkind, "b") == 0)
7766 if (g_fout->remoteVersion >= 70100)
7767 name = oprleft;
7768 else
7769 name = fmtId(oprleft);
7770 appendPQExpBuffer(details, ",\n LEFTARG = %s", name);
7771 appendPQExpBuffer(oprid, "%s", name);
7773 else
7774 appendPQExpBuffer(oprid, "NONE");
7776 if (strcmp(oprkind, "l") == 0 ||
7777 strcmp(oprkind, "b") == 0)
7779 if (g_fout->remoteVersion >= 70100)
7780 name = oprright;
7781 else
7782 name = fmtId(oprright);
7783 appendPQExpBuffer(details, ",\n RIGHTARG = %s", name);
7784 appendPQExpBuffer(oprid, ", %s)", name);
7786 else
7787 appendPQExpBuffer(oprid, ", NONE)");
7789 name = convertOperatorReference(oprcom);
7790 if (name)
7791 appendPQExpBuffer(details, ",\n COMMUTATOR = %s", name);
7793 name = convertOperatorReference(oprnegate);
7794 if (name)
7795 appendPQExpBuffer(details, ",\n NEGATOR = %s", name);
7797 if (strcmp(oprcanmerge, "t") == 0)
7798 appendPQExpBuffer(details, ",\n MERGES");
7800 if (strcmp(oprcanhash, "t") == 0)
7801 appendPQExpBuffer(details, ",\n HASHES");
7803 name = convertRegProcReference(oprrest);
7804 if (name)
7805 appendPQExpBuffer(details, ",\n RESTRICT = %s", name);
7807 name = convertRegProcReference(oprjoin);
7808 if (name)
7809 appendPQExpBuffer(details, ",\n JOIN = %s", name);
7812 * DROP must be fully qualified in case same name appears in pg_catalog
7814 appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
7815 fmtId(oprinfo->dobj.namespace->dobj.name),
7816 oprid->data);
7818 appendPQExpBuffer(q, "CREATE OPERATOR %s (\n%s\n);\n",
7819 oprinfo->dobj.name, details->data);
7821 ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
7822 oprinfo->dobj.name,
7823 oprinfo->dobj.namespace->dobj.name,
7824 NULL,
7825 oprinfo->rolname,
7826 false, "OPERATOR", SECTION_PRE_DATA,
7827 q->data, delq->data, NULL,
7828 oprinfo->dobj.dependencies, oprinfo->dobj.nDeps,
7829 NULL, NULL);
7831 /* Dump Operator Comments */
7832 resetPQExpBuffer(q);
7833 appendPQExpBuffer(q, "OPERATOR %s", oprid->data);
7834 dumpComment(fout, q->data,
7835 oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
7836 oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
7838 PQclear(res);
7840 destroyPQExpBuffer(query);
7841 destroyPQExpBuffer(q);
7842 destroyPQExpBuffer(delq);
7843 destroyPQExpBuffer(oprid);
7844 destroyPQExpBuffer(details);
7848 * Convert a function reference obtained from pg_operator
7850 * Returns what to print, or NULL if function references is InvalidOid
7852 * In 7.3 the input is a REGPROCEDURE display; we have to strip the
7853 * argument-types part. In prior versions, the input is a REGPROC display.
7855 static const char *
7856 convertRegProcReference(const char *proc)
7858 /* In all cases "-" means a null reference */
7859 if (strcmp(proc, "-") == 0)
7860 return NULL;
7862 if (g_fout->remoteVersion >= 70300)
7864 char *name;
7865 char *paren;
7866 bool inquote;
7868 name = strdup(proc);
7869 /* find non-double-quoted left paren */
7870 inquote = false;
7871 for (paren = name; *paren; paren++)
7873 if (*paren == '(' && !inquote)
7875 *paren = '\0';
7876 break;
7878 if (*paren == '"')
7879 inquote = !inquote;
7881 return name;
7884 /* REGPROC before 7.3 does not quote its result */
7885 return fmtId(proc);
7889 * Convert an operator cross-reference obtained from pg_operator
7891 * Returns what to print, or NULL to print nothing
7893 * In 7.3 and up the input is a REGOPERATOR display; we have to strip the
7894 * argument-types part, and add OPERATOR() decoration if the name is
7895 * schema-qualified. In older versions, the input is just a numeric OID,
7896 * which we search our operator list for.
7898 static const char *
7899 convertOperatorReference(const char *opr)
7901 OprInfo *oprInfo;
7903 /* In all cases "0" means a null reference */
7904 if (strcmp(opr, "0") == 0)
7905 return NULL;
7907 if (g_fout->remoteVersion >= 70300)
7909 char *name;
7910 char *oname;
7911 char *ptr;
7912 bool inquote;
7913 bool sawdot;
7915 name = strdup(opr);
7916 /* find non-double-quoted left paren, and check for non-quoted dot */
7917 inquote = false;
7918 sawdot = false;
7919 for (ptr = name; *ptr; ptr++)
7921 if (*ptr == '"')
7922 inquote = !inquote;
7923 else if (*ptr == '.' && !inquote)
7924 sawdot = true;
7925 else if (*ptr == '(' && !inquote)
7927 *ptr = '\0';
7928 break;
7931 /* If not schema-qualified, don't need to add OPERATOR() */
7932 if (!sawdot)
7933 return name;
7934 oname = malloc(strlen(name) + 11);
7935 sprintf(oname, "OPERATOR(%s)", name);
7936 free(name);
7937 return oname;
7940 oprInfo = findOprByOid(atooid(opr));
7941 if (oprInfo == NULL)
7943 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
7944 opr);
7945 return NULL;
7947 return oprInfo->dobj.name;
7951 * Convert a function OID obtained from pg_ts_parser or pg_ts_template
7953 * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
7954 * argument lists of these functions are predetermined. Note that the
7955 * caller should ensure we are in the proper schema, because the results
7956 * are search path dependent!
7958 static const char *
7959 convertTSFunction(Oid funcOid)
7961 char *result;
7962 char query[128];
7963 PGresult *res;
7964 int ntups;
7966 snprintf(query, sizeof(query),
7967 "SELECT '%u'::pg_catalog.regproc", funcOid);
7968 res = PQexec(g_conn, query);
7969 check_sql_result(res, g_conn, query, PGRES_TUPLES_OK);
7971 ntups = PQntuples(res);
7972 if (ntups != 1)
7974 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
7975 "query returned %d rows instead of one: %s\n",
7976 ntups),
7977 ntups, query);
7978 exit_nicely();
7981 result = strdup(PQgetvalue(res, 0, 0));
7983 PQclear(res);
7985 return result;
7990 * dumpOpclass
7991 * write out a single operator class definition
7993 static void
7994 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
7996 PQExpBuffer query;
7997 PQExpBuffer q;
7998 PQExpBuffer delq;
7999 PGresult *res;
8000 int ntups;
8001 int i_opcintype;
8002 int i_opckeytype;
8003 int i_opcdefault;
8004 int i_opcfamily;
8005 int i_opcfamilynsp;
8006 int i_amname;
8007 int i_amopstrategy;
8008 int i_amopreqcheck;
8009 int i_amopopr;
8010 int i_amprocnum;
8011 int i_amproc;
8012 char *opcintype;
8013 char *opckeytype;
8014 char *opcdefault;
8015 char *opcfamily;
8016 char *opcfamilynsp;
8017 char *amname;
8018 char *amopstrategy;
8019 char *amopreqcheck;
8020 char *amopopr;
8021 char *amprocnum;
8022 char *amproc;
8023 bool needComma;
8024 int i;
8026 /* Skip if not to be dumped */
8027 if (!opcinfo->dobj.dump || dataOnly)
8028 return;
8031 * XXX currently we do not implement dumping of operator classes from
8032 * pre-7.3 databases. This could be done but it seems not worth the
8033 * trouble.
8035 if (g_fout->remoteVersion < 70300)
8036 return;
8038 query = createPQExpBuffer();
8039 q = createPQExpBuffer();
8040 delq = createPQExpBuffer();
8042 /* Make sure we are in proper schema so regoperator works correctly */
8043 selectSourceSchema(opcinfo->dobj.namespace->dobj.name);
8045 /* Get additional fields from the pg_opclass row */
8046 if (g_fout->remoteVersion >= 80300)
8048 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
8049 "opckeytype::pg_catalog.regtype, "
8050 "opcdefault, "
8051 "opfname AS opcfamily, "
8052 "nspname AS opcfamilynsp, "
8053 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
8054 "FROM pg_catalog.pg_opclass c "
8055 "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
8056 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
8057 "WHERE c.oid = '%u'::pg_catalog.oid",
8058 opcinfo->dobj.catId.oid);
8060 else
8062 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
8063 "opckeytype::pg_catalog.regtype, "
8064 "opcdefault, "
8065 "NULL AS opcfamily, "
8066 "NULL AS opcfamilynsp, "
8067 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
8068 "FROM pg_catalog.pg_opclass "
8069 "WHERE oid = '%u'::pg_catalog.oid",
8070 opcinfo->dobj.catId.oid);
8073 res = PQexec(g_conn, query->data);
8074 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8076 /* Expecting a single result only */
8077 ntups = PQntuples(res);
8078 if (ntups != 1)
8080 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
8081 "query returned %d rows instead of one: %s\n",
8082 ntups),
8083 ntups, query->data);
8084 exit_nicely();
8087 i_opcintype = PQfnumber(res, "opcintype");
8088 i_opckeytype = PQfnumber(res, "opckeytype");
8089 i_opcdefault = PQfnumber(res, "opcdefault");
8090 i_opcfamily = PQfnumber(res, "opcfamily");
8091 i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
8092 i_amname = PQfnumber(res, "amname");
8094 opcintype = PQgetvalue(res, 0, i_opcintype);
8095 opckeytype = PQgetvalue(res, 0, i_opckeytype);
8096 opcdefault = PQgetvalue(res, 0, i_opcdefault);
8097 opcfamily = PQgetvalue(res, 0, i_opcfamily);
8098 opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
8099 /* amname will still be needed after we PQclear res */
8100 amname = strdup(PQgetvalue(res, 0, i_amname));
8103 * DROP must be fully qualified in case same name appears in pg_catalog
8105 appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
8106 fmtId(opcinfo->dobj.namespace->dobj.name));
8107 appendPQExpBuffer(delq, ".%s",
8108 fmtId(opcinfo->dobj.name));
8109 appendPQExpBuffer(delq, " USING %s;\n",
8110 fmtId(amname));
8112 /* Build the fixed portion of the CREATE command */
8113 appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n ",
8114 fmtId(opcinfo->dobj.name));
8115 if (strcmp(opcdefault, "t") == 0)
8116 appendPQExpBuffer(q, "DEFAULT ");
8117 appendPQExpBuffer(q, "FOR TYPE %s USING %s",
8118 opcintype,
8119 fmtId(amname));
8120 if (strlen(opcfamily) > 0 &&
8121 (strcmp(opcfamily, opcinfo->dobj.name) != 0 ||
8122 strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
8124 appendPQExpBuffer(q, " FAMILY ");
8125 if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
8126 appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
8127 appendPQExpBuffer(q, "%s", fmtId(opcfamily));
8129 appendPQExpBuffer(q, " AS\n ");
8131 needComma = false;
8133 if (strcmp(opckeytype, "-") != 0)
8135 appendPQExpBuffer(q, "STORAGE %s",
8136 opckeytype);
8137 needComma = true;
8140 PQclear(res);
8143 * Now fetch and print the OPERATOR entries (pg_amop rows).
8145 resetPQExpBuffer(query);
8147 if (g_fout->remoteVersion >= 80400)
8150 * Print only those opfamily members that are tied to the opclass by
8151 * pg_depend entries.
8153 * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping
8154 * an older server's opclass in which it is used. This is to avoid
8155 * hard-to-detect breakage if a newer pg_dump is used to dump from an
8156 * older server and then reload into that old version. This can go
8157 * away once 8.3 is so old as to not be of interest to anyone.
8159 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
8160 "amopopr::pg_catalog.regoperator "
8161 "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
8162 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
8163 "AND refobjid = '%u'::pg_catalog.oid "
8164 "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
8165 "AND objid = ao.oid "
8166 "ORDER BY amopstrategy",
8167 opcinfo->dobj.catId.oid);
8169 else if (g_fout->remoteVersion >= 80300)
8172 * Print only those opfamily members that are tied to the opclass by
8173 * pg_depend entries.
8175 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
8176 "amopopr::pg_catalog.regoperator "
8177 "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
8178 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
8179 "AND refobjid = '%u'::pg_catalog.oid "
8180 "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
8181 "AND objid = ao.oid "
8182 "ORDER BY amopstrategy",
8183 opcinfo->dobj.catId.oid);
8185 else
8187 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
8188 "amopopr::pg_catalog.regoperator "
8189 "FROM pg_catalog.pg_amop "
8190 "WHERE amopclaid = '%u'::pg_catalog.oid "
8191 "ORDER BY amopstrategy",
8192 opcinfo->dobj.catId.oid);
8195 res = PQexec(g_conn, query->data);
8196 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8198 ntups = PQntuples(res);
8200 i_amopstrategy = PQfnumber(res, "amopstrategy");
8201 i_amopreqcheck = PQfnumber(res, "amopreqcheck");
8202 i_amopopr = PQfnumber(res, "amopopr");
8204 for (i = 0; i < ntups; i++)
8206 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
8207 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
8208 amopopr = PQgetvalue(res, i, i_amopopr);
8210 if (needComma)
8211 appendPQExpBuffer(q, " ,\n ");
8213 appendPQExpBuffer(q, "OPERATOR %s %s",
8214 amopstrategy, amopopr);
8215 if (strcmp(amopreqcheck, "t") == 0)
8216 appendPQExpBuffer(q, " RECHECK");
8218 needComma = true;
8221 PQclear(res);
8224 * Now fetch and print the FUNCTION entries (pg_amproc rows).
8226 resetPQExpBuffer(query);
8228 if (g_fout->remoteVersion >= 80300)
8231 * Print only those opfamily members that are tied to the opclass by
8232 * pg_depend entries.
8234 appendPQExpBuffer(query, "SELECT amprocnum, "
8235 "amproc::pg_catalog.regprocedure "
8236 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
8237 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
8238 "AND refobjid = '%u'::pg_catalog.oid "
8239 "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
8240 "AND objid = ap.oid "
8241 "ORDER BY amprocnum",
8242 opcinfo->dobj.catId.oid);
8244 else
8246 appendPQExpBuffer(query, "SELECT amprocnum, "
8247 "amproc::pg_catalog.regprocedure "
8248 "FROM pg_catalog.pg_amproc "
8249 "WHERE amopclaid = '%u'::pg_catalog.oid "
8250 "ORDER BY amprocnum",
8251 opcinfo->dobj.catId.oid);
8254 res = PQexec(g_conn, query->data);
8255 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8257 ntups = PQntuples(res);
8259 i_amprocnum = PQfnumber(res, "amprocnum");
8260 i_amproc = PQfnumber(res, "amproc");
8262 for (i = 0; i < ntups; i++)
8264 amprocnum = PQgetvalue(res, i, i_amprocnum);
8265 amproc = PQgetvalue(res, i, i_amproc);
8267 if (needComma)
8268 appendPQExpBuffer(q, " ,\n ");
8270 appendPQExpBuffer(q, "FUNCTION %s %s",
8271 amprocnum, amproc);
8273 needComma = true;
8276 PQclear(res);
8278 appendPQExpBuffer(q, ";\n");
8280 ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
8281 opcinfo->dobj.name,
8282 opcinfo->dobj.namespace->dobj.name,
8283 NULL,
8284 opcinfo->rolname,
8285 false, "OPERATOR CLASS", SECTION_PRE_DATA,
8286 q->data, delq->data, NULL,
8287 opcinfo->dobj.dependencies, opcinfo->dobj.nDeps,
8288 NULL, NULL);
8290 /* Dump Operator Class Comments */
8291 resetPQExpBuffer(q);
8292 appendPQExpBuffer(q, "OPERATOR CLASS %s",
8293 fmtId(opcinfo->dobj.name));
8294 appendPQExpBuffer(q, " USING %s",
8295 fmtId(amname));
8296 dumpComment(fout, q->data,
8297 NULL, opcinfo->rolname,
8298 opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
8300 free(amname);
8301 destroyPQExpBuffer(query);
8302 destroyPQExpBuffer(q);
8303 destroyPQExpBuffer(delq);
8307 * dumpOpfamily
8308 * write out a single operator family definition
8310 static void
8311 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
8313 PQExpBuffer query;
8314 PQExpBuffer q;
8315 PQExpBuffer delq;
8316 PGresult *res;
8317 PGresult *res_ops;
8318 PGresult *res_procs;
8319 int ntups;
8320 int i_amname;
8321 int i_amopstrategy;
8322 int i_amopreqcheck;
8323 int i_amopopr;
8324 int i_amprocnum;
8325 int i_amproc;
8326 int i_amproclefttype;
8327 int i_amprocrighttype;
8328 char *amname;
8329 char *amopstrategy;
8330 char *amopreqcheck;
8331 char *amopopr;
8332 char *amprocnum;
8333 char *amproc;
8334 char *amproclefttype;
8335 char *amprocrighttype;
8336 bool needComma;
8337 int i;
8339 /* Skip if not to be dumped */
8340 if (!opfinfo->dobj.dump || dataOnly)
8341 return;
8344 * We want to dump the opfamily only if (1) it contains "loose" operators
8345 * or functions, or (2) it contains an opclass with a different name or
8346 * owner. Otherwise it's sufficient to let it be created during creation
8347 * of the contained opclass, and not dumping it improves portability of
8348 * the dump. Since we have to fetch the loose operators/funcs anyway, do
8349 * that first.
8352 query = createPQExpBuffer();
8353 q = createPQExpBuffer();
8354 delq = createPQExpBuffer();
8356 /* Make sure we are in proper schema so regoperator works correctly */
8357 selectSourceSchema(opfinfo->dobj.namespace->dobj.name);
8360 * Fetch only those opfamily members that are tied directly to the
8361 * opfamily by pg_depend entries.
8363 if (g_fout->remoteVersion >= 80400)
8366 * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping
8367 * an older server's opclass in which it is used. This is to avoid
8368 * hard-to-detect breakage if a newer pg_dump is used to dump from an
8369 * older server and then reload into that old version. This can go
8370 * away once 8.3 is so old as to not be of interest to anyone.
8372 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
8373 "amopopr::pg_catalog.regoperator "
8374 "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
8375 "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8376 "AND refobjid = '%u'::pg_catalog.oid "
8377 "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
8378 "AND objid = ao.oid "
8379 "ORDER BY amopstrategy",
8380 opfinfo->dobj.catId.oid);
8382 else
8384 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
8385 "amopopr::pg_catalog.regoperator "
8386 "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
8387 "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8388 "AND refobjid = '%u'::pg_catalog.oid "
8389 "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
8390 "AND objid = ao.oid "
8391 "ORDER BY amopstrategy",
8392 opfinfo->dobj.catId.oid);
8395 res_ops = PQexec(g_conn, query->data);
8396 check_sql_result(res_ops, g_conn, query->data, PGRES_TUPLES_OK);
8398 resetPQExpBuffer(query);
8400 appendPQExpBuffer(query, "SELECT amprocnum, "
8401 "amproc::pg_catalog.regprocedure, "
8402 "amproclefttype::pg_catalog.regtype, "
8403 "amprocrighttype::pg_catalog.regtype "
8404 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
8405 "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8406 "AND refobjid = '%u'::pg_catalog.oid "
8407 "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
8408 "AND objid = ap.oid "
8409 "ORDER BY amprocnum",
8410 opfinfo->dobj.catId.oid);
8412 res_procs = PQexec(g_conn, query->data);
8413 check_sql_result(res_procs, g_conn, query->data, PGRES_TUPLES_OK);
8415 if (PQntuples(res_ops) == 0 && PQntuples(res_procs) == 0)
8417 /* No loose members, so check contained opclasses */
8418 resetPQExpBuffer(query);
8420 appendPQExpBuffer(query, "SELECT 1 "
8421 "FROM pg_catalog.pg_opclass c, pg_catalog.pg_opfamily f, pg_catalog.pg_depend "
8422 "WHERE f.oid = '%u'::pg_catalog.oid "
8423 "AND refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8424 "AND refobjid = f.oid "
8425 "AND classid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
8426 "AND objid = c.oid "
8427 "AND (opcname != opfname OR opcnamespace != opfnamespace OR opcowner != opfowner) "
8428 "LIMIT 1",
8429 opfinfo->dobj.catId.oid);
8431 res = PQexec(g_conn, query->data);
8432 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8434 if (PQntuples(res) == 0)
8436 /* no need to dump it, so bail out */
8437 PQclear(res);
8438 PQclear(res_ops);
8439 PQclear(res_procs);
8440 destroyPQExpBuffer(query);
8441 destroyPQExpBuffer(q);
8442 destroyPQExpBuffer(delq);
8443 return;
8446 PQclear(res);
8449 /* Get additional fields from the pg_opfamily row */
8450 resetPQExpBuffer(query);
8452 appendPQExpBuffer(query, "SELECT "
8453 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
8454 "FROM pg_catalog.pg_opfamily "
8455 "WHERE oid = '%u'::pg_catalog.oid",
8456 opfinfo->dobj.catId.oid);
8458 res = PQexec(g_conn, query->data);
8459 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8461 /* Expecting a single result only */
8462 ntups = PQntuples(res);
8463 if (ntups != 1)
8465 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
8466 "query returned %d rows instead of one: %s\n",
8467 ntups),
8468 ntups, query->data);
8469 exit_nicely();
8472 i_amname = PQfnumber(res, "amname");
8474 /* amname will still be needed after we PQclear res */
8475 amname = strdup(PQgetvalue(res, 0, i_amname));
8478 * DROP must be fully qualified in case same name appears in pg_catalog
8480 appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
8481 fmtId(opfinfo->dobj.namespace->dobj.name));
8482 appendPQExpBuffer(delq, ".%s",
8483 fmtId(opfinfo->dobj.name));
8484 appendPQExpBuffer(delq, " USING %s;\n",
8485 fmtId(amname));
8487 /* Build the fixed portion of the CREATE command */
8488 appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
8489 fmtId(opfinfo->dobj.name));
8490 appendPQExpBuffer(q, " USING %s;\n",
8491 fmtId(amname));
8493 PQclear(res);
8495 /* Do we need an ALTER to add loose members? */
8496 if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
8498 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
8499 fmtId(opfinfo->dobj.name));
8500 appendPQExpBuffer(q, " USING %s ADD\n ",
8501 fmtId(amname));
8503 needComma = false;
8506 * Now fetch and print the OPERATOR entries (pg_amop rows).
8508 ntups = PQntuples(res_ops);
8510 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
8511 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
8512 i_amopopr = PQfnumber(res_ops, "amopopr");
8514 for (i = 0; i < ntups; i++)
8516 amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
8517 amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
8518 amopopr = PQgetvalue(res_ops, i, i_amopopr);
8520 if (needComma)
8521 appendPQExpBuffer(q, " ,\n ");
8523 appendPQExpBuffer(q, "OPERATOR %s %s",
8524 amopstrategy, amopopr);
8525 if (strcmp(amopreqcheck, "t") == 0)
8526 appendPQExpBuffer(q, " RECHECK");
8528 needComma = true;
8532 * Now fetch and print the FUNCTION entries (pg_amproc rows).
8534 ntups = PQntuples(res_procs);
8536 i_amprocnum = PQfnumber(res_procs, "amprocnum");
8537 i_amproc = PQfnumber(res_procs, "amproc");
8538 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
8539 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
8541 for (i = 0; i < ntups; i++)
8543 amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
8544 amproc = PQgetvalue(res_procs, i, i_amproc);
8545 amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
8546 amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
8548 if (needComma)
8549 appendPQExpBuffer(q, " ,\n ");
8551 appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
8552 amprocnum, amproclefttype, amprocrighttype,
8553 amproc);
8555 needComma = true;
8558 appendPQExpBuffer(q, ";\n");
8561 ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
8562 opfinfo->dobj.name,
8563 opfinfo->dobj.namespace->dobj.name,
8564 NULL,
8565 opfinfo->rolname,
8566 false, "OPERATOR FAMILY", SECTION_PRE_DATA,
8567 q->data, delq->data, NULL,
8568 opfinfo->dobj.dependencies, opfinfo->dobj.nDeps,
8569 NULL, NULL);
8571 /* Dump Operator Family Comments */
8572 resetPQExpBuffer(q);
8573 appendPQExpBuffer(q, "OPERATOR FAMILY %s",
8574 fmtId(opfinfo->dobj.name));
8575 appendPQExpBuffer(q, " USING %s",
8576 fmtId(amname));
8577 dumpComment(fout, q->data,
8578 NULL, opfinfo->rolname,
8579 opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
8581 free(amname);
8582 PQclear(res_ops);
8583 PQclear(res_procs);
8584 destroyPQExpBuffer(query);
8585 destroyPQExpBuffer(q);
8586 destroyPQExpBuffer(delq);
8590 * dumpConversion
8591 * write out a single conversion definition
8593 static void
8594 dumpConversion(Archive *fout, ConvInfo *convinfo)
8596 PQExpBuffer query;
8597 PQExpBuffer q;
8598 PQExpBuffer delq;
8599 PQExpBuffer details;
8600 PGresult *res;
8601 int ntups;
8602 int i_conname;
8603 int i_conforencoding;
8604 int i_contoencoding;
8605 int i_conproc;
8606 int i_condefault;
8607 const char *conname;
8608 const char *conforencoding;
8609 const char *contoencoding;
8610 const char *conproc;
8611 bool condefault;
8613 /* Skip if not to be dumped */
8614 if (!convinfo->dobj.dump || dataOnly)
8615 return;
8617 query = createPQExpBuffer();
8618 q = createPQExpBuffer();
8619 delq = createPQExpBuffer();
8620 details = createPQExpBuffer();
8622 /* Make sure we are in proper schema */
8623 selectSourceSchema(convinfo->dobj.namespace->dobj.name);
8625 /* Get conversion-specific details */
8626 appendPQExpBuffer(query, "SELECT conname, "
8627 "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
8628 "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
8629 "conproc, condefault "
8630 "FROM pg_catalog.pg_conversion c "
8631 "WHERE c.oid = '%u'::pg_catalog.oid",
8632 convinfo->dobj.catId.oid);
8634 res = PQexec(g_conn, query->data);
8635 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8637 /* Expecting a single result only */
8638 ntups = PQntuples(res);
8639 if (ntups != 1)
8641 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
8642 "query returned %d rows instead of one: %s\n",
8643 ntups),
8644 ntups, query->data);
8645 exit_nicely();
8648 i_conname = PQfnumber(res, "conname");
8649 i_conforencoding = PQfnumber(res, "conforencoding");
8650 i_contoencoding = PQfnumber(res, "contoencoding");
8651 i_conproc = PQfnumber(res, "conproc");
8652 i_condefault = PQfnumber(res, "condefault");
8654 conname = PQgetvalue(res, 0, i_conname);
8655 conforencoding = PQgetvalue(res, 0, i_conforencoding);
8656 contoencoding = PQgetvalue(res, 0, i_contoencoding);
8657 conproc = PQgetvalue(res, 0, i_conproc);
8658 condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
8661 * DROP must be fully qualified in case same name appears in pg_catalog
8663 appendPQExpBuffer(delq, "DROP CONVERSION %s",
8664 fmtId(convinfo->dobj.namespace->dobj.name));
8665 appendPQExpBuffer(delq, ".%s;\n",
8666 fmtId(convinfo->dobj.name));
8668 appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
8669 (condefault) ? "DEFAULT " : "",
8670 fmtId(convinfo->dobj.name));
8671 appendStringLiteralAH(q, conforencoding, fout);
8672 appendPQExpBuffer(q, " TO ");
8673 appendStringLiteralAH(q, contoencoding, fout);
8674 /* regproc is automatically quoted in 7.3 and above */
8675 appendPQExpBuffer(q, " FROM %s;\n", conproc);
8677 ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
8678 convinfo->dobj.name,
8679 convinfo->dobj.namespace->dobj.name,
8680 NULL,
8681 convinfo->rolname,
8682 false, "CONVERSION", SECTION_PRE_DATA,
8683 q->data, delq->data, NULL,
8684 convinfo->dobj.dependencies, convinfo->dobj.nDeps,
8685 NULL, NULL);
8687 /* Dump Conversion Comments */
8688 resetPQExpBuffer(q);
8689 appendPQExpBuffer(q, "CONVERSION %s", fmtId(convinfo->dobj.name));
8690 dumpComment(fout, q->data,
8691 convinfo->dobj.namespace->dobj.name, convinfo->rolname,
8692 convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
8694 PQclear(res);
8696 destroyPQExpBuffer(query);
8697 destroyPQExpBuffer(q);
8698 destroyPQExpBuffer(delq);
8699 destroyPQExpBuffer(details);
8703 * format_aggregate_signature: generate aggregate name and argument list
8705 * The argument type names are qualified if needed. The aggregate name
8706 * is never qualified.
8708 static char *
8709 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
8711 PQExpBufferData buf;
8712 int j;
8714 initPQExpBuffer(&buf);
8715 if (honor_quotes)
8716 appendPQExpBuffer(&buf, "%s",
8717 fmtId(agginfo->aggfn.dobj.name));
8718 else
8719 appendPQExpBuffer(&buf, "%s", agginfo->aggfn.dobj.name);
8721 if (agginfo->aggfn.nargs == 0)
8722 appendPQExpBuffer(&buf, "(*)");
8723 else
8725 appendPQExpBuffer(&buf, "(");
8726 for (j = 0; j < agginfo->aggfn.nargs; j++)
8728 char *typname;
8730 typname = getFormattedTypeName(agginfo->aggfn.argtypes[j], zeroAsOpaque);
8732 appendPQExpBuffer(&buf, "%s%s",
8733 (j > 0) ? ", " : "",
8734 typname);
8735 free(typname);
8737 appendPQExpBuffer(&buf, ")");
8739 return buf.data;
8743 * dumpAgg
8744 * write out a single aggregate definition
8746 static void
8747 dumpAgg(Archive *fout, AggInfo *agginfo)
8749 PQExpBuffer query;
8750 PQExpBuffer q;
8751 PQExpBuffer delq;
8752 PQExpBuffer details;
8753 char *aggsig;
8754 char *aggsig_tag;
8755 PGresult *res;
8756 int ntups;
8757 int i_aggtransfn;
8758 int i_aggfinalfn;
8759 int i_aggsortop;
8760 int i_aggtranstype;
8761 int i_agginitval;
8762 int i_convertok;
8763 const char *aggtransfn;
8764 const char *aggfinalfn;
8765 const char *aggsortop;
8766 const char *aggtranstype;
8767 const char *agginitval;
8768 bool convertok;
8770 /* Skip if not to be dumped */
8771 if (!agginfo->aggfn.dobj.dump || dataOnly)
8772 return;
8774 query = createPQExpBuffer();
8775 q = createPQExpBuffer();
8776 delq = createPQExpBuffer();
8777 details = createPQExpBuffer();
8779 /* Make sure we are in proper schema */
8780 selectSourceSchema(agginfo->aggfn.dobj.namespace->dobj.name);
8782 /* Get aggregate-specific details */
8783 if (g_fout->remoteVersion >= 80100)
8785 appendPQExpBuffer(query, "SELECT aggtransfn, "
8786 "aggfinalfn, aggtranstype::pg_catalog.regtype, "
8787 "aggsortop::pg_catalog.regoperator, "
8788 "agginitval, "
8789 "'t'::boolean AS convertok "
8790 "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
8791 "WHERE a.aggfnoid = p.oid "
8792 "AND p.oid = '%u'::pg_catalog.oid",
8793 agginfo->aggfn.dobj.catId.oid);
8795 else if (g_fout->remoteVersion >= 70300)
8797 appendPQExpBuffer(query, "SELECT aggtransfn, "
8798 "aggfinalfn, aggtranstype::pg_catalog.regtype, "
8799 "0 AS aggsortop, "
8800 "agginitval, "
8801 "'t'::boolean AS convertok "
8802 "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
8803 "WHERE a.aggfnoid = p.oid "
8804 "AND p.oid = '%u'::pg_catalog.oid",
8805 agginfo->aggfn.dobj.catId.oid);
8807 else if (g_fout->remoteVersion >= 70100)
8809 appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
8810 "format_type(aggtranstype, NULL) AS aggtranstype, "
8811 "0 AS aggsortop, "
8812 "agginitval, "
8813 "'t'::boolean AS convertok "
8814 "FROM pg_aggregate "
8815 "WHERE oid = '%u'::oid",
8816 agginfo->aggfn.dobj.catId.oid);
8818 else
8820 appendPQExpBuffer(query, "SELECT aggtransfn1 AS aggtransfn, "
8821 "aggfinalfn, "
8822 "(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
8823 "0 AS aggsortop, "
8824 "agginitval1 AS agginitval, "
8825 "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
8826 "FROM pg_aggregate "
8827 "WHERE oid = '%u'::oid",
8828 agginfo->aggfn.dobj.catId.oid);
8831 res = PQexec(g_conn, query->data);
8832 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8834 /* Expecting a single result only */
8835 ntups = PQntuples(res);
8836 if (ntups != 1)
8838 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
8839 "query returned %d rows instead of one: %s\n",
8840 ntups),
8841 ntups, query->data);
8842 exit_nicely();
8845 i_aggtransfn = PQfnumber(res, "aggtransfn");
8846 i_aggfinalfn = PQfnumber(res, "aggfinalfn");
8847 i_aggsortop = PQfnumber(res, "aggsortop");
8848 i_aggtranstype = PQfnumber(res, "aggtranstype");
8849 i_agginitval = PQfnumber(res, "agginitval");
8850 i_convertok = PQfnumber(res, "convertok");
8852 aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
8853 aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
8854 aggsortop = PQgetvalue(res, 0, i_aggsortop);
8855 aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
8856 agginitval = PQgetvalue(res, 0, i_agginitval);
8857 convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
8859 aggsig = format_aggregate_signature(agginfo, fout, true);
8860 aggsig_tag = format_aggregate_signature(agginfo, fout, false);
8862 if (!convertok)
8864 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
8865 aggsig);
8866 return;
8869 if (g_fout->remoteVersion >= 70300)
8871 /* If using 7.3's regproc or regtype, data is already quoted */
8872 appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
8873 aggtransfn,
8874 aggtranstype);
8876 else if (g_fout->remoteVersion >= 70100)
8878 /* format_type quotes, regproc does not */
8879 appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
8880 fmtId(aggtransfn),
8881 aggtranstype);
8883 else
8885 /* need quotes all around */
8886 appendPQExpBuffer(details, " SFUNC = %s,\n",
8887 fmtId(aggtransfn));
8888 appendPQExpBuffer(details, " STYPE = %s",
8889 fmtId(aggtranstype));
8892 if (!PQgetisnull(res, 0, i_agginitval))
8894 appendPQExpBuffer(details, ",\n INITCOND = ");
8895 appendStringLiteralAH(details, agginitval, fout);
8898 if (strcmp(aggfinalfn, "-") != 0)
8900 appendPQExpBuffer(details, ",\n FINALFUNC = %s",
8901 aggfinalfn);
8904 aggsortop = convertOperatorReference(aggsortop);
8905 if (aggsortop)
8907 appendPQExpBuffer(details, ",\n SORTOP = %s",
8908 aggsortop);
8912 * DROP must be fully qualified in case same name appears in pg_catalog
8914 appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
8915 fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
8916 aggsig);
8918 appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
8919 aggsig, details->data);
8921 ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
8922 aggsig_tag,
8923 agginfo->aggfn.dobj.namespace->dobj.name,
8924 NULL,
8925 agginfo->aggfn.rolname,
8926 false, "AGGREGATE", SECTION_PRE_DATA,
8927 q->data, delq->data, NULL,
8928 agginfo->aggfn.dobj.dependencies, agginfo->aggfn.dobj.nDeps,
8929 NULL, NULL);
8931 /* Dump Aggregate Comments */
8932 resetPQExpBuffer(q);
8933 appendPQExpBuffer(q, "AGGREGATE %s", aggsig);
8934 dumpComment(fout, q->data,
8935 agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
8936 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
8939 * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
8940 * command look like a function's GRANT; in particular this affects the
8941 * syntax for zero-argument aggregates.
8943 free(aggsig);
8944 free(aggsig_tag);
8946 aggsig = format_function_signature(&agginfo->aggfn, true);
8947 aggsig_tag = format_function_signature(&agginfo->aggfn, false);
8949 dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
8950 "FUNCTION",
8951 aggsig, NULL, aggsig_tag,
8952 agginfo->aggfn.dobj.namespace->dobj.name,
8953 agginfo->aggfn.rolname, agginfo->aggfn.proacl);
8955 free(aggsig);
8956 free(aggsig_tag);
8958 PQclear(res);
8960 destroyPQExpBuffer(query);
8961 destroyPQExpBuffer(q);
8962 destroyPQExpBuffer(delq);
8963 destroyPQExpBuffer(details);
8967 * dumpTSParser
8968 * write out a single text search parser
8970 static void
8971 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
8973 PQExpBuffer q;
8974 PQExpBuffer delq;
8976 /* Skip if not to be dumped */
8977 if (!prsinfo->dobj.dump || dataOnly)
8978 return;
8980 q = createPQExpBuffer();
8981 delq = createPQExpBuffer();
8983 /* Make sure we are in proper schema */
8984 selectSourceSchema(prsinfo->dobj.namespace->dobj.name);
8986 appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
8987 fmtId(prsinfo->dobj.name));
8989 appendPQExpBuffer(q, " START = %s,\n",
8990 convertTSFunction(prsinfo->prsstart));
8991 appendPQExpBuffer(q, " GETTOKEN = %s,\n",
8992 convertTSFunction(prsinfo->prstoken));
8993 appendPQExpBuffer(q, " END = %s,\n",
8994 convertTSFunction(prsinfo->prsend));
8995 if (prsinfo->prsheadline != InvalidOid)
8996 appendPQExpBuffer(q, " HEADLINE = %s,\n",
8997 convertTSFunction(prsinfo->prsheadline));
8998 appendPQExpBuffer(q, " LEXTYPES = %s );\n",
8999 convertTSFunction(prsinfo->prslextype));
9002 * DROP must be fully qualified in case same name appears in pg_catalog
9004 appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s",
9005 fmtId(prsinfo->dobj.namespace->dobj.name));
9006 appendPQExpBuffer(delq, ".%s;\n",
9007 fmtId(prsinfo->dobj.name));
9009 ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
9010 prsinfo->dobj.name,
9011 prsinfo->dobj.namespace->dobj.name,
9012 NULL,
9014 false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
9015 q->data, delq->data, NULL,
9016 prsinfo->dobj.dependencies, prsinfo->dobj.nDeps,
9017 NULL, NULL);
9019 /* Dump Parser Comments */
9020 resetPQExpBuffer(q);
9021 appendPQExpBuffer(q, "TEXT SEARCH PARSER %s",
9022 fmtId(prsinfo->dobj.name));
9023 dumpComment(fout, q->data,
9024 NULL, "",
9025 prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
9027 destroyPQExpBuffer(q);
9028 destroyPQExpBuffer(delq);
9032 * dumpTSDictionary
9033 * write out a single text search dictionary
9035 static void
9036 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
9038 PQExpBuffer q;
9039 PQExpBuffer delq;
9040 PQExpBuffer query;
9041 PGresult *res;
9042 int ntups;
9043 char *nspname;
9044 char *tmplname;
9046 /* Skip if not to be dumped */
9047 if (!dictinfo->dobj.dump || dataOnly)
9048 return;
9050 q = createPQExpBuffer();
9051 delq = createPQExpBuffer();
9052 query = createPQExpBuffer();
9054 /* Fetch name and namespace of the dictionary's template */
9055 selectSourceSchema("pg_catalog");
9056 appendPQExpBuffer(query, "SELECT nspname, tmplname "
9057 "FROM pg_ts_template p, pg_namespace n "
9058 "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
9059 dictinfo->dicttemplate);
9060 res = PQexec(g_conn, query->data);
9061 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9062 ntups = PQntuples(res);
9063 if (ntups != 1)
9065 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9066 "query returned %d rows instead of one: %s\n",
9067 ntups),
9068 ntups, query->data);
9069 exit_nicely();
9071 nspname = PQgetvalue(res, 0, 0);
9072 tmplname = PQgetvalue(res, 0, 1);
9074 /* Make sure we are in proper schema */
9075 selectSourceSchema(dictinfo->dobj.namespace->dobj.name);
9077 appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
9078 fmtId(dictinfo->dobj.name));
9080 appendPQExpBuffer(q, " TEMPLATE = ");
9081 if (strcmp(nspname, dictinfo->dobj.namespace->dobj.name) != 0)
9082 appendPQExpBuffer(q, "%s.", fmtId(nspname));
9083 appendPQExpBuffer(q, "%s", fmtId(tmplname));
9085 PQclear(res);
9087 /* the dictinitoption can be dumped straight into the command */
9088 if (dictinfo->dictinitoption)
9089 appendPQExpBuffer(q, ",\n %s", dictinfo->dictinitoption);
9091 appendPQExpBuffer(q, " );\n");
9094 * DROP must be fully qualified in case same name appears in pg_catalog
9096 appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s",
9097 fmtId(dictinfo->dobj.namespace->dobj.name));
9098 appendPQExpBuffer(delq, ".%s;\n",
9099 fmtId(dictinfo->dobj.name));
9101 ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
9102 dictinfo->dobj.name,
9103 dictinfo->dobj.namespace->dobj.name,
9104 NULL,
9105 dictinfo->rolname,
9106 false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
9107 q->data, delq->data, NULL,
9108 dictinfo->dobj.dependencies, dictinfo->dobj.nDeps,
9109 NULL, NULL);
9111 /* Dump Dictionary Comments */
9112 resetPQExpBuffer(q);
9113 appendPQExpBuffer(q, "TEXT SEARCH DICTIONARY %s",
9114 fmtId(dictinfo->dobj.name));
9115 dumpComment(fout, q->data,
9116 NULL, dictinfo->rolname,
9117 dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
9119 destroyPQExpBuffer(q);
9120 destroyPQExpBuffer(delq);
9121 destroyPQExpBuffer(query);
9125 * dumpTSTemplate
9126 * write out a single text search template
9128 static void
9129 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
9131 PQExpBuffer q;
9132 PQExpBuffer delq;
9134 /* Skip if not to be dumped */
9135 if (!tmplinfo->dobj.dump || dataOnly)
9136 return;
9138 q = createPQExpBuffer();
9139 delq = createPQExpBuffer();
9141 /* Make sure we are in proper schema */
9142 selectSourceSchema(tmplinfo->dobj.namespace->dobj.name);
9144 appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
9145 fmtId(tmplinfo->dobj.name));
9147 if (tmplinfo->tmplinit != InvalidOid)
9148 appendPQExpBuffer(q, " INIT = %s,\n",
9149 convertTSFunction(tmplinfo->tmplinit));
9150 appendPQExpBuffer(q, " LEXIZE = %s );\n",
9151 convertTSFunction(tmplinfo->tmpllexize));
9154 * DROP must be fully qualified in case same name appears in pg_catalog
9156 appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s",
9157 fmtId(tmplinfo->dobj.namespace->dobj.name));
9158 appendPQExpBuffer(delq, ".%s;\n",
9159 fmtId(tmplinfo->dobj.name));
9161 ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
9162 tmplinfo->dobj.name,
9163 tmplinfo->dobj.namespace->dobj.name,
9164 NULL,
9166 false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
9167 q->data, delq->data, NULL,
9168 tmplinfo->dobj.dependencies, tmplinfo->dobj.nDeps,
9169 NULL, NULL);
9171 /* Dump Template Comments */
9172 resetPQExpBuffer(q);
9173 appendPQExpBuffer(q, "TEXT SEARCH TEMPLATE %s",
9174 fmtId(tmplinfo->dobj.name));
9175 dumpComment(fout, q->data,
9176 NULL, "",
9177 tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
9179 destroyPQExpBuffer(q);
9180 destroyPQExpBuffer(delq);
9184 * dumpTSConfig
9185 * write out a single text search configuration
9187 static void
9188 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
9190 PQExpBuffer q;
9191 PQExpBuffer delq;
9192 PQExpBuffer query;
9193 PGresult *res;
9194 char *nspname;
9195 char *prsname;
9196 int ntups,
9198 int i_tokenname;
9199 int i_dictname;
9201 /* Skip if not to be dumped */
9202 if (!cfginfo->dobj.dump || dataOnly)
9203 return;
9205 q = createPQExpBuffer();
9206 delq = createPQExpBuffer();
9207 query = createPQExpBuffer();
9209 /* Fetch name and namespace of the config's parser */
9210 selectSourceSchema("pg_catalog");
9211 appendPQExpBuffer(query, "SELECT nspname, prsname "
9212 "FROM pg_ts_parser p, pg_namespace n "
9213 "WHERE p.oid = '%u' AND n.oid = prsnamespace",
9214 cfginfo->cfgparser);
9215 res = PQexec(g_conn, query->data);
9216 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9217 ntups = PQntuples(res);
9218 if (ntups != 1)
9220 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9221 "query returned %d rows instead of one: %s\n",
9222 ntups),
9223 ntups, query->data);
9224 exit_nicely();
9226 nspname = PQgetvalue(res, 0, 0);
9227 prsname = PQgetvalue(res, 0, 1);
9229 /* Make sure we are in proper schema */
9230 selectSourceSchema(cfginfo->dobj.namespace->dobj.name);
9232 appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
9233 fmtId(cfginfo->dobj.name));
9235 appendPQExpBuffer(q, " PARSER = ");
9236 if (strcmp(nspname, cfginfo->dobj.namespace->dobj.name) != 0)
9237 appendPQExpBuffer(q, "%s.", fmtId(nspname));
9238 appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
9240 PQclear(res);
9242 resetPQExpBuffer(query);
9243 appendPQExpBuffer(query,
9244 "SELECT \n"
9245 " ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t \n"
9246 " WHERE t.tokid = m.maptokentype ) AS tokenname, \n"
9247 " m.mapdict::pg_catalog.regdictionary AS dictname \n"
9248 "FROM pg_catalog.pg_ts_config_map AS m \n"
9249 "WHERE m.mapcfg = '%u' \n"
9250 "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
9251 cfginfo->cfgparser, cfginfo->dobj.catId.oid);
9253 res = PQexec(g_conn, query->data);
9254 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9255 ntups = PQntuples(res);
9257 i_tokenname = PQfnumber(res, "tokenname");
9258 i_dictname = PQfnumber(res, "dictname");
9260 for (i = 0; i < ntups; i++)
9262 char *tokenname = PQgetvalue(res, i, i_tokenname);
9263 char *dictname = PQgetvalue(res, i, i_dictname);
9265 if (i == 0 ||
9266 strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
9268 /* starting a new token type, so start a new command */
9269 if (i > 0)
9270 appendPQExpBuffer(q, ";\n");
9271 appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
9272 fmtId(cfginfo->dobj.name));
9273 /* tokenname needs quoting, dictname does NOT */
9274 appendPQExpBuffer(q, " ADD MAPPING FOR %s WITH %s",
9275 fmtId(tokenname), dictname);
9277 else
9278 appendPQExpBuffer(q, ", %s", dictname);
9281 if (ntups > 0)
9282 appendPQExpBuffer(q, ";\n");
9284 PQclear(res);
9287 * DROP must be fully qualified in case same name appears in pg_catalog
9289 appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s",
9290 fmtId(cfginfo->dobj.namespace->dobj.name));
9291 appendPQExpBuffer(delq, ".%s;\n",
9292 fmtId(cfginfo->dobj.name));
9294 ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
9295 cfginfo->dobj.name,
9296 cfginfo->dobj.namespace->dobj.name,
9297 NULL,
9298 cfginfo->rolname,
9299 false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
9300 q->data, delq->data, NULL,
9301 cfginfo->dobj.dependencies, cfginfo->dobj.nDeps,
9302 NULL, NULL);
9304 /* Dump Configuration Comments */
9305 resetPQExpBuffer(q);
9306 appendPQExpBuffer(q, "TEXT SEARCH CONFIGURATION %s",
9307 fmtId(cfginfo->dobj.name));
9308 dumpComment(fout, q->data,
9309 NULL, cfginfo->rolname,
9310 cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
9312 destroyPQExpBuffer(q);
9313 destroyPQExpBuffer(delq);
9314 destroyPQExpBuffer(query);
9318 * dumpForeignDataWrapper
9319 * write out a single foreign-data wrapper definition
9321 static void
9322 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
9324 PQExpBuffer q;
9325 PQExpBuffer delq;
9326 char *namecopy;
9328 /* Skip if not to be dumped */
9329 if (!fdwinfo->dobj.dump || dataOnly)
9330 return;
9332 q = createPQExpBuffer();
9333 delq = createPQExpBuffer();
9335 appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
9336 fmtId(fdwinfo->dobj.name));
9338 if (fdwinfo->fdwvalidator && strcmp(fdwinfo->fdwvalidator, "-") != 0)
9339 appendPQExpBuffer(q, " VALIDATOR %s",
9340 fdwinfo->fdwvalidator);
9342 if (fdwinfo->fdwoptions && strlen(fdwinfo->fdwoptions) > 0)
9343 appendPQExpBuffer(q, " OPTIONS (%s)", fdwinfo->fdwoptions);
9345 appendPQExpBuffer(q, ";\n");
9347 appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
9348 fmtId(fdwinfo->dobj.name));
9350 ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
9351 fdwinfo->dobj.name,
9352 NULL,
9353 NULL,
9354 fdwinfo->rolname,
9355 false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
9356 q->data, delq->data, NULL,
9357 fdwinfo->dobj.dependencies, fdwinfo->dobj.nDeps,
9358 NULL, NULL);
9360 /* Handle the ACL */
9361 namecopy = strdup(fmtId(fdwinfo->dobj.name));
9362 dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
9363 "FOREIGN DATA WRAPPER",
9364 namecopy, NULL, fdwinfo->dobj.name,
9365 NULL, fdwinfo->rolname,
9366 fdwinfo->fdwacl);
9367 free(namecopy);
9369 destroyPQExpBuffer(q);
9370 destroyPQExpBuffer(delq);
9374 * dumpForeignServer
9375 * write out a foreign server definition
9377 static void
9378 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
9380 PQExpBuffer q;
9381 PQExpBuffer delq;
9382 PQExpBuffer query;
9383 PGresult *res;
9384 int ntups;
9385 char *namecopy;
9386 char *fdwname;
9388 /* Skip if not to be dumped */
9389 if (!srvinfo->dobj.dump || dataOnly)
9390 return;
9392 q = createPQExpBuffer();
9393 delq = createPQExpBuffer();
9394 query = createPQExpBuffer();
9396 /* look up the foreign-data wrapper */
9397 appendPQExpBuffer(query, "SELECT fdwname "
9398 "FROM pg_foreign_data_wrapper w "
9399 "WHERE w.oid = '%u'",
9400 srvinfo->srvfdw);
9401 res = PQexec(g_conn, query->data);
9402 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9403 ntups = PQntuples(res);
9404 if (ntups != 1)
9406 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9407 "query returned %d rows instead of one: %s\n",
9408 ntups),
9409 ntups, query->data);
9410 exit_nicely();
9412 fdwname = PQgetvalue(res, 0, 0);
9414 appendPQExpBuffer(q, "CREATE SERVER %s", fmtId(srvinfo->dobj.name));
9415 if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
9417 appendPQExpBuffer(q, " TYPE ");
9418 appendStringLiteralAH(q, srvinfo->srvtype, fout);
9420 if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
9422 appendPQExpBuffer(q, " VERSION ");
9423 appendStringLiteralAH(q, srvinfo->srvversion, fout);
9426 appendPQExpBuffer(q, " FOREIGN DATA WRAPPER ");
9427 appendPQExpBuffer(q, "%s", fmtId(fdwname));
9429 if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
9430 appendPQExpBuffer(q, " OPTIONS (%s)", srvinfo->srvoptions);
9432 appendPQExpBuffer(q, ";\n");
9434 appendPQExpBuffer(delq, "DROP SERVER %s;\n",
9435 fmtId(srvinfo->dobj.name));
9437 ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
9438 srvinfo->dobj.name,
9439 NULL,
9440 NULL,
9441 srvinfo->rolname,
9442 false, "SERVER", SECTION_PRE_DATA,
9443 q->data, delq->data, NULL,
9444 srvinfo->dobj.dependencies, srvinfo->dobj.nDeps,
9445 NULL, NULL);
9447 /* Handle the ACL */
9448 namecopy = strdup(fmtId(srvinfo->dobj.name));
9449 dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
9450 "SERVER",
9451 namecopy, NULL, srvinfo->dobj.name,
9452 NULL, srvinfo->rolname,
9453 srvinfo->srvacl);
9454 free(namecopy);
9456 /* Dump user mappings */
9457 resetPQExpBuffer(q);
9458 appendPQExpBuffer(q, "SERVER %s", fmtId(srvinfo->dobj.name));
9459 dumpUserMappings(fout, q->data,
9460 srvinfo->dobj.name, NULL,
9461 srvinfo->rolname,
9462 srvinfo->dobj.catId, srvinfo->dobj.dumpId);
9464 destroyPQExpBuffer(q);
9465 destroyPQExpBuffer(delq);
9469 * dumpUserMappings
9471 * This routine is used to dump any user mappings associated with the
9472 * server handed to this routine. Should be called after ArchiveEntry()
9473 * for the server.
9475 static void
9476 dumpUserMappings(Archive *fout, const char *target,
9477 const char *servername, const char *namespace,
9478 const char *owner,
9479 CatalogId catalogId, DumpId dumpId)
9481 PQExpBuffer q;
9482 PQExpBuffer delq;
9483 PQExpBuffer query;
9484 PQExpBuffer tag;
9485 PGresult *res;
9486 int ntups;
9487 int i_umuser;
9488 int i_umoptions;
9489 int i;
9491 q = createPQExpBuffer();
9492 tag = createPQExpBuffer();
9493 delq = createPQExpBuffer();
9494 query = createPQExpBuffer();
9496 appendPQExpBuffer(query,
9497 "SELECT (%s umuser) AS umuser, "
9498 "array_to_string(ARRAY(SELECT option_name || ' ' || quote_literal(option_value) FROM pg_options_to_table(umoptions)), ', ') AS umoptions\n"
9499 "FROM pg_user_mapping "
9500 "WHERE umserver=%u",
9501 username_subquery,
9502 catalogId.oid);
9504 res = PQexec(g_conn, query->data);
9505 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9507 ntups = PQntuples(res);
9508 i_umuser = PQfnumber(res, "umuser");
9509 i_umoptions = PQfnumber(res, "umoptions");
9511 for (i = 0; i < ntups; i++)
9513 char *umuser;
9514 char *umoptions;
9516 umuser = PQgetvalue(res, i, i_umuser);
9517 umoptions = PQgetvalue(res, i, i_umoptions);
9519 resetPQExpBuffer(q);
9520 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(umuser));
9521 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
9523 if (umoptions && strlen(umoptions) > 0)
9524 appendPQExpBuffer(q, " OPTIONS (%s)", umoptions);
9526 appendPQExpBuffer(q, ";\n");
9528 resetPQExpBuffer(delq);
9529 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s SERVER %s;\n", fmtId(umuser), fmtId(servername));
9531 resetPQExpBuffer(tag);
9532 appendPQExpBuffer(tag, "USER MAPPING %s %s", fmtId(umuser), target);
9534 ArchiveEntry(fout, nilCatalogId, createDumpId(),
9535 tag->data,
9536 namespace,
9537 NULL,
9538 owner, false,
9539 "USER MAPPING", SECTION_PRE_DATA,
9540 q->data, delq->data, NULL,
9541 &dumpId, 1,
9542 NULL, NULL);
9545 PQclear(res);
9547 destroyPQExpBuffer(query);
9548 destroyPQExpBuffer(delq);
9549 destroyPQExpBuffer(q);
9552 /*----------
9553 * Write out grant/revoke information
9555 * 'objCatId' is the catalog ID of the underlying object.
9556 * 'objDumpId' is the dump ID of the underlying object.
9557 * 'type' must be TABLE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, or TABLESPACE.
9558 * 'name' is the formatted name of the object. Must be quoted etc. already.
9559 * 'subname' is the formatted name of the sub-object, if any. Must be quoted.
9560 * 'tag' is the tag for the archive entry (typ. unquoted name of object).
9561 * 'nspname' is the namespace the object is in (NULL if none).
9562 * 'owner' is the owner, NULL if there is no owner (for languages).
9563 * 'acls' is the string read out of the fooacl system catalog field;
9564 * it will be parsed here.
9565 *----------
9567 static void
9568 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
9569 const char *type, const char *name, const char *subname,
9570 const char *tag, const char *nspname, const char *owner,
9571 const char *acls)
9573 PQExpBuffer sql;
9575 /* Do nothing if ACL dump is not enabled */
9576 if (dataOnly || aclsSkip)
9577 return;
9579 sql = createPQExpBuffer();
9581 if (!buildACLCommands(name, subname, type, acls, owner, fout->remoteVersion, sql))
9583 write_msg(NULL, "could not parse ACL list (%s) for object \"%s\" (%s)\n",
9584 acls, name, type);
9585 exit_nicely();
9588 if (sql->len > 0)
9589 ArchiveEntry(fout, nilCatalogId, createDumpId(),
9590 tag, nspname,
9591 NULL,
9592 owner ? owner : "",
9593 false, "ACL", SECTION_NONE,
9594 sql->data, "", NULL,
9595 &(objDumpId), 1,
9596 NULL, NULL);
9598 destroyPQExpBuffer(sql);
9602 * dumpTable
9603 * write out to fout the declarations (not data) of a user-defined table
9605 static void
9606 dumpTable(Archive *fout, TableInfo *tbinfo)
9608 if (tbinfo->dobj.dump)
9610 char *namecopy;
9612 if (tbinfo->relkind == RELKIND_SEQUENCE)
9613 dumpSequence(fout, tbinfo);
9614 else if (!dataOnly)
9615 dumpTableSchema(fout, tbinfo);
9617 /* Handle the ACL here */
9618 namecopy = strdup(fmtId(tbinfo->dobj.name));
9619 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
9620 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE",
9621 namecopy, NULL, tbinfo->dobj.name,
9622 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
9623 tbinfo->relacl);
9626 * Handle column ACLs, if any. Note: we pull these with a separate
9627 * query rather than trying to fetch them during getTableAttrs, so
9628 * that we won't miss ACLs on system columns.
9630 if (g_fout->remoteVersion >= 80400)
9632 PQExpBuffer query = createPQExpBuffer();
9633 PGresult *res;
9634 int i;
9636 appendPQExpBuffer(query,
9637 "SELECT attname, attacl FROM pg_catalog.pg_attribute "
9638 "WHERE attrelid = '%u' AND NOT attisdropped AND attacl IS NOT NULL "
9639 "ORDER BY attnum",
9640 tbinfo->dobj.catId.oid);
9641 res = PQexec(g_conn, query->data);
9642 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9644 for (i = 0; i < PQntuples(res); i++)
9646 char *attname = PQgetvalue(res, i, 0);
9647 char *attacl = PQgetvalue(res, i, 1);
9648 char *attnamecopy;
9649 char *acltag;
9651 attnamecopy = strdup(fmtId(attname));
9652 acltag = malloc(strlen(tbinfo->dobj.name) + strlen(attname) + 2);
9653 sprintf(acltag, "%s.%s", tbinfo->dobj.name, attname);
9654 /* Column's GRANT type is always TABLE */
9655 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
9656 namecopy, attnamecopy, acltag,
9657 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
9658 attacl);
9659 free(attnamecopy);
9660 free(acltag);
9662 PQclear(res);
9663 destroyPQExpBuffer(query);
9666 free(namecopy);
9671 * dumpTableSchema
9672 * write the declaration (not data) of one user-defined table or view
9674 static void
9675 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
9677 PQExpBuffer query = createPQExpBuffer();
9678 PQExpBuffer q = createPQExpBuffer();
9679 PQExpBuffer delq = createPQExpBuffer();
9680 PGresult *res;
9681 int numParents;
9682 TableInfo **parents;
9683 int actual_atts; /* number of attrs in this CREATE statment */
9684 char *reltypename;
9685 char *storage;
9686 int j,
9689 /* Make sure we are in proper schema */
9690 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
9692 /* Is it a table or a view? */
9693 if (tbinfo->relkind == RELKIND_VIEW)
9695 char *viewdef;
9697 reltypename = "VIEW";
9699 /* Fetch the view definition */
9700 if (g_fout->remoteVersion >= 70300)
9702 /* Beginning in 7.3, viewname is not unique; rely on OID */
9703 appendPQExpBuffer(query,
9704 "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
9705 tbinfo->dobj.catId.oid);
9707 else
9709 appendPQExpBuffer(query, "SELECT definition AS viewdef "
9710 "FROM pg_views WHERE viewname = ");
9711 appendStringLiteralAH(query, tbinfo->dobj.name, fout);
9712 appendPQExpBuffer(query, ";");
9715 res = PQexec(g_conn, query->data);
9716 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9718 if (PQntuples(res) != 1)
9720 if (PQntuples(res) < 1)
9721 write_msg(NULL, "query to obtain definition of view \"%s\" returned no data\n",
9722 tbinfo->dobj.name);
9723 else
9724 write_msg(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
9725 tbinfo->dobj.name);
9726 exit_nicely();
9729 viewdef = PQgetvalue(res, 0, 0);
9731 if (strlen(viewdef) == 0)
9733 write_msg(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
9734 tbinfo->dobj.name);
9735 exit_nicely();
9739 * DROP must be fully qualified in case same name appears in
9740 * pg_catalog
9742 appendPQExpBuffer(delq, "DROP VIEW %s.",
9743 fmtId(tbinfo->dobj.namespace->dobj.name));
9744 appendPQExpBuffer(delq, "%s;\n",
9745 fmtId(tbinfo->dobj.name));
9747 appendPQExpBuffer(q, "CREATE VIEW %s AS\n %s\n",
9748 fmtId(tbinfo->dobj.name), viewdef);
9750 PQclear(res);
9752 else
9754 reltypename = "TABLE";
9755 numParents = tbinfo->numParents;
9756 parents = tbinfo->parents;
9759 * DROP must be fully qualified in case same name appears in
9760 * pg_catalog
9762 appendPQExpBuffer(delq, "DROP TABLE %s.",
9763 fmtId(tbinfo->dobj.namespace->dobj.name));
9764 appendPQExpBuffer(delq, "%s;\n",
9765 fmtId(tbinfo->dobj.name));
9767 appendPQExpBuffer(q, "CREATE TABLE %s (",
9768 fmtId(tbinfo->dobj.name));
9769 actual_atts = 0;
9770 for (j = 0; j < tbinfo->numatts; j++)
9773 * Normally, dump if it's one of the table's own attrs, and not
9774 * dropped. But for binary upgrade, dump all the columns.
9776 if ((!tbinfo->inhAttrs[j] && !tbinfo->attisdropped[j]) ||
9777 binary_upgrade)
9779 /* Format properly if not first attr */
9780 if (actual_atts > 0)
9781 appendPQExpBuffer(q, ",");
9782 appendPQExpBuffer(q, "\n ");
9783 actual_atts++;
9785 /* Attribute name */
9786 appendPQExpBuffer(q, "%s ",
9787 fmtId(tbinfo->attnames[j]));
9789 if (tbinfo->attisdropped[j])
9792 * ALTER TABLE DROP COLUMN clears pg_attribute.atttypid,
9793 * so we will not have gotten a valid type name; insert
9794 * INTEGER as a stopgap. We'll clean things up later.
9796 appendPQExpBuffer(q, "INTEGER /* dummy */");
9797 /* Skip all the rest, too */
9798 continue;
9801 /* Attribute type */
9802 if (g_fout->remoteVersion >= 70100)
9804 appendPQExpBuffer(q, "%s",
9805 tbinfo->atttypnames[j]);
9807 else
9809 /* If no format_type, fake it */
9810 appendPQExpBuffer(q, "%s",
9811 myFormatType(tbinfo->atttypnames[j],
9812 tbinfo->atttypmod[j]));
9816 * Default value --- suppress if inherited (except in
9817 * binary-upgrade case, where we're not doing normal
9818 * inheritance) or if it's to be printed separately.
9820 if (tbinfo->attrdefs[j] != NULL &&
9821 (!tbinfo->inhAttrDef[j] || binary_upgrade) &&
9822 !tbinfo->attrdefs[j]->separate)
9823 appendPQExpBuffer(q, " DEFAULT %s",
9824 tbinfo->attrdefs[j]->adef_expr);
9827 * Not Null constraint --- suppress if inherited, except
9828 * in binary-upgrade case.
9830 if (tbinfo->notnull[j] &&
9831 (!tbinfo->inhNotNull[j] || binary_upgrade))
9832 appendPQExpBuffer(q, " NOT NULL");
9837 * Add non-inherited CHECK constraints, if any.
9839 for (j = 0; j < tbinfo->ncheck; j++)
9841 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
9843 if (constr->separate || !constr->conislocal)
9844 continue;
9846 if (actual_atts > 0)
9847 appendPQExpBuffer(q, ",\n ");
9849 appendPQExpBuffer(q, "CONSTRAINT %s ",
9850 fmtId(constr->dobj.name));
9851 appendPQExpBuffer(q, "%s", constr->condef);
9853 actual_atts++;
9856 appendPQExpBuffer(q, "\n)");
9858 if (numParents > 0 && !binary_upgrade)
9860 appendPQExpBuffer(q, "\nINHERITS (");
9861 for (k = 0; k < numParents; k++)
9863 TableInfo *parentRel = parents[k];
9865 if (k > 0)
9866 appendPQExpBuffer(q, ", ");
9867 if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
9868 appendPQExpBuffer(q, "%s.",
9869 fmtId(parentRel->dobj.namespace->dobj.name));
9870 appendPQExpBuffer(q, "%s",
9871 fmtId(parentRel->dobj.name));
9873 appendPQExpBuffer(q, ")");
9876 if ((tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) ||
9877 (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0))
9879 bool addcomma = false;
9881 appendPQExpBuffer(q, "\nWITH (");
9882 if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
9884 addcomma = true;
9885 appendPQExpBuffer(q, "%s", tbinfo->reloptions);
9887 if (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0)
9889 appendPQExpBuffer(q, "%s%s", addcomma ? ", " : "",
9890 tbinfo->toast_reloptions);
9892 appendPQExpBuffer(q, ")");
9895 appendPQExpBuffer(q, ";\n");
9898 * To create binary-compatible heap files, we have to ensure the
9899 * same physical column order, including dropped columns, as in the
9900 * original. Therefore, we create dropped columns above and drop
9901 * them here, also updating their attlen/attalign values so that
9902 * the dropped column can be skipped properly. (We do not bother
9903 * with restoring the original attbyval setting.) Also, inheritance
9904 * relationships are set up by doing ALTER INHERIT rather than using
9905 * an INHERITS clause --- the latter would possibly mess up the
9906 * column order. That also means we have to take care about setting
9907 * attislocal correctly, plus fix up any inherited CHECK constraints.
9909 if (binary_upgrade)
9911 for (j = 0; j < tbinfo->numatts; j++)
9913 if (tbinfo->attisdropped[j])
9915 appendPQExpBuffer(q, "\n-- For binary upgrade, recreate dropped column.\n");
9916 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
9917 "SET attlen = %d, "
9918 "attalign = '%c', attbyval = false\n"
9919 "WHERE attname = ",
9920 tbinfo->attlen[j],
9921 tbinfo->attalign[j]);
9922 appendStringLiteralAH(q, tbinfo->attnames[j], fout);
9923 appendPQExpBuffer(q, "\n AND attrelid = ");
9924 appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
9925 appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
9927 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
9928 fmtId(tbinfo->dobj.name));
9929 appendPQExpBuffer(q, "DROP COLUMN %s;\n",
9930 fmtId(tbinfo->attnames[j]));
9932 else if (!tbinfo->attislocal[j])
9934 appendPQExpBuffer(q, "\n-- For binary upgrade, recreate inherited column.\n");
9935 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
9936 "SET attislocal = false\n"
9937 "WHERE attname = ");
9938 appendStringLiteralAH(q, tbinfo->attnames[j], fout);
9939 appendPQExpBuffer(q, "\n AND attrelid = ");
9940 appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
9941 appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
9945 for (k = 0; k < tbinfo->ncheck; k++)
9947 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
9949 if (constr->separate || constr->conislocal)
9950 continue;
9952 appendPQExpBuffer(q, "\n-- For binary upgrade, set up inherited constraint.\n");
9953 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
9954 fmtId(tbinfo->dobj.name));
9955 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
9956 fmtId(constr->dobj.name));
9957 appendPQExpBuffer(q, "%s;\n", constr->condef);
9958 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_constraint\n"
9959 "SET conislocal = false\n"
9960 "WHERE contype = 'c' AND conname = ");
9961 appendStringLiteralAH(q, constr->dobj.name, fout);
9962 appendPQExpBuffer(q, "\n AND conrelid = ");
9963 appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
9964 appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
9967 if (numParents > 0)
9969 appendPQExpBuffer(q, "\n-- For binary upgrade, set up inheritance this way.\n");
9970 for (k = 0; k < numParents; k++)
9972 TableInfo *parentRel = parents[k];
9974 appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
9975 fmtId(tbinfo->dobj.name));
9976 if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
9977 appendPQExpBuffer(q, "%s.",
9978 fmtId(parentRel->dobj.namespace->dobj.name));
9979 appendPQExpBuffer(q, "%s;\n",
9980 fmtId(parentRel->dobj.name));
9984 appendPQExpBuffer(q, "\n-- For binary upgrade, set relfrozenxid.\n");
9985 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
9986 "SET relfrozenxid = '%u'\n"
9987 "WHERE oid = ",
9988 tbinfo->frozenxid);
9989 appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
9990 appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
9993 /* Loop dumping statistics and storage statements */
9994 for (j = 0; j < tbinfo->numatts; j++)
9997 * Dump per-column statistics information. We only issue an ALTER
9998 * TABLE statement if the attstattarget entry for this column is
9999 * non-negative (i.e. it's not the default value)
10001 if (tbinfo->attstattarget[j] >= 0 &&
10002 !tbinfo->attisdropped[j])
10004 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
10005 fmtId(tbinfo->dobj.name));
10006 appendPQExpBuffer(q, "ALTER COLUMN %s ",
10007 fmtId(tbinfo->attnames[j]));
10008 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
10009 tbinfo->attstattarget[j]);
10013 * Dump per-column storage information. The statement is only
10014 * dumped if the storage has been changed from the type's default.
10016 if (!tbinfo->attisdropped[j] && tbinfo->attstorage[j] != tbinfo->typstorage[j])
10018 switch (tbinfo->attstorage[j])
10020 case 'p':
10021 storage = "PLAIN";
10022 break;
10023 case 'e':
10024 storage = "EXTERNAL";
10025 break;
10026 case 'm':
10027 storage = "MAIN";
10028 break;
10029 case 'x':
10030 storage = "EXTENDED";
10031 break;
10032 default:
10033 storage = NULL;
10037 * Only dump the statement if it's a storage type we recognize
10039 if (storage != NULL)
10041 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
10042 fmtId(tbinfo->dobj.name));
10043 appendPQExpBuffer(q, "ALTER COLUMN %s ",
10044 fmtId(tbinfo->attnames[j]));
10045 appendPQExpBuffer(q, "SET STORAGE %s;\n",
10046 storage);
10052 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
10053 tbinfo->dobj.name,
10054 tbinfo->dobj.namespace->dobj.name,
10055 (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
10056 tbinfo->rolname,
10057 (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
10058 reltypename, SECTION_PRE_DATA,
10059 q->data, delq->data, NULL,
10060 tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
10061 NULL, NULL);
10063 /* Dump Table Comments */
10064 dumpTableComment(fout, tbinfo, reltypename);
10066 /* Dump comments on inlined table constraints */
10067 for (j = 0; j < tbinfo->ncheck; j++)
10069 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
10071 if (constr->separate || !constr->conislocal)
10072 continue;
10074 dumpTableConstraintComment(fout, constr);
10077 destroyPQExpBuffer(query);
10078 destroyPQExpBuffer(q);
10079 destroyPQExpBuffer(delq);
10083 * dumpAttrDef --- dump an attribute's default-value declaration
10085 static void
10086 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
10088 TableInfo *tbinfo = adinfo->adtable;
10089 int adnum = adinfo->adnum;
10090 PQExpBuffer q;
10091 PQExpBuffer delq;
10093 /* Only print it if "separate" mode is selected */
10094 if (!tbinfo->dobj.dump || !adinfo->separate || dataOnly)
10095 return;
10097 /* Don't print inherited defaults, either, except for binary upgrade */
10098 if (tbinfo->inhAttrDef[adnum - 1] && !binary_upgrade)
10099 return;
10101 q = createPQExpBuffer();
10102 delq = createPQExpBuffer();
10104 appendPQExpBuffer(q, "ALTER TABLE %s ",
10105 fmtId(tbinfo->dobj.name));
10106 appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
10107 fmtId(tbinfo->attnames[adnum - 1]),
10108 adinfo->adef_expr);
10111 * DROP must be fully qualified in case same name appears in pg_catalog
10113 appendPQExpBuffer(delq, "ALTER TABLE %s.",
10114 fmtId(tbinfo->dobj.namespace->dobj.name));
10115 appendPQExpBuffer(delq, "%s ",
10116 fmtId(tbinfo->dobj.name));
10117 appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
10118 fmtId(tbinfo->attnames[adnum - 1]));
10120 ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
10121 tbinfo->attnames[adnum - 1],
10122 tbinfo->dobj.namespace->dobj.name,
10123 NULL,
10124 tbinfo->rolname,
10125 false, "DEFAULT", SECTION_PRE_DATA,
10126 q->data, delq->data, NULL,
10127 adinfo->dobj.dependencies, adinfo->dobj.nDeps,
10128 NULL, NULL);
10130 destroyPQExpBuffer(q);
10131 destroyPQExpBuffer(delq);
10135 * getAttrName: extract the correct name for an attribute
10137 * The array tblInfo->attnames[] only provides names of user attributes;
10138 * if a system attribute number is supplied, we have to fake it.
10139 * We also do a little bit of bounds checking for safety's sake.
10141 static const char *
10142 getAttrName(int attrnum, TableInfo *tblInfo)
10144 if (attrnum > 0 && attrnum <= tblInfo->numatts)
10145 return tblInfo->attnames[attrnum - 1];
10146 switch (attrnum)
10148 case SelfItemPointerAttributeNumber:
10149 return "ctid";
10150 case ObjectIdAttributeNumber:
10151 return "oid";
10152 case MinTransactionIdAttributeNumber:
10153 return "xmin";
10154 case MinCommandIdAttributeNumber:
10155 return "cmin";
10156 case MaxTransactionIdAttributeNumber:
10157 return "xmax";
10158 case MaxCommandIdAttributeNumber:
10159 return "cmax";
10160 case TableOidAttributeNumber:
10161 return "tableoid";
10163 write_msg(NULL, "invalid column number %d for table \"%s\"\n",
10164 attrnum, tblInfo->dobj.name);
10165 exit_nicely();
10166 return NULL; /* keep compiler quiet */
10170 * dumpIndex
10171 * write out to fout a user-defined index
10173 static void
10174 dumpIndex(Archive *fout, IndxInfo *indxinfo)
10176 TableInfo *tbinfo = indxinfo->indextable;
10177 PQExpBuffer q;
10178 PQExpBuffer delq;
10180 if (dataOnly)
10181 return;
10183 q = createPQExpBuffer();
10184 delq = createPQExpBuffer();
10187 * If there's an associated constraint, don't dump the index per se, but
10188 * do dump any comment for it. (This is safe because dependency ordering
10189 * will have ensured the constraint is emitted first.)
10191 if (indxinfo->indexconstraint == 0)
10193 /* Plain secondary index */
10194 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
10196 /* If the index is clustered, we need to record that. */
10197 if (indxinfo->indisclustered)
10199 appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
10200 fmtId(tbinfo->dobj.name));
10201 appendPQExpBuffer(q, " ON %s;\n",
10202 fmtId(indxinfo->dobj.name));
10206 * DROP must be fully qualified in case same name appears in
10207 * pg_catalog
10209 appendPQExpBuffer(delq, "DROP INDEX %s.",
10210 fmtId(tbinfo->dobj.namespace->dobj.name));
10211 appendPQExpBuffer(delq, "%s;\n",
10212 fmtId(indxinfo->dobj.name));
10214 ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
10215 indxinfo->dobj.name,
10216 tbinfo->dobj.namespace->dobj.name,
10217 indxinfo->tablespace,
10218 tbinfo->rolname, false,
10219 "INDEX", SECTION_POST_DATA,
10220 q->data, delq->data, NULL,
10221 indxinfo->dobj.dependencies, indxinfo->dobj.nDeps,
10222 NULL, NULL);
10225 /* Dump Index Comments */
10226 resetPQExpBuffer(q);
10227 appendPQExpBuffer(q, "INDEX %s",
10228 fmtId(indxinfo->dobj.name));
10229 dumpComment(fout, q->data,
10230 tbinfo->dobj.namespace->dobj.name,
10231 tbinfo->rolname,
10232 indxinfo->dobj.catId, 0, indxinfo->dobj.dumpId);
10234 destroyPQExpBuffer(q);
10235 destroyPQExpBuffer(delq);
10239 * dumpConstraint
10240 * write out to fout a user-defined constraint
10242 static void
10243 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
10245 TableInfo *tbinfo = coninfo->contable;
10246 PQExpBuffer q;
10247 PQExpBuffer delq;
10249 /* Skip if not to be dumped */
10250 if (!coninfo->dobj.dump || dataOnly)
10251 return;
10253 q = createPQExpBuffer();
10254 delq = createPQExpBuffer();
10256 if (coninfo->contype == 'p' || coninfo->contype == 'u')
10258 /* Index-related constraint */
10259 IndxInfo *indxinfo;
10260 int k;
10262 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
10264 if (indxinfo == NULL)
10266 write_msg(NULL, "missing index for constraint \"%s\"\n",
10267 coninfo->dobj.name);
10268 exit_nicely();
10271 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
10272 fmtId(tbinfo->dobj.name));
10273 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s (",
10274 fmtId(coninfo->dobj.name),
10275 coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
10277 for (k = 0; k < indxinfo->indnkeys; k++)
10279 int indkey = (int) indxinfo->indkeys[k];
10280 const char *attname;
10282 if (indkey == InvalidAttrNumber)
10283 break;
10284 attname = getAttrName(indkey, tbinfo);
10286 appendPQExpBuffer(q, "%s%s",
10287 (k == 0) ? "" : ", ",
10288 fmtId(attname));
10291 appendPQExpBuffer(q, ")");
10293 if (indxinfo->options && strlen(indxinfo->options) > 0)
10294 appendPQExpBuffer(q, " WITH (%s)", indxinfo->options);
10296 appendPQExpBuffer(q, ";\n");
10298 /* If the index is clustered, we need to record that. */
10299 if (indxinfo->indisclustered)
10301 appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
10302 fmtId(tbinfo->dobj.name));
10303 appendPQExpBuffer(q, " ON %s;\n",
10304 fmtId(indxinfo->dobj.name));
10308 * DROP must be fully qualified in case same name appears in
10309 * pg_catalog
10311 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
10312 fmtId(tbinfo->dobj.namespace->dobj.name));
10313 appendPQExpBuffer(delq, "%s ",
10314 fmtId(tbinfo->dobj.name));
10315 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
10316 fmtId(coninfo->dobj.name));
10318 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
10319 coninfo->dobj.name,
10320 tbinfo->dobj.namespace->dobj.name,
10321 indxinfo->tablespace,
10322 tbinfo->rolname, false,
10323 "CONSTRAINT", SECTION_POST_DATA,
10324 q->data, delq->data, NULL,
10325 coninfo->dobj.dependencies, coninfo->dobj.nDeps,
10326 NULL, NULL);
10328 else if (coninfo->contype == 'f')
10331 * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
10332 * current table data is not processed
10334 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
10335 fmtId(tbinfo->dobj.name));
10336 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
10337 fmtId(coninfo->dobj.name),
10338 coninfo->condef);
10341 * DROP must be fully qualified in case same name appears in
10342 * pg_catalog
10344 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
10345 fmtId(tbinfo->dobj.namespace->dobj.name));
10346 appendPQExpBuffer(delq, "%s ",
10347 fmtId(tbinfo->dobj.name));
10348 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
10349 fmtId(coninfo->dobj.name));
10351 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
10352 coninfo->dobj.name,
10353 tbinfo->dobj.namespace->dobj.name,
10354 NULL,
10355 tbinfo->rolname, false,
10356 "FK CONSTRAINT", SECTION_POST_DATA,
10357 q->data, delq->data, NULL,
10358 coninfo->dobj.dependencies, coninfo->dobj.nDeps,
10359 NULL, NULL);
10361 else if (coninfo->contype == 'c' && tbinfo)
10363 /* CHECK constraint on a table */
10365 /* Ignore if not to be dumped separately */
10366 if (coninfo->separate)
10368 /* not ONLY since we want it to propagate to children */
10369 appendPQExpBuffer(q, "ALTER TABLE %s\n",
10370 fmtId(tbinfo->dobj.name));
10371 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
10372 fmtId(coninfo->dobj.name),
10373 coninfo->condef);
10376 * DROP must be fully qualified in case same name appears in
10377 * pg_catalog
10379 appendPQExpBuffer(delq, "ALTER TABLE %s.",
10380 fmtId(tbinfo->dobj.namespace->dobj.name));
10381 appendPQExpBuffer(delq, "%s ",
10382 fmtId(tbinfo->dobj.name));
10383 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
10384 fmtId(coninfo->dobj.name));
10386 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
10387 coninfo->dobj.name,
10388 tbinfo->dobj.namespace->dobj.name,
10389 NULL,
10390 tbinfo->rolname, false,
10391 "CHECK CONSTRAINT", SECTION_POST_DATA,
10392 q->data, delq->data, NULL,
10393 coninfo->dobj.dependencies, coninfo->dobj.nDeps,
10394 NULL, NULL);
10397 else if (coninfo->contype == 'c' && tbinfo == NULL)
10399 /* CHECK constraint on a domain */
10400 TypeInfo *tinfo = coninfo->condomain;
10402 /* Ignore if not to be dumped separately */
10403 if (coninfo->separate)
10405 appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
10406 fmtId(tinfo->dobj.name));
10407 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
10408 fmtId(coninfo->dobj.name),
10409 coninfo->condef);
10412 * DROP must be fully qualified in case same name appears in
10413 * pg_catalog
10415 appendPQExpBuffer(delq, "ALTER DOMAIN %s.",
10416 fmtId(tinfo->dobj.namespace->dobj.name));
10417 appendPQExpBuffer(delq, "%s ",
10418 fmtId(tinfo->dobj.name));
10419 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
10420 fmtId(coninfo->dobj.name));
10422 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
10423 coninfo->dobj.name,
10424 tinfo->dobj.namespace->dobj.name,
10425 NULL,
10426 tinfo->rolname, false,
10427 "CHECK CONSTRAINT", SECTION_POST_DATA,
10428 q->data, delq->data, NULL,
10429 coninfo->dobj.dependencies, coninfo->dobj.nDeps,
10430 NULL, NULL);
10433 else
10435 write_msg(NULL, "unrecognized constraint type: %c\n", coninfo->contype);
10436 exit_nicely();
10439 /* Dump Constraint Comments --- only works for table constraints */
10440 if (tbinfo && coninfo->separate)
10441 dumpTableConstraintComment(fout, coninfo);
10443 destroyPQExpBuffer(q);
10444 destroyPQExpBuffer(delq);
10448 * dumpTableConstraintComment --- dump a constraint's comment if any
10450 * This is split out because we need the function in two different places
10451 * depending on whether the constraint is dumped as part of CREATE TABLE
10452 * or as a separate ALTER command.
10454 static void
10455 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
10457 TableInfo *tbinfo = coninfo->contable;
10458 PQExpBuffer q = createPQExpBuffer();
10460 appendPQExpBuffer(q, "CONSTRAINT %s ",
10461 fmtId(coninfo->dobj.name));
10462 appendPQExpBuffer(q, "ON %s",
10463 fmtId(tbinfo->dobj.name));
10464 dumpComment(fout, q->data,
10465 tbinfo->dobj.namespace->dobj.name,
10466 tbinfo->rolname,
10467 coninfo->dobj.catId, 0,
10468 coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
10470 destroyPQExpBuffer(q);
10474 * findLastBuiltInOid -
10475 * find the last built in oid
10477 * For 7.1 and 7.2, we do this by retrieving datlastsysoid from the
10478 * pg_database entry for the current database
10480 static Oid
10481 findLastBuiltinOid_V71(const char *dbname)
10483 PGresult *res;
10484 int ntups;
10485 Oid last_oid;
10486 PQExpBuffer query = createPQExpBuffer();
10488 resetPQExpBuffer(query);
10489 appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
10490 appendStringLiteralAH(query, dbname, g_fout);
10492 res = PQexec(g_conn, query->data);
10493 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10495 ntups = PQntuples(res);
10496 if (ntups < 1)
10498 write_msg(NULL, "missing pg_database entry for this database\n");
10499 exit_nicely();
10501 if (ntups > 1)
10503 write_msg(NULL, "found more than one pg_database entry for this database\n");
10504 exit_nicely();
10506 last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
10507 PQclear(res);
10508 destroyPQExpBuffer(query);
10509 return last_oid;
10513 * findLastBuiltInOid -
10514 * find the last built in oid
10516 * For 7.0, we do this by assuming that the last thing that initdb does is to
10517 * create the pg_indexes view. This sucks in general, but seeing that 7.0.x
10518 * initdb won't be changing anymore, it'll do.
10520 static Oid
10521 findLastBuiltinOid_V70(void)
10523 PGresult *res;
10524 int ntups;
10525 int last_oid;
10527 res = PQexec(g_conn,
10528 "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'");
10529 check_sql_result(res, g_conn,
10530 "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'",
10531 PGRES_TUPLES_OK);
10532 ntups = PQntuples(res);
10533 if (ntups < 1)
10535 write_msg(NULL, "could not find entry for pg_indexes in pg_class\n");
10536 exit_nicely();
10538 if (ntups > 1)
10540 write_msg(NULL, "found more than one entry for pg_indexes in pg_class\n");
10541 exit_nicely();
10543 last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
10544 PQclear(res);
10545 return last_oid;
10548 static void
10549 dumpSequence(Archive *fout, TableInfo *tbinfo)
10551 PGresult *res;
10552 char *startv,
10553 *last,
10554 *incby,
10555 *maxv = NULL,
10556 *minv = NULL,
10557 *cache;
10558 char bufm[100],
10559 bufx[100];
10560 bool cycled,
10561 called;
10562 PQExpBuffer query = createPQExpBuffer();
10563 PQExpBuffer delqry = createPQExpBuffer();
10565 /* Make sure we are in proper schema */
10566 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
10568 snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
10569 snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
10571 if (g_fout->remoteVersion >= 80400)
10573 appendPQExpBuffer(query,
10574 "SELECT sequence_name, "
10575 "start_value, last_value, increment_by, "
10576 "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
10577 " WHEN increment_by < 0 AND max_value = -1 THEN NULL "
10578 " ELSE max_value "
10579 "END AS max_value, "
10580 "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
10581 " WHEN increment_by < 0 AND min_value = %s THEN NULL "
10582 " ELSE min_value "
10583 "END AS min_value, "
10584 "cache_value, is_cycled, is_called from %s",
10585 bufx, bufm,
10586 fmtId(tbinfo->dobj.name));
10588 else
10590 appendPQExpBuffer(query,
10591 "SELECT sequence_name, "
10592 "0 AS start_value, last_value, increment_by, "
10593 "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
10594 " WHEN increment_by < 0 AND max_value = -1 THEN NULL "
10595 " ELSE max_value "
10596 "END AS max_value, "
10597 "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
10598 " WHEN increment_by < 0 AND min_value = %s THEN NULL "
10599 " ELSE min_value "
10600 "END AS min_value, "
10601 "cache_value, is_cycled, is_called from %s",
10602 bufx, bufm,
10603 fmtId(tbinfo->dobj.name));
10606 res = PQexec(g_conn, query->data);
10607 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10609 if (PQntuples(res) != 1)
10611 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
10612 "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
10613 PQntuples(res)),
10614 tbinfo->dobj.name, PQntuples(res));
10615 exit_nicely();
10618 /* Disable this check: it fails if sequence has been renamed */
10619 #ifdef NOT_USED
10620 if (strcmp(PQgetvalue(res, 0, 0), tbinfo->dobj.name) != 0)
10622 write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
10623 tbinfo->dobj.name, PQgetvalue(res, 0, 0));
10624 exit_nicely();
10626 #endif
10628 startv = PQgetvalue(res, 0, 1);
10629 last = PQgetvalue(res, 0, 2);
10630 incby = PQgetvalue(res, 0, 3);
10631 if (!PQgetisnull(res, 0, 4))
10632 maxv = PQgetvalue(res, 0, 4);
10633 if (!PQgetisnull(res, 0, 5))
10634 minv = PQgetvalue(res, 0, 5);
10635 cache = PQgetvalue(res, 0, 6);
10636 cycled = (strcmp(PQgetvalue(res, 0, 7), "t") == 0);
10637 called = (strcmp(PQgetvalue(res, 0, 8), "t") == 0);
10640 * The logic we use for restoring sequences is as follows:
10642 * Add a CREATE SEQUENCE statement as part of a "schema" dump (use
10643 * last_val for start if called is false, else use min_val for start_val).
10644 * Also, if the sequence is owned by a column, add an ALTER SEQUENCE OWNED
10645 * BY command for it.
10647 * Add a 'SETVAL(seq, last_val, iscalled)' as part of a "data" dump.
10649 if (!dataOnly)
10651 resetPQExpBuffer(delqry);
10654 * DROP must be fully qualified in case same name appears in
10655 * pg_catalog
10657 appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
10658 fmtId(tbinfo->dobj.namespace->dobj.name));
10659 appendPQExpBuffer(delqry, "%s;\n",
10660 fmtId(tbinfo->dobj.name));
10662 resetPQExpBuffer(query);
10663 appendPQExpBuffer(query,
10664 "CREATE SEQUENCE %s\n",
10665 fmtId(tbinfo->dobj.name));
10667 if (g_fout->remoteVersion >= 80400)
10668 appendPQExpBuffer(query, " START WITH %s\n", startv);
10669 else
10672 * Versions before 8.4 did not remember the true start value. If
10673 * is_called is false then the sequence has never been incremented
10674 * so we can use last_val. Otherwise punt and let it default.
10676 if (!called)
10677 appendPQExpBuffer(query, " START WITH %s\n", last);
10680 appendPQExpBuffer(query, " INCREMENT BY %s\n", incby);
10682 if (maxv)
10683 appendPQExpBuffer(query, " MAXVALUE %s\n", maxv);
10684 else
10685 appendPQExpBuffer(query, " NO MAXVALUE\n");
10687 if (minv)
10688 appendPQExpBuffer(query, " MINVALUE %s\n", minv);
10689 else
10690 appendPQExpBuffer(query, " NO MINVALUE\n");
10692 appendPQExpBuffer(query,
10693 " CACHE %s%s",
10694 cache, (cycled ? "\n CYCLE" : ""));
10696 appendPQExpBuffer(query, ";\n");
10698 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
10699 tbinfo->dobj.name,
10700 tbinfo->dobj.namespace->dobj.name,
10701 NULL,
10702 tbinfo->rolname,
10703 false, "SEQUENCE", SECTION_PRE_DATA,
10704 query->data, delqry->data, NULL,
10705 tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
10706 NULL, NULL);
10709 * If the sequence is owned by a table column, emit the ALTER for it
10710 * as a separate TOC entry immediately following the sequence's own
10711 * entry. It's OK to do this rather than using full sorting logic,
10712 * because the dependency that tells us it's owned will have forced
10713 * the table to be created first. We can't just include the ALTER in
10714 * the TOC entry because it will fail if we haven't reassigned the
10715 * sequence owner to match the table's owner.
10717 * We need not schema-qualify the table reference because both
10718 * sequence and table must be in the same schema.
10720 if (OidIsValid(tbinfo->owning_tab))
10722 TableInfo *owning_tab = findTableByOid(tbinfo->owning_tab);
10724 if (owning_tab && owning_tab->dobj.dump)
10726 resetPQExpBuffer(query);
10727 appendPQExpBuffer(query, "ALTER SEQUENCE %s",
10728 fmtId(tbinfo->dobj.name));
10729 appendPQExpBuffer(query, " OWNED BY %s",
10730 fmtId(owning_tab->dobj.name));
10731 appendPQExpBuffer(query, ".%s;\n",
10732 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
10734 ArchiveEntry(fout, nilCatalogId, createDumpId(),
10735 tbinfo->dobj.name,
10736 tbinfo->dobj.namespace->dobj.name,
10737 NULL,
10738 tbinfo->rolname,
10739 false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
10740 query->data, "", NULL,
10741 &(tbinfo->dobj.dumpId), 1,
10742 NULL, NULL);
10746 /* Dump Sequence Comments */
10747 resetPQExpBuffer(query);
10748 appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
10749 dumpComment(fout, query->data,
10750 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
10751 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
10754 if (!schemaOnly)
10756 resetPQExpBuffer(query);
10757 appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
10758 appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
10759 appendPQExpBuffer(query, ", %s, %s);\n",
10760 last, (called ? "true" : "false"));
10762 ArchiveEntry(fout, nilCatalogId, createDumpId(),
10763 tbinfo->dobj.name,
10764 tbinfo->dobj.namespace->dobj.name,
10765 NULL,
10766 tbinfo->rolname,
10767 false, "SEQUENCE SET", SECTION_PRE_DATA,
10768 query->data, "", NULL,
10769 &(tbinfo->dobj.dumpId), 1,
10770 NULL, NULL);
10773 PQclear(res);
10775 destroyPQExpBuffer(query);
10776 destroyPQExpBuffer(delqry);
10779 static void
10780 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
10782 TableInfo *tbinfo = tginfo->tgtable;
10783 PQExpBuffer query;
10784 PQExpBuffer delqry;
10785 const char *p;
10786 int findx;
10788 if (dataOnly)
10789 return;
10791 query = createPQExpBuffer();
10792 delqry = createPQExpBuffer();
10795 * DROP must be fully qualified in case same name appears in pg_catalog
10797 appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
10798 fmtId(tginfo->dobj.name));
10799 appendPQExpBuffer(delqry, "ON %s.",
10800 fmtId(tbinfo->dobj.namespace->dobj.name));
10801 appendPQExpBuffer(delqry, "%s;\n",
10802 fmtId(tbinfo->dobj.name));
10804 if (tginfo->tgisconstraint)
10806 appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
10807 appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
10809 else
10811 appendPQExpBuffer(query, "CREATE TRIGGER ");
10812 appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
10814 appendPQExpBuffer(query, "\n ");
10816 /* Trigger type */
10817 findx = 0;
10818 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
10819 appendPQExpBuffer(query, "BEFORE");
10820 else
10821 appendPQExpBuffer(query, "AFTER");
10822 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
10824 appendPQExpBuffer(query, " INSERT");
10825 findx++;
10827 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
10829 if (findx > 0)
10830 appendPQExpBuffer(query, " OR DELETE");
10831 else
10832 appendPQExpBuffer(query, " DELETE");
10833 findx++;
10835 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
10837 if (findx > 0)
10838 appendPQExpBuffer(query, " OR UPDATE");
10839 else
10840 appendPQExpBuffer(query, " UPDATE");
10842 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
10844 if (findx > 0)
10845 appendPQExpBuffer(query, " OR TRUNCATE");
10846 else
10847 appendPQExpBuffer(query, " TRUNCATE");
10849 appendPQExpBuffer(query, " ON %s\n",
10850 fmtId(tbinfo->dobj.name));
10852 if (tginfo->tgisconstraint)
10854 if (OidIsValid(tginfo->tgconstrrelid))
10856 /* If we are using regclass, name is already quoted */
10857 if (g_fout->remoteVersion >= 70300)
10858 appendPQExpBuffer(query, " FROM %s\n ",
10859 tginfo->tgconstrrelname);
10860 else
10861 appendPQExpBuffer(query, " FROM %s\n ",
10862 fmtId(tginfo->tgconstrrelname));
10864 if (!tginfo->tgdeferrable)
10865 appendPQExpBuffer(query, "NOT ");
10866 appendPQExpBuffer(query, "DEFERRABLE INITIALLY ");
10867 if (tginfo->tginitdeferred)
10868 appendPQExpBuffer(query, "DEFERRED\n");
10869 else
10870 appendPQExpBuffer(query, "IMMEDIATE\n");
10873 if (TRIGGER_FOR_ROW(tginfo->tgtype))
10874 appendPQExpBuffer(query, " FOR EACH ROW\n ");
10875 else
10876 appendPQExpBuffer(query, " FOR EACH STATEMENT\n ");
10878 /* In 7.3, result of regproc is already quoted */
10879 if (g_fout->remoteVersion >= 70300)
10880 appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
10881 tginfo->tgfname);
10882 else
10883 appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
10884 fmtId(tginfo->tgfname));
10886 p = tginfo->tgargs;
10887 for (findx = 0; findx < tginfo->tgnargs; findx++)
10889 const char *s = p;
10891 /* Set 'p' to end of arg string. marked by '\000' */
10892 for (;;)
10894 p = strchr(p, '\\');
10895 if (p == NULL)
10897 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
10898 tginfo->tgargs,
10899 tginfo->dobj.name,
10900 tbinfo->dobj.name);
10901 exit_nicely();
10903 p++;
10904 if (*p == '\\') /* is it '\\'? */
10906 p++;
10907 continue;
10909 if (p[0] == '0' && p[1] == '0' && p[2] == '0') /* is it '\000'? */
10910 break;
10912 p--;
10914 appendPQExpBufferChar(query, '\'');
10915 while (s < p)
10917 if (*s == '\'')
10918 appendPQExpBufferChar(query, '\'');
10921 * bytea unconditionally doubles backslashes, so we suppress the
10922 * doubling for standard_conforming_strings.
10924 if (fout->std_strings && *s == '\\' && s[1] == '\\')
10925 s++;
10926 appendPQExpBufferChar(query, *s++);
10928 appendPQExpBufferChar(query, '\'');
10929 appendPQExpBuffer(query,
10930 (findx < tginfo->tgnargs - 1) ? ", " : "");
10931 p = p + 4;
10933 appendPQExpBuffer(query, ");\n");
10935 if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
10937 appendPQExpBuffer(query, "\nALTER TABLE %s ",
10938 fmtId(tbinfo->dobj.name));
10939 switch (tginfo->tgenabled)
10941 case 'D':
10942 case 'f':
10943 appendPQExpBuffer(query, "DISABLE");
10944 break;
10945 case 'A':
10946 appendPQExpBuffer(query, "ENABLE ALWAYS");
10947 break;
10948 case 'R':
10949 appendPQExpBuffer(query, "ENABLE REPLICA");
10950 break;
10951 default:
10952 appendPQExpBuffer(query, "ENABLE");
10953 break;
10955 appendPQExpBuffer(query, " TRIGGER %s;\n",
10956 fmtId(tginfo->dobj.name));
10959 ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
10960 tginfo->dobj.name,
10961 tbinfo->dobj.namespace->dobj.name,
10962 NULL,
10963 tbinfo->rolname, false,
10964 "TRIGGER", SECTION_POST_DATA,
10965 query->data, delqry->data, NULL,
10966 tginfo->dobj.dependencies, tginfo->dobj.nDeps,
10967 NULL, NULL);
10969 resetPQExpBuffer(query);
10970 appendPQExpBuffer(query, "TRIGGER %s ",
10971 fmtId(tginfo->dobj.name));
10972 appendPQExpBuffer(query, "ON %s",
10973 fmtId(tbinfo->dobj.name));
10975 dumpComment(fout, query->data,
10976 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
10977 tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
10979 destroyPQExpBuffer(query);
10980 destroyPQExpBuffer(delqry);
10984 * dumpRule
10985 * Dump a rule
10987 static void
10988 dumpRule(Archive *fout, RuleInfo *rinfo)
10990 TableInfo *tbinfo = rinfo->ruletable;
10991 PQExpBuffer query;
10992 PQExpBuffer cmd;
10993 PQExpBuffer delcmd;
10994 PGresult *res;
10996 /* Skip if not to be dumped */
10997 if (!rinfo->dobj.dump || dataOnly)
10998 return;
11001 * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
11002 * we do not want to dump it as a separate object.
11004 if (!rinfo->separate)
11005 return;
11008 * Make sure we are in proper schema.
11010 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
11012 query = createPQExpBuffer();
11013 cmd = createPQExpBuffer();
11014 delcmd = createPQExpBuffer();
11016 if (g_fout->remoteVersion >= 70300)
11018 appendPQExpBuffer(query,
11019 "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid) AS definition",
11020 rinfo->dobj.catId.oid);
11022 else
11024 /* Rule name was unique before 7.3 ... */
11025 appendPQExpBuffer(query,
11026 "SELECT pg_get_ruledef('%s') AS definition",
11027 rinfo->dobj.name);
11030 res = PQexec(g_conn, query->data);
11031 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11033 if (PQntuples(res) != 1)
11035 write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
11036 rinfo->dobj.name, tbinfo->dobj.name);
11037 exit_nicely();
11040 printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
11043 * Add the command to alter the rules replication firing semantics if it
11044 * differs from the default.
11046 if (rinfo->ev_enabled != 'O')
11048 appendPQExpBuffer(cmd, "ALTER TABLE %s.",
11049 fmtId(tbinfo->dobj.namespace->dobj.name));
11050 appendPQExpBuffer(cmd, "%s ",
11051 fmtId(tbinfo->dobj.name));
11052 switch (rinfo->ev_enabled)
11054 case 'A':
11055 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
11056 fmtId(rinfo->dobj.name));
11057 break;
11058 case 'R':
11059 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
11060 fmtId(rinfo->dobj.name));
11061 break;
11062 case 'D':
11063 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
11064 fmtId(rinfo->dobj.name));
11065 break;
11070 * DROP must be fully qualified in case same name appears in pg_catalog
11072 appendPQExpBuffer(delcmd, "DROP RULE %s ",
11073 fmtId(rinfo->dobj.name));
11074 appendPQExpBuffer(delcmd, "ON %s.",
11075 fmtId(tbinfo->dobj.namespace->dobj.name));
11076 appendPQExpBuffer(delcmd, "%s;\n",
11077 fmtId(tbinfo->dobj.name));
11079 ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
11080 rinfo->dobj.name,
11081 tbinfo->dobj.namespace->dobj.name,
11082 NULL,
11083 tbinfo->rolname, false,
11084 "RULE", SECTION_POST_DATA,
11085 cmd->data, delcmd->data, NULL,
11086 rinfo->dobj.dependencies, rinfo->dobj.nDeps,
11087 NULL, NULL);
11089 /* Dump rule comments */
11090 resetPQExpBuffer(query);
11091 appendPQExpBuffer(query, "RULE %s",
11092 fmtId(rinfo->dobj.name));
11093 appendPQExpBuffer(query, " ON %s",
11094 fmtId(tbinfo->dobj.name));
11095 dumpComment(fout, query->data,
11096 tbinfo->dobj.namespace->dobj.name,
11097 tbinfo->rolname,
11098 rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
11100 PQclear(res);
11102 destroyPQExpBuffer(query);
11103 destroyPQExpBuffer(cmd);
11104 destroyPQExpBuffer(delcmd);
11108 * getDependencies --- obtain available dependency data
11110 static void
11111 getDependencies(void)
11113 PQExpBuffer query;
11114 PGresult *res;
11115 int ntups,
11117 int i_classid,
11118 i_objid,
11119 i_refclassid,
11120 i_refobjid,
11121 i_deptype;
11122 DumpableObject *dobj,
11123 *refdobj;
11125 /* No dependency info available before 7.3 */
11126 if (g_fout->remoteVersion < 70300)
11127 return;
11129 if (g_verbose)
11130 write_msg(NULL, "reading dependency data\n");
11132 /* Make sure we are in proper schema */
11133 selectSourceSchema("pg_catalog");
11135 query = createPQExpBuffer();
11137 appendPQExpBuffer(query, "SELECT "
11138 "classid, objid, refclassid, refobjid, deptype "
11139 "FROM pg_depend "
11140 "WHERE deptype != 'p' "
11141 "ORDER BY 1,2");
11143 res = PQexec(g_conn, query->data);
11144 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11146 ntups = PQntuples(res);
11148 i_classid = PQfnumber(res, "classid");
11149 i_objid = PQfnumber(res, "objid");
11150 i_refclassid = PQfnumber(res, "refclassid");
11151 i_refobjid = PQfnumber(res, "refobjid");
11152 i_deptype = PQfnumber(res, "deptype");
11155 * Since we ordered the SELECT by referencing ID, we can expect that
11156 * multiple entries for the same object will appear together; this saves
11157 * on searches.
11159 dobj = NULL;
11161 for (i = 0; i < ntups; i++)
11163 CatalogId objId;
11164 CatalogId refobjId;
11165 char deptype;
11167 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
11168 objId.oid = atooid(PQgetvalue(res, i, i_objid));
11169 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
11170 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
11171 deptype = *(PQgetvalue(res, i, i_deptype));
11173 if (dobj == NULL ||
11174 dobj->catId.tableoid != objId.tableoid ||
11175 dobj->catId.oid != objId.oid)
11176 dobj = findObjectByCatalogId(objId);
11179 * Failure to find objects mentioned in pg_depend is not unexpected,
11180 * since for example we don't collect info about TOAST tables.
11182 if (dobj == NULL)
11184 #ifdef NOT_USED
11185 fprintf(stderr, "no referencing object %u %u\n",
11186 objId.tableoid, objId.oid);
11187 #endif
11188 continue;
11191 refdobj = findObjectByCatalogId(refobjId);
11193 if (refdobj == NULL)
11195 #ifdef NOT_USED
11196 fprintf(stderr, "no referenced object %u %u\n",
11197 refobjId.tableoid, refobjId.oid);
11198 #endif
11199 continue;
11203 * Ordinarily, table rowtypes have implicit dependencies on their
11204 * tables. However, for a composite type the implicit dependency goes
11205 * the other way in pg_depend; which is the right thing for DROP but
11206 * it doesn't produce the dependency ordering we need. So in that one
11207 * case, we reverse the direction of the dependency.
11209 if (deptype == 'i' &&
11210 dobj->objType == DO_TABLE &&
11211 refdobj->objType == DO_TYPE)
11212 addObjectDependency(refdobj, dobj->dumpId);
11213 else
11214 /* normal case */
11215 addObjectDependency(dobj, refdobj->dumpId);
11218 PQclear(res);
11220 destroyPQExpBuffer(query);
11225 * selectSourceSchema - make the specified schema the active search path
11226 * in the source database.
11228 * NB: pg_catalog is explicitly searched after the specified schema;
11229 * so user names are only qualified if they are cross-schema references,
11230 * and system names are only qualified if they conflict with a user name
11231 * in the current schema.
11233 * Whenever the selected schema is not pg_catalog, be careful to qualify
11234 * references to system catalogs and types in our emitted commands!
11236 static void
11237 selectSourceSchema(const char *schemaName)
11239 static char *curSchemaName = NULL;
11240 PQExpBuffer query;
11242 /* Not relevant if fetching from pre-7.3 DB */
11243 if (g_fout->remoteVersion < 70300)
11244 return;
11245 /* Ignore null schema names */
11246 if (schemaName == NULL || *schemaName == '\0')
11247 return;
11248 /* Optimize away repeated selection of same schema */
11249 if (curSchemaName && strcmp(curSchemaName, schemaName) == 0)
11250 return;
11252 query = createPQExpBuffer();
11253 appendPQExpBuffer(query, "SET search_path = %s",
11254 fmtId(schemaName));
11255 if (strcmp(schemaName, "pg_catalog") != 0)
11256 appendPQExpBuffer(query, ", pg_catalog");
11258 do_sql_command(g_conn, query->data);
11260 destroyPQExpBuffer(query);
11261 if (curSchemaName)
11262 free(curSchemaName);
11263 curSchemaName = strdup(schemaName);
11267 * getFormattedTypeName - retrieve a nicely-formatted type name for the
11268 * given type name.
11270 * NB: in 7.3 and up the result may depend on the currently-selected
11271 * schema; this is why we don't try to cache the names.
11273 static char *
11274 getFormattedTypeName(Oid oid, OidOptions opts)
11276 char *result;
11277 PQExpBuffer query;
11278 PGresult *res;
11279 int ntups;
11281 if (oid == 0)
11283 if ((opts & zeroAsOpaque) != 0)
11284 return strdup(g_opaque_type);
11285 else if ((opts & zeroAsAny) != 0)
11286 return strdup("'any'");
11287 else if ((opts & zeroAsStar) != 0)
11288 return strdup("*");
11289 else if ((opts & zeroAsNone) != 0)
11290 return strdup("NONE");
11293 query = createPQExpBuffer();
11294 if (g_fout->remoteVersion >= 70300)
11296 appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
11297 oid);
11299 else if (g_fout->remoteVersion >= 70100)
11301 appendPQExpBuffer(query, "SELECT format_type('%u'::oid, NULL)",
11302 oid);
11304 else
11306 appendPQExpBuffer(query, "SELECT typname "
11307 "FROM pg_type "
11308 "WHERE oid = '%u'::oid",
11309 oid);
11312 res = PQexec(g_conn, query->data);
11313 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11315 /* Expecting a single result only */
11316 ntups = PQntuples(res);
11317 if (ntups != 1)
11319 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
11320 "query returned %d rows instead of one: %s\n",
11321 ntups),
11322 ntups, query->data);
11323 exit_nicely();
11326 if (g_fout->remoteVersion >= 70100)
11328 /* already quoted */
11329 result = strdup(PQgetvalue(res, 0, 0));
11331 else
11333 /* may need to quote it */
11334 result = strdup(fmtId(PQgetvalue(res, 0, 0)));
11337 PQclear(res);
11338 destroyPQExpBuffer(query);
11340 return result;
11344 * myFormatType --- local implementation of format_type for use with 7.0.
11346 static char *
11347 myFormatType(const char *typname, int32 typmod)
11349 char *result;
11350 bool isarray = false;
11351 PQExpBuffer buf = createPQExpBuffer();
11353 /* Handle array types */
11354 if (typname[0] == '_')
11356 isarray = true;
11357 typname++;
11360 /* Show lengths on bpchar and varchar */
11361 if (!strcmp(typname, "bpchar"))
11363 int len = (typmod - VARHDRSZ);
11365 appendPQExpBuffer(buf, "character");
11366 if (len > 1)
11367 appendPQExpBuffer(buf, "(%d)",
11368 typmod - VARHDRSZ);
11370 else if (!strcmp(typname, "varchar"))
11372 appendPQExpBuffer(buf, "character varying");
11373 if (typmod != -1)
11374 appendPQExpBuffer(buf, "(%d)",
11375 typmod - VARHDRSZ);
11377 else if (!strcmp(typname, "numeric"))
11379 appendPQExpBuffer(buf, "numeric");
11380 if (typmod != -1)
11382 int32 tmp_typmod;
11383 int precision;
11384 int scale;
11386 tmp_typmod = typmod - VARHDRSZ;
11387 precision = (tmp_typmod >> 16) & 0xffff;
11388 scale = tmp_typmod & 0xffff;
11389 appendPQExpBuffer(buf, "(%d,%d)",
11390 precision, scale);
11395 * char is an internal single-byte data type; Let's make sure we force it
11396 * through with quotes. - thomas 1998-12-13
11398 else if (strcmp(typname, "char") == 0)
11399 appendPQExpBuffer(buf, "\"char\"");
11400 else
11401 appendPQExpBuffer(buf, "%s", fmtId(typname));
11403 /* Append array qualifier for array types */
11404 if (isarray)
11405 appendPQExpBuffer(buf, "[]");
11407 result = strdup(buf->data);
11408 destroyPQExpBuffer(buf);
11410 return result;
11414 * fmtQualifiedId - convert a qualified name to the proper format for
11415 * the source database.
11417 * Like fmtId, use the result before calling again.
11419 static const char *
11420 fmtQualifiedId(const char *schema, const char *id)
11422 static PQExpBuffer id_return = NULL;
11424 if (id_return) /* first time through? */
11425 resetPQExpBuffer(id_return);
11426 else
11427 id_return = createPQExpBuffer();
11429 /* Suppress schema name if fetching from pre-7.3 DB */
11430 if (g_fout->remoteVersion >= 70300 && schema && *schema)
11432 appendPQExpBuffer(id_return, "%s.",
11433 fmtId(schema));
11435 appendPQExpBuffer(id_return, "%s",
11436 fmtId(id));
11438 return id_return->data;
11442 * Return a column list clause for the given relation.
11444 * Special case: if there are no undropped columns in the relation, return
11445 * "", not an invalid "()" column list.
11447 static const char *
11448 fmtCopyColumnList(const TableInfo *ti)
11450 static PQExpBuffer q = NULL;
11451 int numatts = ti->numatts;
11452 char **attnames = ti->attnames;
11453 bool *attisdropped = ti->attisdropped;
11454 bool needComma;
11455 int i;
11457 if (q) /* first time through? */
11458 resetPQExpBuffer(q);
11459 else
11460 q = createPQExpBuffer();
11462 appendPQExpBuffer(q, "(");
11463 needComma = false;
11464 for (i = 0; i < numatts; i++)
11466 if (attisdropped[i])
11467 continue;
11468 if (needComma)
11469 appendPQExpBuffer(q, ", ");
11470 appendPQExpBuffer(q, "%s", fmtId(attnames[i]));
11471 needComma = true;
11474 if (!needComma)
11475 return ""; /* no undropped columns */
11477 appendPQExpBuffer(q, ")");
11478 return q->data;
11482 * Convenience subroutine to execute a SQL command and check for
11483 * COMMAND_OK status.
11485 static void
11486 do_sql_command(PGconn *conn, const char *query)
11488 PGresult *res;
11490 res = PQexec(conn, query);
11491 check_sql_result(res, conn, query, PGRES_COMMAND_OK);
11492 PQclear(res);
11496 * Convenience subroutine to verify a SQL command succeeded,
11497 * and exit with a useful error message if not.
11499 static void
11500 check_sql_result(PGresult *res, PGconn *conn, const char *query,
11501 ExecStatusType expected)
11503 const char *err;
11505 if (res && PQresultStatus(res) == expected)
11506 return; /* A-OK */
11508 write_msg(NULL, "SQL command failed\n");
11509 if (res)
11510 err = PQresultErrorMessage(res);
11511 else
11512 err = PQerrorMessage(conn);
11513 write_msg(NULL, "Error message from server: %s", err);
11514 write_msg(NULL, "The command was: %s\n", query);
11515 exit_nicely();