Make LC_COLLATE and LC_CTYPE database-level settings. Collation and
[PostgreSQL.git] / src / bin / pg_dump / pg_dump.c
blob6a31dccc35c9802b5b42bf08f58d82529871a7e2
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-2008, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
10 * pg_dump will read the system catalogs in a database and dump out a
11 * script that reproduces the schema in terms of SQL that is understood
12 * by PostgreSQL
14 * IDENTIFICATION
15 * $PostgreSQL$
17 *-------------------------------------------------------------------------
20 #include "postgres_fe.h"
22 #include <unistd.h>
23 #include <ctype.h>
24 #ifdef ENABLE_NLS
25 #include <locale.h>
26 #endif
27 #ifdef HAVE_TERMIOS_H
28 #include <termios.h>
29 #endif
31 #include "getopt_long.h"
33 #ifndef HAVE_INT_OPTRESET
34 int optreset;
35 #endif
37 #include "access/attnum.h"
38 #include "access/sysattr.h"
39 #include "catalog/pg_class.h"
40 #include "catalog/pg_proc.h"
41 #include "catalog/pg_trigger.h"
42 #include "catalog/pg_type.h"
43 #include "libpq/libpq-fs.h"
45 #include "pg_backup_archiver.h"
46 #include "dumputils.h"
48 extern char *optarg;
49 extern int optind,
50 opterr;
53 typedef struct
55 const char *descr; /* comment for an object */
56 Oid classoid; /* object class (catalog OID) */
57 Oid objoid; /* object OID */
58 int objsubid; /* subobject (table column #) */
59 } CommentItem;
62 /* global decls */
63 bool g_verbose; /* User wants verbose narration of our
64 * activities. */
65 Archive *g_fout; /* the script file */
66 PGconn *g_conn; /* the database connection */
68 /* various user-settable parameters */
69 bool dumpInserts; /* dump data using proper insert strings */
70 bool attrNames; /* put attr names into insert strings */
71 bool schemaOnly;
72 bool dataOnly;
73 bool aclsSkip;
74 const char *lockWaitTimeout;
76 /* subquery used to convert user ID (eg, datdba) to user name */
77 static const char *username_subquery;
79 /* obsolete as of 7.3: */
80 static Oid g_last_builtin_oid; /* value of the last builtin oid */
83 * Object inclusion/exclusion lists
85 * The string lists record the patterns given by command-line switches,
86 * which we then convert to lists of OIDs of matching objects.
88 static SimpleStringList schema_include_patterns = {NULL, NULL};
89 static SimpleOidList schema_include_oids = {NULL, NULL};
90 static SimpleStringList schema_exclude_patterns = {NULL, NULL};
91 static SimpleOidList schema_exclude_oids = {NULL, NULL};
93 static SimpleStringList table_include_patterns = {NULL, NULL};
94 static SimpleOidList table_include_oids = {NULL, NULL};
95 static SimpleStringList table_exclude_patterns = {NULL, NULL};
96 static SimpleOidList table_exclude_oids = {NULL, NULL};
98 /* default, if no "inclusion" switches appear, is to dump everything */
99 static bool include_everything = true;
101 char g_opaque_type[10]; /* name for the opaque type */
103 /* placeholders for the delimiters for comments */
104 char g_comment_start[10];
105 char g_comment_end[10];
107 static const CatalogId nilCatalogId = {0, 0};
109 /* these are to avoid passing around info for findNamespace() */
110 static NamespaceInfo *g_namespaces;
111 static int g_numNamespaces;
113 /* flag to turn on/off dollar quoting */
114 static int disable_dollar_quoting = 0;
117 static void help(const char *progname);
118 static void expand_schema_name_patterns(SimpleStringList *patterns,
119 SimpleOidList *oids);
120 static void expand_table_name_patterns(SimpleStringList *patterns,
121 SimpleOidList *oids);
122 static NamespaceInfo *findNamespace(Oid nsoid, Oid objoid);
123 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
124 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
125 static void dumpComment(Archive *fout, const char *target,
126 const char *namespace, const char *owner,
127 CatalogId catalogId, int subid, DumpId dumpId);
128 static int findComments(Archive *fout, Oid classoid, Oid objoid,
129 CommentItem **items);
130 static int collectComments(Archive *fout, CommentItem **items);
131 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
132 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
133 static void dumpType(Archive *fout, TypeInfo *tinfo);
134 static void dumpBaseType(Archive *fout, TypeInfo *tinfo);
135 static void dumpEnumType(Archive *fout, TypeInfo *tinfo);
136 static void dumpDomain(Archive *fout, TypeInfo *tinfo);
137 static void dumpCompositeType(Archive *fout, TypeInfo *tinfo);
138 static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
139 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
140 static void dumpFunc(Archive *fout, FuncInfo *finfo);
141 static void dumpCast(Archive *fout, CastInfo *cast);
142 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
143 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
144 static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
145 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
146 static void dumpRule(Archive *fout, RuleInfo *rinfo);
147 static void dumpAgg(Archive *fout, AggInfo *agginfo);
148 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
149 static void dumpTable(Archive *fout, TableInfo *tbinfo);
150 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
151 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
152 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
153 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
154 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
155 static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
156 static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
157 static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
158 static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
159 static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
161 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
162 const char *type, const char *name,
163 const char *tag, const char *nspname, const char *owner,
164 const char *acls);
166 static void getDependencies(void);
167 static void getDomainConstraints(TypeInfo *tinfo);
168 static void getTableData(TableInfo *tblinfo, int numTables, bool oids);
169 static void getTableDataFKConstraints(void);
170 static char *format_function_arguments(FuncInfo *finfo, char *funcargs);
171 static char *format_function_arguments_old(FuncInfo *finfo, int nallargs,
172 char **allargtypes,
173 char **argmodes,
174 char **argnames);
175 static char *format_function_signature(FuncInfo *finfo, bool honor_quotes);
176 static const char *convertRegProcReference(const char *proc);
177 static const char *convertOperatorReference(const char *opr);
178 static const char *convertTSFunction(Oid funcOid);
179 static Oid findLastBuiltinOid_V71(const char *);
180 static Oid findLastBuiltinOid_V70(void);
181 static void selectSourceSchema(const char *schemaName);
182 static char *getFormattedTypeName(Oid oid, OidOptions opts);
183 static char *myFormatType(const char *typname, int32 typmod);
184 static const char *fmtQualifiedId(const char *schema, const char *id);
185 static bool hasBlobs(Archive *AH);
186 static int dumpBlobs(Archive *AH, void *arg);
187 static int dumpBlobComments(Archive *AH, void *arg);
188 static void dumpDatabase(Archive *AH);
189 static void dumpEncoding(Archive *AH);
190 static void dumpStdStrings(Archive *AH);
191 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
192 static const char *fmtCopyColumnList(const TableInfo *ti);
193 static void do_sql_command(PGconn *conn, const char *query);
194 static void check_sql_result(PGresult *res, PGconn *conn, const char *query,
195 ExecStatusType expected);
199 main(int argc, char **argv)
201 int c;
202 const char *filename = NULL;
203 const char *format = "p";
204 const char *dbname = NULL;
205 const char *pghost = NULL;
206 const char *pgport = NULL;
207 const char *username = NULL;
208 const char *dumpencoding = NULL;
209 const char *std_strings;
210 bool oids = false;
211 TableInfo *tblinfo;
212 int numTables;
213 DumpableObject **dobjs;
214 int numObjs;
215 int i;
216 bool force_password = false;
217 int compressLevel = -1;
218 int plainText = 0;
219 int outputClean = 0;
220 int outputCreate = 0;
221 bool outputBlobs = false;
222 int outputNoOwner = 0;
223 char *outputSuperuser = NULL;
224 int my_version;
225 int optindex;
226 RestoreOptions *ropt;
228 static int disable_triggers = 0;
229 static int outputNoTablespaces = 0;
230 static int use_setsessauth = 0;
232 static struct option long_options[] = {
233 {"data-only", no_argument, NULL, 'a'},
234 {"blobs", no_argument, NULL, 'b'},
235 {"clean", no_argument, NULL, 'c'},
236 {"create", no_argument, NULL, 'C'},
237 {"file", required_argument, NULL, 'f'},
238 {"format", required_argument, NULL, 'F'},
239 {"inserts", no_argument, NULL, 'd'},
240 {"attribute-inserts", no_argument, NULL, 'D'},
241 {"column-inserts", no_argument, NULL, 'D'},
242 {"host", required_argument, NULL, 'h'},
243 {"ignore-version", no_argument, NULL, 'i'},
244 {"no-reconnect", no_argument, NULL, 'R'},
245 {"oids", no_argument, NULL, 'o'},
246 {"no-owner", no_argument, NULL, 'O'},
247 {"port", required_argument, NULL, 'p'},
248 {"schema", required_argument, NULL, 'n'},
249 {"exclude-schema", required_argument, NULL, 'N'},
250 {"schema-only", no_argument, NULL, 's'},
251 {"superuser", required_argument, NULL, 'S'},
252 {"table", required_argument, NULL, 't'},
253 {"exclude-table", required_argument, NULL, 'T'},
254 {"password", no_argument, NULL, 'W'},
255 {"username", required_argument, NULL, 'U'},
256 {"verbose", no_argument, NULL, 'v'},
257 {"no-privileges", no_argument, NULL, 'x'},
258 {"no-acl", no_argument, NULL, 'x'},
259 {"compress", required_argument, NULL, 'Z'},
260 {"encoding", required_argument, NULL, 'E'},
261 {"help", no_argument, NULL, '?'},
262 {"version", no_argument, NULL, 'V'},
265 * the following options don't have an equivalent short option letter
267 {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
268 {"disable-triggers", no_argument, &disable_triggers, 1},
269 {"lock-wait-timeout", required_argument, NULL, 2},
270 {"no-tablespaces", no_argument, &outputNoTablespaces, 1},
271 {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
273 {NULL, 0, NULL, 0}
276 set_pglocale_pgservice(argv[0], "pg_dump");
278 g_verbose = false;
280 strcpy(g_comment_start, "-- ");
281 g_comment_end[0] = '\0';
282 strcpy(g_opaque_type, "opaque");
284 dataOnly = schemaOnly = dumpInserts = attrNames = false;
285 lockWaitTimeout = NULL;
287 progname = get_progname(argv[0]);
289 /* Set default options based on progname */
290 if (strcmp(progname, "pg_backup") == 0)
291 format = "c";
293 if (argc > 1)
295 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
297 help(progname);
298 exit(0);
300 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
302 puts("pg_dump (PostgreSQL) " PG_VERSION);
303 exit(0);
307 while ((c = getopt_long(argc, argv, "abcCdDE:f:F:h:in:N:oOp:RsS:t:T:U:vWxX:Z:",
308 long_options, &optindex)) != -1)
310 switch (c)
312 case 'a': /* Dump data only */
313 dataOnly = true;
314 break;
316 case 'b': /* Dump blobs */
317 outputBlobs = true;
318 break;
320 case 'c': /* clean (i.e., drop) schema prior to create */
321 outputClean = 1;
322 break;
324 case 'C': /* Create DB */
325 outputCreate = 1;
326 break;
328 case 'd': /* dump data as proper insert strings */
329 dumpInserts = true;
330 break;
332 case 'D': /* dump data as proper insert strings with
333 * attr names */
334 dumpInserts = true;
335 attrNames = true;
336 break;
338 case 'E': /* Dump encoding */
339 dumpencoding = optarg;
340 break;
342 case 'f':
343 filename = optarg;
344 break;
346 case 'F':
347 format = optarg;
348 break;
350 case 'h': /* server host */
351 pghost = optarg;
352 break;
354 case 'i':
355 /* ignored, deprecated option */
356 break;
358 case 'n': /* include schema(s) */
359 simple_string_list_append(&schema_include_patterns, optarg);
360 include_everything = false;
361 break;
363 case 'N': /* exclude schema(s) */
364 simple_string_list_append(&schema_exclude_patterns, optarg);
365 break;
367 case 'o': /* Dump oids */
368 oids = true;
369 break;
371 case 'O': /* Don't reconnect to match owner */
372 outputNoOwner = 1;
373 break;
375 case 'p': /* server port */
376 pgport = optarg;
377 break;
379 case 'R':
380 /* no-op, still accepted for backwards compatibility */
381 break;
383 case 's': /* dump schema only */
384 schemaOnly = true;
385 break;
387 case 'S': /* Username for superuser in plain text output */
388 outputSuperuser = strdup(optarg);
389 break;
391 case 't': /* include table(s) */
392 simple_string_list_append(&table_include_patterns, optarg);
393 include_everything = false;
394 break;
396 case 'T': /* exclude table(s) */
397 simple_string_list_append(&table_exclude_patterns, optarg);
398 break;
400 case 'U':
401 username = optarg;
402 break;
404 case 'v': /* verbose */
405 g_verbose = true;
406 break;
408 case 'W':
409 force_password = true;
410 break;
412 case 'x': /* skip ACL dump */
413 aclsSkip = true;
414 break;
416 case 'X':
417 /* -X is a deprecated alternative to long options */
418 if (strcmp(optarg, "disable-dollar-quoting") == 0)
419 disable_dollar_quoting = 1;
420 else if (strcmp(optarg, "disable-triggers") == 0)
421 disable_triggers = 1;
422 else if (strcmp(optarg, "no-tablespaces") == 0)
423 outputNoTablespaces = 1;
424 else if (strcmp(optarg, "use-set-session-authorization") == 0)
425 use_setsessauth = 1;
426 else
428 fprintf(stderr,
429 _("%s: invalid -X option -- %s\n"),
430 progname, optarg);
431 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
432 exit(1);
434 break;
436 case 'Z': /* Compression Level */
437 compressLevel = atoi(optarg);
438 break;
440 case 0:
441 /* This covers the long options equivalent to -X xxx. */
442 break;
444 case 2:
445 /* lock-wait-timeout */
446 lockWaitTimeout = optarg;
447 break;
449 default:
450 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
451 exit(1);
455 if (optind < (argc - 1))
457 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
458 progname, argv[optind + 1]);
459 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
460 progname);
461 exit(1);
464 /* Get database name from command line */
465 if (optind < argc)
466 dbname = argv[optind];
468 if (dataOnly && schemaOnly)
470 write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
471 exit(1);
474 if (dataOnly && outputClean)
476 write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
477 exit(1);
480 if (dumpInserts == true && oids == true)
482 write_msg(NULL, "options -d/-D/--inserts/--column-inserts and -o/--oids cannot be used together\n");
483 write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
484 exit(1);
487 /* open the output file */
488 if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
490 /* This is used by pg_dumpall, and is not documented */
491 plainText = 1;
492 g_fout = CreateArchive(filename, archNull, 0, archModeAppend);
494 else if (pg_strcasecmp(format, "c") == 0 || pg_strcasecmp(format, "custom") == 0)
495 g_fout = CreateArchive(filename, archCustom, compressLevel, archModeWrite);
496 else if (pg_strcasecmp(format, "f") == 0 || pg_strcasecmp(format, "file") == 0)
499 * Dump files into the current directory; for demonstration only, not
500 * documented.
502 g_fout = CreateArchive(filename, archFiles, compressLevel, archModeWrite);
504 else if (pg_strcasecmp(format, "p") == 0 || pg_strcasecmp(format, "plain") == 0)
506 plainText = 1;
507 g_fout = CreateArchive(filename, archNull, 0, archModeWrite);
509 else if (pg_strcasecmp(format, "t") == 0 || pg_strcasecmp(format, "tar") == 0)
510 g_fout = CreateArchive(filename, archTar, compressLevel, archModeWrite);
511 else
513 write_msg(NULL, "invalid output format \"%s\" specified\n", format);
514 exit(1);
517 if (g_fout == NULL)
519 write_msg(NULL, "could not open output file \"%s\" for writing\n", filename);
520 exit(1);
523 /* Let the archiver know how noisy to be */
524 g_fout->verbose = g_verbose;
526 my_version = parse_version(PG_VERSION);
527 if (my_version < 0)
529 write_msg(NULL, "could not parse version string \"%s\"\n", PG_VERSION);
530 exit(1);
534 * We allow the server to be back to 7.0, and up to any minor release
535 * of our own major version. (See also version check in pg_dumpall.c.)
537 g_fout->minRemoteVersion = 70000;
538 g_fout->maxRemoteVersion = (my_version / 100) * 100 + 99;
541 * Open the database using the Archiver, so it knows about it. Errors mean
542 * death.
544 g_conn = ConnectDatabase(g_fout, dbname, pghost, pgport,
545 username, force_password);
547 /* Set the client encoding if requested */
548 if (dumpencoding)
550 if (PQsetClientEncoding(g_conn, dumpencoding) < 0)
552 write_msg(NULL, "invalid client encoding \"%s\" specified\n",
553 dumpencoding);
554 exit(1);
559 * Get the active encoding and the standard_conforming_strings setting, so
560 * we know how to escape strings.
562 g_fout->encoding = PQclientEncoding(g_conn);
564 std_strings = PQparameterStatus(g_conn, "standard_conforming_strings");
565 g_fout->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
567 /* Set the datestyle to ISO to ensure the dump's portability */
568 do_sql_command(g_conn, "SET DATESTYLE = ISO");
571 * If supported, set extra_float_digits so that we can dump float data
572 * exactly (given correctly implemented float I/O code, anyway)
574 if (g_fout->remoteVersion >= 70400)
575 do_sql_command(g_conn, "SET extra_float_digits TO 2");
578 * If synchronized scanning is supported, disable it, to prevent
579 * unpredictable changes in row ordering across a dump and reload.
581 if (g_fout->remoteVersion >= 80300)
582 do_sql_command(g_conn, "SET synchronize_seqscans TO off");
585 * Disable timeouts if supported.
587 if (g_fout->remoteVersion >= 70300)
588 do_sql_command(g_conn, "SET statement_timeout = 0");
591 * Start serializable transaction to dump consistent data.
593 do_sql_command(g_conn, "BEGIN");
595 do_sql_command(g_conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
597 /* Select the appropriate subquery to convert user IDs to names */
598 if (g_fout->remoteVersion >= 80100)
599 username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
600 else if (g_fout->remoteVersion >= 70300)
601 username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
602 else
603 username_subquery = "SELECT usename FROM pg_user WHERE usesysid =";
605 /* Find the last built-in OID, if needed */
606 if (g_fout->remoteVersion < 70300)
608 if (g_fout->remoteVersion >= 70100)
609 g_last_builtin_oid = findLastBuiltinOid_V71(PQdb(g_conn));
610 else
611 g_last_builtin_oid = findLastBuiltinOid_V70();
612 if (g_verbose)
613 write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
616 /* Expand schema selection patterns into OID lists */
617 if (schema_include_patterns.head != NULL)
619 expand_schema_name_patterns(&schema_include_patterns,
620 &schema_include_oids);
621 if (schema_include_oids.head == NULL)
623 write_msg(NULL, "No matching schemas were found\n");
624 exit_nicely();
627 expand_schema_name_patterns(&schema_exclude_patterns,
628 &schema_exclude_oids);
629 /* non-matching exclusion patterns aren't an error */
631 /* Expand table selection patterns into OID lists */
632 if (table_include_patterns.head != NULL)
634 expand_table_name_patterns(&table_include_patterns,
635 &table_include_oids);
636 if (table_include_oids.head == NULL)
638 write_msg(NULL, "No matching tables were found\n");
639 exit_nicely();
642 expand_table_name_patterns(&table_exclude_patterns,
643 &table_exclude_oids);
644 /* non-matching exclusion patterns aren't an error */
647 * Dumping blobs is now default unless we saw an inclusion switch or -s
648 * ... but even if we did see one of these, -b turns it back on.
650 if (include_everything && !schemaOnly)
651 outputBlobs = true;
654 * Now scan the database and create DumpableObject structs for all the
655 * objects we intend to dump.
657 tblinfo = getSchemaData(&numTables);
659 if (g_fout->remoteVersion < 80400)
660 guessConstraintInheritance(tblinfo, numTables);
662 if (!schemaOnly)
664 getTableData(tblinfo, numTables, oids);
665 if (dataOnly)
666 getTableDataFKConstraints();
669 if (outputBlobs && hasBlobs(g_fout))
671 /* Add placeholders to allow correct sorting of blobs */
672 DumpableObject *blobobj;
674 blobobj = (DumpableObject *) malloc(sizeof(DumpableObject));
675 blobobj->objType = DO_BLOBS;
676 blobobj->catId = nilCatalogId;
677 AssignDumpId(blobobj);
678 blobobj->name = strdup("BLOBS");
680 blobobj = (DumpableObject *) malloc(sizeof(DumpableObject));
681 blobobj->objType = DO_BLOB_COMMENTS;
682 blobobj->catId = nilCatalogId;
683 AssignDumpId(blobobj);
684 blobobj->name = strdup("BLOB COMMENTS");
688 * Collect dependency data to assist in ordering the objects.
690 getDependencies();
693 * Sort the objects into a safe dump order (no forward references).
695 * In 7.3 or later, we can rely on dependency information to help us
696 * determine a safe order, so the initial sort is mostly for cosmetic
697 * purposes: we sort by name to ensure that logically identical schemas
698 * will dump identically. Before 7.3 we don't have dependencies and we
699 * use OID ordering as an (unreliable) guide to creation order.
701 getDumpableObjects(&dobjs, &numObjs);
703 if (g_fout->remoteVersion >= 70300)
704 sortDumpableObjectsByTypeName(dobjs, numObjs);
705 else
706 sortDumpableObjectsByTypeOid(dobjs, numObjs);
708 sortDumpableObjects(dobjs, numObjs);
711 * Create archive TOC entries for all the objects to be dumped, in a safe
712 * order.
715 /* First the special ENCODING and STDSTRINGS entries. */
716 dumpEncoding(g_fout);
717 dumpStdStrings(g_fout);
719 /* The database item is always next, unless we don't want it at all */
720 if (include_everything && !dataOnly)
721 dumpDatabase(g_fout);
723 /* Now the rearrangeable objects. */
724 for (i = 0; i < numObjs; i++)
725 dumpDumpableObject(g_fout, dobjs[i]);
728 * And finally we can do the actual output.
730 if (plainText)
732 ropt = NewRestoreOptions();
733 ropt->filename = (char *) filename;
734 ropt->dropSchema = outputClean;
735 ropt->aclsSkip = aclsSkip;
736 ropt->superuser = outputSuperuser;
737 ropt->create = outputCreate;
738 ropt->noOwner = outputNoOwner;
739 ropt->noTablespace = outputNoTablespaces;
740 ropt->disable_triggers = disable_triggers;
741 ropt->use_setsessauth = use_setsessauth;
742 ropt->dataOnly = dataOnly;
744 if (compressLevel == -1)
745 ropt->compression = 0;
746 else
747 ropt->compression = compressLevel;
749 ropt->suppressDumpWarnings = true; /* We've already shown them */
751 RestoreArchive(g_fout, ropt);
754 CloseArchive(g_fout);
756 PQfinish(g_conn);
758 exit(0);
762 static void
763 help(const char *progname)
765 printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
766 printf(_("Usage:\n"));
767 printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
769 printf(_("\nGeneral options:\n"));
770 printf(_(" -f, --file=FILENAME output file name\n"));
771 printf(_(" -F, --format=c|t|p output file format (custom, tar, plain text)\n"));
772 printf(_(" -v, --verbose verbose mode\n"));
773 printf(_(" -Z, --compress=0-9 compression level for compressed formats\n"));
774 printf(_(" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
775 printf(_(" --help show this help, then exit\n"));
776 printf(_(" --version output version information, then exit\n"));
778 printf(_("\nOptions controlling the output content:\n"));
779 printf(_(" -a, --data-only dump only the data, not the schema\n"));
780 printf(_(" -b, --blobs include large objects in dump\n"));
781 printf(_(" -c, --clean clean (drop) schema prior to create\n"));
782 printf(_(" -C, --create include commands to create database in dump\n"));
783 printf(_(" -d, --inserts dump data as INSERT commands, rather than COPY\n"));
784 printf(_(" -D, --column-inserts dump data as INSERT commands with column names\n"));
785 printf(_(" -E, --encoding=ENCODING dump the data in encoding ENCODING\n"));
786 printf(_(" -n, --schema=SCHEMA dump the named schema(s) only\n"));
787 printf(_(" -N, --exclude-schema=SCHEMA do NOT dump the named schema(s)\n"));
788 printf(_(" -o, --oids include OIDs in dump\n"));
789 printf(_(" -O, --no-owner skip restoration of object ownership\n"
790 " in plain text format\n"));
791 printf(_(" -s, --schema-only dump only the schema, no data\n"));
792 printf(_(" -S, --superuser=NAME specify the superuser user name to use in\n"
793 " plain text format\n"));
794 printf(_(" -t, --table=TABLE dump the named table(s) only\n"));
795 printf(_(" -T, --exclude-table=TABLE do NOT dump the named table(s)\n"));
796 printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
797 printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n"));
798 printf(_(" --disable-triggers disable triggers during data-only restore\n"));
799 printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
800 printf(_(" --use-set-session-authorization\n"
801 " use SESSION AUTHORIZATION commands instead of\n"
802 " ALTER OWNER commands to set ownership\n"));
804 printf(_("\nConnection options:\n"));
805 printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
806 printf(_(" -p, --port=PORT database server port number\n"));
807 printf(_(" -U, --username=NAME connect as specified database user\n"));
808 printf(_(" -W, --password force password prompt (should happen automatically)\n"));
810 printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
811 "variable value is used.\n\n"));
812 printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
815 void
816 exit_nicely(void)
818 PQfinish(g_conn);
819 if (g_verbose)
820 write_msg(NULL, "*** aborted because of error\n");
821 exit(1);
825 * Find the OIDs of all schemas matching the given list of patterns,
826 * and append them to the given OID list.
828 static void
829 expand_schema_name_patterns(SimpleStringList *patterns, SimpleOidList *oids)
831 PQExpBuffer query;
832 PGresult *res;
833 SimpleStringListCell *cell;
834 int i;
836 if (patterns->head == NULL)
837 return; /* nothing to do */
839 if (g_fout->remoteVersion < 70300)
841 write_msg(NULL, "server version must be at least 7.3 to use schema selection switches\n");
842 exit_nicely();
845 query = createPQExpBuffer();
848 * We use UNION ALL rather than UNION; this might sometimes result in
849 * duplicate entries in the OID list, but we don't care.
852 for (cell = patterns->head; cell; cell = cell->next)
854 if (cell != patterns->head)
855 appendPQExpBuffer(query, "UNION ALL\n");
856 appendPQExpBuffer(query,
857 "SELECT oid FROM pg_catalog.pg_namespace n\n");
858 processSQLNamePattern(g_conn, query, cell->val, false, false,
859 NULL, "n.nspname", NULL,
860 NULL);
863 res = PQexec(g_conn, query->data);
864 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
866 for (i = 0; i < PQntuples(res); i++)
868 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
871 PQclear(res);
872 destroyPQExpBuffer(query);
876 * Find the OIDs of all tables matching the given list of patterns,
877 * and append them to the given OID list.
879 static void
880 expand_table_name_patterns(SimpleStringList *patterns, SimpleOidList *oids)
882 PQExpBuffer query;
883 PGresult *res;
884 SimpleStringListCell *cell;
885 int i;
887 if (patterns->head == NULL)
888 return; /* nothing to do */
890 query = createPQExpBuffer();
893 * We use UNION ALL rather than UNION; this might sometimes result in
894 * duplicate entries in the OID list, but we don't care.
897 for (cell = patterns->head; cell; cell = cell->next)
899 if (cell != patterns->head)
900 appendPQExpBuffer(query, "UNION ALL\n");
901 appendPQExpBuffer(query,
902 "SELECT c.oid"
903 "\nFROM pg_catalog.pg_class c"
904 "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
905 "\nWHERE c.relkind in ('%c', '%c', '%c')\n",
906 RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
907 processSQLNamePattern(g_conn, query, cell->val, true, false,
908 "n.nspname", "c.relname", NULL,
909 "pg_catalog.pg_table_is_visible(c.oid)");
912 res = PQexec(g_conn, query->data);
913 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
915 for (i = 0; i < PQntuples(res); i++)
917 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
920 PQclear(res);
921 destroyPQExpBuffer(query);
925 * selectDumpableNamespace: policy-setting subroutine
926 * Mark a namespace as to be dumped or not
928 static void
929 selectDumpableNamespace(NamespaceInfo *nsinfo)
932 * If specific tables are being dumped, do not dump any complete
933 * namespaces. If specific namespaces are being dumped, dump just those
934 * namespaces. Otherwise, dump all non-system namespaces.
936 if (table_include_oids.head != NULL)
937 nsinfo->dobj.dump = false;
938 else if (schema_include_oids.head != NULL)
939 nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
940 nsinfo->dobj.catId.oid);
941 else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
942 strcmp(nsinfo->dobj.name, "information_schema") == 0)
943 nsinfo->dobj.dump = false;
944 else
945 nsinfo->dobj.dump = true;
948 * In any case, a namespace can be excluded by an exclusion switch
950 if (nsinfo->dobj.dump &&
951 simple_oid_list_member(&schema_exclude_oids,
952 nsinfo->dobj.catId.oid))
953 nsinfo->dobj.dump = false;
957 * selectDumpableTable: policy-setting subroutine
958 * Mark a table as to be dumped or not
960 static void
961 selectDumpableTable(TableInfo *tbinfo)
964 * If specific tables are being dumped, dump just those tables; else, dump
965 * according to the parent namespace's dump flag.
967 if (table_include_oids.head != NULL)
968 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
969 tbinfo->dobj.catId.oid);
970 else
971 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
974 * In any case, a table can be excluded by an exclusion switch
976 if (tbinfo->dobj.dump &&
977 simple_oid_list_member(&table_exclude_oids,
978 tbinfo->dobj.catId.oid))
979 tbinfo->dobj.dump = false;
983 * selectDumpableType: policy-setting subroutine
984 * Mark a type as to be dumped or not
986 static void
987 selectDumpableType(TypeInfo *tinfo)
989 /* Dump only types in dumpable namespaces */
990 if (!tinfo->dobj.namespace->dobj.dump)
991 tinfo->dobj.dump = false;
993 /* skip complex types, except for standalone composite types */
994 /* (note: this test should now be unnecessary) */
995 else if (OidIsValid(tinfo->typrelid) &&
996 tinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
997 tinfo->dobj.dump = false;
999 /* skip undefined placeholder types */
1000 else if (!tinfo->isDefined)
1001 tinfo->dobj.dump = false;
1003 /* skip auto-generated array types */
1004 else if (tinfo->isArray)
1005 tinfo->dobj.dump = false;
1007 else
1008 tinfo->dobj.dump = true;
1012 * selectDumpableObject: policy-setting subroutine
1013 * Mark a generic dumpable object as to be dumped or not
1015 * Use this only for object types without a special-case routine above.
1017 static void
1018 selectDumpableObject(DumpableObject *dobj)
1021 * Default policy is to dump if parent namespace is dumpable, or always
1022 * for non-namespace-associated items.
1024 if (dobj->namespace)
1025 dobj->dump = dobj->namespace->dobj.dump;
1026 else
1027 dobj->dump = true;
1031 * Dump a table's contents for loading using the COPY command
1032 * - this routine is called by the Archiver when it wants the table
1033 * to be dumped.
1036 static int
1037 dumpTableData_copy(Archive *fout, void *dcontext)
1039 TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1040 TableInfo *tbinfo = tdinfo->tdtable;
1041 const char *classname = tbinfo->dobj.name;
1042 const bool hasoids = tbinfo->hasoids;
1043 const bool oids = tdinfo->oids;
1044 PQExpBuffer q = createPQExpBuffer();
1045 PGresult *res;
1046 int ret;
1047 char *copybuf;
1048 const char *column_list;
1050 if (g_verbose)
1051 write_msg(NULL, "dumping contents of table %s\n", classname);
1054 * Make sure we are in proper schema. We will qualify the table name
1055 * below anyway (in case its name conflicts with a pg_catalog table); but
1056 * this ensures reproducible results in case the table contains regproc,
1057 * regclass, etc columns.
1059 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
1062 * If possible, specify the column list explicitly so that we have no
1063 * possibility of retrieving data in the wrong column order. (The default
1064 * column ordering of COPY will not be what we want in certain corner
1065 * cases involving ADD COLUMN and inheritance.)
1067 if (g_fout->remoteVersion >= 70300)
1068 column_list = fmtCopyColumnList(tbinfo);
1069 else
1070 column_list = ""; /* can't select columns in COPY */
1072 if (oids && hasoids)
1074 appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
1075 fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1076 classname),
1077 column_list);
1079 else
1081 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1082 fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1083 classname),
1084 column_list);
1086 res = PQexec(g_conn, q->data);
1087 check_sql_result(res, g_conn, q->data, PGRES_COPY_OUT);
1088 PQclear(res);
1090 for (;;)
1092 ret = PQgetCopyData(g_conn, &copybuf, 0);
1094 if (ret < 0)
1095 break; /* done or error */
1097 if (copybuf)
1099 WriteData(fout, copybuf, ret);
1100 PQfreemem(copybuf);
1103 /* ----------
1104 * THROTTLE:
1106 * There was considerable discussion in late July, 2000 regarding
1107 * slowing down pg_dump when backing up large tables. Users with both
1108 * slow & fast (multi-processor) machines experienced performance
1109 * degradation when doing a backup.
1111 * Initial attempts based on sleeping for a number of ms for each ms
1112 * of work were deemed too complex, then a simple 'sleep in each loop'
1113 * implementation was suggested. The latter failed because the loop
1114 * was too tight. Finally, the following was implemented:
1116 * If throttle is non-zero, then
1117 * See how long since the last sleep.
1118 * Work out how long to sleep (based on ratio).
1119 * If sleep is more than 100ms, then
1120 * sleep
1121 * reset timer
1122 * EndIf
1123 * EndIf
1125 * where the throttle value was the number of ms to sleep per ms of
1126 * work. The calculation was done in each loop.
1128 * Most of the hard work is done in the backend, and this solution
1129 * still did not work particularly well: on slow machines, the ratio
1130 * was 50:1, and on medium paced machines, 1:1, and on fast
1131 * multi-processor machines, it had little or no effect, for reasons
1132 * that were unclear.
1134 * Further discussion ensued, and the proposal was dropped.
1136 * For those people who want this feature, it can be implemented using
1137 * gettimeofday in each loop, calculating the time since last sleep,
1138 * multiplying that by the sleep ratio, then if the result is more
1139 * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1140 * function to sleep for a subsecond period ie.
1142 * select(0, NULL, NULL, NULL, &tvi);
1144 * This will return after the interval specified in the structure tvi.
1145 * Finally, call gettimeofday again to save the 'last sleep time'.
1146 * ----------
1149 archprintf(fout, "\\.\n\n\n");
1151 if (ret == -2)
1153 /* copy data transfer failed */
1154 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
1155 write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
1156 write_msg(NULL, "The command was: %s\n", q->data);
1157 exit_nicely();
1160 /* Check command status and return to normal libpq state */
1161 res = PQgetResult(g_conn);
1162 check_sql_result(res, g_conn, q->data, PGRES_COMMAND_OK);
1163 PQclear(res);
1165 destroyPQExpBuffer(q);
1166 return 1;
1169 static int
1170 dumpTableData_insert(Archive *fout, void *dcontext)
1172 TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1173 TableInfo *tbinfo = tdinfo->tdtable;
1174 const char *classname = tbinfo->dobj.name;
1175 PQExpBuffer q = createPQExpBuffer();
1176 PGresult *res;
1177 int tuple;
1178 int nfields;
1179 int field;
1182 * Make sure we are in proper schema. We will qualify the table name
1183 * below anyway (in case its name conflicts with a pg_catalog table); but
1184 * this ensures reproducible results in case the table contains regproc,
1185 * regclass, etc columns.
1187 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
1189 if (fout->remoteVersion >= 70100)
1191 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1192 "SELECT * FROM ONLY %s",
1193 fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1194 classname));
1196 else
1198 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1199 "SELECT * FROM %s",
1200 fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1201 classname));
1204 res = PQexec(g_conn, q->data);
1205 check_sql_result(res, g_conn, q->data, PGRES_COMMAND_OK);
1209 PQclear(res);
1211 res = PQexec(g_conn, "FETCH 100 FROM _pg_dump_cursor");
1212 check_sql_result(res, g_conn, "FETCH 100 FROM _pg_dump_cursor",
1213 PGRES_TUPLES_OK);
1214 nfields = PQnfields(res);
1215 for (tuple = 0; tuple < PQntuples(res); tuple++)
1217 archprintf(fout, "INSERT INTO %s ", fmtId(classname));
1218 if (nfields == 0)
1220 /* corner case for zero-column table */
1221 archprintf(fout, "DEFAULT VALUES;\n");
1222 continue;
1224 if (attrNames == true)
1226 resetPQExpBuffer(q);
1227 appendPQExpBuffer(q, "(");
1228 for (field = 0; field < nfields; field++)
1230 if (field > 0)
1231 appendPQExpBuffer(q, ", ");
1232 appendPQExpBufferStr(q, fmtId(PQfname(res, field)));
1234 appendPQExpBuffer(q, ") ");
1235 archputs(q->data, fout);
1237 archprintf(fout, "VALUES (");
1238 for (field = 0; field < nfields; field++)
1240 if (field > 0)
1241 archprintf(fout, ", ");
1242 if (PQgetisnull(res, tuple, field))
1244 archprintf(fout, "NULL");
1245 continue;
1248 /* XXX This code is partially duplicated in ruleutils.c */
1249 switch (PQftype(res, field))
1251 case INT2OID:
1252 case INT4OID:
1253 case INT8OID:
1254 case OIDOID:
1255 case FLOAT4OID:
1256 case FLOAT8OID:
1257 case NUMERICOID:
1260 * These types are printed without quotes unless
1261 * they contain values that aren't accepted by the
1262 * scanner unquoted (e.g., 'NaN'). Note that
1263 * strtod() and friends might accept NaN, so we
1264 * can't use that to test.
1266 * In reality we only need to defend against
1267 * infinity and NaN, so we need not get too crazy
1268 * about pattern matching here.
1270 const char *s = PQgetvalue(res, tuple, field);
1272 if (strspn(s, "0123456789 +-eE.") == strlen(s))
1273 archprintf(fout, "%s", s);
1274 else
1275 archprintf(fout, "'%s'", s);
1277 break;
1279 case BITOID:
1280 case VARBITOID:
1281 archprintf(fout, "B'%s'",
1282 PQgetvalue(res, tuple, field));
1283 break;
1285 case BOOLOID:
1286 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
1287 archprintf(fout, "true");
1288 else
1289 archprintf(fout, "false");
1290 break;
1292 default:
1293 /* All other types are printed as string literals. */
1294 resetPQExpBuffer(q);
1295 appendStringLiteralAH(q,
1296 PQgetvalue(res, tuple, field),
1297 fout);
1298 archputs(q->data, fout);
1299 break;
1302 archprintf(fout, ");\n");
1304 } while (PQntuples(res) > 0);
1306 PQclear(res);
1308 archprintf(fout, "\n\n");
1310 do_sql_command(g_conn, "CLOSE _pg_dump_cursor");
1312 destroyPQExpBuffer(q);
1313 return 1;
1318 * dumpTableData -
1319 * dump the contents of a single table
1321 * Actually, this just makes an ArchiveEntry for the table contents.
1323 static void
1324 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
1326 TableInfo *tbinfo = tdinfo->tdtable;
1327 PQExpBuffer copyBuf = createPQExpBuffer();
1328 DataDumperPtr dumpFn;
1329 char *copyStmt;
1331 if (!dumpInserts)
1333 /* Dump/restore using COPY */
1334 dumpFn = dumpTableData_copy;
1335 /* must use 2 steps here 'cause fmtId is nonreentrant */
1336 appendPQExpBuffer(copyBuf, "COPY %s ",
1337 fmtId(tbinfo->dobj.name));
1338 appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
1339 fmtCopyColumnList(tbinfo),
1340 (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
1341 copyStmt = copyBuf->data;
1343 else
1345 /* Restore using INSERT */
1346 dumpFn = dumpTableData_insert;
1347 copyStmt = NULL;
1350 ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
1351 tbinfo->dobj.name,
1352 tbinfo->dobj.namespace->dobj.name,
1353 NULL,
1354 tbinfo->rolname, false,
1355 "TABLE DATA", "", "", copyStmt,
1356 tdinfo->dobj.dependencies, tdinfo->dobj.nDeps,
1357 dumpFn, tdinfo);
1359 destroyPQExpBuffer(copyBuf);
1363 * getTableData -
1364 * set up dumpable objects representing the contents of tables
1366 static void
1367 getTableData(TableInfo *tblinfo, int numTables, bool oids)
1369 int i;
1371 for (i = 0; i < numTables; i++)
1373 /* Skip VIEWs (no data to dump) */
1374 if (tblinfo[i].relkind == RELKIND_VIEW)
1375 continue;
1376 /* Skip SEQUENCEs (handled elsewhere) */
1377 if (tblinfo[i].relkind == RELKIND_SEQUENCE)
1378 continue;
1380 if (tblinfo[i].dobj.dump)
1382 TableDataInfo *tdinfo;
1384 tdinfo = (TableDataInfo *) malloc(sizeof(TableDataInfo));
1386 tdinfo->dobj.objType = DO_TABLE_DATA;
1389 * Note: use tableoid 0 so that this object won't be mistaken for
1390 * something that pg_depend entries apply to.
1392 tdinfo->dobj.catId.tableoid = 0;
1393 tdinfo->dobj.catId.oid = tblinfo[i].dobj.catId.oid;
1394 AssignDumpId(&tdinfo->dobj);
1395 tdinfo->dobj.name = tblinfo[i].dobj.name;
1396 tdinfo->dobj.namespace = tblinfo[i].dobj.namespace;
1397 tdinfo->tdtable = &(tblinfo[i]);
1398 tdinfo->oids = oids;
1399 addObjectDependency(&tdinfo->dobj, tblinfo[i].dobj.dumpId);
1401 tblinfo[i].dataObj = tdinfo;
1407 * getTableDataFKConstraints -
1408 * add dump-order dependencies reflecting foreign key constraints
1410 * This code is executed only in a data-only dump --- in schema+data dumps
1411 * we handle foreign key issues by not creating the FK constraints until
1412 * after the data is loaded. In a data-only dump, however, we want to
1413 * order the table data objects in such a way that a table's referenced
1414 * tables are restored first. (In the presence of circular references or
1415 * self-references this may be impossible; we'll detect and complain about
1416 * that during the dependency sorting step.)
1418 static void
1419 getTableDataFKConstraints(void)
1421 DumpableObject **dobjs;
1422 int numObjs;
1423 int i;
1425 /* Search through all the dumpable objects for FK constraints */
1426 getDumpableObjects(&dobjs, &numObjs);
1427 for (i = 0; i < numObjs; i++)
1429 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
1431 ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
1432 TableInfo *ftable;
1434 /* Not interesting unless both tables are to be dumped */
1435 if (cinfo->contable == NULL ||
1436 cinfo->contable->dataObj == NULL)
1437 continue;
1438 ftable = findTableByOid(cinfo->confrelid);
1439 if (ftable == NULL ||
1440 ftable->dataObj == NULL)
1441 continue;
1443 * Okay, make referencing table's TABLE_DATA object depend on
1444 * the referenced table's TABLE_DATA object.
1446 addObjectDependency(&cinfo->contable->dataObj->dobj,
1447 ftable->dataObj->dobj.dumpId);
1450 free(dobjs);
1455 * guessConstraintInheritance:
1456 * In pre-8.4 databases, we can't tell for certain which constraints
1457 * are inherited. We assume a CHECK constraint is inherited if its name
1458 * matches the name of any constraint in the parent. Originally this code
1459 * tried to compare the expression texts, but that can fail for various
1460 * reasons --- for example, if the parent and child tables are in different
1461 * schemas, reverse-listing of function calls may produce different text
1462 * (schema-qualified or not) depending on search path.
1464 * In 8.4 and up we can rely on the conislocal field to decide which
1465 * constraints must be dumped; much safer.
1467 * This function assumes all conislocal flags were initialized to TRUE.
1468 * It clears the flag on anything that seems to be inherited.
1470 static void
1471 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
1473 int i,
1477 for (i = 0; i < numTables; i++)
1479 TableInfo *tbinfo = &(tblinfo[i]);
1480 int numParents;
1481 TableInfo **parents;
1482 TableInfo *parent;
1484 /* Sequences and views never have parents */
1485 if (tbinfo->relkind == RELKIND_SEQUENCE ||
1486 tbinfo->relkind == RELKIND_VIEW)
1487 continue;
1489 /* Don't bother computing anything for non-target tables, either */
1490 if (!tbinfo->dobj.dump)
1491 continue;
1493 numParents = tbinfo->numParents;
1494 parents = tbinfo->parents;
1496 if (numParents == 0)
1497 continue; /* nothing to see here, move along */
1499 /* scan for inherited CHECK constraints */
1500 for (j = 0; j < tbinfo->ncheck; j++)
1502 ConstraintInfo *constr;
1504 constr = &(tbinfo->checkexprs[j]);
1506 for (k = 0; k < numParents; k++)
1508 int l;
1510 parent = parents[k];
1511 for (l = 0; l < parent->ncheck; l++)
1513 ConstraintInfo *pconstr = &(parent->checkexprs[l]);
1515 if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
1517 constr->conislocal = false;
1518 break;
1521 if (!constr->conislocal)
1522 break;
1530 * dumpDatabase:
1531 * dump the database definition
1533 static void
1534 dumpDatabase(Archive *AH)
1536 PQExpBuffer dbQry = createPQExpBuffer();
1537 PQExpBuffer delQry = createPQExpBuffer();
1538 PQExpBuffer creaQry = createPQExpBuffer();
1539 PGresult *res;
1540 int ntups;
1541 int i_tableoid,
1542 i_oid,
1543 i_dba,
1544 i_encoding,
1545 i_collate,
1546 i_ctype,
1547 i_tablespace;
1548 CatalogId dbCatId;
1549 DumpId dbDumpId;
1550 const char *datname,
1551 *dba,
1552 *encoding,
1553 *collate,
1554 *ctype,
1555 *tablespace;
1557 datname = PQdb(g_conn);
1559 if (g_verbose)
1560 write_msg(NULL, "saving database definition\n");
1562 /* Make sure we are in proper schema */
1563 selectSourceSchema("pg_catalog");
1565 /* Get the database owner and parameters from pg_database */
1566 if (g_fout->remoteVersion >= 80400)
1568 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1569 "(%s datdba) as dba, "
1570 "pg_encoding_to_char(encoding) as encoding, "
1571 "datcollate, datctype, "
1572 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) as tablespace, "
1573 "shobj_description(oid, 'pg_database') as description "
1575 "FROM pg_database "
1576 "WHERE datname = ",
1577 username_subquery);
1578 appendStringLiteralAH(dbQry, datname, AH);
1580 else if (g_fout->remoteVersion >= 80200)
1582 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1583 "(%s datdba) as dba, "
1584 "pg_encoding_to_char(encoding) as encoding, "
1585 "NULL as datcollate, NULL as datctype, "
1586 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) as tablespace, "
1587 "shobj_description(oid, 'pg_database') as description "
1589 "FROM pg_database "
1590 "WHERE datname = ",
1591 username_subquery);
1592 appendStringLiteralAH(dbQry, datname, AH);
1594 else if (g_fout->remoteVersion >= 80000)
1596 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1597 "(%s datdba) as dba, "
1598 "pg_encoding_to_char(encoding) as encoding, "
1599 "NULL as datcollate, NULL as datctype, "
1600 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) as tablespace "
1601 "FROM pg_database "
1602 "WHERE datname = ",
1603 username_subquery);
1604 appendStringLiteralAH(dbQry, datname, AH);
1606 else if (g_fout->remoteVersion >= 70100)
1608 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1609 "(%s datdba) as dba, "
1610 "pg_encoding_to_char(encoding) as encoding, "
1611 "NULL as datcollate, NULL as datctype, "
1612 "NULL as tablespace "
1613 "FROM pg_database "
1614 "WHERE datname = ",
1615 username_subquery);
1616 appendStringLiteralAH(dbQry, datname, AH);
1618 else
1620 appendPQExpBuffer(dbQry, "SELECT "
1621 "(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, "
1622 "oid, "
1623 "(%s datdba) as dba, "
1624 "pg_encoding_to_char(encoding) as encoding, "
1625 "NULL as datcollate, NULL as datctype, "
1626 "NULL as tablespace "
1627 "FROM pg_database "
1628 "WHERE datname = ",
1629 username_subquery);
1630 appendStringLiteralAH(dbQry, datname, AH);
1633 res = PQexec(g_conn, dbQry->data);
1634 check_sql_result(res, g_conn, dbQry->data, PGRES_TUPLES_OK);
1636 ntups = PQntuples(res);
1638 if (ntups <= 0)
1640 write_msg(NULL, "missing pg_database entry for database \"%s\"\n",
1641 datname);
1642 exit_nicely();
1645 if (ntups != 1)
1647 write_msg(NULL, "query returned more than one (%d) pg_database entry for database \"%s\"\n",
1648 ntups, datname);
1649 exit_nicely();
1652 i_tableoid = PQfnumber(res, "tableoid");
1653 i_oid = PQfnumber(res, "oid");
1654 i_dba = PQfnumber(res, "dba");
1655 i_encoding = PQfnumber(res, "encoding");
1656 i_collate = PQfnumber(res, "collate");
1657 i_ctype = PQfnumber(res, "ctype");
1658 i_tablespace = PQfnumber(res, "tablespace");
1660 dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
1661 dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
1662 dba = PQgetvalue(res, 0, i_dba);
1663 encoding = PQgetvalue(res, 0, i_encoding);
1664 collate = PQgetvalue(res, 0, i_collate);
1665 ctype = PQgetvalue(res, 0, i_ctype);
1666 tablespace = PQgetvalue(res, 0, i_tablespace);
1668 appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
1669 fmtId(datname));
1670 if (strlen(encoding) > 0)
1672 appendPQExpBuffer(creaQry, " ENCODING = ");
1673 appendStringLiteralAH(creaQry, encoding, AH);
1675 if (strlen(collate) > 0)
1677 appendPQExpBuffer(creaQry, " COLLATE = ");
1678 appendStringLiteralAH(creaQry, collate, AH);
1680 if (strlen(ctype) > 0)
1682 appendPQExpBuffer(creaQry, " CTYPE = ");
1683 appendStringLiteralAH(creaQry, ctype, AH);
1685 if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0)
1686 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
1687 fmtId(tablespace));
1688 appendPQExpBuffer(creaQry, ";\n");
1690 appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
1691 fmtId(datname));
1693 dbDumpId = createDumpId();
1695 ArchiveEntry(AH,
1696 dbCatId, /* catalog ID */
1697 dbDumpId, /* dump ID */
1698 datname, /* Name */
1699 NULL, /* Namespace */
1700 NULL, /* Tablespace */
1701 dba, /* Owner */
1702 false, /* with oids */
1703 "DATABASE", /* Desc */
1704 creaQry->data, /* Create */
1705 delQry->data, /* Del */
1706 NULL, /* Copy */
1707 NULL, /* Deps */
1708 0, /* # Deps */
1709 NULL, /* Dumper */
1710 NULL); /* Dumper Arg */
1712 /* Dump DB comment if any */
1713 if (g_fout->remoteVersion >= 80200)
1716 * 8.2 keeps comments on shared objects in a shared table, so we
1717 * cannot use the dumpComment used for other database objects.
1719 char *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
1721 if (comment && strlen(comment))
1723 resetPQExpBuffer(dbQry);
1724 /* Generates warning when loaded into a differently-named database.*/
1725 appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
1726 appendStringLiteralAH(dbQry, comment, AH);
1727 appendPQExpBuffer(dbQry, ";\n");
1729 ArchiveEntry(AH, dbCatId, createDumpId(), datname, NULL, NULL,
1730 dba, false, "COMMENT", dbQry->data, "", NULL,
1731 &dbDumpId, 1, NULL, NULL);
1734 else
1736 resetPQExpBuffer(dbQry);
1737 appendPQExpBuffer(dbQry, "DATABASE %s", fmtId(datname));
1738 dumpComment(AH, dbQry->data, NULL, "",
1739 dbCatId, 0, dbDumpId);
1742 PQclear(res);
1744 destroyPQExpBuffer(dbQry);
1745 destroyPQExpBuffer(delQry);
1746 destroyPQExpBuffer(creaQry);
1751 * dumpEncoding: put the correct encoding into the archive
1753 static void
1754 dumpEncoding(Archive *AH)
1756 const char *encname = pg_encoding_to_char(AH->encoding);
1757 PQExpBuffer qry = createPQExpBuffer();
1759 if (g_verbose)
1760 write_msg(NULL, "saving encoding = %s\n", encname);
1762 appendPQExpBuffer(qry, "SET client_encoding = ");
1763 appendStringLiteralAH(qry, encname, AH);
1764 appendPQExpBuffer(qry, ";\n");
1766 ArchiveEntry(AH, nilCatalogId, createDumpId(),
1767 "ENCODING", NULL, NULL, "",
1768 false, "ENCODING", qry->data, "", NULL,
1769 NULL, 0,
1770 NULL, NULL);
1772 destroyPQExpBuffer(qry);
1777 * dumpStdStrings: put the correct escape string behavior into the archive
1779 static void
1780 dumpStdStrings(Archive *AH)
1782 const char *stdstrings = AH->std_strings ? "on" : "off";
1783 PQExpBuffer qry = createPQExpBuffer();
1785 if (g_verbose)
1786 write_msg(NULL, "saving standard_conforming_strings = %s\n",
1787 stdstrings);
1789 appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
1790 stdstrings);
1792 ArchiveEntry(AH, nilCatalogId, createDumpId(),
1793 "STDSTRINGS", NULL, NULL, "",
1794 false, "STDSTRINGS", qry->data, "", NULL,
1795 NULL, 0,
1796 NULL, NULL);
1798 destroyPQExpBuffer(qry);
1803 * hasBlobs:
1804 * Test whether database contains any large objects
1806 static bool
1807 hasBlobs(Archive *AH)
1809 bool result;
1810 const char *blobQry;
1811 PGresult *res;
1813 /* Make sure we are in proper schema */
1814 selectSourceSchema("pg_catalog");
1816 /* Check for BLOB OIDs */
1817 if (AH->remoteVersion >= 70100)
1818 blobQry = "SELECT loid FROM pg_largeobject LIMIT 1";
1819 else
1820 blobQry = "SELECT oid FROM pg_class WHERE relkind = 'l' LIMIT 1";
1822 res = PQexec(g_conn, blobQry);
1823 check_sql_result(res, g_conn, blobQry, PGRES_TUPLES_OK);
1825 result = PQntuples(res) > 0;
1827 PQclear(res);
1829 return result;
1833 * dumpBlobs:
1834 * dump all blobs
1836 static int
1837 dumpBlobs(Archive *AH, void *arg)
1839 const char *blobQry;
1840 const char *blobFetchQry;
1841 PGresult *res;
1842 char buf[LOBBUFSIZE];
1843 int i;
1844 int cnt;
1846 if (g_verbose)
1847 write_msg(NULL, "saving large objects\n");
1849 /* Make sure we are in proper schema */
1850 selectSourceSchema("pg_catalog");
1852 /* Cursor to get all BLOB OIDs */
1853 if (AH->remoteVersion >= 70100)
1854 blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
1855 else
1856 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'";
1858 res = PQexec(g_conn, blobQry);
1859 check_sql_result(res, g_conn, blobQry, PGRES_COMMAND_OK);
1861 /* Command to fetch from cursor */
1862 blobFetchQry = "FETCH 1000 IN bloboid";
1866 PQclear(res);
1868 /* Do a fetch */
1869 res = PQexec(g_conn, blobFetchQry);
1870 check_sql_result(res, g_conn, blobFetchQry, PGRES_TUPLES_OK);
1872 /* Process the tuples, if any */
1873 for (i = 0; i < PQntuples(res); i++)
1875 Oid blobOid;
1876 int loFd;
1878 blobOid = atooid(PQgetvalue(res, i, 0));
1879 /* Open the BLOB */
1880 loFd = lo_open(g_conn, blobOid, INV_READ);
1881 if (loFd == -1)
1883 write_msg(NULL, "dumpBlobs(): could not open large object: %s",
1884 PQerrorMessage(g_conn));
1885 exit_nicely();
1888 StartBlob(AH, blobOid);
1890 /* Now read it in chunks, sending data to archive */
1893 cnt = lo_read(g_conn, loFd, buf, LOBBUFSIZE);
1894 if (cnt < 0)
1896 write_msg(NULL, "dumpBlobs(): error reading large object: %s",
1897 PQerrorMessage(g_conn));
1898 exit_nicely();
1901 WriteData(AH, buf, cnt);
1902 } while (cnt > 0);
1904 lo_close(g_conn, loFd);
1906 EndBlob(AH, blobOid);
1908 } while (PQntuples(res) > 0);
1910 PQclear(res);
1912 return 1;
1916 * dumpBlobComments
1917 * dump all blob comments
1919 * Since we don't provide any way to be selective about dumping blobs,
1920 * there's no need to be selective about their comments either. We put
1921 * all the comments into one big TOC entry.
1923 static int
1924 dumpBlobComments(Archive *AH, void *arg)
1926 const char *blobQry;
1927 const char *blobFetchQry;
1928 PQExpBuffer commentcmd = createPQExpBuffer();
1929 PGresult *res;
1930 int i;
1932 if (g_verbose)
1933 write_msg(NULL, "saving large object comments\n");
1935 /* Make sure we are in proper schema */
1936 selectSourceSchema("pg_catalog");
1938 /* Cursor to get all BLOB comments */
1939 if (AH->remoteVersion >= 70200)
1940 blobQry = "DECLARE blobcmt CURSOR FOR SELECT loid, obj_description(loid, 'pg_largeobject') FROM (SELECT DISTINCT loid FROM pg_largeobject) ss";
1941 else if (AH->remoteVersion >= 70100)
1942 blobQry = "DECLARE blobcmt CURSOR FOR SELECT loid, obj_description(loid) FROM (SELECT DISTINCT loid FROM pg_largeobject) ss";
1943 else
1944 blobQry = "DECLARE blobcmt CURSOR FOR SELECT oid, (SELECT description FROM pg_description pd WHERE pd.objoid=pc.oid) FROM pg_class pc WHERE relkind = 'l'";
1946 res = PQexec(g_conn, blobQry);
1947 check_sql_result(res, g_conn, blobQry, PGRES_COMMAND_OK);
1949 /* Command to fetch from cursor */
1950 blobFetchQry = "FETCH 100 IN blobcmt";
1954 PQclear(res);
1956 /* Do a fetch */
1957 res = PQexec(g_conn, blobFetchQry);
1958 check_sql_result(res, g_conn, blobFetchQry, PGRES_TUPLES_OK);
1960 /* Process the tuples, if any */
1961 for (i = 0; i < PQntuples(res); i++)
1963 Oid blobOid;
1964 char *comment;
1966 /* ignore blobs without comments */
1967 if (PQgetisnull(res, i, 1))
1968 continue;
1970 blobOid = atooid(PQgetvalue(res, i, 0));
1971 comment = PQgetvalue(res, i, 1);
1973 printfPQExpBuffer(commentcmd, "COMMENT ON LARGE OBJECT %u IS ",
1974 blobOid);
1975 appendStringLiteralAH(commentcmd, comment, AH);
1976 appendPQExpBuffer(commentcmd, ";\n");
1978 archputs(commentcmd->data, AH);
1980 } while (PQntuples(res) > 0);
1982 PQclear(res);
1984 archputs("\n", AH);
1986 destroyPQExpBuffer(commentcmd);
1988 return 1;
1992 * getNamespaces:
1993 * read all namespaces in the system catalogs and return them in the
1994 * NamespaceInfo* structure
1996 * numNamespaces is set to the number of namespaces read in
1998 NamespaceInfo *
1999 getNamespaces(int *numNamespaces)
2001 PGresult *res;
2002 int ntups;
2003 int i;
2004 PQExpBuffer query;
2005 NamespaceInfo *nsinfo;
2006 int i_tableoid;
2007 int i_oid;
2008 int i_nspname;
2009 int i_rolname;
2010 int i_nspacl;
2013 * Before 7.3, there are no real namespaces; create two dummy entries, one
2014 * for user stuff and one for system stuff.
2016 if (g_fout->remoteVersion < 70300)
2018 nsinfo = (NamespaceInfo *) malloc(2 * sizeof(NamespaceInfo));
2020 nsinfo[0].dobj.objType = DO_NAMESPACE;
2021 nsinfo[0].dobj.catId.tableoid = 0;
2022 nsinfo[0].dobj.catId.oid = 0;
2023 AssignDumpId(&nsinfo[0].dobj);
2024 nsinfo[0].dobj.name = strdup("public");
2025 nsinfo[0].rolname = strdup("");
2026 nsinfo[0].nspacl = strdup("");
2028 selectDumpableNamespace(&nsinfo[0]);
2030 nsinfo[1].dobj.objType = DO_NAMESPACE;
2031 nsinfo[1].dobj.catId.tableoid = 0;
2032 nsinfo[1].dobj.catId.oid = 1;
2033 AssignDumpId(&nsinfo[1].dobj);
2034 nsinfo[1].dobj.name = strdup("pg_catalog");
2035 nsinfo[1].rolname = strdup("");
2036 nsinfo[1].nspacl = strdup("");
2038 selectDumpableNamespace(&nsinfo[1]);
2040 g_namespaces = nsinfo;
2041 g_numNamespaces = *numNamespaces = 2;
2043 return nsinfo;
2046 query = createPQExpBuffer();
2048 /* Make sure we are in proper schema */
2049 selectSourceSchema("pg_catalog");
2052 * we fetch all namespaces including system ones, so that every object we
2053 * read in can be linked to a containing namespace.
2055 appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
2056 "(%s nspowner) as rolname, "
2057 "nspacl FROM pg_namespace",
2058 username_subquery);
2060 res = PQexec(g_conn, query->data);
2061 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2063 ntups = PQntuples(res);
2065 nsinfo = (NamespaceInfo *) malloc(ntups * sizeof(NamespaceInfo));
2067 i_tableoid = PQfnumber(res, "tableoid");
2068 i_oid = PQfnumber(res, "oid");
2069 i_nspname = PQfnumber(res, "nspname");
2070 i_rolname = PQfnumber(res, "rolname");
2071 i_nspacl = PQfnumber(res, "nspacl");
2073 for (i = 0; i < ntups; i++)
2075 nsinfo[i].dobj.objType = DO_NAMESPACE;
2076 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2077 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2078 AssignDumpId(&nsinfo[i].dobj);
2079 nsinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_nspname));
2080 nsinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2081 nsinfo[i].nspacl = strdup(PQgetvalue(res, i, i_nspacl));
2083 /* Decide whether to dump this namespace */
2084 selectDumpableNamespace(&nsinfo[i]);
2086 if (strlen(nsinfo[i].rolname) == 0)
2087 write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
2088 nsinfo[i].dobj.name);
2091 PQclear(res);
2092 destroyPQExpBuffer(query);
2094 g_namespaces = nsinfo;
2095 g_numNamespaces = *numNamespaces = ntups;
2097 return nsinfo;
2101 * findNamespace:
2102 * given a namespace OID and an object OID, look up the info read by
2103 * getNamespaces
2105 * NB: for pre-7.3 source database, we use object OID to guess whether it's
2106 * a system object or not. In 7.3 and later there is no guessing.
2108 static NamespaceInfo *
2109 findNamespace(Oid nsoid, Oid objoid)
2111 int i;
2113 if (g_fout->remoteVersion >= 70300)
2115 for (i = 0; i < g_numNamespaces; i++)
2117 NamespaceInfo *nsinfo = &g_namespaces[i];
2119 if (nsoid == nsinfo->dobj.catId.oid)
2120 return nsinfo;
2122 write_msg(NULL, "schema with OID %u does not exist\n", nsoid);
2123 exit_nicely();
2125 else
2127 /* This code depends on the layout set up by getNamespaces. */
2128 if (objoid > g_last_builtin_oid)
2129 i = 0; /* user object */
2130 else
2131 i = 1; /* system object */
2132 return &g_namespaces[i];
2135 return NULL; /* keep compiler quiet */
2139 * getTypes:
2140 * read all types in the system catalogs and return them in the
2141 * TypeInfo* structure
2143 * numTypes is set to the number of types read in
2145 * NB: this must run after getFuncs() because we assume we can do
2146 * findFuncByOid().
2148 TypeInfo *
2149 getTypes(int *numTypes)
2151 PGresult *res;
2152 int ntups;
2153 int i;
2154 PQExpBuffer query = createPQExpBuffer();
2155 TypeInfo *tinfo;
2156 ShellTypeInfo *stinfo;
2157 int i_tableoid;
2158 int i_oid;
2159 int i_typname;
2160 int i_typnamespace;
2161 int i_rolname;
2162 int i_typinput;
2163 int i_typoutput;
2164 int i_typelem;
2165 int i_typrelid;
2166 int i_typrelkind;
2167 int i_typtype;
2168 int i_typisdefined;
2169 int i_isarray;
2172 * we include even the built-in types because those may be used as array
2173 * elements by user-defined types
2175 * we filter out the built-in types when we dump out the types
2177 * same approach for undefined (shell) types and array types
2179 * Note: as of 8.3 we can reliably detect whether a type is an
2180 * auto-generated array type by checking the element type's typarray.
2181 * (Before that the test is capable of generating false positives.) We
2182 * still check for name beginning with '_', though, so as to avoid the
2183 * cost of the subselect probe for all standard types. This would have to
2184 * be revisited if the backend ever allows renaming of array types.
2187 /* Make sure we are in proper schema */
2188 selectSourceSchema("pg_catalog");
2190 if (g_fout->remoteVersion >= 80300)
2192 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2193 "typnamespace, "
2194 "(%s typowner) as rolname, "
2195 "typinput::oid as typinput, "
2196 "typoutput::oid as typoutput, typelem, typrelid, "
2197 "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2198 "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END as typrelkind, "
2199 "typtype, typisdefined, "
2200 "typname[0] = '_' AND typelem != 0 AND "
2201 "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
2202 "FROM pg_type",
2203 username_subquery);
2205 else if (g_fout->remoteVersion >= 70300)
2207 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2208 "typnamespace, "
2209 "(%s typowner) as rolname, "
2210 "typinput::oid as typinput, "
2211 "typoutput::oid as typoutput, typelem, typrelid, "
2212 "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2213 "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END as typrelkind, "
2214 "typtype, typisdefined, "
2215 "typname[0] = '_' AND typelem != 0 AS isarray "
2216 "FROM pg_type",
2217 username_subquery);
2219 else if (g_fout->remoteVersion >= 70100)
2221 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2222 "0::oid as typnamespace, "
2223 "(%s typowner) as rolname, "
2224 "typinput::oid as typinput, "
2225 "typoutput::oid as typoutput, typelem, typrelid, "
2226 "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2227 "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END as typrelkind, "
2228 "typtype, typisdefined, "
2229 "typname[0] = '_' AND typelem != 0 AS isarray "
2230 "FROM pg_type",
2231 username_subquery);
2233 else
2235 appendPQExpBuffer(query, "SELECT "
2236 "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
2237 "oid, typname, "
2238 "0::oid as typnamespace, "
2239 "(%s typowner) as rolname, "
2240 "typinput::oid as typinput, "
2241 "typoutput::oid as typoutput, typelem, typrelid, "
2242 "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2243 "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END as typrelkind, "
2244 "typtype, typisdefined, "
2245 "typname[0] = '_' AND typelem != 0 AS isarray "
2246 "FROM pg_type",
2247 username_subquery);
2250 res = PQexec(g_conn, query->data);
2251 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2253 ntups = PQntuples(res);
2255 tinfo = (TypeInfo *) malloc(ntups * sizeof(TypeInfo));
2257 i_tableoid = PQfnumber(res, "tableoid");
2258 i_oid = PQfnumber(res, "oid");
2259 i_typname = PQfnumber(res, "typname");
2260 i_typnamespace = PQfnumber(res, "typnamespace");
2261 i_rolname = PQfnumber(res, "rolname");
2262 i_typinput = PQfnumber(res, "typinput");
2263 i_typoutput = PQfnumber(res, "typoutput");
2264 i_typelem = PQfnumber(res, "typelem");
2265 i_typrelid = PQfnumber(res, "typrelid");
2266 i_typrelkind = PQfnumber(res, "typrelkind");
2267 i_typtype = PQfnumber(res, "typtype");
2268 i_typisdefined = PQfnumber(res, "typisdefined");
2269 i_isarray = PQfnumber(res, "isarray");
2271 for (i = 0; i < ntups; i++)
2273 tinfo[i].dobj.objType = DO_TYPE;
2274 tinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2275 tinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2276 AssignDumpId(&tinfo[i].dobj);
2277 tinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_typname));
2278 tinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)),
2279 tinfo[i].dobj.catId.oid);
2280 tinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2281 tinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
2282 tinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
2283 tinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
2284 tinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
2285 tinfo[i].shellType = NULL;
2288 * If it's a table's rowtype, use special type code to facilitate
2289 * sorting into the desired order. (We don't want to consider it an
2290 * ordinary type because that would bring the table up into the
2291 * datatype part of the dump order.)
2293 if (OidIsValid(tinfo[i].typrelid) &&
2294 tinfo[i].typrelkind != RELKIND_COMPOSITE_TYPE)
2295 tinfo[i].dobj.objType = DO_TABLE_TYPE;
2297 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
2298 tinfo[i].isDefined = true;
2299 else
2300 tinfo[i].isDefined = false;
2302 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
2303 tinfo[i].isArray = true;
2304 else
2305 tinfo[i].isArray = false;
2307 /* Decide whether we want to dump it */
2308 selectDumpableType(&tinfo[i]);
2311 * If it's a domain, fetch info about its constraints, if any
2313 tinfo[i].nDomChecks = 0;
2314 tinfo[i].domChecks = NULL;
2315 if (tinfo[i].dobj.dump && tinfo[i].typtype == TYPTYPE_DOMAIN)
2316 getDomainConstraints(&(tinfo[i]));
2319 * If it's a base type, make a DumpableObject representing a shell
2320 * definition of the type. We will need to dump that ahead of the I/O
2321 * functions for the type.
2323 * Note: the shell type doesn't have a catId. You might think it
2324 * should copy the base type's catId, but then it might capture the
2325 * pg_depend entries for the type, which we don't want.
2327 if (tinfo[i].dobj.dump && tinfo[i].typtype == TYPTYPE_BASE)
2329 stinfo = (ShellTypeInfo *) malloc(sizeof(ShellTypeInfo));
2330 stinfo->dobj.objType = DO_SHELL_TYPE;
2331 stinfo->dobj.catId = nilCatalogId;
2332 AssignDumpId(&stinfo->dobj);
2333 stinfo->dobj.name = strdup(tinfo[i].dobj.name);
2334 stinfo->dobj.namespace = tinfo[i].dobj.namespace;
2335 stinfo->baseType = &(tinfo[i]);
2336 tinfo[i].shellType = stinfo;
2339 * Initially mark the shell type as not to be dumped. We'll only
2340 * dump it if the I/O functions need to be dumped; this is taken
2341 * care of while sorting dependencies.
2343 stinfo->dobj.dump = false;
2346 * However, if dumping from pre-7.3, there will be no dependency
2347 * info so we have to fake it here. We only need to worry about
2348 * typinput and typoutput since the other functions only exist
2349 * post-7.3.
2351 if (g_fout->remoteVersion < 70300)
2353 Oid typinput;
2354 Oid typoutput;
2355 FuncInfo *funcInfo;
2357 typinput = atooid(PQgetvalue(res, i, i_typinput));
2358 typoutput = atooid(PQgetvalue(res, i, i_typoutput));
2360 funcInfo = findFuncByOid(typinput);
2361 if (funcInfo && funcInfo->dobj.dump)
2363 /* base type depends on function */
2364 addObjectDependency(&tinfo[i].dobj,
2365 funcInfo->dobj.dumpId);
2366 /* function depends on shell type */
2367 addObjectDependency(&funcInfo->dobj,
2368 stinfo->dobj.dumpId);
2369 /* mark shell type as to be dumped */
2370 stinfo->dobj.dump = true;
2373 funcInfo = findFuncByOid(typoutput);
2374 if (funcInfo && funcInfo->dobj.dump)
2376 /* base type depends on function */
2377 addObjectDependency(&tinfo[i].dobj,
2378 funcInfo->dobj.dumpId);
2379 /* function depends on shell type */
2380 addObjectDependency(&funcInfo->dobj,
2381 stinfo->dobj.dumpId);
2382 /* mark shell type as to be dumped */
2383 stinfo->dobj.dump = true;
2388 if (strlen(tinfo[i].rolname) == 0 && tinfo[i].isDefined)
2389 write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
2390 tinfo[i].dobj.name);
2393 *numTypes = ntups;
2395 PQclear(res);
2397 destroyPQExpBuffer(query);
2399 return tinfo;
2403 * getOperators:
2404 * read all operators in the system catalogs and return them in the
2405 * OprInfo* structure
2407 * numOprs is set to the number of operators read in
2409 OprInfo *
2410 getOperators(int *numOprs)
2412 PGresult *res;
2413 int ntups;
2414 int i;
2415 PQExpBuffer query = createPQExpBuffer();
2416 OprInfo *oprinfo;
2417 int i_tableoid;
2418 int i_oid;
2419 int i_oprname;
2420 int i_oprnamespace;
2421 int i_rolname;
2422 int i_oprcode;
2425 * find all operators, including builtin operators; we filter out
2426 * system-defined operators at dump-out time.
2429 /* Make sure we are in proper schema */
2430 selectSourceSchema("pg_catalog");
2432 if (g_fout->remoteVersion >= 70300)
2434 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
2435 "oprnamespace, "
2436 "(%s oprowner) as rolname, "
2437 "oprcode::oid as oprcode "
2438 "FROM pg_operator",
2439 username_subquery);
2441 else if (g_fout->remoteVersion >= 70100)
2443 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
2444 "0::oid as oprnamespace, "
2445 "(%s oprowner) as rolname, "
2446 "oprcode::oid as oprcode "
2447 "FROM pg_operator",
2448 username_subquery);
2450 else
2452 appendPQExpBuffer(query, "SELECT "
2453 "(SELECT oid FROM pg_class WHERE relname = 'pg_operator') AS tableoid, "
2454 "oid, oprname, "
2455 "0::oid as oprnamespace, "
2456 "(%s oprowner) as rolname, "
2457 "oprcode::oid as oprcode "
2458 "FROM pg_operator",
2459 username_subquery);
2462 res = PQexec(g_conn, query->data);
2463 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2465 ntups = PQntuples(res);
2466 *numOprs = ntups;
2468 oprinfo = (OprInfo *) malloc(ntups * sizeof(OprInfo));
2470 i_tableoid = PQfnumber(res, "tableoid");
2471 i_oid = PQfnumber(res, "oid");
2472 i_oprname = PQfnumber(res, "oprname");
2473 i_oprnamespace = PQfnumber(res, "oprnamespace");
2474 i_rolname = PQfnumber(res, "rolname");
2475 i_oprcode = PQfnumber(res, "oprcode");
2477 for (i = 0; i < ntups; i++)
2479 oprinfo[i].dobj.objType = DO_OPERATOR;
2480 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2481 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2482 AssignDumpId(&oprinfo[i].dobj);
2483 oprinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_oprname));
2484 oprinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)),
2485 oprinfo[i].dobj.catId.oid);
2486 oprinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2487 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
2489 /* Decide whether we want to dump it */
2490 selectDumpableObject(&(oprinfo[i].dobj));
2492 if (strlen(oprinfo[i].rolname) == 0)
2493 write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
2494 oprinfo[i].dobj.name);
2497 PQclear(res);
2499 destroyPQExpBuffer(query);
2501 return oprinfo;
2505 * getConversions:
2506 * read all conversions in the system catalogs and return them in the
2507 * ConvInfo* structure
2509 * numConversions is set to the number of conversions read in
2511 ConvInfo *
2512 getConversions(int *numConversions)
2514 PGresult *res;
2515 int ntups;
2516 int i;
2517 PQExpBuffer query = createPQExpBuffer();
2518 ConvInfo *convinfo;
2519 int i_tableoid;
2520 int i_oid;
2521 int i_conname;
2522 int i_connamespace;
2523 int i_rolname;
2525 /* Conversions didn't exist pre-7.3 */
2526 if (g_fout->remoteVersion < 70300)
2528 *numConversions = 0;
2529 return NULL;
2533 * find all conversions, including builtin conversions; we filter out
2534 * system-defined conversions at dump-out time.
2537 /* Make sure we are in proper schema */
2538 selectSourceSchema("pg_catalog");
2540 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
2541 "connamespace, "
2542 "(%s conowner) as rolname "
2543 "FROM pg_conversion",
2544 username_subquery);
2546 res = PQexec(g_conn, query->data);
2547 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2549 ntups = PQntuples(res);
2550 *numConversions = ntups;
2552 convinfo = (ConvInfo *) malloc(ntups * sizeof(ConvInfo));
2554 i_tableoid = PQfnumber(res, "tableoid");
2555 i_oid = PQfnumber(res, "oid");
2556 i_conname = PQfnumber(res, "conname");
2557 i_connamespace = PQfnumber(res, "connamespace");
2558 i_rolname = PQfnumber(res, "rolname");
2560 for (i = 0; i < ntups; i++)
2562 convinfo[i].dobj.objType = DO_CONVERSION;
2563 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2564 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2565 AssignDumpId(&convinfo[i].dobj);
2566 convinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_conname));
2567 convinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_connamespace)),
2568 convinfo[i].dobj.catId.oid);
2569 convinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2571 /* Decide whether we want to dump it */
2572 selectDumpableObject(&(convinfo[i].dobj));
2575 PQclear(res);
2577 destroyPQExpBuffer(query);
2579 return convinfo;
2583 * getOpclasses:
2584 * read all opclasses in the system catalogs and return them in the
2585 * OpclassInfo* structure
2587 * numOpclasses is set to the number of opclasses read in
2589 OpclassInfo *
2590 getOpclasses(int *numOpclasses)
2592 PGresult *res;
2593 int ntups;
2594 int i;
2595 PQExpBuffer query = createPQExpBuffer();
2596 OpclassInfo *opcinfo;
2597 int i_tableoid;
2598 int i_oid;
2599 int i_opcname;
2600 int i_opcnamespace;
2601 int i_rolname;
2604 * find all opclasses, including builtin opclasses; we filter out
2605 * system-defined opclasses at dump-out time.
2608 /* Make sure we are in proper schema */
2609 selectSourceSchema("pg_catalog");
2611 if (g_fout->remoteVersion >= 70300)
2613 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
2614 "opcnamespace, "
2615 "(%s opcowner) as rolname "
2616 "FROM pg_opclass",
2617 username_subquery);
2619 else if (g_fout->remoteVersion >= 70100)
2621 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
2622 "0::oid as opcnamespace, "
2623 "''::name as rolname "
2624 "FROM pg_opclass");
2626 else
2628 appendPQExpBuffer(query, "SELECT "
2629 "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, "
2630 "oid, opcname, "
2631 "0::oid as opcnamespace, "
2632 "''::name as rolname "
2633 "FROM pg_opclass");
2636 res = PQexec(g_conn, query->data);
2637 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2639 ntups = PQntuples(res);
2640 *numOpclasses = ntups;
2642 opcinfo = (OpclassInfo *) malloc(ntups * sizeof(OpclassInfo));
2644 i_tableoid = PQfnumber(res, "tableoid");
2645 i_oid = PQfnumber(res, "oid");
2646 i_opcname = PQfnumber(res, "opcname");
2647 i_opcnamespace = PQfnumber(res, "opcnamespace");
2648 i_rolname = PQfnumber(res, "rolname");
2650 for (i = 0; i < ntups; i++)
2652 opcinfo[i].dobj.objType = DO_OPCLASS;
2653 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2654 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2655 AssignDumpId(&opcinfo[i].dobj);
2656 opcinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_opcname));
2657 opcinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)),
2658 opcinfo[i].dobj.catId.oid);
2659 opcinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2661 /* Decide whether we want to dump it */
2662 selectDumpableObject(&(opcinfo[i].dobj));
2664 if (g_fout->remoteVersion >= 70300)
2666 if (strlen(opcinfo[i].rolname) == 0)
2667 write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
2668 opcinfo[i].dobj.name);
2672 PQclear(res);
2674 destroyPQExpBuffer(query);
2676 return opcinfo;
2680 * getOpfamilies:
2681 * read all opfamilies in the system catalogs and return them in the
2682 * OpfamilyInfo* structure
2684 * numOpfamilies is set to the number of opfamilies read in
2686 OpfamilyInfo *
2687 getOpfamilies(int *numOpfamilies)
2689 PGresult *res;
2690 int ntups;
2691 int i;
2692 PQExpBuffer query;
2693 OpfamilyInfo *opfinfo;
2694 int i_tableoid;
2695 int i_oid;
2696 int i_opfname;
2697 int i_opfnamespace;
2698 int i_rolname;
2700 /* Before 8.3, there is no separate concept of opfamilies */
2701 if (g_fout->remoteVersion < 80300)
2703 *numOpfamilies = 0;
2704 return NULL;
2707 query = createPQExpBuffer();
2710 * find all opfamilies, including builtin opfamilies; we filter out
2711 * system-defined opfamilies at dump-out time.
2714 /* Make sure we are in proper schema */
2715 selectSourceSchema("pg_catalog");
2717 appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
2718 "opfnamespace, "
2719 "(%s opfowner) as rolname "
2720 "FROM pg_opfamily",
2721 username_subquery);
2723 res = PQexec(g_conn, query->data);
2724 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2726 ntups = PQntuples(res);
2727 *numOpfamilies = ntups;
2729 opfinfo = (OpfamilyInfo *) malloc(ntups * sizeof(OpfamilyInfo));
2731 i_tableoid = PQfnumber(res, "tableoid");
2732 i_oid = PQfnumber(res, "oid");
2733 i_opfname = PQfnumber(res, "opfname");
2734 i_opfnamespace = PQfnumber(res, "opfnamespace");
2735 i_rolname = PQfnumber(res, "rolname");
2737 for (i = 0; i < ntups; i++)
2739 opfinfo[i].dobj.objType = DO_OPFAMILY;
2740 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2741 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2742 AssignDumpId(&opfinfo[i].dobj);
2743 opfinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_opfname));
2744 opfinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)),
2745 opfinfo[i].dobj.catId.oid);
2746 opfinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2748 /* Decide whether we want to dump it */
2749 selectDumpableObject(&(opfinfo[i].dobj));
2751 if (g_fout->remoteVersion >= 70300)
2753 if (strlen(opfinfo[i].rolname) == 0)
2754 write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
2755 opfinfo[i].dobj.name);
2759 PQclear(res);
2761 destroyPQExpBuffer(query);
2763 return opfinfo;
2767 * getAggregates:
2768 * read all the user-defined aggregates in the system catalogs and
2769 * return them in the AggInfo* structure
2771 * numAggs is set to the number of aggregates read in
2773 AggInfo *
2774 getAggregates(int *numAggs)
2776 PGresult *res;
2777 int ntups;
2778 int i;
2779 PQExpBuffer query = createPQExpBuffer();
2780 AggInfo *agginfo;
2781 int i_tableoid;
2782 int i_oid;
2783 int i_aggname;
2784 int i_aggnamespace;
2785 int i_pronargs;
2786 int i_proargtypes;
2787 int i_rolname;
2788 int i_aggacl;
2790 /* Make sure we are in proper schema */
2791 selectSourceSchema("pg_catalog");
2793 /* find all user-defined aggregates */
2795 if (g_fout->remoteVersion >= 80200)
2797 appendPQExpBuffer(query, "SELECT tableoid, oid, proname as aggname, "
2798 "pronamespace as aggnamespace, "
2799 "pronargs, proargtypes, "
2800 "(%s proowner) as rolname, "
2801 "proacl as aggacl "
2802 "FROM pg_proc "
2803 "WHERE proisagg "
2804 "AND pronamespace != "
2805 "(select oid from pg_namespace where nspname = 'pg_catalog')",
2806 username_subquery);
2808 else if (g_fout->remoteVersion >= 70300)
2810 appendPQExpBuffer(query, "SELECT tableoid, oid, proname as aggname, "
2811 "pronamespace as aggnamespace, "
2812 "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END as pronargs, "
2813 "proargtypes, "
2814 "(%s proowner) as rolname, "
2815 "proacl as aggacl "
2816 "FROM pg_proc "
2817 "WHERE proisagg "
2818 "AND pronamespace != "
2819 "(select oid from pg_namespace where nspname = 'pg_catalog')",
2820 username_subquery);
2822 else if (g_fout->remoteVersion >= 70100)
2824 appendPQExpBuffer(query, "SELECT tableoid, oid, aggname, "
2825 "0::oid as aggnamespace, "
2826 "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END as pronargs, "
2827 "aggbasetype as proargtypes, "
2828 "(%s aggowner) as rolname, "
2829 "'{=X}' as aggacl "
2830 "FROM pg_aggregate "
2831 "where oid > '%u'::oid",
2832 username_subquery,
2833 g_last_builtin_oid);
2835 else
2837 appendPQExpBuffer(query, "SELECT "
2838 "(SELECT oid FROM pg_class WHERE relname = 'pg_aggregate') AS tableoid, "
2839 "oid, aggname, "
2840 "0::oid as aggnamespace, "
2841 "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END as pronargs, "
2842 "aggbasetype as proargtypes, "
2843 "(%s aggowner) as rolname, "
2844 "'{=X}' as aggacl "
2845 "FROM pg_aggregate "
2846 "where oid > '%u'::oid",
2847 username_subquery,
2848 g_last_builtin_oid);
2851 res = PQexec(g_conn, query->data);
2852 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2854 ntups = PQntuples(res);
2855 *numAggs = ntups;
2857 agginfo = (AggInfo *) malloc(ntups * sizeof(AggInfo));
2859 i_tableoid = PQfnumber(res, "tableoid");
2860 i_oid = PQfnumber(res, "oid");
2861 i_aggname = PQfnumber(res, "aggname");
2862 i_aggnamespace = PQfnumber(res, "aggnamespace");
2863 i_pronargs = PQfnumber(res, "pronargs");
2864 i_proargtypes = PQfnumber(res, "proargtypes");
2865 i_rolname = PQfnumber(res, "rolname");
2866 i_aggacl = PQfnumber(res, "aggacl");
2868 for (i = 0; i < ntups; i++)
2870 agginfo[i].aggfn.dobj.objType = DO_AGG;
2871 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2872 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2873 AssignDumpId(&agginfo[i].aggfn.dobj);
2874 agginfo[i].aggfn.dobj.name = strdup(PQgetvalue(res, i, i_aggname));
2875 agginfo[i].aggfn.dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)),
2876 agginfo[i].aggfn.dobj.catId.oid);
2877 agginfo[i].aggfn.rolname = strdup(PQgetvalue(res, i, i_rolname));
2878 if (strlen(agginfo[i].aggfn.rolname) == 0)
2879 write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
2880 agginfo[i].aggfn.dobj.name);
2881 agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
2882 agginfo[i].aggfn.prorettype = InvalidOid; /* not saved */
2883 agginfo[i].aggfn.proacl = strdup(PQgetvalue(res, i, i_aggacl));
2884 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
2885 if (agginfo[i].aggfn.nargs == 0)
2886 agginfo[i].aggfn.argtypes = NULL;
2887 else
2889 agginfo[i].aggfn.argtypes = (Oid *) malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
2890 if (g_fout->remoteVersion >= 70300)
2891 parseOidArray(PQgetvalue(res, i, i_proargtypes),
2892 agginfo[i].aggfn.argtypes,
2893 agginfo[i].aggfn.nargs);
2894 else
2895 /* it's just aggbasetype */
2896 agginfo[i].aggfn.argtypes[0] = atooid(PQgetvalue(res, i, i_proargtypes));
2899 /* Decide whether we want to dump it */
2900 selectDumpableObject(&(agginfo[i].aggfn.dobj));
2903 PQclear(res);
2905 destroyPQExpBuffer(query);
2907 return agginfo;
2911 * getFuncs:
2912 * read all the user-defined functions in the system catalogs and
2913 * return them in the FuncInfo* structure
2915 * numFuncs is set to the number of functions read in
2917 FuncInfo *
2918 getFuncs(int *numFuncs)
2920 PGresult *res;
2921 int ntups;
2922 int i;
2923 PQExpBuffer query = createPQExpBuffer();
2924 FuncInfo *finfo;
2925 int i_tableoid;
2926 int i_oid;
2927 int i_proname;
2928 int i_pronamespace;
2929 int i_rolname;
2930 int i_prolang;
2931 int i_pronargs;
2932 int i_proargtypes;
2933 int i_prorettype;
2934 int i_proacl;
2936 /* Make sure we are in proper schema */
2937 selectSourceSchema("pg_catalog");
2939 /* find all user-defined funcs */
2941 if (g_fout->remoteVersion >= 70300)
2943 appendPQExpBuffer(query,
2944 "SELECT tableoid, oid, proname, prolang, "
2945 "pronargs, proargtypes, prorettype, proacl, "
2946 "pronamespace, "
2947 "(%s proowner) as rolname "
2948 "FROM pg_proc "
2949 "WHERE NOT proisagg "
2950 "AND pronamespace != "
2951 "(select oid from pg_namespace"
2952 " where nspname = 'pg_catalog')",
2953 username_subquery);
2955 else if (g_fout->remoteVersion >= 70100)
2957 appendPQExpBuffer(query,
2958 "SELECT tableoid, oid, proname, prolang, "
2959 "pronargs, proargtypes, prorettype, "
2960 "'{=X}' as proacl, "
2961 "0::oid as pronamespace, "
2962 "(%s proowner) as rolname "
2963 "FROM pg_proc "
2964 "where pg_proc.oid > '%u'::oid",
2965 username_subquery,
2966 g_last_builtin_oid);
2968 else
2970 appendPQExpBuffer(query,
2971 "SELECT "
2972 "(SELECT oid FROM pg_class "
2973 " WHERE relname = 'pg_proc') AS tableoid, "
2974 "oid, proname, prolang, "
2975 "pronargs, proargtypes, prorettype, "
2976 "'{=X}' as proacl, "
2977 "0::oid as pronamespace, "
2978 "(%s proowner) as rolname "
2979 "FROM pg_proc "
2980 "where pg_proc.oid > '%u'::oid",
2981 username_subquery,
2982 g_last_builtin_oid);
2985 res = PQexec(g_conn, query->data);
2986 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2988 ntups = PQntuples(res);
2990 *numFuncs = ntups;
2992 finfo = (FuncInfo *) calloc(ntups, sizeof(FuncInfo));
2994 i_tableoid = PQfnumber(res, "tableoid");
2995 i_oid = PQfnumber(res, "oid");
2996 i_proname = PQfnumber(res, "proname");
2997 i_pronamespace = PQfnumber(res, "pronamespace");
2998 i_rolname = PQfnumber(res, "rolname");
2999 i_prolang = PQfnumber(res, "prolang");
3000 i_pronargs = PQfnumber(res, "pronargs");
3001 i_proargtypes = PQfnumber(res, "proargtypes");
3002 i_prorettype = PQfnumber(res, "prorettype");
3003 i_proacl = PQfnumber(res, "proacl");
3005 for (i = 0; i < ntups; i++)
3007 finfo[i].dobj.objType = DO_FUNC;
3008 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3009 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3010 AssignDumpId(&finfo[i].dobj);
3011 finfo[i].dobj.name = strdup(PQgetvalue(res, i, i_proname));
3012 finfo[i].dobj.namespace =
3013 findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)),
3014 finfo[i].dobj.catId.oid);
3015 finfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
3016 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
3017 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
3018 finfo[i].proacl = strdup(PQgetvalue(res, i, i_proacl));
3019 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
3020 if (finfo[i].nargs == 0)
3021 finfo[i].argtypes = NULL;
3022 else
3024 finfo[i].argtypes = (Oid *) malloc(finfo[i].nargs * sizeof(Oid));
3025 parseOidArray(PQgetvalue(res, i, i_proargtypes),
3026 finfo[i].argtypes, finfo[i].nargs);
3029 /* Decide whether we want to dump it */
3030 selectDumpableObject(&(finfo[i].dobj));
3032 if (strlen(finfo[i].rolname) == 0)
3033 write_msg(NULL,
3034 "WARNING: owner of function \"%s\" appears to be invalid\n",
3035 finfo[i].dobj.name);
3038 PQclear(res);
3040 destroyPQExpBuffer(query);
3042 return finfo;
3046 * getTables
3047 * read all the user-defined tables (no indexes, no catalogs)
3048 * in the system catalogs return them in the TableInfo* structure
3050 * numTables is set to the number of tables read in
3052 TableInfo *
3053 getTables(int *numTables)
3055 PGresult *res;
3056 int ntups;
3057 int i;
3058 PQExpBuffer query = createPQExpBuffer();
3059 TableInfo *tblinfo;
3060 int i_reltableoid;
3061 int i_reloid;
3062 int i_relname;
3063 int i_relnamespace;
3064 int i_relkind;
3065 int i_relacl;
3066 int i_rolname;
3067 int i_relchecks;
3068 int i_reltriggers;
3069 int i_relhasindex;
3070 int i_relhasrules;
3071 int i_relhasoids;
3072 int i_owning_tab;
3073 int i_owning_col;
3074 int i_reltablespace;
3075 int i_reloptions;
3077 /* Make sure we are in proper schema */
3078 selectSourceSchema("pg_catalog");
3081 * Find all the tables (including views and sequences).
3083 * We include system catalogs, so that we can work if a user table is
3084 * defined to inherit from a system catalog (pretty weird, but...)
3086 * We ignore tables that are not type 'r' (ordinary relation), 'S'
3087 * (sequence), 'v' (view), or 'c' (composite type).
3089 * Composite-type table entries won't be dumped as such, but we have to
3090 * make a DumpableObject for them so that we can track dependencies of the
3091 * composite type (pg_depend entries for columns of the composite type
3092 * link to the pg_class entry not the pg_type entry).
3094 * Note: in this phase we should collect only a minimal amount of
3095 * information about each table, basically just enough to decide if it is
3096 * interesting. We must fetch all tables in this phase because otherwise
3097 * we cannot correctly identify inherited columns, owned sequences, etc.
3100 if (g_fout->remoteVersion >= 80200)
3103 * Left join to pick up dependency info linking sequences to their
3104 * owning column, if any (note this dependency is AUTO as of 8.2)
3106 appendPQExpBuffer(query,
3107 "SELECT c.tableoid, c.oid, relname, "
3108 "relacl, relkind, relnamespace, "
3109 "(%s relowner) as rolname, "
3110 "relchecks, reltriggers, "
3111 "relhasindex, relhasrules, relhasoids, "
3112 "d.refobjid as owning_tab, "
3113 "d.refobjsubid as owning_col, "
3114 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
3115 "array_to_string(c.reloptions, ', ') as reloptions "
3116 "from pg_class c "
3117 "left join pg_depend d on "
3118 "(c.relkind = '%c' and "
3119 "d.classid = c.tableoid and d.objid = c.oid and "
3120 "d.objsubid = 0 and "
3121 "d.refclassid = c.tableoid and d.deptype = 'a') "
3122 "where relkind in ('%c', '%c', '%c', '%c') "
3123 "order by c.oid",
3124 username_subquery,
3125 RELKIND_SEQUENCE,
3126 RELKIND_RELATION, RELKIND_SEQUENCE,
3127 RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3129 else if (g_fout->remoteVersion >= 80000)
3132 * Left join to pick up dependency info linking sequences to their
3133 * owning column, if any
3135 appendPQExpBuffer(query,
3136 "SELECT c.tableoid, c.oid, relname, "
3137 "relacl, relkind, relnamespace, "
3138 "(%s relowner) as rolname, "
3139 "relchecks, reltriggers, "
3140 "relhasindex, relhasrules, relhasoids, "
3141 "d.refobjid as owning_tab, "
3142 "d.refobjsubid as owning_col, "
3143 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
3144 "NULL as reloptions "
3145 "from pg_class c "
3146 "left join pg_depend d on "
3147 "(c.relkind = '%c' and "
3148 "d.classid = c.tableoid and d.objid = c.oid and "
3149 "d.objsubid = 0 and "
3150 "d.refclassid = c.tableoid and d.deptype = 'i') "
3151 "where relkind in ('%c', '%c', '%c', '%c') "
3152 "order by c.oid",
3153 username_subquery,
3154 RELKIND_SEQUENCE,
3155 RELKIND_RELATION, RELKIND_SEQUENCE,
3156 RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3158 else if (g_fout->remoteVersion >= 70300)
3161 * Left join to pick up dependency info linking sequences to their
3162 * owning column, if any
3164 appendPQExpBuffer(query,
3165 "SELECT c.tableoid, c.oid, relname, "
3166 "relacl, relkind, relnamespace, "
3167 "(%s relowner) as rolname, "
3168 "relchecks, reltriggers, "
3169 "relhasindex, relhasrules, relhasoids, "
3170 "d.refobjid as owning_tab, "
3171 "d.refobjsubid as owning_col, "
3172 "NULL as reltablespace, "
3173 "NULL as reloptions "
3174 "from pg_class c "
3175 "left join pg_depend d on "
3176 "(c.relkind = '%c' and "
3177 "d.classid = c.tableoid and d.objid = c.oid and "
3178 "d.objsubid = 0 and "
3179 "d.refclassid = c.tableoid and d.deptype = 'i') "
3180 "where relkind in ('%c', '%c', '%c', '%c') "
3181 "order by c.oid",
3182 username_subquery,
3183 RELKIND_SEQUENCE,
3184 RELKIND_RELATION, RELKIND_SEQUENCE,
3185 RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3187 else if (g_fout->remoteVersion >= 70200)
3189 appendPQExpBuffer(query,
3190 "SELECT tableoid, oid, relname, relacl, relkind, "
3191 "0::oid as relnamespace, "
3192 "(%s relowner) as rolname, "
3193 "relchecks, reltriggers, "
3194 "relhasindex, relhasrules, relhasoids, "
3195 "NULL::oid as owning_tab, "
3196 "NULL::int4 as owning_col, "
3197 "NULL as reltablespace, "
3198 "NULL as reloptions "
3199 "from pg_class "
3200 "where relkind in ('%c', '%c', '%c') "
3201 "order by oid",
3202 username_subquery,
3203 RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
3205 else if (g_fout->remoteVersion >= 70100)
3207 /* all tables have oids in 7.1 */
3208 appendPQExpBuffer(query,
3209 "SELECT tableoid, oid, relname, relacl, relkind, "
3210 "0::oid as relnamespace, "
3211 "(%s relowner) as rolname, "
3212 "relchecks, reltriggers, "
3213 "relhasindex, relhasrules, "
3214 "'t'::bool as relhasoids, "
3215 "NULL::oid as owning_tab, "
3216 "NULL::int4 as owning_col, "
3217 "NULL as reltablespace, "
3218 "NULL as reloptions "
3219 "from pg_class "
3220 "where relkind in ('%c', '%c', '%c') "
3221 "order by oid",
3222 username_subquery,
3223 RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
3225 else
3228 * Before 7.1, view relkind was not set to 'v', so we must check if we
3229 * have a view by looking for a rule in pg_rewrite.
3231 appendPQExpBuffer(query,
3232 "SELECT "
3233 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
3234 "oid, relname, relacl, "
3235 "CASE WHEN relhasrules and relkind = 'r' "
3236 " and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
3237 " r.ev_class = c.oid AND r.ev_type = '1') "
3238 "THEN '%c'::\"char\" "
3239 "ELSE relkind END AS relkind,"
3240 "0::oid as relnamespace, "
3241 "(%s relowner) as rolname, "
3242 "relchecks, reltriggers, "
3243 "relhasindex, relhasrules, "
3244 "'t'::bool as relhasoids, "
3245 "NULL::oid as owning_tab, "
3246 "NULL::int4 as owning_col, "
3247 "NULL as reltablespace, "
3248 "NULL as reloptions "
3249 "from pg_class c "
3250 "where relkind in ('%c', '%c') "
3251 "order by oid",
3252 RELKIND_VIEW,
3253 username_subquery,
3254 RELKIND_RELATION, RELKIND_SEQUENCE);
3257 res = PQexec(g_conn, query->data);
3258 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3260 ntups = PQntuples(res);
3262 *numTables = ntups;
3265 * Extract data from result and lock dumpable tables. We do the locking
3266 * before anything else, to minimize the window wherein a table could
3267 * disappear under us.
3269 * Note that we have to save info about all tables here, even when dumping
3270 * only one, because we don't yet know which tables might be inheritance
3271 * ancestors of the target table.
3273 tblinfo = (TableInfo *) calloc(ntups, sizeof(TableInfo));
3275 i_reltableoid = PQfnumber(res, "tableoid");
3276 i_reloid = PQfnumber(res, "oid");
3277 i_relname = PQfnumber(res, "relname");
3278 i_relnamespace = PQfnumber(res, "relnamespace");
3279 i_relacl = PQfnumber(res, "relacl");
3280 i_relkind = PQfnumber(res, "relkind");
3281 i_rolname = PQfnumber(res, "rolname");
3282 i_relchecks = PQfnumber(res, "relchecks");
3283 i_reltriggers = PQfnumber(res, "reltriggers");
3284 i_relhasindex = PQfnumber(res, "relhasindex");
3285 i_relhasrules = PQfnumber(res, "relhasrules");
3286 i_relhasoids = PQfnumber(res, "relhasoids");
3287 i_owning_tab = PQfnumber(res, "owning_tab");
3288 i_owning_col = PQfnumber(res, "owning_col");
3289 i_reltablespace = PQfnumber(res, "reltablespace");
3290 i_reloptions = PQfnumber(res, "reloptions");
3292 if (lockWaitTimeout && g_fout->remoteVersion >= 70300)
3295 * Arrange to fail instead of waiting forever for a table lock.
3297 * NB: this coding assumes that the only queries issued within
3298 * the following loop are LOCK TABLEs; else the timeout may be
3299 * undesirably applied to other things too.
3301 resetPQExpBuffer(query);
3302 appendPQExpBuffer(query, "SET statement_timeout = ");
3303 appendStringLiteralConn(query, lockWaitTimeout, g_conn);
3304 do_sql_command(g_conn, query->data);
3307 for (i = 0; i < ntups; i++)
3309 tblinfo[i].dobj.objType = DO_TABLE;
3310 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
3311 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
3312 AssignDumpId(&tblinfo[i].dobj);
3313 tblinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_relname));
3314 tblinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)),
3315 tblinfo[i].dobj.catId.oid);
3316 tblinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
3317 tblinfo[i].relacl = strdup(PQgetvalue(res, i, i_relacl));
3318 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
3319 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
3320 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
3321 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
3322 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
3323 tblinfo[i].ntrig = atoi(PQgetvalue(res, i, i_reltriggers));
3324 if (PQgetisnull(res, i, i_owning_tab))
3326 tblinfo[i].owning_tab = InvalidOid;
3327 tblinfo[i].owning_col = 0;
3329 else
3331 tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
3332 tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
3334 tblinfo[i].reltablespace = strdup(PQgetvalue(res, i, i_reltablespace));
3335 tblinfo[i].reloptions = strdup(PQgetvalue(res, i, i_reloptions));
3337 /* other fields were zeroed above */
3340 * Decide whether we want to dump this table.
3342 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
3343 tblinfo[i].dobj.dump = false;
3344 else
3345 selectDumpableTable(&tblinfo[i]);
3346 tblinfo[i].interesting = tblinfo[i].dobj.dump;
3349 * Read-lock target tables to make sure they aren't DROPPED or altered
3350 * in schema before we get around to dumping them.
3352 * Note that we don't explicitly lock parents of the target tables; we
3353 * assume our lock on the child is enough to prevent schema
3354 * alterations to parent tables.
3356 * NOTE: it'd be kinda nice to lock views and sequences too, not only
3357 * plain tables, but the backend doesn't presently allow that.
3359 if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION)
3361 resetPQExpBuffer(query);
3362 appendPQExpBuffer(query,
3363 "LOCK TABLE %s IN ACCESS SHARE MODE",
3364 fmtQualifiedId(tblinfo[i].dobj.namespace->dobj.name,
3365 tblinfo[i].dobj.name));
3366 do_sql_command(g_conn, query->data);
3369 /* Emit notice if join for owner failed */
3370 if (strlen(tblinfo[i].rolname) == 0)
3371 write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
3372 tblinfo[i].dobj.name);
3375 if (lockWaitTimeout && g_fout->remoteVersion >= 70300)
3377 do_sql_command(g_conn, "SET statement_timeout = 0");
3380 PQclear(res);
3383 * Force sequences that are "owned" by table columns to be dumped whenever
3384 * their owning table is being dumped.
3386 for (i = 0; i < ntups; i++)
3388 TableInfo *seqinfo = &tblinfo[i];
3389 int j;
3391 if (!OidIsValid(seqinfo->owning_tab))
3392 continue; /* not an owned sequence */
3393 if (seqinfo->dobj.dump)
3394 continue; /* no need to search */
3396 /* can't use findTableByOid yet, unfortunately */
3397 for (j = 0; j < ntups; j++)
3399 if (tblinfo[j].dobj.catId.oid == seqinfo->owning_tab)
3401 if (tblinfo[j].dobj.dump)
3403 seqinfo->interesting = true;
3404 seqinfo->dobj.dump = true;
3406 break;
3411 destroyPQExpBuffer(query);
3413 return tblinfo;
3417 * getInherits
3418 * read all the inheritance information
3419 * from the system catalogs return them in the InhInfo* structure
3421 * numInherits is set to the number of pairs read in
3423 InhInfo *
3424 getInherits(int *numInherits)
3426 PGresult *res;
3427 int ntups;
3428 int i;
3429 PQExpBuffer query = createPQExpBuffer();
3430 InhInfo *inhinfo;
3432 int i_inhrelid;
3433 int i_inhparent;
3435 /* Make sure we are in proper schema */
3436 selectSourceSchema("pg_catalog");
3438 /* find all the inheritance information */
3440 appendPQExpBuffer(query, "SELECT inhrelid, inhparent from pg_inherits");
3442 res = PQexec(g_conn, query->data);
3443 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3445 ntups = PQntuples(res);
3447 *numInherits = ntups;
3449 inhinfo = (InhInfo *) malloc(ntups * sizeof(InhInfo));
3451 i_inhrelid = PQfnumber(res, "inhrelid");
3452 i_inhparent = PQfnumber(res, "inhparent");
3454 for (i = 0; i < ntups; i++)
3456 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
3457 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
3460 PQclear(res);
3462 destroyPQExpBuffer(query);
3464 return inhinfo;
3468 * getIndexes
3469 * get information about every index on a dumpable table
3471 * Note: index data is not returned directly to the caller, but it
3472 * does get entered into the DumpableObject tables.
3474 void
3475 getIndexes(TableInfo tblinfo[], int numTables)
3477 int i,
3479 PQExpBuffer query = createPQExpBuffer();
3480 PGresult *res;
3481 IndxInfo *indxinfo;
3482 ConstraintInfo *constrinfo;
3483 int i_tableoid,
3484 i_oid,
3485 i_indexname,
3486 i_indexdef,
3487 i_indnkeys,
3488 i_indkey,
3489 i_indisclustered,
3490 i_contype,
3491 i_conname,
3492 i_contableoid,
3493 i_conoid,
3494 i_tablespace,
3495 i_options;
3496 int ntups;
3498 for (i = 0; i < numTables; i++)
3500 TableInfo *tbinfo = &tblinfo[i];
3502 /* Only plain tables have indexes */
3503 if (tbinfo->relkind != RELKIND_RELATION || !tbinfo->hasindex)
3504 continue;
3506 /* Ignore indexes of tables not to be dumped */
3507 if (!tbinfo->dobj.dump)
3508 continue;
3510 if (g_verbose)
3511 write_msg(NULL, "reading indexes for table \"%s\"\n",
3512 tbinfo->dobj.name);
3514 /* Make sure we are in proper schema so indexdef is right */
3515 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
3518 * The point of the messy-looking outer join is to find a constraint
3519 * that is related by an internal dependency link to the index. If we
3520 * find one, create a CONSTRAINT entry linked to the INDEX entry. We
3521 * assume an index won't have more than one internal dependency.
3523 resetPQExpBuffer(query);
3524 if (g_fout->remoteVersion >= 80200)
3526 appendPQExpBuffer(query,
3527 "SELECT t.tableoid, t.oid, "
3528 "t.relname as indexname, "
3529 "pg_catalog.pg_get_indexdef(i.indexrelid) as indexdef, "
3530 "t.relnatts as indnkeys, "
3531 "i.indkey, i.indisclustered, "
3532 "c.contype, c.conname, "
3533 "c.tableoid as contableoid, "
3534 "c.oid as conoid, "
3535 "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) as tablespace, "
3536 "array_to_string(t.reloptions, ', ') as options "
3537 "FROM pg_catalog.pg_index i "
3538 "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
3539 "LEFT JOIN pg_catalog.pg_depend d "
3540 "ON (d.classid = t.tableoid "
3541 "AND d.objid = t.oid "
3542 "AND d.deptype = 'i') "
3543 "LEFT JOIN pg_catalog.pg_constraint c "
3544 "ON (d.refclassid = c.tableoid "
3545 "AND d.refobjid = c.oid) "
3546 "WHERE i.indrelid = '%u'::pg_catalog.oid "
3547 "ORDER BY indexname",
3548 tbinfo->dobj.catId.oid);
3550 else if (g_fout->remoteVersion >= 80000)
3552 appendPQExpBuffer(query,
3553 "SELECT t.tableoid, t.oid, "
3554 "t.relname as indexname, "
3555 "pg_catalog.pg_get_indexdef(i.indexrelid) as indexdef, "
3556 "t.relnatts as indnkeys, "
3557 "i.indkey, i.indisclustered, "
3558 "c.contype, c.conname, "
3559 "c.tableoid as contableoid, "
3560 "c.oid as conoid, "
3561 "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) as tablespace, "
3562 "null as options "
3563 "FROM pg_catalog.pg_index i "
3564 "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
3565 "LEFT JOIN pg_catalog.pg_depend d "
3566 "ON (d.classid = t.tableoid "
3567 "AND d.objid = t.oid "
3568 "AND d.deptype = 'i') "
3569 "LEFT JOIN pg_catalog.pg_constraint c "
3570 "ON (d.refclassid = c.tableoid "
3571 "AND d.refobjid = c.oid) "
3572 "WHERE i.indrelid = '%u'::pg_catalog.oid "
3573 "ORDER BY indexname",
3574 tbinfo->dobj.catId.oid);
3576 else if (g_fout->remoteVersion >= 70300)
3578 appendPQExpBuffer(query,
3579 "SELECT t.tableoid, t.oid, "
3580 "t.relname as indexname, "
3581 "pg_catalog.pg_get_indexdef(i.indexrelid) as indexdef, "
3582 "t.relnatts as indnkeys, "
3583 "i.indkey, i.indisclustered, "
3584 "c.contype, c.conname, "
3585 "c.tableoid as contableoid, "
3586 "c.oid as conoid, "
3587 "NULL as tablespace, "
3588 "null as options "
3589 "FROM pg_catalog.pg_index i "
3590 "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
3591 "LEFT JOIN pg_catalog.pg_depend d "
3592 "ON (d.classid = t.tableoid "
3593 "AND d.objid = t.oid "
3594 "AND d.deptype = 'i') "
3595 "LEFT JOIN pg_catalog.pg_constraint c "
3596 "ON (d.refclassid = c.tableoid "
3597 "AND d.refobjid = c.oid) "
3598 "WHERE i.indrelid = '%u'::pg_catalog.oid "
3599 "ORDER BY indexname",
3600 tbinfo->dobj.catId.oid);
3602 else if (g_fout->remoteVersion >= 70100)
3604 appendPQExpBuffer(query,
3605 "SELECT t.tableoid, t.oid, "
3606 "t.relname as indexname, "
3607 "pg_get_indexdef(i.indexrelid) as indexdef, "
3608 "t.relnatts as indnkeys, "
3609 "i.indkey, false as indisclustered, "
3610 "CASE WHEN i.indisprimary THEN 'p'::char "
3611 "ELSE '0'::char END as contype, "
3612 "t.relname as conname, "
3613 "0::oid as contableoid, "
3614 "t.oid as conoid, "
3615 "NULL as tablespace, "
3616 "null as options "
3617 "FROM pg_index i, pg_class t "
3618 "WHERE t.oid = i.indexrelid "
3619 "AND i.indrelid = '%u'::oid "
3620 "ORDER BY indexname",
3621 tbinfo->dobj.catId.oid);
3623 else
3625 appendPQExpBuffer(query,
3626 "SELECT "
3627 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
3628 "t.oid, "
3629 "t.relname as indexname, "
3630 "pg_get_indexdef(i.indexrelid) as indexdef, "
3631 "t.relnatts as indnkeys, "
3632 "i.indkey, false as indisclustered, "
3633 "CASE WHEN i.indisprimary THEN 'p'::char "
3634 "ELSE '0'::char END as contype, "
3635 "t.relname as conname, "
3636 "0::oid as contableoid, "
3637 "t.oid as conoid, "
3638 "NULL as tablespace, "
3639 "null as options "
3640 "FROM pg_index i, pg_class t "
3641 "WHERE t.oid = i.indexrelid "
3642 "AND i.indrelid = '%u'::oid "
3643 "ORDER BY indexname",
3644 tbinfo->dobj.catId.oid);
3647 res = PQexec(g_conn, query->data);
3648 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3650 ntups = PQntuples(res);
3652 i_tableoid = PQfnumber(res, "tableoid");
3653 i_oid = PQfnumber(res, "oid");
3654 i_indexname = PQfnumber(res, "indexname");
3655 i_indexdef = PQfnumber(res, "indexdef");
3656 i_indnkeys = PQfnumber(res, "indnkeys");
3657 i_indkey = PQfnumber(res, "indkey");
3658 i_indisclustered = PQfnumber(res, "indisclustered");
3659 i_contype = PQfnumber(res, "contype");
3660 i_conname = PQfnumber(res, "conname");
3661 i_contableoid = PQfnumber(res, "contableoid");
3662 i_conoid = PQfnumber(res, "conoid");
3663 i_tablespace = PQfnumber(res, "tablespace");
3664 i_options = PQfnumber(res, "options");
3666 indxinfo = (IndxInfo *) malloc(ntups * sizeof(IndxInfo));
3667 constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
3669 for (j = 0; j < ntups; j++)
3671 char contype;
3673 indxinfo[j].dobj.objType = DO_INDEX;
3674 indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
3675 indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3676 AssignDumpId(&indxinfo[j].dobj);
3677 indxinfo[j].dobj.name = strdup(PQgetvalue(res, j, i_indexname));
3678 indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3679 indxinfo[j].indextable = tbinfo;
3680 indxinfo[j].indexdef = strdup(PQgetvalue(res, j, i_indexdef));
3681 indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
3682 indxinfo[j].tablespace = strdup(PQgetvalue(res, j, i_tablespace));
3683 indxinfo[j].options = strdup(PQgetvalue(res, j, i_options));
3686 * In pre-7.4 releases, indkeys may contain more entries than
3687 * indnkeys says (since indnkeys will be 1 for a functional
3688 * index). We don't actually care about this case since we don't
3689 * examine indkeys except for indexes associated with PRIMARY and
3690 * UNIQUE constraints, which are never functional indexes. But we
3691 * have to allocate enough space to keep parseOidArray from
3692 * complaining.
3694 indxinfo[j].indkeys = (Oid *) malloc(INDEX_MAX_KEYS * sizeof(Oid));
3695 parseOidArray(PQgetvalue(res, j, i_indkey),
3696 indxinfo[j].indkeys, INDEX_MAX_KEYS);
3697 indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
3698 contype = *(PQgetvalue(res, j, i_contype));
3700 if (contype == 'p' || contype == 'u')
3703 * If we found a constraint matching the index, create an
3704 * entry for it.
3706 * In a pre-7.3 database, we take this path iff the index was
3707 * marked indisprimary.
3709 constrinfo[j].dobj.objType = DO_CONSTRAINT;
3710 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
3711 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
3712 AssignDumpId(&constrinfo[j].dobj);
3713 constrinfo[j].dobj.name = strdup(PQgetvalue(res, j, i_conname));
3714 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3715 constrinfo[j].contable = tbinfo;
3716 constrinfo[j].condomain = NULL;
3717 constrinfo[j].contype = contype;
3718 constrinfo[j].condef = NULL;
3719 constrinfo[j].confrelid = InvalidOid;
3720 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
3721 constrinfo[j].conislocal = true;
3722 constrinfo[j].separate = true;
3724 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
3726 /* If pre-7.3 DB, better make sure table comes first */
3727 addObjectDependency(&constrinfo[j].dobj,
3728 tbinfo->dobj.dumpId);
3730 else
3732 /* Plain secondary index */
3733 indxinfo[j].indexconstraint = 0;
3737 PQclear(res);
3740 destroyPQExpBuffer(query);
3744 * getConstraints
3746 * Get info about constraints on dumpable tables.
3748 * Currently handles foreign keys only.
3749 * Unique and primary key constraints are handled with indexes,
3750 * while check constraints are processed in getTableAttrs().
3752 void
3753 getConstraints(TableInfo tblinfo[], int numTables)
3755 int i,
3757 ConstraintInfo *constrinfo;
3758 PQExpBuffer query;
3759 PGresult *res;
3760 int i_contableoid,
3761 i_conoid,
3762 i_conname,
3763 i_confrelid,
3764 i_condef;
3765 int ntups;
3767 /* pg_constraint was created in 7.3, so nothing to do if older */
3768 if (g_fout->remoteVersion < 70300)
3769 return;
3771 query = createPQExpBuffer();
3773 for (i = 0; i < numTables; i++)
3775 TableInfo *tbinfo = &tblinfo[i];
3777 if (tbinfo->ntrig == 0 || !tbinfo->dobj.dump)
3778 continue;
3780 if (g_verbose)
3781 write_msg(NULL, "reading foreign key constraints for table \"%s\"\n",
3782 tbinfo->dobj.name);
3785 * select table schema to ensure constraint expr is qualified if
3786 * needed
3788 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
3790 resetPQExpBuffer(query);
3791 appendPQExpBuffer(query,
3792 "SELECT tableoid, oid, conname, confrelid, "
3793 "pg_catalog.pg_get_constraintdef(oid) as condef "
3794 "FROM pg_catalog.pg_constraint "
3795 "WHERE conrelid = '%u'::pg_catalog.oid "
3796 "AND contype = 'f'",
3797 tbinfo->dobj.catId.oid);
3798 res = PQexec(g_conn, query->data);
3799 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3801 ntups = PQntuples(res);
3803 i_contableoid = PQfnumber(res, "tableoid");
3804 i_conoid = PQfnumber(res, "oid");
3805 i_conname = PQfnumber(res, "conname");
3806 i_confrelid = PQfnumber(res, "confrelid");
3807 i_condef = PQfnumber(res, "condef");
3809 constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
3811 for (j = 0; j < ntups; j++)
3813 constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
3814 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
3815 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
3816 AssignDumpId(&constrinfo[j].dobj);
3817 constrinfo[j].dobj.name = strdup(PQgetvalue(res, j, i_conname));
3818 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3819 constrinfo[j].contable = tbinfo;
3820 constrinfo[j].condomain = NULL;
3821 constrinfo[j].contype = 'f';
3822 constrinfo[j].condef = strdup(PQgetvalue(res, j, i_condef));
3823 constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
3824 constrinfo[j].conindex = 0;
3825 constrinfo[j].conislocal = true;
3826 constrinfo[j].separate = true;
3829 PQclear(res);
3832 destroyPQExpBuffer(query);
3836 * getDomainConstraints
3838 * Get info about constraints on a domain.
3840 static void
3841 getDomainConstraints(TypeInfo *tinfo)
3843 int i;
3844 ConstraintInfo *constrinfo;
3845 PQExpBuffer query;
3846 PGresult *res;
3847 int i_tableoid,
3848 i_oid,
3849 i_conname,
3850 i_consrc;
3851 int ntups;
3853 /* pg_constraint was created in 7.3, so nothing to do if older */
3854 if (g_fout->remoteVersion < 70300)
3855 return;
3858 * select appropriate schema to ensure names in constraint are properly
3859 * qualified
3861 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
3863 query = createPQExpBuffer();
3865 if (g_fout->remoteVersion >= 70400)
3866 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
3867 "pg_catalog.pg_get_constraintdef(oid) AS consrc "
3868 "FROM pg_catalog.pg_constraint "
3869 "WHERE contypid = '%u'::pg_catalog.oid "
3870 "ORDER BY conname",
3871 tinfo->dobj.catId.oid);
3872 else
3873 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
3874 "'CHECK (' || consrc || ')' AS consrc "
3875 "FROM pg_catalog.pg_constraint "
3876 "WHERE contypid = '%u'::pg_catalog.oid "
3877 "ORDER BY conname",
3878 tinfo->dobj.catId.oid);
3880 res = PQexec(g_conn, query->data);
3881 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3883 ntups = PQntuples(res);
3885 i_tableoid = PQfnumber(res, "tableoid");
3886 i_oid = PQfnumber(res, "oid");
3887 i_conname = PQfnumber(res, "conname");
3888 i_consrc = PQfnumber(res, "consrc");
3890 constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
3892 tinfo->nDomChecks = ntups;
3893 tinfo->domChecks = constrinfo;
3895 for (i = 0; i < ntups; i++)
3897 constrinfo[i].dobj.objType = DO_CONSTRAINT;
3898 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3899 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3900 AssignDumpId(&constrinfo[i].dobj);
3901 constrinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_conname));
3902 constrinfo[i].dobj.namespace = tinfo->dobj.namespace;
3903 constrinfo[i].contable = NULL;
3904 constrinfo[i].condomain = tinfo;
3905 constrinfo[i].contype = 'c';
3906 constrinfo[i].condef = strdup(PQgetvalue(res, i, i_consrc));
3907 constrinfo[i].confrelid = InvalidOid;
3908 constrinfo[i].conindex = 0;
3909 constrinfo[i].conislocal = true;
3910 constrinfo[i].separate = false;
3913 * Make the domain depend on the constraint, ensuring it won't be
3914 * output till any constraint dependencies are OK.
3916 addObjectDependency(&tinfo->dobj,
3917 constrinfo[i].dobj.dumpId);
3920 PQclear(res);
3922 destroyPQExpBuffer(query);
3926 * getRules
3927 * get basic information about every rule in the system
3929 * numRules is set to the number of rules read in
3931 RuleInfo *
3932 getRules(int *numRules)
3934 PGresult *res;
3935 int ntups;
3936 int i;
3937 PQExpBuffer query = createPQExpBuffer();
3938 RuleInfo *ruleinfo;
3939 int i_tableoid;
3940 int i_oid;
3941 int i_rulename;
3942 int i_ruletable;
3943 int i_ev_type;
3944 int i_is_instead;
3945 int i_ev_enabled;
3947 /* Make sure we are in proper schema */
3948 selectSourceSchema("pg_catalog");
3950 if (g_fout->remoteVersion >= 80300)
3952 appendPQExpBuffer(query, "SELECT "
3953 "tableoid, oid, rulename, "
3954 "ev_class as ruletable, ev_type, is_instead, "
3955 "ev_enabled "
3956 "FROM pg_rewrite "
3957 "ORDER BY oid");
3959 else if (g_fout->remoteVersion >= 70100)
3961 appendPQExpBuffer(query, "SELECT "
3962 "tableoid, oid, rulename, "
3963 "ev_class as ruletable, ev_type, is_instead, "
3964 "'O'::char as ev_enabled "
3965 "FROM pg_rewrite "
3966 "ORDER BY oid");
3968 else
3970 appendPQExpBuffer(query, "SELECT "
3971 "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
3972 "oid, rulename, "
3973 "ev_class as ruletable, ev_type, is_instead, "
3974 "'O'::char as ev_enabled "
3975 "FROM pg_rewrite "
3976 "ORDER BY oid");
3979 res = PQexec(g_conn, query->data);
3980 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3982 ntups = PQntuples(res);
3984 *numRules = ntups;
3986 ruleinfo = (RuleInfo *) malloc(ntups * sizeof(RuleInfo));
3988 i_tableoid = PQfnumber(res, "tableoid");
3989 i_oid = PQfnumber(res, "oid");
3990 i_rulename = PQfnumber(res, "rulename");
3991 i_ruletable = PQfnumber(res, "ruletable");
3992 i_ev_type = PQfnumber(res, "ev_type");
3993 i_is_instead = PQfnumber(res, "is_instead");
3994 i_ev_enabled = PQfnumber(res, "ev_enabled");
3996 for (i = 0; i < ntups; i++)
3998 Oid ruletableoid;
4000 ruleinfo[i].dobj.objType = DO_RULE;
4001 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4002 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4003 AssignDumpId(&ruleinfo[i].dobj);
4004 ruleinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_rulename));
4005 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
4006 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
4007 if (ruleinfo[i].ruletable == NULL)
4009 write_msg(NULL, "failed sanity check, parent table OID %u of pg_rewrite entry OID %u not found\n",
4010 ruletableoid,
4011 ruleinfo[i].dobj.catId.oid);
4012 exit_nicely();
4014 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
4015 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
4016 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
4017 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
4018 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
4019 if (ruleinfo[i].ruletable)
4022 * If the table is a view, force its ON SELECT rule to be sorted
4023 * before the view itself --- this ensures that any dependencies
4024 * for the rule affect the table's positioning. Other rules are
4025 * forced to appear after their table.
4027 if (ruleinfo[i].ruletable->relkind == RELKIND_VIEW &&
4028 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
4030 addObjectDependency(&ruleinfo[i].ruletable->dobj,
4031 ruleinfo[i].dobj.dumpId);
4032 /* We'll merge the rule into CREATE VIEW, if possible */
4033 ruleinfo[i].separate = false;
4035 else
4037 addObjectDependency(&ruleinfo[i].dobj,
4038 ruleinfo[i].ruletable->dobj.dumpId);
4039 ruleinfo[i].separate = true;
4042 else
4043 ruleinfo[i].separate = true;
4046 PQclear(res);
4048 destroyPQExpBuffer(query);
4050 return ruleinfo;
4054 * getTriggers
4055 * get information about every trigger on a dumpable table
4057 * Note: trigger data is not returned directly to the caller, but it
4058 * does get entered into the DumpableObject tables.
4060 void
4061 getTriggers(TableInfo tblinfo[], int numTables)
4063 int i,
4065 PQExpBuffer query = createPQExpBuffer();
4066 PGresult *res;
4067 TriggerInfo *tginfo;
4068 int i_tableoid,
4069 i_oid,
4070 i_tgname,
4071 i_tgfname,
4072 i_tgtype,
4073 i_tgnargs,
4074 i_tgargs,
4075 i_tgisconstraint,
4076 i_tgconstrname,
4077 i_tgconstrrelid,
4078 i_tgconstrrelname,
4079 i_tgenabled,
4080 i_tgdeferrable,
4081 i_tginitdeferred;
4082 int ntups;
4084 for (i = 0; i < numTables; i++)
4086 TableInfo *tbinfo = &tblinfo[i];
4088 if (tbinfo->ntrig == 0 || !tbinfo->dobj.dump)
4089 continue;
4091 if (g_verbose)
4092 write_msg(NULL, "reading triggers for table \"%s\"\n",
4093 tbinfo->dobj.name);
4096 * select table schema to ensure regproc name is qualified if needed
4098 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
4100 resetPQExpBuffer(query);
4101 if (g_fout->remoteVersion >= 80300)
4104 * We ignore triggers that are tied to a foreign-key constraint
4106 appendPQExpBuffer(query,
4107 "SELECT tgname, "
4108 "tgfoid::pg_catalog.regproc as tgfname, "
4109 "tgtype, tgnargs, tgargs, tgenabled, "
4110 "tgisconstraint, tgconstrname, tgdeferrable, "
4111 "tgconstrrelid, tginitdeferred, tableoid, oid, "
4112 "tgconstrrelid::pg_catalog.regclass as tgconstrrelname "
4113 "from pg_catalog.pg_trigger t "
4114 "where tgrelid = '%u'::pg_catalog.oid "
4115 "and tgconstraint = 0",
4116 tbinfo->dobj.catId.oid);
4118 else if (g_fout->remoteVersion >= 70300)
4121 * We ignore triggers that are tied to a foreign-key constraint,
4122 * but in these versions we have to grovel through pg_constraint
4123 * to find out
4125 appendPQExpBuffer(query,
4126 "SELECT tgname, "
4127 "tgfoid::pg_catalog.regproc as tgfname, "
4128 "tgtype, tgnargs, tgargs, tgenabled, "
4129 "tgisconstraint, tgconstrname, tgdeferrable, "
4130 "tgconstrrelid, tginitdeferred, tableoid, oid, "
4131 "tgconstrrelid::pg_catalog.regclass as tgconstrrelname "
4132 "from pg_catalog.pg_trigger t "
4133 "where tgrelid = '%u'::pg_catalog.oid "
4134 "and (not tgisconstraint "
4135 " OR NOT EXISTS"
4136 " (SELECT 1 FROM pg_catalog.pg_depend d "
4137 " JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
4138 " WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
4139 tbinfo->dobj.catId.oid);
4141 else if (g_fout->remoteVersion >= 70100)
4143 appendPQExpBuffer(query,
4144 "SELECT tgname, tgfoid::regproc as tgfname, "
4145 "tgtype, tgnargs, tgargs, tgenabled, "
4146 "tgisconstraint, tgconstrname, tgdeferrable, "
4147 "tgconstrrelid, tginitdeferred, tableoid, oid, "
4148 "(select relname from pg_class where oid = tgconstrrelid) "
4149 " as tgconstrrelname "
4150 "from pg_trigger "
4151 "where tgrelid = '%u'::oid",
4152 tbinfo->dobj.catId.oid);
4154 else
4156 appendPQExpBuffer(query,
4157 "SELECT tgname, tgfoid::regproc as tgfname, "
4158 "tgtype, tgnargs, tgargs, tgenabled, "
4159 "tgisconstraint, tgconstrname, tgdeferrable, "
4160 "tgconstrrelid, tginitdeferred, "
4161 "(SELECT oid FROM pg_class WHERE relname = 'pg_trigger') AS tableoid, "
4163 "oid, "
4164 "(select relname from pg_class where oid = tgconstrrelid) "
4165 " as tgconstrrelname "
4166 "from pg_trigger "
4167 "where tgrelid = '%u'::oid",
4168 tbinfo->dobj.catId.oid);
4170 res = PQexec(g_conn, query->data);
4171 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4173 ntups = PQntuples(res);
4176 * We may have less triggers than recorded due to having ignored
4177 * foreign-key triggers
4179 if (ntups > tbinfo->ntrig)
4181 write_msg(NULL, "expected %d triggers on table \"%s\" but found %d\n",
4182 tbinfo->ntrig, tbinfo->dobj.name, ntups);
4183 exit_nicely();
4185 i_tableoid = PQfnumber(res, "tableoid");
4186 i_oid = PQfnumber(res, "oid");
4187 i_tgname = PQfnumber(res, "tgname");
4188 i_tgfname = PQfnumber(res, "tgfname");
4189 i_tgtype = PQfnumber(res, "tgtype");
4190 i_tgnargs = PQfnumber(res, "tgnargs");
4191 i_tgargs = PQfnumber(res, "tgargs");
4192 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
4193 i_tgconstrname = PQfnumber(res, "tgconstrname");
4194 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
4195 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
4196 i_tgenabled = PQfnumber(res, "tgenabled");
4197 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
4198 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
4200 tginfo = (TriggerInfo *) malloc(ntups * sizeof(TriggerInfo));
4202 for (j = 0; j < ntups; j++)
4204 tginfo[j].dobj.objType = DO_TRIGGER;
4205 tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
4206 tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
4207 AssignDumpId(&tginfo[j].dobj);
4208 tginfo[j].dobj.name = strdup(PQgetvalue(res, j, i_tgname));
4209 tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
4210 tginfo[j].tgtable = tbinfo;
4211 tginfo[j].tgfname = strdup(PQgetvalue(res, j, i_tgfname));
4212 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
4213 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
4214 tginfo[j].tgargs = strdup(PQgetvalue(res, j, i_tgargs));
4215 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
4216 tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
4217 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
4218 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
4220 if (tginfo[j].tgisconstraint)
4222 tginfo[j].tgconstrname = strdup(PQgetvalue(res, j, i_tgconstrname));
4223 tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
4224 if (OidIsValid(tginfo[j].tgconstrrelid))
4226 if (PQgetisnull(res, j, i_tgconstrrelname))
4228 write_msg(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
4229 tginfo[j].dobj.name, tbinfo->dobj.name,
4230 tginfo[j].tgconstrrelid);
4231 exit_nicely();
4233 tginfo[j].tgconstrrelname = strdup(PQgetvalue(res, j, i_tgconstrrelname));
4235 else
4236 tginfo[j].tgconstrrelname = NULL;
4238 else
4240 tginfo[j].tgconstrname = NULL;
4241 tginfo[j].tgconstrrelid = InvalidOid;
4242 tginfo[j].tgconstrrelname = NULL;
4246 PQclear(res);
4249 destroyPQExpBuffer(query);
4253 * getProcLangs
4254 * get basic information about every procedural language in the system
4256 * numProcLangs is set to the number of langs read in
4258 * NB: this must run after getFuncs() because we assume we can do
4259 * findFuncByOid().
4261 ProcLangInfo *
4262 getProcLangs(int *numProcLangs)
4264 PGresult *res;
4265 int ntups;
4266 int i;
4267 PQExpBuffer query = createPQExpBuffer();
4268 ProcLangInfo *planginfo;
4269 int i_tableoid;
4270 int i_oid;
4271 int i_lanname;
4272 int i_lanpltrusted;
4273 int i_lanplcallfoid;
4274 int i_lanvalidator;
4275 int i_lanacl;
4276 int i_lanowner;
4278 /* Make sure we are in proper schema */
4279 selectSourceSchema("pg_catalog");
4281 if (g_fout->remoteVersion >= 80300)
4283 /* pg_language has a lanowner column */
4284 appendPQExpBuffer(query, "SELECT tableoid, oid, "
4285 "lanname, lanpltrusted, lanplcallfoid, "
4286 "lanvalidator, lanacl, "
4287 "(%s lanowner) as lanowner "
4288 "FROM pg_language "
4289 "WHERE lanispl "
4290 "ORDER BY oid",
4291 username_subquery);
4293 else if (g_fout->remoteVersion >= 80100)
4295 /* Languages are owned by the bootstrap superuser, OID 10 */
4296 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
4297 "(%s '10') as lanowner "
4298 "FROM pg_language "
4299 "WHERE lanispl "
4300 "ORDER BY oid",
4301 username_subquery);
4303 else if (g_fout->remoteVersion >= 70400)
4305 /* Languages are owned by the bootstrap superuser, sysid 1 */
4306 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
4307 "(%s '1') as lanowner "
4308 "FROM pg_language "
4309 "WHERE lanispl "
4310 "ORDER BY oid",
4311 username_subquery);
4313 else if (g_fout->remoteVersion >= 70100)
4315 /* No clear notion of an owner at all before 7.4 ... */
4316 appendPQExpBuffer(query, "SELECT tableoid, oid, * FROM pg_language "
4317 "WHERE lanispl "
4318 "ORDER BY oid");
4320 else
4322 appendPQExpBuffer(query, "SELECT "
4323 "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, "
4324 "oid, * FROM pg_language "
4325 "WHERE lanispl "
4326 "ORDER BY oid");
4329 res = PQexec(g_conn, query->data);
4330 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4332 ntups = PQntuples(res);
4334 *numProcLangs = ntups;
4336 planginfo = (ProcLangInfo *) malloc(ntups * sizeof(ProcLangInfo));
4338 i_tableoid = PQfnumber(res, "tableoid");
4339 i_oid = PQfnumber(res, "oid");
4340 i_lanname = PQfnumber(res, "lanname");
4341 i_lanpltrusted = PQfnumber(res, "lanpltrusted");
4342 i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
4343 /* these may fail and return -1: */
4344 i_lanvalidator = PQfnumber(res, "lanvalidator");
4345 i_lanacl = PQfnumber(res, "lanacl");
4346 i_lanowner = PQfnumber(res, "lanowner");
4348 for (i = 0; i < ntups; i++)
4350 planginfo[i].dobj.objType = DO_PROCLANG;
4351 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4352 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4353 AssignDumpId(&planginfo[i].dobj);
4355 planginfo[i].dobj.name = strdup(PQgetvalue(res, i, i_lanname));
4356 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
4357 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
4358 if (i_lanvalidator >= 0)
4359 planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
4360 else
4361 planginfo[i].lanvalidator = InvalidOid;
4362 if (i_lanacl >= 0)
4363 planginfo[i].lanacl = strdup(PQgetvalue(res, i, i_lanacl));
4364 else
4365 planginfo[i].lanacl = strdup("{=U}");
4366 if (i_lanowner >= 0)
4367 planginfo[i].lanowner = strdup(PQgetvalue(res, i, i_lanowner));
4368 else
4369 planginfo[i].lanowner = strdup("");
4371 if (g_fout->remoteVersion < 70300)
4374 * We need to make a dependency to ensure the function will be
4375 * dumped first. (In 7.3 and later the regular dependency
4376 * mechanism will handle this for us.)
4378 FuncInfo *funcInfo = findFuncByOid(planginfo[i].lanplcallfoid);
4380 if (funcInfo)
4381 addObjectDependency(&planginfo[i].dobj,
4382 funcInfo->dobj.dumpId);
4386 PQclear(res);
4388 destroyPQExpBuffer(query);
4390 return planginfo;
4394 * getCasts
4395 * get basic information about every cast in the system
4397 * numCasts is set to the number of casts read in
4399 CastInfo *
4400 getCasts(int *numCasts)
4402 PGresult *res;
4403 int ntups;
4404 int i;
4405 PQExpBuffer query = createPQExpBuffer();
4406 CastInfo *castinfo;
4407 int i_tableoid;
4408 int i_oid;
4409 int i_castsource;
4410 int i_casttarget;
4411 int i_castfunc;
4412 int i_castcontext;
4414 /* Make sure we are in proper schema */
4415 selectSourceSchema("pg_catalog");
4417 if (g_fout->remoteVersion >= 70300)
4419 appendPQExpBuffer(query, "SELECT tableoid, oid, "
4420 "castsource, casttarget, castfunc, castcontext "
4421 "FROM pg_cast ORDER BY 3,4");
4423 else
4425 appendPQExpBuffer(query, "SELECT 0 as tableoid, p.oid, "
4426 "t1.oid as castsource, t2.oid as casttarget, "
4427 "p.oid as castfunc, 'e' as castcontext "
4428 "FROM pg_type t1, pg_type t2, pg_proc p "
4429 "WHERE p.pronargs = 1 AND "
4430 "p.proargtypes[0] = t1.oid AND "
4431 "p.prorettype = t2.oid AND p.proname = t2.typname "
4432 "ORDER BY 3,4");
4435 res = PQexec(g_conn, query->data);
4436 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4438 ntups = PQntuples(res);
4440 *numCasts = ntups;
4442 castinfo = (CastInfo *) malloc(ntups * sizeof(CastInfo));
4444 i_tableoid = PQfnumber(res, "tableoid");
4445 i_oid = PQfnumber(res, "oid");
4446 i_castsource = PQfnumber(res, "castsource");
4447 i_casttarget = PQfnumber(res, "casttarget");
4448 i_castfunc = PQfnumber(res, "castfunc");
4449 i_castcontext = PQfnumber(res, "castcontext");
4451 for (i = 0; i < ntups; i++)
4453 PQExpBufferData namebuf;
4454 TypeInfo *sTypeInfo;
4455 TypeInfo *tTypeInfo;
4457 castinfo[i].dobj.objType = DO_CAST;
4458 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4459 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4460 AssignDumpId(&castinfo[i].dobj);
4461 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
4462 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
4463 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
4464 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
4467 * Try to name cast as concatenation of typnames. This is only used
4468 * for purposes of sorting. If we fail to find either type, the name
4469 * will be an empty string.
4471 initPQExpBuffer(&namebuf);
4472 sTypeInfo = findTypeByOid(castinfo[i].castsource);
4473 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
4474 if (sTypeInfo && tTypeInfo)
4475 appendPQExpBuffer(&namebuf, "%s %s",
4476 sTypeInfo->dobj.name, tTypeInfo->dobj.name);
4477 castinfo[i].dobj.name = namebuf.data;
4479 if (OidIsValid(castinfo[i].castfunc))
4482 * We need to make a dependency to ensure the function will be
4483 * dumped first. (In 7.3 and later the regular dependency
4484 * mechanism will handle this for us.)
4486 FuncInfo *funcInfo;
4488 funcInfo = findFuncByOid(castinfo[i].castfunc);
4489 if (funcInfo)
4490 addObjectDependency(&castinfo[i].dobj,
4491 funcInfo->dobj.dumpId);
4495 PQclear(res);
4497 destroyPQExpBuffer(query);
4499 return castinfo;
4503 * getTableAttrs -
4504 * for each interesting table, read info about its attributes
4505 * (names, types, default values, CHECK constraints, etc)
4507 * This is implemented in a very inefficient way right now, looping
4508 * through the tblinfo and doing a join per table to find the attrs and their
4509 * types. However, because we want type names and so forth to be named
4510 * relative to the schema of each table, we couldn't do it in just one
4511 * query. (Maybe one query per schema?)
4513 * modifies tblinfo
4515 void
4516 getTableAttrs(TableInfo *tblinfo, int numTables)
4518 int i,
4520 PQExpBuffer q = createPQExpBuffer();
4521 int i_attnum;
4522 int i_attname;
4523 int i_atttypname;
4524 int i_atttypmod;
4525 int i_attstattarget;
4526 int i_attstorage;
4527 int i_typstorage;
4528 int i_attnotnull;
4529 int i_atthasdef;
4530 int i_attisdropped;
4531 int i_attislocal;
4532 PGresult *res;
4533 int ntups;
4534 bool hasdefaults;
4536 for (i = 0; i < numTables; i++)
4538 TableInfo *tbinfo = &tblinfo[i];
4540 /* Don't bother to collect info for sequences */
4541 if (tbinfo->relkind == RELKIND_SEQUENCE)
4542 continue;
4544 /* Don't bother with uninteresting tables, either */
4545 if (!tbinfo->interesting)
4546 continue;
4549 * Make sure we are in proper schema for this table; this allows
4550 * correct retrieval of formatted type names and default exprs
4552 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
4554 /* find all the user attributes and their types */
4557 * we must read the attribute names in attribute number order! because
4558 * we will use the attnum to index into the attnames array later. We
4559 * actually ask to order by "attrelid, attnum" because (at least up to
4560 * 7.3) the planner is not smart enough to realize it needn't re-sort
4561 * the output of an indexscan on pg_attribute_relid_attnum_index.
4563 if (g_verbose)
4564 write_msg(NULL, "finding the columns and types of table \"%s\"\n",
4565 tbinfo->dobj.name);
4567 resetPQExpBuffer(q);
4569 if (g_fout->remoteVersion >= 70300)
4571 /* need left join here to not fail on dropped columns ... */
4572 appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, a.attstattarget, a.attstorage, t.typstorage, "
4573 "a.attnotnull, a.atthasdef, a.attisdropped, a.attislocal, "
4574 "pg_catalog.format_type(t.oid,a.atttypmod) as atttypname "
4575 "from pg_catalog.pg_attribute a left join pg_catalog.pg_type t "
4576 "on a.atttypid = t.oid "
4577 "where a.attrelid = '%u'::pg_catalog.oid "
4578 "and a.attnum > 0::pg_catalog.int2 "
4579 "order by a.attrelid, a.attnum",
4580 tbinfo->dobj.catId.oid);
4582 else if (g_fout->remoteVersion >= 70100)
4585 * attstattarget doesn't exist in 7.1. It does exist in 7.2, but
4586 * we don't dump it because we can't tell whether it's been
4587 * explicitly set or was just a default.
4589 appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, -1 as attstattarget, a.attstorage, t.typstorage, "
4590 "a.attnotnull, a.atthasdef, false as attisdropped, false as attislocal, "
4591 "format_type(t.oid,a.atttypmod) as atttypname "
4592 "from pg_attribute a left join pg_type t "
4593 "on a.atttypid = t.oid "
4594 "where a.attrelid = '%u'::oid "
4595 "and a.attnum > 0::int2 "
4596 "order by a.attrelid, a.attnum",
4597 tbinfo->dobj.catId.oid);
4599 else
4601 /* format_type not available before 7.1 */
4602 appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, -1 as attstattarget, attstorage, attstorage as typstorage, "
4603 "attnotnull, atthasdef, false as attisdropped, false as attislocal, "
4604 "(select typname from pg_type where oid = atttypid) as atttypname "
4605 "from pg_attribute a "
4606 "where attrelid = '%u'::oid "
4607 "and attnum > 0::int2 "
4608 "order by attrelid, attnum",
4609 tbinfo->dobj.catId.oid);
4612 res = PQexec(g_conn, q->data);
4613 check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
4615 ntups = PQntuples(res);
4617 i_attnum = PQfnumber(res, "attnum");
4618 i_attname = PQfnumber(res, "attname");
4619 i_atttypname = PQfnumber(res, "atttypname");
4620 i_atttypmod = PQfnumber(res, "atttypmod");
4621 i_attstattarget = PQfnumber(res, "attstattarget");
4622 i_attstorage = PQfnumber(res, "attstorage");
4623 i_typstorage = PQfnumber(res, "typstorage");
4624 i_attnotnull = PQfnumber(res, "attnotnull");
4625 i_atthasdef = PQfnumber(res, "atthasdef");
4626 i_attisdropped = PQfnumber(res, "attisdropped");
4627 i_attislocal = PQfnumber(res, "attislocal");
4629 tbinfo->numatts = ntups;
4630 tbinfo->attnames = (char **) malloc(ntups * sizeof(char *));
4631 tbinfo->atttypnames = (char **) malloc(ntups * sizeof(char *));
4632 tbinfo->atttypmod = (int *) malloc(ntups * sizeof(int));
4633 tbinfo->attstattarget = (int *) malloc(ntups * sizeof(int));
4634 tbinfo->attstorage = (char *) malloc(ntups * sizeof(char));
4635 tbinfo->typstorage = (char *) malloc(ntups * sizeof(char));
4636 tbinfo->attisdropped = (bool *) malloc(ntups * sizeof(bool));
4637 tbinfo->attislocal = (bool *) malloc(ntups * sizeof(bool));
4638 tbinfo->notnull = (bool *) malloc(ntups * sizeof(bool));
4639 tbinfo->attrdefs = (AttrDefInfo **) malloc(ntups * sizeof(AttrDefInfo *));
4640 tbinfo->inhAttrs = (bool *) malloc(ntups * sizeof(bool));
4641 tbinfo->inhAttrDef = (bool *) malloc(ntups * sizeof(bool));
4642 tbinfo->inhNotNull = (bool *) malloc(ntups * sizeof(bool));
4643 hasdefaults = false;
4645 for (j = 0; j < ntups; j++)
4647 if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
4649 write_msg(NULL, "invalid column numbering in table \"%s\"\n",
4650 tbinfo->dobj.name);
4651 exit_nicely();
4653 tbinfo->attnames[j] = strdup(PQgetvalue(res, j, i_attname));
4654 tbinfo->atttypnames[j] = strdup(PQgetvalue(res, j, i_atttypname));
4655 tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
4656 tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
4657 tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
4658 tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
4659 tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
4660 tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
4661 tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
4662 tbinfo->attrdefs[j] = NULL; /* fix below */
4663 if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
4664 hasdefaults = true;
4665 /* these flags will be set in flagInhAttrs() */
4666 tbinfo->inhAttrs[j] = false;
4667 tbinfo->inhAttrDef[j] = false;
4668 tbinfo->inhNotNull[j] = false;
4671 PQclear(res);
4674 * Get info about column defaults
4676 if (hasdefaults)
4678 AttrDefInfo *attrdefs;
4679 int numDefaults;
4681 if (g_verbose)
4682 write_msg(NULL, "finding default expressions of table \"%s\"\n",
4683 tbinfo->dobj.name);
4685 resetPQExpBuffer(q);
4686 if (g_fout->remoteVersion >= 70300)
4688 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
4689 "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
4690 "FROM pg_catalog.pg_attrdef "
4691 "WHERE adrelid = '%u'::pg_catalog.oid",
4692 tbinfo->dobj.catId.oid);
4694 else if (g_fout->remoteVersion >= 70200)
4696 /* 7.2 did not have OIDs in pg_attrdef */
4697 appendPQExpBuffer(q, "SELECT tableoid, 0 as oid, adnum, "
4698 "pg_get_expr(adbin, adrelid) AS adsrc "
4699 "FROM pg_attrdef "
4700 "WHERE adrelid = '%u'::oid",
4701 tbinfo->dobj.catId.oid);
4703 else if (g_fout->remoteVersion >= 70100)
4705 /* no pg_get_expr, so must rely on adsrc */
4706 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, adsrc "
4707 "FROM pg_attrdef "
4708 "WHERE adrelid = '%u'::oid",
4709 tbinfo->dobj.catId.oid);
4711 else
4713 /* no pg_get_expr, no tableoid either */
4714 appendPQExpBuffer(q, "SELECT "
4715 "(SELECT oid FROM pg_class WHERE relname = 'pg_attrdef') AS tableoid, "
4716 "oid, adnum, adsrc "
4717 "FROM pg_attrdef "
4718 "WHERE adrelid = '%u'::oid",
4719 tbinfo->dobj.catId.oid);
4721 res = PQexec(g_conn, q->data);
4722 check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
4724 numDefaults = PQntuples(res);
4725 attrdefs = (AttrDefInfo *) malloc(numDefaults * sizeof(AttrDefInfo));
4727 for (j = 0; j < numDefaults; j++)
4729 int adnum;
4731 attrdefs[j].dobj.objType = DO_ATTRDEF;
4732 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
4733 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
4734 AssignDumpId(&attrdefs[j].dobj);
4735 attrdefs[j].adtable = tbinfo;
4736 attrdefs[j].adnum = adnum = atoi(PQgetvalue(res, j, 2));
4737 attrdefs[j].adef_expr = strdup(PQgetvalue(res, j, 3));
4739 attrdefs[j].dobj.name = strdup(tbinfo->dobj.name);
4740 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
4742 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
4745 * Defaults on a VIEW must always be dumped as separate ALTER
4746 * TABLE commands. Defaults on regular tables are dumped as
4747 * part of the CREATE TABLE if possible. To check if it's
4748 * safe, we mark the default as needing to appear before the
4749 * CREATE.
4751 if (tbinfo->relkind == RELKIND_VIEW)
4753 attrdefs[j].separate = true;
4754 /* needed in case pre-7.3 DB: */
4755 addObjectDependency(&attrdefs[j].dobj,
4756 tbinfo->dobj.dumpId);
4758 else
4760 attrdefs[j].separate = false;
4761 addObjectDependency(&tbinfo->dobj,
4762 attrdefs[j].dobj.dumpId);
4765 if (adnum <= 0 || adnum > ntups)
4767 write_msg(NULL, "invalid adnum value %d for table \"%s\"\n",
4768 adnum, tbinfo->dobj.name);
4769 exit_nicely();
4771 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
4773 PQclear(res);
4777 * Get info about table CHECK constraints
4779 if (tbinfo->ncheck > 0)
4781 ConstraintInfo *constrs;
4782 int numConstrs;
4784 if (g_verbose)
4785 write_msg(NULL, "finding check constraints for table \"%s\"\n",
4786 tbinfo->dobj.name);
4788 resetPQExpBuffer(q);
4789 if (g_fout->remoteVersion >= 80400)
4791 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
4792 "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
4793 "conislocal "
4794 "FROM pg_catalog.pg_constraint "
4795 "WHERE conrelid = '%u'::pg_catalog.oid "
4796 " AND contype = 'c' "
4797 "ORDER BY conname",
4798 tbinfo->dobj.catId.oid);
4800 else if (g_fout->remoteVersion >= 70400)
4802 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
4803 "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
4804 "true as conislocal "
4805 "FROM pg_catalog.pg_constraint "
4806 "WHERE conrelid = '%u'::pg_catalog.oid "
4807 " AND contype = 'c' "
4808 "ORDER BY conname",
4809 tbinfo->dobj.catId.oid);
4811 else if (g_fout->remoteVersion >= 70300)
4813 /* no pg_get_constraintdef, must use consrc */
4814 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
4815 "'CHECK (' || consrc || ')' AS consrc, "
4816 "true as conislocal "
4817 "FROM pg_catalog.pg_constraint "
4818 "WHERE conrelid = '%u'::pg_catalog.oid "
4819 " AND contype = 'c' "
4820 "ORDER BY conname",
4821 tbinfo->dobj.catId.oid);
4823 else if (g_fout->remoteVersion >= 70200)
4825 /* 7.2 did not have OIDs in pg_relcheck */
4826 appendPQExpBuffer(q, "SELECT tableoid, 0 as oid, "
4827 "rcname AS conname, "
4828 "'CHECK (' || rcsrc || ')' AS consrc, "
4829 "true as conislocal "
4830 "FROM pg_relcheck "
4831 "WHERE rcrelid = '%u'::oid "
4832 "ORDER BY rcname",
4833 tbinfo->dobj.catId.oid);
4835 else if (g_fout->remoteVersion >= 70100)
4837 appendPQExpBuffer(q, "SELECT tableoid, oid, "
4838 "rcname AS conname, "
4839 "'CHECK (' || rcsrc || ')' AS consrc, "
4840 "true as conislocal "
4841 "FROM pg_relcheck "
4842 "WHERE rcrelid = '%u'::oid "
4843 "ORDER BY rcname",
4844 tbinfo->dobj.catId.oid);
4846 else
4848 /* no tableoid in 7.0 */
4849 appendPQExpBuffer(q, "SELECT "
4850 "(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
4851 "oid, rcname AS conname, "
4852 "'CHECK (' || rcsrc || ')' AS consrc, "
4853 "true as conislocal "
4854 "FROM pg_relcheck "
4855 "WHERE rcrelid = '%u'::oid "
4856 "ORDER BY rcname",
4857 tbinfo->dobj.catId.oid);
4859 res = PQexec(g_conn, q->data);
4860 check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
4862 numConstrs = PQntuples(res);
4863 if (numConstrs != tbinfo->ncheck)
4865 write_msg(NULL, "expected %d check constraints on table \"%s\" but found %d\n",
4866 tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
4867 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
4868 exit_nicely();
4871 constrs = (ConstraintInfo *) malloc(numConstrs * sizeof(ConstraintInfo));
4872 tbinfo->checkexprs = constrs;
4874 for (j = 0; j < numConstrs; j++)
4876 constrs[j].dobj.objType = DO_CONSTRAINT;
4877 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
4878 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
4879 AssignDumpId(&constrs[j].dobj);
4880 constrs[j].dobj.name = strdup(PQgetvalue(res, j, 2));
4881 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
4882 constrs[j].contable = tbinfo;
4883 constrs[j].condomain = NULL;
4884 constrs[j].contype = 'c';
4885 constrs[j].condef = strdup(PQgetvalue(res, j, 3));
4886 constrs[j].confrelid = InvalidOid;
4887 constrs[j].conindex = 0;
4888 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
4889 constrs[j].separate = false;
4891 constrs[j].dobj.dump = tbinfo->dobj.dump;
4894 * Mark the constraint as needing to appear before the table
4895 * --- this is so that any other dependencies of the
4896 * constraint will be emitted before we try to create the
4897 * table.
4899 addObjectDependency(&tbinfo->dobj,
4900 constrs[j].dobj.dumpId);
4903 * If the constraint is inherited, this will be detected
4904 * later (in pre-8.4 databases). We also detect later if the
4905 * constraint must be split out from the table definition.
4908 PQclear(res);
4912 destroyPQExpBuffer(q);
4917 * getTSParsers:
4918 * read all text search parsers in the system catalogs and return them
4919 * in the TSParserInfo* structure
4921 * numTSParsers is set to the number of parsers read in
4923 TSParserInfo *
4924 getTSParsers(int *numTSParsers)
4926 PGresult *res;
4927 int ntups;
4928 int i;
4929 PQExpBuffer query = createPQExpBuffer();
4930 TSParserInfo *prsinfo;
4931 int i_tableoid;
4932 int i_oid;
4933 int i_prsname;
4934 int i_prsnamespace;
4935 int i_prsstart;
4936 int i_prstoken;
4937 int i_prsend;
4938 int i_prsheadline;
4939 int i_prslextype;
4941 /* Before 8.3, there is no built-in text search support */
4942 if (g_fout->remoteVersion < 80300)
4944 *numTSParsers = 0;
4945 return NULL;
4949 * find all text search objects, including builtin ones; we filter out
4950 * system-defined objects at dump-out time.
4953 /* Make sure we are in proper schema */
4954 selectSourceSchema("pg_catalog");
4956 appendPQExpBuffer(query, "SELECT tableoid, oid, prsname, prsnamespace, "
4957 "prsstart::oid, prstoken::oid, "
4958 "prsend::oid, prsheadline::oid, prslextype::oid "
4959 "FROM pg_ts_parser");
4961 res = PQexec(g_conn, query->data);
4962 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4964 ntups = PQntuples(res);
4965 *numTSParsers = ntups;
4967 prsinfo = (TSParserInfo *) malloc(ntups * sizeof(TSParserInfo));
4969 i_tableoid = PQfnumber(res, "tableoid");
4970 i_oid = PQfnumber(res, "oid");
4971 i_prsname = PQfnumber(res, "prsname");
4972 i_prsnamespace = PQfnumber(res, "prsnamespace");
4973 i_prsstart = PQfnumber(res, "prsstart");
4974 i_prstoken = PQfnumber(res, "prstoken");
4975 i_prsend = PQfnumber(res, "prsend");
4976 i_prsheadline = PQfnumber(res, "prsheadline");
4977 i_prslextype = PQfnumber(res, "prslextype");
4979 for (i = 0; i < ntups; i++)
4981 prsinfo[i].dobj.objType = DO_TSPARSER;
4982 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4983 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4984 AssignDumpId(&prsinfo[i].dobj);
4985 prsinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_prsname));
4986 prsinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)),
4987 prsinfo[i].dobj.catId.oid);
4988 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
4989 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
4990 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
4991 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
4992 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
4994 /* Decide whether we want to dump it */
4995 selectDumpableObject(&(prsinfo[i].dobj));
4998 PQclear(res);
5000 destroyPQExpBuffer(query);
5002 return prsinfo;
5006 * getTSDictionaries:
5007 * read all text search dictionaries in the system catalogs and return them
5008 * in the TSDictInfo* structure
5010 * numTSDicts is set to the number of dictionaries read in
5012 TSDictInfo *
5013 getTSDictionaries(int *numTSDicts)
5015 PGresult *res;
5016 int ntups;
5017 int i;
5018 PQExpBuffer query = createPQExpBuffer();
5019 TSDictInfo *dictinfo;
5020 int i_tableoid;
5021 int i_oid;
5022 int i_dictname;
5023 int i_dictnamespace;
5024 int i_rolname;
5025 int i_dicttemplate;
5026 int i_dictinitoption;
5028 /* Before 8.3, there is no built-in text search support */
5029 if (g_fout->remoteVersion < 80300)
5031 *numTSDicts = 0;
5032 return NULL;
5035 /* Make sure we are in proper schema */
5036 selectSourceSchema("pg_catalog");
5038 appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
5039 "dictnamespace, (%s dictowner) as rolname, "
5040 "dicttemplate, dictinitoption "
5041 "FROM pg_ts_dict",
5042 username_subquery);
5044 res = PQexec(g_conn, query->data);
5045 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5047 ntups = PQntuples(res);
5048 *numTSDicts = ntups;
5050 dictinfo = (TSDictInfo *) malloc(ntups * sizeof(TSDictInfo));
5052 i_tableoid = PQfnumber(res, "tableoid");
5053 i_oid = PQfnumber(res, "oid");
5054 i_dictname = PQfnumber(res, "dictname");
5055 i_dictnamespace = PQfnumber(res, "dictnamespace");
5056 i_rolname = PQfnumber(res, "rolname");
5057 i_dictinitoption = PQfnumber(res, "dictinitoption");
5058 i_dicttemplate = PQfnumber(res, "dicttemplate");
5060 for (i = 0; i < ntups; i++)
5062 dictinfo[i].dobj.objType = DO_TSDICT;
5063 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5064 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5065 AssignDumpId(&dictinfo[i].dobj);
5066 dictinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_dictname));
5067 dictinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)),
5068 dictinfo[i].dobj.catId.oid);
5069 dictinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
5070 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
5071 if (PQgetisnull(res, i, i_dictinitoption))
5072 dictinfo[i].dictinitoption = NULL;
5073 else
5074 dictinfo[i].dictinitoption = strdup(PQgetvalue(res, i, i_dictinitoption));
5076 /* Decide whether we want to dump it */
5077 selectDumpableObject(&(dictinfo[i].dobj));
5080 PQclear(res);
5082 destroyPQExpBuffer(query);
5084 return dictinfo;
5088 * getTSTemplates:
5089 * read all text search templates in the system catalogs and return them
5090 * in the TSTemplateInfo* structure
5092 * numTSTemplates is set to the number of templates read in
5094 TSTemplateInfo *
5095 getTSTemplates(int *numTSTemplates)
5097 PGresult *res;
5098 int ntups;
5099 int i;
5100 PQExpBuffer query = createPQExpBuffer();
5101 TSTemplateInfo *tmplinfo;
5102 int i_tableoid;
5103 int i_oid;
5104 int i_tmplname;
5105 int i_tmplnamespace;
5106 int i_tmplinit;
5107 int i_tmpllexize;
5109 /* Before 8.3, there is no built-in text search support */
5110 if (g_fout->remoteVersion < 80300)
5112 *numTSTemplates = 0;
5113 return NULL;
5116 /* Make sure we are in proper schema */
5117 selectSourceSchema("pg_catalog");
5119 appendPQExpBuffer(query, "SELECT tableoid, oid, tmplname, "
5120 "tmplnamespace, tmplinit::oid, tmpllexize::oid "
5121 "FROM pg_ts_template");
5123 res = PQexec(g_conn, query->data);
5124 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5126 ntups = PQntuples(res);
5127 *numTSTemplates = ntups;
5129 tmplinfo = (TSTemplateInfo *) malloc(ntups * sizeof(TSTemplateInfo));
5131 i_tableoid = PQfnumber(res, "tableoid");
5132 i_oid = PQfnumber(res, "oid");
5133 i_tmplname = PQfnumber(res, "tmplname");
5134 i_tmplnamespace = PQfnumber(res, "tmplnamespace");
5135 i_tmplinit = PQfnumber(res, "tmplinit");
5136 i_tmpllexize = PQfnumber(res, "tmpllexize");
5138 for (i = 0; i < ntups; i++)
5140 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
5141 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5142 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5143 AssignDumpId(&tmplinfo[i].dobj);
5144 tmplinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_tmplname));
5145 tmplinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)),
5146 tmplinfo[i].dobj.catId.oid);
5147 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
5148 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
5150 /* Decide whether we want to dump it */
5151 selectDumpableObject(&(tmplinfo[i].dobj));
5154 PQclear(res);
5156 destroyPQExpBuffer(query);
5158 return tmplinfo;
5162 * getTSConfigurations:
5163 * read all text search configurations in the system catalogs and return
5164 * them in the TSConfigInfo* structure
5166 * numTSConfigs is set to the number of configurations read in
5168 TSConfigInfo *
5169 getTSConfigurations(int *numTSConfigs)
5171 PGresult *res;
5172 int ntups;
5173 int i;
5174 PQExpBuffer query = createPQExpBuffer();
5175 TSConfigInfo *cfginfo;
5176 int i_tableoid;
5177 int i_oid;
5178 int i_cfgname;
5179 int i_cfgnamespace;
5180 int i_rolname;
5181 int i_cfgparser;
5183 /* Before 8.3, there is no built-in text search support */
5184 if (g_fout->remoteVersion < 80300)
5186 *numTSConfigs = 0;
5187 return NULL;
5190 /* Make sure we are in proper schema */
5191 selectSourceSchema("pg_catalog");
5193 appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
5194 "cfgnamespace, (%s cfgowner) as rolname, cfgparser "
5195 "FROM pg_ts_config",
5196 username_subquery);
5198 res = PQexec(g_conn, query->data);
5199 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5201 ntups = PQntuples(res);
5202 *numTSConfigs = ntups;
5204 cfginfo = (TSConfigInfo *) malloc(ntups * sizeof(TSConfigInfo));
5206 i_tableoid = PQfnumber(res, "tableoid");
5207 i_oid = PQfnumber(res, "oid");
5208 i_cfgname = PQfnumber(res, "cfgname");
5209 i_cfgnamespace = PQfnumber(res, "cfgnamespace");
5210 i_rolname = PQfnumber(res, "rolname");
5211 i_cfgparser = PQfnumber(res, "cfgparser");
5213 for (i = 0; i < ntups; i++)
5215 cfginfo[i].dobj.objType = DO_TSCONFIG;
5216 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5217 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5218 AssignDumpId(&cfginfo[i].dobj);
5219 cfginfo[i].dobj.name = strdup(PQgetvalue(res, i, i_cfgname));
5220 cfginfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)),
5221 cfginfo[i].dobj.catId.oid);
5222 cfginfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
5223 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
5225 /* Decide whether we want to dump it */
5226 selectDumpableObject(&(cfginfo[i].dobj));
5229 PQclear(res);
5231 destroyPQExpBuffer(query);
5233 return cfginfo;
5238 * dumpComment --
5240 * This routine is used to dump any comments associated with the
5241 * object handed to this routine. The routine takes a constant character
5242 * string for the target part of the comment-creation command, plus
5243 * the namespace and owner of the object (for labeling the ArchiveEntry),
5244 * plus catalog ID and subid which are the lookup key for pg_description,
5245 * plus the dump ID for the object (for setting a dependency).
5246 * If a matching pg_description entry is found, it is dumped.
5248 * Note: although this routine takes a dumpId for dependency purposes,
5249 * that purpose is just to mark the dependency in the emitted dump file
5250 * for possible future use by pg_restore. We do NOT use it for determining
5251 * ordering of the comment in the dump file, because this routine is called
5252 * after dependency sorting occurs. This routine should be called just after
5253 * calling ArchiveEntry() for the specified object.
5255 static void
5256 dumpComment(Archive *fout, const char *target,
5257 const char *namespace, const char *owner,
5258 CatalogId catalogId, int subid, DumpId dumpId)
5260 CommentItem *comments;
5261 int ncomments;
5263 /* Comments are SCHEMA not data */
5264 if (dataOnly)
5265 return;
5267 /* Search for comments associated with catalogId, using table */
5268 ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
5269 &comments);
5271 /* Is there one matching the subid? */
5272 while (ncomments > 0)
5274 if (comments->objsubid == subid)
5275 break;
5276 comments++;
5277 ncomments--;
5280 /* If a comment exists, build COMMENT ON statement */
5281 if (ncomments > 0)
5283 PQExpBuffer query = createPQExpBuffer();
5285 appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
5286 appendStringLiteralAH(query, comments->descr, fout);
5287 appendPQExpBuffer(query, ";\n");
5289 ArchiveEntry(fout, nilCatalogId, createDumpId(),
5290 target, namespace, NULL, owner, false,
5291 "COMMENT", query->data, "", NULL,
5292 &(dumpId), 1,
5293 NULL, NULL);
5295 destroyPQExpBuffer(query);
5300 * dumpTableComment --
5302 * As above, but dump comments for both the specified table (or view)
5303 * and its columns.
5305 static void
5306 dumpTableComment(Archive *fout, TableInfo *tbinfo,
5307 const char *reltypename)
5309 CommentItem *comments;
5310 int ncomments;
5311 PQExpBuffer query;
5312 PQExpBuffer target;
5314 /* Comments are SCHEMA not data */
5315 if (dataOnly)
5316 return;
5318 /* Search for comments associated with relation, using table */
5319 ncomments = findComments(fout,
5320 tbinfo->dobj.catId.tableoid,
5321 tbinfo->dobj.catId.oid,
5322 &comments);
5324 /* If comments exist, build COMMENT ON statements */
5325 if (ncomments <= 0)
5326 return;
5328 query = createPQExpBuffer();
5329 target = createPQExpBuffer();
5331 while (ncomments > 0)
5333 const char *descr = comments->descr;
5334 int objsubid = comments->objsubid;
5336 if (objsubid == 0)
5338 resetPQExpBuffer(target);
5339 appendPQExpBuffer(target, "%s %s", reltypename,
5340 fmtId(tbinfo->dobj.name));
5342 resetPQExpBuffer(query);
5343 appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
5344 appendStringLiteralAH(query, descr, fout);
5345 appendPQExpBuffer(query, ";\n");
5347 ArchiveEntry(fout, nilCatalogId, createDumpId(),
5348 target->data,
5349 tbinfo->dobj.namespace->dobj.name,
5350 NULL,
5351 tbinfo->rolname,
5352 false, "COMMENT", query->data, "", NULL,
5353 &(tbinfo->dobj.dumpId), 1,
5354 NULL, NULL);
5356 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
5358 resetPQExpBuffer(target);
5359 appendPQExpBuffer(target, "COLUMN %s.",
5360 fmtId(tbinfo->dobj.name));
5361 appendPQExpBuffer(target, "%s",
5362 fmtId(tbinfo->attnames[objsubid - 1]));
5364 resetPQExpBuffer(query);
5365 appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
5366 appendStringLiteralAH(query, descr, fout);
5367 appendPQExpBuffer(query, ";\n");
5369 ArchiveEntry(fout, nilCatalogId, createDumpId(),
5370 target->data,
5371 tbinfo->dobj.namespace->dobj.name,
5372 NULL,
5373 tbinfo->rolname,
5374 false, "COMMENT", query->data, "", NULL,
5375 &(tbinfo->dobj.dumpId), 1,
5376 NULL, NULL);
5379 comments++;
5380 ncomments--;
5383 destroyPQExpBuffer(query);
5384 destroyPQExpBuffer(target);
5388 * findComments --
5390 * Find the comment(s), if any, associated with the given object. All the
5391 * objsubid values associated with the given classoid/objoid are found with
5392 * one search.
5394 static int
5395 findComments(Archive *fout, Oid classoid, Oid objoid,
5396 CommentItem **items)
5398 /* static storage for table of comments */
5399 static CommentItem *comments = NULL;
5400 static int ncomments = -1;
5402 CommentItem *middle = NULL;
5403 CommentItem *low;
5404 CommentItem *high;
5405 int nmatch;
5407 /* Get comments if we didn't already */
5408 if (ncomments < 0)
5409 ncomments = collectComments(fout, &comments);
5412 * Pre-7.2, pg_description does not contain classoid, so collectComments
5413 * just stores a zero. If there's a collision on object OID, well, you
5414 * get duplicate comments.
5416 if (fout->remoteVersion < 70200)
5417 classoid = 0;
5420 * Do binary search to find some item matching the object.
5422 low = &comments[0];
5423 high = &comments[ncomments - 1];
5424 while (low <= high)
5426 middle = low + (high - low) / 2;
5428 if (classoid < middle->classoid)
5429 high = middle - 1;
5430 else if (classoid > middle->classoid)
5431 low = middle + 1;
5432 else if (objoid < middle->objoid)
5433 high = middle - 1;
5434 else if (objoid > middle->objoid)
5435 low = middle + 1;
5436 else
5437 break; /* found a match */
5440 if (low > high) /* no matches */
5442 *items = NULL;
5443 return 0;
5447 * Now determine how many items match the object. The search loop
5448 * invariant still holds: only items between low and high inclusive could
5449 * match.
5451 nmatch = 1;
5452 while (middle > low)
5454 if (classoid != middle[-1].classoid ||
5455 objoid != middle[-1].objoid)
5456 break;
5457 middle--;
5458 nmatch++;
5461 *items = middle;
5463 middle += nmatch;
5464 while (middle <= high)
5466 if (classoid != middle->classoid ||
5467 objoid != middle->objoid)
5468 break;
5469 middle++;
5470 nmatch++;
5473 return nmatch;
5477 * collectComments --
5479 * Construct a table of all comments available for database objects.
5480 * We used to do per-object queries for the comments, but it's much faster
5481 * to pull them all over at once, and on most databases the memory cost
5482 * isn't high.
5484 * The table is sorted by classoid/objid/objsubid for speed in lookup.
5486 static int
5487 collectComments(Archive *fout, CommentItem **items)
5489 PGresult *res;
5490 PQExpBuffer query;
5491 int i_description;
5492 int i_classoid;
5493 int i_objoid;
5494 int i_objsubid;
5495 int ntups;
5496 int i;
5497 CommentItem *comments;
5500 * Note we do NOT change source schema here; preserve the caller's
5501 * setting, instead.
5504 query = createPQExpBuffer();
5506 if (fout->remoteVersion >= 70300)
5508 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
5509 "FROM pg_catalog.pg_description "
5510 "ORDER BY classoid, objoid, objsubid");
5512 else if (fout->remoteVersion >= 70200)
5514 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
5515 "FROM pg_description "
5516 "ORDER BY classoid, objoid, objsubid");
5518 else
5520 /* Note: this will fail to find attribute comments in pre-7.2... */
5521 appendPQExpBuffer(query, "SELECT description, 0 as classoid, objoid, 0 as objsubid "
5522 "FROM pg_description "
5523 "ORDER BY objoid");
5526 res = PQexec(g_conn, query->data);
5527 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5529 /* Construct lookup table containing OIDs in numeric form */
5531 i_description = PQfnumber(res, "description");
5532 i_classoid = PQfnumber(res, "classoid");
5533 i_objoid = PQfnumber(res, "objoid");
5534 i_objsubid = PQfnumber(res, "objsubid");
5536 ntups = PQntuples(res);
5538 comments = (CommentItem *) malloc(ntups * sizeof(CommentItem));
5540 for (i = 0; i < ntups; i++)
5542 comments[i].descr = PQgetvalue(res, i, i_description);
5543 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
5544 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
5545 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
5548 /* Do NOT free the PGresult since we are keeping pointers into it */
5549 destroyPQExpBuffer(query);
5551 *items = comments;
5552 return ntups;
5556 * dumpDumpableObject
5558 * This routine and its subsidiaries are responsible for creating
5559 * ArchiveEntries (TOC objects) for each object to be dumped.
5561 static void
5562 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
5564 switch (dobj->objType)
5566 case DO_NAMESPACE:
5567 dumpNamespace(fout, (NamespaceInfo *) dobj);
5568 break;
5569 case DO_TYPE:
5570 dumpType(fout, (TypeInfo *) dobj);
5571 break;
5572 case DO_SHELL_TYPE:
5573 dumpShellType(fout, (ShellTypeInfo *) dobj);
5574 break;
5575 case DO_FUNC:
5576 dumpFunc(fout, (FuncInfo *) dobj);
5577 break;
5578 case DO_AGG:
5579 dumpAgg(fout, (AggInfo *) dobj);
5580 break;
5581 case DO_OPERATOR:
5582 dumpOpr(fout, (OprInfo *) dobj);
5583 break;
5584 case DO_OPCLASS:
5585 dumpOpclass(fout, (OpclassInfo *) dobj);
5586 break;
5587 case DO_OPFAMILY:
5588 dumpOpfamily(fout, (OpfamilyInfo *) dobj);
5589 break;
5590 case DO_CONVERSION:
5591 dumpConversion(fout, (ConvInfo *) dobj);
5592 break;
5593 case DO_TABLE:
5594 dumpTable(fout, (TableInfo *) dobj);
5595 break;
5596 case DO_ATTRDEF:
5597 dumpAttrDef(fout, (AttrDefInfo *) dobj);
5598 break;
5599 case DO_INDEX:
5600 dumpIndex(fout, (IndxInfo *) dobj);
5601 break;
5602 case DO_RULE:
5603 dumpRule(fout, (RuleInfo *) dobj);
5604 break;
5605 case DO_TRIGGER:
5606 dumpTrigger(fout, (TriggerInfo *) dobj);
5607 break;
5608 case DO_CONSTRAINT:
5609 dumpConstraint(fout, (ConstraintInfo *) dobj);
5610 break;
5611 case DO_FK_CONSTRAINT:
5612 dumpConstraint(fout, (ConstraintInfo *) dobj);
5613 break;
5614 case DO_PROCLANG:
5615 dumpProcLang(fout, (ProcLangInfo *) dobj);
5616 break;
5617 case DO_CAST:
5618 dumpCast(fout, (CastInfo *) dobj);
5619 break;
5620 case DO_TABLE_DATA:
5621 dumpTableData(fout, (TableDataInfo *) dobj);
5622 break;
5623 case DO_TABLE_TYPE:
5624 /* table rowtypes are never dumped separately */
5625 break;
5626 case DO_TSPARSER:
5627 dumpTSParser(fout, (TSParserInfo *) dobj);
5628 break;
5629 case DO_TSDICT:
5630 dumpTSDictionary(fout, (TSDictInfo *) dobj);
5631 break;
5632 case DO_TSTEMPLATE:
5633 dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
5634 break;
5635 case DO_TSCONFIG:
5636 dumpTSConfig(fout, (TSConfigInfo *) dobj);
5637 break;
5638 case DO_BLOBS:
5639 ArchiveEntry(fout, dobj->catId, dobj->dumpId,
5640 dobj->name, NULL, NULL, "",
5641 false, "BLOBS", "", "", NULL,
5642 NULL, 0,
5643 dumpBlobs, NULL);
5644 break;
5645 case DO_BLOB_COMMENTS:
5646 ArchiveEntry(fout, dobj->catId, dobj->dumpId,
5647 dobj->name, NULL, NULL, "",
5648 false, "BLOB COMMENTS", "", "", NULL,
5649 NULL, 0,
5650 dumpBlobComments, NULL);
5651 break;
5656 * dumpNamespace
5657 * writes out to fout the queries to recreate a user-defined namespace
5659 static void
5660 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
5662 PQExpBuffer q;
5663 PQExpBuffer delq;
5664 char *qnspname;
5666 /* Skip if not to be dumped */
5667 if (!nspinfo->dobj.dump || dataOnly)
5668 return;
5670 /* don't dump dummy namespace from pre-7.3 source */
5671 if (strlen(nspinfo->dobj.name) == 0)
5672 return;
5674 q = createPQExpBuffer();
5675 delq = createPQExpBuffer();
5677 qnspname = strdup(fmtId(nspinfo->dobj.name));
5679 appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
5681 appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
5683 ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
5684 nspinfo->dobj.name,
5685 NULL, NULL,
5686 nspinfo->rolname,
5687 false, "SCHEMA", q->data, delq->data, NULL,
5688 nspinfo->dobj.dependencies, nspinfo->dobj.nDeps,
5689 NULL, NULL);
5691 /* Dump Schema Comments */
5692 resetPQExpBuffer(q);
5693 appendPQExpBuffer(q, "SCHEMA %s", qnspname);
5694 dumpComment(fout, q->data,
5695 NULL, nspinfo->rolname,
5696 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
5698 dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
5699 qnspname, nspinfo->dobj.name, NULL,
5700 nspinfo->rolname, nspinfo->nspacl);
5702 free(qnspname);
5704 destroyPQExpBuffer(q);
5705 destroyPQExpBuffer(delq);
5709 * dumpType
5710 * writes out to fout the queries to recreate a user-defined type
5712 static void
5713 dumpType(Archive *fout, TypeInfo *tinfo)
5715 /* Skip if not to be dumped */
5716 if (!tinfo->dobj.dump || dataOnly)
5717 return;
5719 /* Dump out in proper style */
5720 if (tinfo->typtype == TYPTYPE_BASE)
5721 dumpBaseType(fout, tinfo);
5722 else if (tinfo->typtype == TYPTYPE_DOMAIN)
5723 dumpDomain(fout, tinfo);
5724 else if (tinfo->typtype == TYPTYPE_COMPOSITE)
5725 dumpCompositeType(fout, tinfo);
5726 else if (tinfo->typtype == TYPTYPE_ENUM)
5727 dumpEnumType(fout, tinfo);
5731 * dumpEnumType
5732 * writes out to fout the queries to recreate a user-defined enum type
5734 static void
5735 dumpEnumType(Archive *fout, TypeInfo *tinfo)
5737 PQExpBuffer q = createPQExpBuffer();
5738 PQExpBuffer delq = createPQExpBuffer();
5739 PQExpBuffer query = createPQExpBuffer();
5740 PGresult *res;
5741 int num,
5743 char *label;
5745 /* Set proper schema search path so regproc references list correctly */
5746 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
5748 appendPQExpBuffer(query, "SELECT enumlabel FROM pg_catalog.pg_enum "
5749 "WHERE enumtypid = '%u'"
5750 "ORDER BY oid",
5751 tinfo->dobj.catId.oid);
5753 res = PQexec(g_conn, query->data);
5754 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5756 num = PQntuples(res);
5757 /* should be at least 1 value */
5758 if (num == 0)
5760 write_msg(NULL, "no label definitions found for enum ID %u\n", tinfo->dobj.catId.oid);
5761 exit_nicely();
5765 * DROP must be fully qualified in case same name appears in pg_catalog.
5766 * CASCADE shouldn't be required here as for normal types since the I/O
5767 * functions are generic and do not get dropped.
5769 appendPQExpBuffer(delq, "DROP TYPE %s.",
5770 fmtId(tinfo->dobj.namespace->dobj.name));
5771 appendPQExpBuffer(delq, "%s;\n",
5772 fmtId(tinfo->dobj.name));
5773 appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (\n",
5774 fmtId(tinfo->dobj.name));
5775 for (i = 0; i < num; i++)
5777 label = PQgetvalue(res, i, 0);
5778 if (i > 0)
5779 appendPQExpBuffer(q, ",\n");
5780 appendPQExpBuffer(q, " ");
5781 appendStringLiteralAH(q, label, fout);
5783 appendPQExpBuffer(q, "\n);\n");
5785 ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
5786 tinfo->dobj.name,
5787 tinfo->dobj.namespace->dobj.name,
5788 NULL,
5789 tinfo->rolname, false,
5790 "TYPE", q->data, delq->data, NULL,
5791 tinfo->dobj.dependencies, tinfo->dobj.nDeps,
5792 NULL, NULL);
5794 /* Dump Type Comments */
5795 resetPQExpBuffer(q);
5797 appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->dobj.name));
5798 dumpComment(fout, q->data,
5799 tinfo->dobj.namespace->dobj.name, tinfo->rolname,
5800 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
5802 PQclear(res);
5803 destroyPQExpBuffer(q);
5804 destroyPQExpBuffer(delq);
5805 destroyPQExpBuffer(query);
5809 * dumpBaseType
5810 * writes out to fout the queries to recreate a user-defined base type
5812 static void
5813 dumpBaseType(Archive *fout, TypeInfo *tinfo)
5815 PQExpBuffer q = createPQExpBuffer();
5816 PQExpBuffer delq = createPQExpBuffer();
5817 PQExpBuffer query = createPQExpBuffer();
5818 PGresult *res;
5819 int ntups;
5820 char *typlen;
5821 char *typinput;
5822 char *typoutput;
5823 char *typreceive;
5824 char *typsend;
5825 char *typmodin;
5826 char *typmodout;
5827 char *typanalyze;
5828 Oid typinputoid;
5829 Oid typoutputoid;
5830 Oid typreceiveoid;
5831 Oid typsendoid;
5832 Oid typmodinoid;
5833 Oid typmodoutoid;
5834 Oid typanalyzeoid;
5835 char *typcategory;
5836 char *typispreferred;
5837 char *typdelim;
5838 char *typbyval;
5839 char *typalign;
5840 char *typstorage;
5841 char *typdefault;
5842 bool typdefault_is_literal = false;
5844 /* Set proper schema search path so regproc references list correctly */
5845 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
5847 /* Fetch type-specific details */
5848 if (fout->remoteVersion >= 80400)
5850 appendPQExpBuffer(query, "SELECT typlen, "
5851 "typinput, typoutput, typreceive, typsend, "
5852 "typmodin, typmodout, typanalyze, "
5853 "typinput::pg_catalog.oid as typinputoid, "
5854 "typoutput::pg_catalog.oid as typoutputoid, "
5855 "typreceive::pg_catalog.oid as typreceiveoid, "
5856 "typsend::pg_catalog.oid as typsendoid, "
5857 "typmodin::pg_catalog.oid as typmodinoid, "
5858 "typmodout::pg_catalog.oid as typmodoutoid, "
5859 "typanalyze::pg_catalog.oid as typanalyzeoid, "
5860 "typcategory, typispreferred, "
5861 "typdelim, typbyval, typalign, typstorage, "
5862 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) as typdefaultbin, typdefault "
5863 "FROM pg_catalog.pg_type "
5864 "WHERE oid = '%u'::pg_catalog.oid",
5865 tinfo->dobj.catId.oid);
5867 else if (fout->remoteVersion >= 80300)
5869 appendPQExpBuffer(query, "SELECT typlen, "
5870 "typinput, typoutput, typreceive, typsend, "
5871 "typmodin, typmodout, typanalyze, "
5872 "typinput::pg_catalog.oid as typinputoid, "
5873 "typoutput::pg_catalog.oid as typoutputoid, "
5874 "typreceive::pg_catalog.oid as typreceiveoid, "
5875 "typsend::pg_catalog.oid as typsendoid, "
5876 "typmodin::pg_catalog.oid as typmodinoid, "
5877 "typmodout::pg_catalog.oid as typmodoutoid, "
5878 "typanalyze::pg_catalog.oid as typanalyzeoid, "
5879 "'U' as typcategory, false as typispreferred, "
5880 "typdelim, typbyval, typalign, typstorage, "
5881 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) as typdefaultbin, typdefault "
5882 "FROM pg_catalog.pg_type "
5883 "WHERE oid = '%u'::pg_catalog.oid",
5884 tinfo->dobj.catId.oid);
5886 else if (fout->remoteVersion >= 80000)
5888 appendPQExpBuffer(query, "SELECT typlen, "
5889 "typinput, typoutput, typreceive, typsend, "
5890 "'-' as typmodin, '-' as typmodout, "
5891 "typanalyze, "
5892 "typinput::pg_catalog.oid as typinputoid, "
5893 "typoutput::pg_catalog.oid as typoutputoid, "
5894 "typreceive::pg_catalog.oid as typreceiveoid, "
5895 "typsend::pg_catalog.oid as typsendoid, "
5896 "0 as typmodinoid, 0 as typmodoutoid, "
5897 "typanalyze::pg_catalog.oid as typanalyzeoid, "
5898 "'U' as typcategory, false as typispreferred, "
5899 "typdelim, typbyval, typalign, typstorage, "
5900 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) as typdefaultbin, typdefault "
5901 "FROM pg_catalog.pg_type "
5902 "WHERE oid = '%u'::pg_catalog.oid",
5903 tinfo->dobj.catId.oid);
5905 else if (fout->remoteVersion >= 70400)
5907 appendPQExpBuffer(query, "SELECT typlen, "
5908 "typinput, typoutput, typreceive, typsend, "
5909 "'-' as typmodin, '-' as typmodout, "
5910 "'-' as typanalyze, "
5911 "typinput::pg_catalog.oid as typinputoid, "
5912 "typoutput::pg_catalog.oid as typoutputoid, "
5913 "typreceive::pg_catalog.oid as typreceiveoid, "
5914 "typsend::pg_catalog.oid as typsendoid, "
5915 "0 as typmodinoid, 0 as typmodoutoid, "
5916 "0 as typanalyzeoid, "
5917 "'U' as typcategory, false as typispreferred, "
5918 "typdelim, typbyval, typalign, typstorage, "
5919 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) as typdefaultbin, typdefault "
5920 "FROM pg_catalog.pg_type "
5921 "WHERE oid = '%u'::pg_catalog.oid",
5922 tinfo->dobj.catId.oid);
5924 else if (fout->remoteVersion >= 70300)
5926 appendPQExpBuffer(query, "SELECT typlen, "
5927 "typinput, typoutput, "
5928 "'-' as typreceive, '-' as typsend, "
5929 "'-' as typmodin, '-' as typmodout, "
5930 "'-' as typanalyze, "
5931 "typinput::pg_catalog.oid as typinputoid, "
5932 "typoutput::pg_catalog.oid as typoutputoid, "
5933 "0 as typreceiveoid, 0 as typsendoid, "
5934 "0 as typmodinoid, 0 as typmodoutoid, "
5935 "0 as typanalyzeoid, "
5936 "'U' as typcategory, false as typispreferred, "
5937 "typdelim, typbyval, typalign, typstorage, "
5938 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) as typdefaultbin, typdefault "
5939 "FROM pg_catalog.pg_type "
5940 "WHERE oid = '%u'::pg_catalog.oid",
5941 tinfo->dobj.catId.oid);
5943 else if (fout->remoteVersion >= 70200)
5946 * Note: although pre-7.3 catalogs contain typreceive and typsend,
5947 * ignore them because they are not right.
5949 appendPQExpBuffer(query, "SELECT typlen, "
5950 "typinput, typoutput, "
5951 "'-' as typreceive, '-' as typsend, "
5952 "'-' as typmodin, '-' as typmodout, "
5953 "'-' as typanalyze, "
5954 "typinput::oid as typinputoid, "
5955 "typoutput::oid as typoutputoid, "
5956 "0 as typreceiveoid, 0 as typsendoid, "
5957 "0 as typmodinoid, 0 as typmodoutoid, "
5958 "0 as typanalyzeoid, "
5959 "'U' as typcategory, false as typispreferred, "
5960 "typdelim, typbyval, typalign, typstorage, "
5961 "NULL as typdefaultbin, typdefault "
5962 "FROM pg_type "
5963 "WHERE oid = '%u'::oid",
5964 tinfo->dobj.catId.oid);
5966 else if (fout->remoteVersion >= 70100)
5969 * Ignore pre-7.2 typdefault; the field exists but has an unusable
5970 * representation.
5972 appendPQExpBuffer(query, "SELECT typlen, "
5973 "typinput, typoutput, "
5974 "'-' as typreceive, '-' as typsend, "
5975 "'-' as typmodin, '-' as typmodout, "
5976 "'-' as typanalyze, "
5977 "typinput::oid as typinputoid, "
5978 "typoutput::oid as typoutputoid, "
5979 "0 as typreceiveoid, 0 as typsendoid, "
5980 "0 as typmodinoid, 0 as typmodoutoid, "
5981 "0 as typanalyzeoid, "
5982 "'U' as typcategory, false as typispreferred, "
5983 "typdelim, typbyval, typalign, typstorage, "
5984 "NULL as typdefaultbin, NULL as typdefault "
5985 "FROM pg_type "
5986 "WHERE oid = '%u'::oid",
5987 tinfo->dobj.catId.oid);
5989 else
5991 appendPQExpBuffer(query, "SELECT typlen, "
5992 "typinput, typoutput, "
5993 "'-' as typreceive, '-' as typsend, "
5994 "'-' as typmodin, '-' as typmodout, "
5995 "'-' as typanalyze, "
5996 "typinput::oid as typinputoid, "
5997 "typoutput::oid as typoutputoid, "
5998 "0 as typreceiveoid, 0 as typsendoid, "
5999 "0 as typmodinoid, 0 as typmodoutoid, "
6000 "0 as typanalyzeoid, "
6001 "'U' as typcategory, false as typispreferred, "
6002 "typdelim, typbyval, typalign, "
6003 "'p'::char as typstorage, "
6004 "NULL as typdefaultbin, NULL as typdefault "
6005 "FROM pg_type "
6006 "WHERE oid = '%u'::oid",
6007 tinfo->dobj.catId.oid);
6010 res = PQexec(g_conn, query->data);
6011 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6013 /* Expecting a single result only */
6014 ntups = PQntuples(res);
6015 if (ntups != 1)
6017 write_msg(NULL, "query returned %d rows instead of one: %s\n",
6018 ntups, query->data);
6019 exit_nicely();
6022 typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
6023 typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
6024 typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
6025 typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
6026 typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
6027 typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
6028 typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
6029 typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
6030 typinputoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typinputoid")));
6031 typoutputoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typoutputoid")));
6032 typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
6033 typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
6034 typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
6035 typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
6036 typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
6037 typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
6038 typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
6039 typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
6040 typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
6041 typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
6042 typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
6043 if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
6044 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
6045 else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
6047 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
6048 typdefault_is_literal = true; /* it needs quotes */
6050 else
6051 typdefault = NULL;
6054 * DROP must be fully qualified in case same name appears in pg_catalog.
6055 * The reason we include CASCADE is that the circular dependency between
6056 * the type and its I/O functions makes it impossible to drop the type any
6057 * other way.
6059 appendPQExpBuffer(delq, "DROP TYPE %s.",
6060 fmtId(tinfo->dobj.namespace->dobj.name));
6061 appendPQExpBuffer(delq, "%s CASCADE;\n",
6062 fmtId(tinfo->dobj.name));
6064 appendPQExpBuffer(q,
6065 "CREATE TYPE %s (\n"
6066 " INTERNALLENGTH = %s",
6067 fmtId(tinfo->dobj.name),
6068 (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
6070 if (fout->remoteVersion >= 70300)
6072 /* regproc result is correctly quoted as of 7.3 */
6073 appendPQExpBuffer(q, ",\n INPUT = %s", typinput);
6074 appendPQExpBuffer(q, ",\n OUTPUT = %s", typoutput);
6075 if (OidIsValid(typreceiveoid))
6076 appendPQExpBuffer(q, ",\n RECEIVE = %s", typreceive);
6077 if (OidIsValid(typsendoid))
6078 appendPQExpBuffer(q, ",\n SEND = %s", typsend);
6079 if (OidIsValid(typmodinoid))
6080 appendPQExpBuffer(q, ",\n TYPMOD_IN = %s", typmodin);
6081 if (OidIsValid(typmodoutoid))
6082 appendPQExpBuffer(q, ",\n TYPMOD_OUT = %s", typmodout);
6083 if (OidIsValid(typanalyzeoid))
6084 appendPQExpBuffer(q, ",\n ANALYZE = %s", typanalyze);
6086 else
6088 /* regproc delivers an unquoted name before 7.3 */
6089 /* cannot combine these because fmtId uses static result area */
6090 appendPQExpBuffer(q, ",\n INPUT = %s", fmtId(typinput));
6091 appendPQExpBuffer(q, ",\n OUTPUT = %s", fmtId(typoutput));
6092 /* receive/send/typmodin/typmodout/analyze need not be printed */
6095 if (typdefault != NULL)
6097 appendPQExpBuffer(q, ",\n DEFAULT = ");
6098 if (typdefault_is_literal)
6099 appendStringLiteralAH(q, typdefault, fout);
6100 else
6101 appendPQExpBufferStr(q, typdefault);
6104 if (OidIsValid(tinfo->typelem))
6106 char *elemType;
6108 /* reselect schema in case changed by function dump */
6109 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6110 elemType = getFormattedTypeName(tinfo->typelem, zeroAsOpaque);
6111 appendPQExpBuffer(q, ",\n ELEMENT = %s", elemType);
6112 free(elemType);
6115 if (strcmp(typcategory, "U") != 0)
6117 appendPQExpBuffer(q, ",\n CATEGORY = ");
6118 appendStringLiteralAH(q, typcategory, fout);
6121 if (strcmp(typispreferred, "t") == 0)
6122 appendPQExpBuffer(q, ",\n PREFERRED = true");
6124 if (typdelim && strcmp(typdelim, ",") != 0)
6126 appendPQExpBuffer(q, ",\n DELIMITER = ");
6127 appendStringLiteralAH(q, typdelim, fout);
6130 if (strcmp(typalign, "c") == 0)
6131 appendPQExpBuffer(q, ",\n ALIGNMENT = char");
6132 else if (strcmp(typalign, "s") == 0)
6133 appendPQExpBuffer(q, ",\n ALIGNMENT = int2");
6134 else if (strcmp(typalign, "i") == 0)
6135 appendPQExpBuffer(q, ",\n ALIGNMENT = int4");
6136 else if (strcmp(typalign, "d") == 0)
6137 appendPQExpBuffer(q, ",\n ALIGNMENT = double");
6139 if (strcmp(typstorage, "p") == 0)
6140 appendPQExpBuffer(q, ",\n STORAGE = plain");
6141 else if (strcmp(typstorage, "e") == 0)
6142 appendPQExpBuffer(q, ",\n STORAGE = external");
6143 else if (strcmp(typstorage, "x") == 0)
6144 appendPQExpBuffer(q, ",\n STORAGE = extended");
6145 else if (strcmp(typstorage, "m") == 0)
6146 appendPQExpBuffer(q, ",\n STORAGE = main");
6148 if (strcmp(typbyval, "t") == 0)
6149 appendPQExpBuffer(q, ",\n PASSEDBYVALUE");
6151 appendPQExpBuffer(q, "\n);\n");
6153 ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
6154 tinfo->dobj.name,
6155 tinfo->dobj.namespace->dobj.name,
6156 NULL,
6157 tinfo->rolname, false,
6158 "TYPE", q->data, delq->data, NULL,
6159 tinfo->dobj.dependencies, tinfo->dobj.nDeps,
6160 NULL, NULL);
6162 /* Dump Type Comments */
6163 resetPQExpBuffer(q);
6165 appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->dobj.name));
6166 dumpComment(fout, q->data,
6167 tinfo->dobj.namespace->dobj.name, tinfo->rolname,
6168 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
6170 PQclear(res);
6171 destroyPQExpBuffer(q);
6172 destroyPQExpBuffer(delq);
6173 destroyPQExpBuffer(query);
6177 * dumpDomain
6178 * writes out to fout the queries to recreate a user-defined domain
6180 static void
6181 dumpDomain(Archive *fout, TypeInfo *tinfo)
6183 PQExpBuffer q = createPQExpBuffer();
6184 PQExpBuffer delq = createPQExpBuffer();
6185 PQExpBuffer query = createPQExpBuffer();
6186 PGresult *res;
6187 int ntups;
6188 int i;
6189 char *typnotnull;
6190 char *typdefn;
6191 char *typdefault;
6192 bool typdefault_is_literal = false;
6194 /* Set proper schema search path so type references list correctly */
6195 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6197 /* Fetch domain specific details */
6198 /* We assume here that remoteVersion must be at least 70300 */
6199 appendPQExpBuffer(query, "SELECT typnotnull, "
6200 "pg_catalog.format_type(typbasetype, typtypmod) as typdefn, "
6201 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) as typdefaultbin, typdefault "
6202 "FROM pg_catalog.pg_type "
6203 "WHERE oid = '%u'::pg_catalog.oid",
6204 tinfo->dobj.catId.oid);
6206 res = PQexec(g_conn, query->data);
6207 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6209 /* Expecting a single result only */
6210 ntups = PQntuples(res);
6211 if (ntups != 1)
6213 write_msg(NULL, "query returned %d rows instead of one: %s\n",
6214 ntups, query->data);
6215 exit_nicely();
6218 typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
6219 typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
6220 if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
6221 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
6222 else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
6224 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
6225 typdefault_is_literal = true; /* it needs quotes */
6227 else
6228 typdefault = NULL;
6230 appendPQExpBuffer(q,
6231 "CREATE DOMAIN %s AS %s",
6232 fmtId(tinfo->dobj.name),
6233 typdefn);
6235 if (typnotnull[0] == 't')
6236 appendPQExpBuffer(q, " NOT NULL");
6238 if (typdefault != NULL)
6240 appendPQExpBuffer(q, " DEFAULT ");
6241 if (typdefault_is_literal)
6242 appendStringLiteralAH(q, typdefault, fout);
6243 else
6244 appendPQExpBufferStr(q, typdefault);
6247 PQclear(res);
6250 * Add any CHECK constraints for the domain
6252 for (i = 0; i < tinfo->nDomChecks; i++)
6254 ConstraintInfo *domcheck = &(tinfo->domChecks[i]);
6256 if (!domcheck->separate)
6257 appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
6258 fmtId(domcheck->dobj.name), domcheck->condef);
6261 appendPQExpBuffer(q, ";\n");
6264 * DROP must be fully qualified in case same name appears in pg_catalog
6266 appendPQExpBuffer(delq, "DROP DOMAIN %s.",
6267 fmtId(tinfo->dobj.namespace->dobj.name));
6268 appendPQExpBuffer(delq, "%s;\n",
6269 fmtId(tinfo->dobj.name));
6271 ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
6272 tinfo->dobj.name,
6273 tinfo->dobj.namespace->dobj.name,
6274 NULL,
6275 tinfo->rolname, false,
6276 "DOMAIN", q->data, delq->data, NULL,
6277 tinfo->dobj.dependencies, tinfo->dobj.nDeps,
6278 NULL, NULL);
6280 /* Dump Domain Comments */
6281 resetPQExpBuffer(q);
6283 appendPQExpBuffer(q, "DOMAIN %s", fmtId(tinfo->dobj.name));
6284 dumpComment(fout, q->data,
6285 tinfo->dobj.namespace->dobj.name, tinfo->rolname,
6286 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
6288 destroyPQExpBuffer(q);
6289 destroyPQExpBuffer(delq);
6290 destroyPQExpBuffer(query);
6294 * dumpCompositeType
6295 * writes out to fout the queries to recreate a user-defined stand-alone
6296 * composite type
6298 static void
6299 dumpCompositeType(Archive *fout, TypeInfo *tinfo)
6301 PQExpBuffer q = createPQExpBuffer();
6302 PQExpBuffer delq = createPQExpBuffer();
6303 PQExpBuffer query = createPQExpBuffer();
6304 PGresult *res;
6305 int ntups;
6306 int i_attname;
6307 int i_atttypdefn;
6308 int i;
6310 /* Set proper schema search path so type references list correctly */
6311 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6313 /* Fetch type specific details */
6314 /* We assume here that remoteVersion must be at least 70300 */
6316 appendPQExpBuffer(query, "SELECT a.attname, "
6317 "pg_catalog.format_type(a.atttypid, a.atttypmod) as atttypdefn "
6318 "FROM pg_catalog.pg_type t, pg_catalog.pg_attribute a "
6319 "WHERE t.oid = '%u'::pg_catalog.oid "
6320 "AND a.attrelid = t.typrelid "
6321 "AND NOT a.attisdropped "
6322 "ORDER BY a.attnum ",
6323 tinfo->dobj.catId.oid);
6325 res = PQexec(g_conn, query->data);
6326 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6328 /* Expecting at least a single result */
6329 ntups = PQntuples(res);
6330 if (ntups < 1)
6332 write_msg(NULL, "query returned no rows: %s\n", query->data);
6333 exit_nicely();
6336 i_attname = PQfnumber(res, "attname");
6337 i_atttypdefn = PQfnumber(res, "atttypdefn");
6339 appendPQExpBuffer(q, "CREATE TYPE %s AS (",
6340 fmtId(tinfo->dobj.name));
6342 for (i = 0; i < ntups; i++)
6344 char *attname;
6345 char *atttypdefn;
6347 attname = PQgetvalue(res, i, i_attname);
6348 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
6350 appendPQExpBuffer(q, "\n\t%s %s", fmtId(attname), atttypdefn);
6351 if (i < ntups - 1)
6352 appendPQExpBuffer(q, ",");
6354 appendPQExpBuffer(q, "\n);\n");
6357 * DROP must be fully qualified in case same name appears in pg_catalog
6359 appendPQExpBuffer(delq, "DROP TYPE %s.",
6360 fmtId(tinfo->dobj.namespace->dobj.name));
6361 appendPQExpBuffer(delq, "%s;\n",
6362 fmtId(tinfo->dobj.name));
6364 ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
6365 tinfo->dobj.name,
6366 tinfo->dobj.namespace->dobj.name,
6367 NULL,
6368 tinfo->rolname, false,
6369 "TYPE", q->data, delq->data, NULL,
6370 tinfo->dobj.dependencies, tinfo->dobj.nDeps,
6371 NULL, NULL);
6374 /* Dump Type Comments */
6375 resetPQExpBuffer(q);
6377 appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->dobj.name));
6378 dumpComment(fout, q->data,
6379 tinfo->dobj.namespace->dobj.name, tinfo->rolname,
6380 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
6382 PQclear(res);
6383 destroyPQExpBuffer(q);
6384 destroyPQExpBuffer(delq);
6385 destroyPQExpBuffer(query);
6389 * dumpShellType
6390 * writes out to fout the queries to create a shell type
6392 * We dump a shell definition in advance of the I/O functions for the type.
6394 static void
6395 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
6397 PQExpBuffer q;
6399 /* Skip if not to be dumped */
6400 if (!stinfo->dobj.dump || dataOnly)
6401 return;
6403 q = createPQExpBuffer();
6406 * Note the lack of a DROP command for the shell type; any required DROP
6407 * is driven off the base type entry, instead. This interacts with
6408 * _printTocEntry()'s use of the presence of a DROP command to decide
6409 * whether an entry needs an ALTER OWNER command. We don't want to alter
6410 * the shell type's owner immediately on creation; that should happen only
6411 * after it's filled in, otherwise the backend complains.
6414 appendPQExpBuffer(q, "CREATE TYPE %s;\n",
6415 fmtId(stinfo->dobj.name));
6417 ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
6418 stinfo->dobj.name,
6419 stinfo->dobj.namespace->dobj.name,
6420 NULL,
6421 stinfo->baseType->rolname, false,
6422 "SHELL TYPE", q->data, "", NULL,
6423 stinfo->dobj.dependencies, stinfo->dobj.nDeps,
6424 NULL, NULL);
6426 destroyPQExpBuffer(q);
6430 * Determine whether we want to dump definitions for procedural languages.
6431 * Since the languages themselves don't have schemas, we can't rely on
6432 * the normal schema-based selection mechanism. We choose to dump them
6433 * whenever neither --schema nor --table was given. (Before 8.1, we used
6434 * the dump flag of the PL's call handler function, but in 8.1 this will
6435 * probably always be false since call handlers are created in pg_catalog.)
6437 * For some backwards compatibility with the older behavior, we forcibly
6438 * dump a PL if its handler function (and validator if any) are in a
6439 * dumpable namespace. That case is not checked here.
6441 static bool
6442 shouldDumpProcLangs(void)
6444 if (!include_everything)
6445 return false;
6446 /* And they're schema not data */
6447 if (dataOnly)
6448 return false;
6449 return true;
6453 * dumpProcLang
6454 * writes out to fout the queries to recreate a user-defined
6455 * procedural language
6457 static void
6458 dumpProcLang(Archive *fout, ProcLangInfo *plang)
6460 PQExpBuffer defqry;
6461 PQExpBuffer delqry;
6462 bool useParams;
6463 char *qlanname;
6464 char *lanschema;
6465 FuncInfo *funcInfo;
6466 FuncInfo *validatorInfo = NULL;
6468 if (dataOnly)
6469 return;
6472 * Try to find the support function(s). It is not an error if we don't
6473 * find them --- if the functions are in the pg_catalog schema, as is
6474 * standard in 8.1 and up, then we won't have loaded them. (In this case
6475 * we will emit a parameterless CREATE LANGUAGE command, which will
6476 * require PL template knowledge in the backend to reload.)
6479 funcInfo = findFuncByOid(plang->lanplcallfoid);
6480 if (funcInfo != NULL && !funcInfo->dobj.dump)
6481 funcInfo = NULL; /* treat not-dumped same as not-found */
6483 if (OidIsValid(plang->lanvalidator))
6485 validatorInfo = findFuncByOid(plang->lanvalidator);
6486 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
6487 validatorInfo = NULL;
6491 * If the functions are dumpable then emit a traditional CREATE LANGUAGE
6492 * with parameters. Otherwise, dump only if shouldDumpProcLangs() says to
6493 * dump it.
6495 useParams = (funcInfo != NULL &&
6496 (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
6498 if (!useParams && !shouldDumpProcLangs())
6499 return;
6501 defqry = createPQExpBuffer();
6502 delqry = createPQExpBuffer();
6504 qlanname = strdup(fmtId(plang->dobj.name));
6507 * If dumping a HANDLER clause, treat the language as being in the handler
6508 * function's schema; this avoids cluttering the HANDLER clause. Otherwise
6509 * it doesn't really have a schema.
6511 if (useParams)
6512 lanschema = funcInfo->dobj.namespace->dobj.name;
6513 else
6514 lanschema = NULL;
6516 appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
6517 qlanname);
6519 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
6520 (useParams && plang->lanpltrusted) ? "TRUSTED " : "",
6521 qlanname);
6522 if (useParams)
6524 appendPQExpBuffer(defqry, " HANDLER %s",
6525 fmtId(funcInfo->dobj.name));
6526 if (OidIsValid(plang->lanvalidator))
6528 appendPQExpBuffer(defqry, " VALIDATOR ");
6529 /* Cope with possibility that validator is in different schema */
6530 if (validatorInfo->dobj.namespace != funcInfo->dobj.namespace)
6531 appendPQExpBuffer(defqry, "%s.",
6532 fmtId(validatorInfo->dobj.namespace->dobj.name));
6533 appendPQExpBuffer(defqry, "%s",
6534 fmtId(validatorInfo->dobj.name));
6537 appendPQExpBuffer(defqry, ";\n");
6539 ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
6540 plang->dobj.name,
6541 lanschema, NULL, plang->lanowner,
6542 false, "PROCEDURAL LANGUAGE",
6543 defqry->data, delqry->data, NULL,
6544 plang->dobj.dependencies, plang->dobj.nDeps,
6545 NULL, NULL);
6547 /* Dump Proc Lang Comments */
6548 resetPQExpBuffer(defqry);
6549 appendPQExpBuffer(defqry, "LANGUAGE %s", qlanname);
6550 dumpComment(fout, defqry->data,
6551 NULL, "",
6552 plang->dobj.catId, 0, plang->dobj.dumpId);
6554 if (plang->lanpltrusted)
6555 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
6556 qlanname, plang->dobj.name,
6557 lanschema,
6558 plang->lanowner, plang->lanacl);
6560 free(qlanname);
6562 destroyPQExpBuffer(defqry);
6563 destroyPQExpBuffer(delqry);
6567 * format_function_arguments: generate function name and argument list
6569 * This is used when we can rely on pg_get_function_arguments to format
6570 * the argument list.
6572 static char *format_function_arguments(FuncInfo *finfo, char *funcargs)
6574 PQExpBufferData fn;
6576 initPQExpBuffer(&fn);
6577 appendPQExpBuffer(&fn, "%s(%s)", fmtId(finfo->dobj.name), funcargs);
6578 return fn.data;
6582 * format_function_arguments_old: generate function name and argument list
6584 * The argument type names are qualified if needed. The function name
6585 * is never qualified.
6587 * This is used only with pre-8.4 servers, so we aren't expecting to see
6588 * VARIADIC or TABLE arguments.
6590 * Any or all of allargtypes, argmodes, argnames may be NULL.
6592 static char *
6593 format_function_arguments_old(FuncInfo *finfo, int nallargs,
6594 char **allargtypes,
6595 char **argmodes,
6596 char **argnames)
6598 PQExpBufferData fn;
6599 int j;
6601 initPQExpBuffer(&fn);
6602 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
6603 for (j = 0; j < nallargs; j++)
6605 Oid typid;
6606 char *typname;
6607 const char *argmode;
6608 const char *argname;
6610 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
6611 typname = getFormattedTypeName(typid, zeroAsOpaque);
6613 if (argmodes)
6615 switch (argmodes[j][0])
6617 case PROARGMODE_IN:
6618 argmode = "";
6619 break;
6620 case PROARGMODE_OUT:
6621 argmode = "OUT ";
6622 break;
6623 case PROARGMODE_INOUT:
6624 argmode = "INOUT ";
6625 break;
6626 default:
6627 write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
6628 argmode = "";
6629 break;
6632 else
6633 argmode = "";
6635 argname = argnames ? argnames[j] : (char *) NULL;
6636 if (argname && argname[0] == '\0')
6637 argname = NULL;
6639 appendPQExpBuffer(&fn, "%s%s%s%s%s",
6640 (j > 0) ? ", " : "",
6641 argmode,
6642 argname ? fmtId(argname) : "",
6643 argname ? " " : "",
6644 typname);
6645 free(typname);
6647 appendPQExpBuffer(&fn, ")");
6648 return fn.data;
6652 * format_function_signature: generate function name and argument list
6654 * This is like format_function_arguments_old except that only a minimal
6655 * list of input argument types is generated; this is sufficient to
6656 * reference the function, but not to define it.
6658 * If honor_quotes is false then the function name is never quoted.
6659 * This is appropriate for use in TOC tags, but not in SQL commands.
6661 static char *
6662 format_function_signature(FuncInfo *finfo, bool honor_quotes)
6664 PQExpBufferData fn;
6665 int j;
6667 initPQExpBuffer(&fn);
6668 if (honor_quotes)
6669 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
6670 else
6671 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
6672 for (j = 0; j < finfo->nargs; j++)
6674 char *typname;
6676 typname = getFormattedTypeName(finfo->argtypes[j], zeroAsOpaque);
6678 appendPQExpBuffer(&fn, "%s%s",
6679 (j > 0) ? ", " : "",
6680 typname);
6681 free(typname);
6683 appendPQExpBuffer(&fn, ")");
6684 return fn.data;
6689 * dumpFunc:
6690 * dump out one function
6692 static void
6693 dumpFunc(Archive *fout, FuncInfo *finfo)
6695 PQExpBuffer query;
6696 PQExpBuffer q;
6697 PQExpBuffer delqry;
6698 PQExpBuffer asPart;
6699 PGresult *res;
6700 char *funcsig;
6701 char *funcsig_tag;
6702 int ntups;
6703 char *proretset;
6704 char *prosrc;
6705 char *probin;
6706 char *funcargs;
6707 char *funcresult;
6708 char *proallargtypes;
6709 char *proargmodes;
6710 char *proargnames;
6711 char *provolatile;
6712 char *proisstrict;
6713 char *prosecdef;
6714 char *proconfig;
6715 char *procost;
6716 char *prorows;
6717 char *lanname;
6718 char *rettypename;
6719 int nallargs;
6720 char **allargtypes = NULL;
6721 char **argmodes = NULL;
6722 char **argnames = NULL;
6723 char **configitems = NULL;
6724 int nconfigitems = 0;
6725 int i;
6727 /* Skip if not to be dumped */
6728 if (!finfo->dobj.dump || dataOnly)
6729 return;
6731 query = createPQExpBuffer();
6732 q = createPQExpBuffer();
6733 delqry = createPQExpBuffer();
6734 asPart = createPQExpBuffer();
6736 /* Set proper schema search path so type references list correctly */
6737 selectSourceSchema(finfo->dobj.namespace->dobj.name);
6739 /* Fetch function-specific details */
6740 if (g_fout->remoteVersion >= 80400)
6743 * In 8.4 and up we rely on pg_get_function_arguments and
6744 * pg_get_function_result instead of examining proallargtypes etc.
6746 appendPQExpBuffer(query,
6747 "SELECT proretset, prosrc, probin, "
6748 "pg_catalog.pg_get_function_arguments(oid) as funcargs, "
6749 "pg_catalog.pg_get_function_result(oid) as funcresult, "
6750 "provolatile, proisstrict, prosecdef, "
6751 "proconfig, procost, prorows, "
6752 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
6753 "FROM pg_catalog.pg_proc "
6754 "WHERE oid = '%u'::pg_catalog.oid",
6755 finfo->dobj.catId.oid);
6757 else if (g_fout->remoteVersion >= 80300)
6759 appendPQExpBuffer(query,
6760 "SELECT proretset, prosrc, probin, "
6761 "proallargtypes, proargmodes, proargnames, "
6762 "provolatile, proisstrict, prosecdef, "
6763 "proconfig, procost, prorows, "
6764 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
6765 "FROM pg_catalog.pg_proc "
6766 "WHERE oid = '%u'::pg_catalog.oid",
6767 finfo->dobj.catId.oid);
6769 else if (g_fout->remoteVersion >= 80100)
6771 appendPQExpBuffer(query,
6772 "SELECT proretset, prosrc, probin, "
6773 "proallargtypes, proargmodes, proargnames, "
6774 "provolatile, proisstrict, prosecdef, "
6775 "null as proconfig, 0 as procost, 0 as prorows, "
6776 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
6777 "FROM pg_catalog.pg_proc "
6778 "WHERE oid = '%u'::pg_catalog.oid",
6779 finfo->dobj.catId.oid);
6781 else if (g_fout->remoteVersion >= 80000)
6783 appendPQExpBuffer(query,
6784 "SELECT proretset, prosrc, probin, "
6785 "null as proallargtypes, "
6786 "null as proargmodes, "
6787 "proargnames, "
6788 "provolatile, proisstrict, prosecdef, "
6789 "null as proconfig, 0 as procost, 0 as prorows, "
6790 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
6791 "FROM pg_catalog.pg_proc "
6792 "WHERE oid = '%u'::pg_catalog.oid",
6793 finfo->dobj.catId.oid);
6795 else if (g_fout->remoteVersion >= 70300)
6797 appendPQExpBuffer(query,
6798 "SELECT proretset, prosrc, probin, "
6799 "null as proallargtypes, "
6800 "null as proargmodes, "
6801 "null as proargnames, "
6802 "provolatile, proisstrict, prosecdef, "
6803 "null as proconfig, 0 as procost, 0 as prorows, "
6804 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
6805 "FROM pg_catalog.pg_proc "
6806 "WHERE oid = '%u'::pg_catalog.oid",
6807 finfo->dobj.catId.oid);
6809 else if (g_fout->remoteVersion >= 70100)
6811 appendPQExpBuffer(query,
6812 "SELECT proretset, prosrc, probin, "
6813 "null as proallargtypes, "
6814 "null as proargmodes, "
6815 "null as proargnames, "
6816 "case when proiscachable then 'i' else 'v' end as provolatile, "
6817 "proisstrict, "
6818 "'f'::boolean as prosecdef, "
6819 "null as proconfig, 0 as procost, 0 as prorows, "
6820 "(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
6821 "FROM pg_proc "
6822 "WHERE oid = '%u'::oid",
6823 finfo->dobj.catId.oid);
6825 else
6827 appendPQExpBuffer(query,
6828 "SELECT proretset, prosrc, probin, "
6829 "null as proallargtypes, "
6830 "null as proargmodes, "
6831 "null as proargnames, "
6832 "case when proiscachable then 'i' else 'v' end as provolatile, "
6833 "'f'::boolean as proisstrict, "
6834 "'f'::boolean as prosecdef, "
6835 "null as proconfig, 0 as procost, 0 as prorows, "
6836 "(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
6837 "FROM pg_proc "
6838 "WHERE oid = '%u'::oid",
6839 finfo->dobj.catId.oid);
6842 res = PQexec(g_conn, query->data);
6843 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6845 /* Expecting a single result only */
6846 ntups = PQntuples(res);
6847 if (ntups != 1)
6849 write_msg(NULL, "query returned %d rows instead of one: %s\n",
6850 ntups, query->data);
6851 exit_nicely();
6854 proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
6855 prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
6856 probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
6857 if (g_fout->remoteVersion >= 80400)
6859 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
6860 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
6861 proallargtypes = proargmodes = proargnames = NULL;
6863 else
6865 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
6866 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
6867 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
6868 funcargs = funcresult = NULL;
6870 provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
6871 proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
6872 prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
6873 proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
6874 procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
6875 prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
6876 lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
6879 * See backend/commands/functioncmds.c for details of how the 'AS' clause
6880 * is used. In 8.4 and up, an unused probin is NULL (here ""); previous
6881 * versions would set it to "-". There are no known cases in which prosrc
6882 * is unused, so the tests below for "-" are probably useless.
6884 if (probin[0] != '\0' && strcmp(probin, "-") != 0)
6886 appendPQExpBuffer(asPart, "AS ");
6887 appendStringLiteralAH(asPart, probin, fout);
6888 if (strcmp(prosrc, "-") != 0)
6890 appendPQExpBuffer(asPart, ", ");
6893 * where we have bin, use dollar quoting if allowed and src
6894 * contains quote or backslash; else use regular quoting.
6896 if (disable_dollar_quoting ||
6897 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
6898 appendStringLiteralAH(asPart, prosrc, fout);
6899 else
6900 appendStringLiteralDQ(asPart, prosrc, NULL);
6903 else
6905 if (strcmp(prosrc, "-") != 0)
6907 appendPQExpBuffer(asPart, "AS ");
6908 /* with no bin, dollar quote src unconditionally if allowed */
6909 if (disable_dollar_quoting)
6910 appendStringLiteralAH(asPart, prosrc, fout);
6911 else
6912 appendStringLiteralDQ(asPart, prosrc, NULL);
6916 nallargs = finfo->nargs; /* unless we learn different from allargs */
6918 if (proallargtypes && *proallargtypes)
6920 int nitems = 0;
6922 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
6923 nitems < finfo->nargs)
6925 write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
6926 if (allargtypes)
6927 free(allargtypes);
6928 allargtypes = NULL;
6930 else
6931 nallargs = nitems;
6934 if (proargmodes && *proargmodes)
6936 int nitems = 0;
6938 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
6939 nitems != nallargs)
6941 write_msg(NULL, "WARNING: could not parse proargmodes array\n");
6942 if (argmodes)
6943 free(argmodes);
6944 argmodes = NULL;
6948 if (proargnames && *proargnames)
6950 int nitems = 0;
6952 if (!parsePGArray(proargnames, &argnames, &nitems) ||
6953 nitems != nallargs)
6955 write_msg(NULL, "WARNING: could not parse proargnames array\n");
6956 if (argnames)
6957 free(argnames);
6958 argnames = NULL;
6962 if (proconfig && *proconfig)
6964 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
6966 write_msg(NULL, "WARNING: could not parse proconfig array\n");
6967 if (configitems)
6968 free(configitems);
6969 configitems = NULL;
6970 nconfigitems = 0;
6974 if (funcargs)
6975 funcsig = format_function_arguments(finfo, funcargs);
6976 else
6977 funcsig = format_function_arguments_old(finfo, nallargs, allargtypes,
6978 argmodes, argnames);
6979 funcsig_tag = format_function_signature(finfo, false);
6982 * DROP must be fully qualified in case same name appears in pg_catalog
6984 appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
6985 fmtId(finfo->dobj.namespace->dobj.name),
6986 funcsig);
6988 appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcsig);
6989 if (funcresult)
6990 appendPQExpBuffer(q, "RETURNS %s", funcresult);
6991 else
6993 rettypename = getFormattedTypeName(finfo->prorettype, zeroAsOpaque);
6994 appendPQExpBuffer(q, "RETURNS %s%s",
6995 (proretset[0] == 't') ? "SETOF " : "",
6996 rettypename);
6997 free(rettypename);
7000 appendPQExpBuffer(q, "\n LANGUAGE %s", fmtId(lanname));
7001 if (provolatile[0] != PROVOLATILE_VOLATILE)
7003 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
7004 appendPQExpBuffer(q, " IMMUTABLE");
7005 else if (provolatile[0] == PROVOLATILE_STABLE)
7006 appendPQExpBuffer(q, " STABLE");
7007 else if (provolatile[0] != PROVOLATILE_VOLATILE)
7009 write_msg(NULL, "unrecognized provolatile value for function \"%s\"\n",
7010 finfo->dobj.name);
7011 exit_nicely();
7015 if (proisstrict[0] == 't')
7016 appendPQExpBuffer(q, " STRICT");
7018 if (prosecdef[0] == 't')
7019 appendPQExpBuffer(q, " SECURITY DEFINER");
7022 * COST and ROWS are emitted only if present and not default, so as not to
7023 * break backwards-compatibility of the dump without need. Keep this code
7024 * in sync with the defaults in functioncmds.c.
7026 if (strcmp(procost, "0") != 0)
7028 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
7030 /* default cost is 1 */
7031 if (strcmp(procost, "1") != 0)
7032 appendPQExpBuffer(q, " COST %s", procost);
7034 else
7036 /* default cost is 100 */
7037 if (strcmp(procost, "100") != 0)
7038 appendPQExpBuffer(q, " COST %s", procost);
7041 if (proretset[0] == 't' &&
7042 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
7043 appendPQExpBuffer(q, " ROWS %s", prorows);
7045 for (i = 0; i < nconfigitems; i++)
7047 /* we feel free to scribble on configitems[] here */
7048 char *configitem = configitems[i];
7049 char *pos;
7051 pos = strchr(configitem, '=');
7052 if (pos == NULL)
7053 continue;
7054 *pos++ = '\0';
7055 appendPQExpBuffer(q, "\n SET %s TO ", fmtId(configitem));
7058 * Some GUC variable names are 'LIST' type and hence must not be
7059 * quoted.
7061 if (pg_strcasecmp(configitem, "DateStyle") == 0
7062 || pg_strcasecmp(configitem, "search_path") == 0)
7063 appendPQExpBuffer(q, "%s", pos);
7064 else
7065 appendStringLiteralAH(q, pos, fout);
7068 appendPQExpBuffer(q, "\n %s;\n", asPart->data);
7070 ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
7071 funcsig_tag,
7072 finfo->dobj.namespace->dobj.name,
7073 NULL,
7074 finfo->rolname, false,
7075 "FUNCTION", q->data, delqry->data, NULL,
7076 finfo->dobj.dependencies, finfo->dobj.nDeps,
7077 NULL, NULL);
7079 /* Dump Function Comments */
7080 resetPQExpBuffer(q);
7081 appendPQExpBuffer(q, "FUNCTION %s", funcsig);
7082 dumpComment(fout, q->data,
7083 finfo->dobj.namespace->dobj.name, finfo->rolname,
7084 finfo->dobj.catId, 0, finfo->dobj.dumpId);
7086 dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
7087 funcsig, funcsig_tag,
7088 finfo->dobj.namespace->dobj.name,
7089 finfo->rolname, finfo->proacl);
7091 PQclear(res);
7093 destroyPQExpBuffer(query);
7094 destroyPQExpBuffer(q);
7095 destroyPQExpBuffer(delqry);
7096 destroyPQExpBuffer(asPart);
7097 free(funcsig);
7098 free(funcsig_tag);
7099 if (allargtypes)
7100 free(allargtypes);
7101 if (argmodes)
7102 free(argmodes);
7103 if (argnames)
7104 free(argnames);
7105 if (configitems)
7106 free(configitems);
7111 * Dump a user-defined cast
7113 static void
7114 dumpCast(Archive *fout, CastInfo *cast)
7116 PQExpBuffer defqry;
7117 PQExpBuffer delqry;
7118 PQExpBuffer castsig;
7119 FuncInfo *funcInfo = NULL;
7120 TypeInfo *sourceInfo;
7121 TypeInfo *targetInfo;
7123 if (dataOnly)
7124 return;
7126 if (OidIsValid(cast->castfunc))
7128 funcInfo = findFuncByOid(cast->castfunc);
7129 if (funcInfo == NULL)
7130 return;
7134 * As per discussion we dump casts if one or more of the underlying
7135 * objects (the conversion function and the two data types) are not
7136 * builtin AND if all of the non-builtin objects are included in the dump.
7137 * Builtin meaning, the namespace name does not start with "pg_".
7139 sourceInfo = findTypeByOid(cast->castsource);
7140 targetInfo = findTypeByOid(cast->casttarget);
7142 if (sourceInfo == NULL || targetInfo == NULL)
7143 return;
7146 * Skip this cast if all objects are from pg_
7148 if ((funcInfo == NULL ||
7149 strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
7150 strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) == 0 &&
7151 strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) == 0)
7152 return;
7155 * Skip cast if function isn't from pg_ and is not to be dumped.
7157 if (funcInfo &&
7158 strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
7159 !funcInfo->dobj.dump)
7160 return;
7163 * Same for the source type
7165 if (strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
7166 !sourceInfo->dobj.dump)
7167 return;
7170 * and the target type.
7172 if (strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
7173 !targetInfo->dobj.dump)
7174 return;
7176 /* Make sure we are in proper schema (needed for getFormattedTypeName) */
7177 selectSourceSchema("pg_catalog");
7179 defqry = createPQExpBuffer();
7180 delqry = createPQExpBuffer();
7181 castsig = createPQExpBuffer();
7183 appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
7184 getFormattedTypeName(cast->castsource, zeroAsNone),
7185 getFormattedTypeName(cast->casttarget, zeroAsNone));
7187 appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
7188 getFormattedTypeName(cast->castsource, zeroAsNone),
7189 getFormattedTypeName(cast->casttarget, zeroAsNone));
7191 if (!OidIsValid(cast->castfunc))
7192 appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
7193 else
7196 * Always qualify the function name, in case it is not in pg_catalog
7197 * schema (format_function_signature won't qualify it).
7199 appendPQExpBuffer(defqry, "WITH FUNCTION %s.",
7200 fmtId(funcInfo->dobj.namespace->dobj.name));
7201 appendPQExpBuffer(defqry, "%s",
7202 format_function_signature(funcInfo, true));
7205 if (cast->castcontext == 'a')
7206 appendPQExpBuffer(defqry, " AS ASSIGNMENT");
7207 else if (cast->castcontext == 'i')
7208 appendPQExpBuffer(defqry, " AS IMPLICIT");
7209 appendPQExpBuffer(defqry, ";\n");
7211 appendPQExpBuffer(castsig, "CAST (%s AS %s)",
7212 getFormattedTypeName(cast->castsource, zeroAsNone),
7213 getFormattedTypeName(cast->casttarget, zeroAsNone));
7215 ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
7216 castsig->data,
7217 "pg_catalog", NULL, "",
7218 false, "CAST", defqry->data, delqry->data, NULL,
7219 cast->dobj.dependencies, cast->dobj.nDeps,
7220 NULL, NULL);
7222 /* Dump Cast Comments */
7223 resetPQExpBuffer(defqry);
7224 appendPQExpBuffer(defqry, "CAST (%s AS %s)",
7225 getFormattedTypeName(cast->castsource, zeroAsNone),
7226 getFormattedTypeName(cast->casttarget, zeroAsNone));
7227 dumpComment(fout, defqry->data,
7228 NULL, "",
7229 cast->dobj.catId, 0, cast->dobj.dumpId);
7231 destroyPQExpBuffer(defqry);
7232 destroyPQExpBuffer(delqry);
7233 destroyPQExpBuffer(castsig);
7237 * dumpOpr
7238 * write out a single operator definition
7240 static void
7241 dumpOpr(Archive *fout, OprInfo *oprinfo)
7243 PQExpBuffer query;
7244 PQExpBuffer q;
7245 PQExpBuffer delq;
7246 PQExpBuffer oprid;
7247 PQExpBuffer details;
7248 const char *name;
7249 PGresult *res;
7250 int ntups;
7251 int i_oprkind;
7252 int i_oprcode;
7253 int i_oprleft;
7254 int i_oprright;
7255 int i_oprcom;
7256 int i_oprnegate;
7257 int i_oprrest;
7258 int i_oprjoin;
7259 int i_oprcanmerge;
7260 int i_oprcanhash;
7261 char *oprkind;
7262 char *oprcode;
7263 char *oprleft;
7264 char *oprright;
7265 char *oprcom;
7266 char *oprnegate;
7267 char *oprrest;
7268 char *oprjoin;
7269 char *oprcanmerge;
7270 char *oprcanhash;
7272 /* Skip if not to be dumped */
7273 if (!oprinfo->dobj.dump || dataOnly)
7274 return;
7277 * some operators are invalid because they were the result of user
7278 * defining operators before commutators exist
7280 if (!OidIsValid(oprinfo->oprcode))
7281 return;
7283 query = createPQExpBuffer();
7284 q = createPQExpBuffer();
7285 delq = createPQExpBuffer();
7286 oprid = createPQExpBuffer();
7287 details = createPQExpBuffer();
7289 /* Make sure we are in proper schema so regoperator works correctly */
7290 selectSourceSchema(oprinfo->dobj.namespace->dobj.name);
7292 if (g_fout->remoteVersion >= 80300)
7294 appendPQExpBuffer(query, "SELECT oprkind, "
7295 "oprcode::pg_catalog.regprocedure, "
7296 "oprleft::pg_catalog.regtype, "
7297 "oprright::pg_catalog.regtype, "
7298 "oprcom::pg_catalog.regoperator, "
7299 "oprnegate::pg_catalog.regoperator, "
7300 "oprrest::pg_catalog.regprocedure, "
7301 "oprjoin::pg_catalog.regprocedure, "
7302 "oprcanmerge, oprcanhash "
7303 "from pg_catalog.pg_operator "
7304 "where oid = '%u'::pg_catalog.oid",
7305 oprinfo->dobj.catId.oid);
7307 else if (g_fout->remoteVersion >= 70300)
7309 appendPQExpBuffer(query, "SELECT oprkind, "
7310 "oprcode::pg_catalog.regprocedure, "
7311 "oprleft::pg_catalog.regtype, "
7312 "oprright::pg_catalog.regtype, "
7313 "oprcom::pg_catalog.regoperator, "
7314 "oprnegate::pg_catalog.regoperator, "
7315 "oprrest::pg_catalog.regprocedure, "
7316 "oprjoin::pg_catalog.regprocedure, "
7317 "(oprlsortop != 0) as oprcanmerge, "
7318 "oprcanhash "
7319 "from pg_catalog.pg_operator "
7320 "where oid = '%u'::pg_catalog.oid",
7321 oprinfo->dobj.catId.oid);
7323 else if (g_fout->remoteVersion >= 70100)
7325 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
7326 "CASE WHEN oprleft = 0 THEN '-' "
7327 "ELSE format_type(oprleft, NULL) END as oprleft, "
7328 "CASE WHEN oprright = 0 THEN '-' "
7329 "ELSE format_type(oprright, NULL) END as oprright, "
7330 "oprcom, oprnegate, oprrest, oprjoin, "
7331 "(oprlsortop != 0) as oprcanmerge, "
7332 "oprcanhash "
7333 "from pg_operator "
7334 "where oid = '%u'::oid",
7335 oprinfo->dobj.catId.oid);
7337 else
7339 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
7340 "CASE WHEN oprleft = 0 THEN '-'::name "
7341 "ELSE (select typname from pg_type where oid = oprleft) END as oprleft, "
7342 "CASE WHEN oprright = 0 THEN '-'::name "
7343 "ELSE (select typname from pg_type where oid = oprright) END as oprright, "
7344 "oprcom, oprnegate, oprrest, oprjoin, "
7345 "(oprlsortop != 0) as oprcanmerge, "
7346 "oprcanhash "
7347 "from pg_operator "
7348 "where oid = '%u'::oid",
7349 oprinfo->dobj.catId.oid);
7352 res = PQexec(g_conn, query->data);
7353 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7355 /* Expecting a single result only */
7356 ntups = PQntuples(res);
7357 if (ntups != 1)
7359 write_msg(NULL, "query returned %d rows instead of one: %s\n",
7360 ntups, query->data);
7361 exit_nicely();
7364 i_oprkind = PQfnumber(res, "oprkind");
7365 i_oprcode = PQfnumber(res, "oprcode");
7366 i_oprleft = PQfnumber(res, "oprleft");
7367 i_oprright = PQfnumber(res, "oprright");
7368 i_oprcom = PQfnumber(res, "oprcom");
7369 i_oprnegate = PQfnumber(res, "oprnegate");
7370 i_oprrest = PQfnumber(res, "oprrest");
7371 i_oprjoin = PQfnumber(res, "oprjoin");
7372 i_oprcanmerge = PQfnumber(res, "oprcanmerge");
7373 i_oprcanhash = PQfnumber(res, "oprcanhash");
7375 oprkind = PQgetvalue(res, 0, i_oprkind);
7376 oprcode = PQgetvalue(res, 0, i_oprcode);
7377 oprleft = PQgetvalue(res, 0, i_oprleft);
7378 oprright = PQgetvalue(res, 0, i_oprright);
7379 oprcom = PQgetvalue(res, 0, i_oprcom);
7380 oprnegate = PQgetvalue(res, 0, i_oprnegate);
7381 oprrest = PQgetvalue(res, 0, i_oprrest);
7382 oprjoin = PQgetvalue(res, 0, i_oprjoin);
7383 oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
7384 oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
7386 appendPQExpBuffer(details, " PROCEDURE = %s",
7387 convertRegProcReference(oprcode));
7389 appendPQExpBuffer(oprid, "%s (",
7390 oprinfo->dobj.name);
7393 * right unary means there's a left arg and left unary means there's a
7394 * right arg
7396 if (strcmp(oprkind, "r") == 0 ||
7397 strcmp(oprkind, "b") == 0)
7399 if (g_fout->remoteVersion >= 70100)
7400 name = oprleft;
7401 else
7402 name = fmtId(oprleft);
7403 appendPQExpBuffer(details, ",\n LEFTARG = %s", name);
7404 appendPQExpBuffer(oprid, "%s", name);
7406 else
7407 appendPQExpBuffer(oprid, "NONE");
7409 if (strcmp(oprkind, "l") == 0 ||
7410 strcmp(oprkind, "b") == 0)
7412 if (g_fout->remoteVersion >= 70100)
7413 name = oprright;
7414 else
7415 name = fmtId(oprright);
7416 appendPQExpBuffer(details, ",\n RIGHTARG = %s", name);
7417 appendPQExpBuffer(oprid, ", %s)", name);
7419 else
7420 appendPQExpBuffer(oprid, ", NONE)");
7422 name = convertOperatorReference(oprcom);
7423 if (name)
7424 appendPQExpBuffer(details, ",\n COMMUTATOR = %s", name);
7426 name = convertOperatorReference(oprnegate);
7427 if (name)
7428 appendPQExpBuffer(details, ",\n NEGATOR = %s", name);
7430 if (strcmp(oprcanmerge, "t") == 0)
7431 appendPQExpBuffer(details, ",\n MERGES");
7433 if (strcmp(oprcanhash, "t") == 0)
7434 appendPQExpBuffer(details, ",\n HASHES");
7436 name = convertRegProcReference(oprrest);
7437 if (name)
7438 appendPQExpBuffer(details, ",\n RESTRICT = %s", name);
7440 name = convertRegProcReference(oprjoin);
7441 if (name)
7442 appendPQExpBuffer(details, ",\n JOIN = %s", name);
7445 * DROP must be fully qualified in case same name appears in pg_catalog
7447 appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
7448 fmtId(oprinfo->dobj.namespace->dobj.name),
7449 oprid->data);
7451 appendPQExpBuffer(q, "CREATE OPERATOR %s (\n%s\n);\n",
7452 oprinfo->dobj.name, details->data);
7454 ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
7455 oprinfo->dobj.name,
7456 oprinfo->dobj.namespace->dobj.name,
7457 NULL,
7458 oprinfo->rolname,
7459 false, "OPERATOR", q->data, delq->data, NULL,
7460 oprinfo->dobj.dependencies, oprinfo->dobj.nDeps,
7461 NULL, NULL);
7463 /* Dump Operator Comments */
7464 resetPQExpBuffer(q);
7465 appendPQExpBuffer(q, "OPERATOR %s", oprid->data);
7466 dumpComment(fout, q->data,
7467 oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
7468 oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
7470 PQclear(res);
7472 destroyPQExpBuffer(query);
7473 destroyPQExpBuffer(q);
7474 destroyPQExpBuffer(delq);
7475 destroyPQExpBuffer(oprid);
7476 destroyPQExpBuffer(details);
7480 * Convert a function reference obtained from pg_operator
7482 * Returns what to print, or NULL if function references is InvalidOid
7484 * In 7.3 the input is a REGPROCEDURE display; we have to strip the
7485 * argument-types part. In prior versions, the input is a REGPROC display.
7487 static const char *
7488 convertRegProcReference(const char *proc)
7490 /* In all cases "-" means a null reference */
7491 if (strcmp(proc, "-") == 0)
7492 return NULL;
7494 if (g_fout->remoteVersion >= 70300)
7496 char *name;
7497 char *paren;
7498 bool inquote;
7500 name = strdup(proc);
7501 /* find non-double-quoted left paren */
7502 inquote = false;
7503 for (paren = name; *paren; paren++)
7505 if (*paren == '(' && !inquote)
7507 *paren = '\0';
7508 break;
7510 if (*paren == '"')
7511 inquote = !inquote;
7513 return name;
7516 /* REGPROC before 7.3 does not quote its result */
7517 return fmtId(proc);
7521 * Convert an operator cross-reference obtained from pg_operator
7523 * Returns what to print, or NULL to print nothing
7525 * In 7.3 and up the input is a REGOPERATOR display; we have to strip the
7526 * argument-types part, and add OPERATOR() decoration if the name is
7527 * schema-qualified. In older versions, the input is just a numeric OID,
7528 * which we search our operator list for.
7530 static const char *
7531 convertOperatorReference(const char *opr)
7533 OprInfo *oprInfo;
7535 /* In all cases "0" means a null reference */
7536 if (strcmp(opr, "0") == 0)
7537 return NULL;
7539 if (g_fout->remoteVersion >= 70300)
7541 char *name;
7542 char *oname;
7543 char *ptr;
7544 bool inquote;
7545 bool sawdot;
7547 name = strdup(opr);
7548 /* find non-double-quoted left paren, and check for non-quoted dot */
7549 inquote = false;
7550 sawdot = false;
7551 for (ptr = name; *ptr; ptr++)
7553 if (*ptr == '"')
7554 inquote = !inquote;
7555 else if (*ptr == '.' && !inquote)
7556 sawdot = true;
7557 else if (*ptr == '(' && !inquote)
7559 *ptr = '\0';
7560 break;
7563 /* If not schema-qualified, don't need to add OPERATOR() */
7564 if (!sawdot)
7565 return name;
7566 oname = malloc(strlen(name) + 11);
7567 sprintf(oname, "OPERATOR(%s)", name);
7568 free(name);
7569 return oname;
7572 oprInfo = findOprByOid(atooid(opr));
7573 if (oprInfo == NULL)
7575 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
7576 opr);
7577 return NULL;
7579 return oprInfo->dobj.name;
7583 * Convert a function OID obtained from pg_ts_parser or pg_ts_template
7585 * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
7586 * argument lists of these functions are predetermined. Note that the
7587 * caller should ensure we are in the proper schema, because the results
7588 * are search path dependent!
7590 static const char *
7591 convertTSFunction(Oid funcOid)
7593 char *result;
7594 char query[128];
7595 PGresult *res;
7596 int ntups;
7598 snprintf(query, sizeof(query),
7599 "SELECT '%u'::pg_catalog.regproc", funcOid);
7600 res = PQexec(g_conn, query);
7601 check_sql_result(res, g_conn, query, PGRES_TUPLES_OK);
7603 ntups = PQntuples(res);
7604 if (ntups != 1)
7606 write_msg(NULL, "query returned %d rows instead of one: %s\n",
7607 ntups, query);
7608 exit_nicely();
7611 result = strdup(PQgetvalue(res, 0, 0));
7613 PQclear(res);
7615 return result;
7620 * dumpOpclass
7621 * write out a single operator class definition
7623 static void
7624 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
7626 PQExpBuffer query;
7627 PQExpBuffer q;
7628 PQExpBuffer delq;
7629 PGresult *res;
7630 int ntups;
7631 int i_opcintype;
7632 int i_opckeytype;
7633 int i_opcdefault;
7634 int i_opcfamily;
7635 int i_opcfamilynsp;
7636 int i_amname;
7637 int i_amopstrategy;
7638 int i_amopreqcheck;
7639 int i_amopopr;
7640 int i_amprocnum;
7641 int i_amproc;
7642 char *opcintype;
7643 char *opckeytype;
7644 char *opcdefault;
7645 char *opcfamily;
7646 char *opcfamilynsp;
7647 char *amname;
7648 char *amopstrategy;
7649 char *amopreqcheck;
7650 char *amopopr;
7651 char *amprocnum;
7652 char *amproc;
7653 bool needComma;
7654 int i;
7656 /* Skip if not to be dumped */
7657 if (!opcinfo->dobj.dump || dataOnly)
7658 return;
7661 * XXX currently we do not implement dumping of operator classes from
7662 * pre-7.3 databases. This could be done but it seems not worth the
7663 * trouble.
7665 if (g_fout->remoteVersion < 70300)
7666 return;
7668 query = createPQExpBuffer();
7669 q = createPQExpBuffer();
7670 delq = createPQExpBuffer();
7672 /* Make sure we are in proper schema so regoperator works correctly */
7673 selectSourceSchema(opcinfo->dobj.namespace->dobj.name);
7675 /* Get additional fields from the pg_opclass row */
7676 if (g_fout->remoteVersion >= 80300)
7678 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
7679 "opckeytype::pg_catalog.regtype, "
7680 "opcdefault, "
7681 "opfname AS opcfamily, "
7682 "nspname AS opcfamilynsp, "
7683 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
7684 "FROM pg_catalog.pg_opclass c "
7685 "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
7686 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
7687 "WHERE c.oid = '%u'::pg_catalog.oid",
7688 opcinfo->dobj.catId.oid);
7690 else
7692 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
7693 "opckeytype::pg_catalog.regtype, "
7694 "opcdefault, "
7695 "NULL AS opcfamily, "
7696 "NULL AS opcfamilynsp, "
7697 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
7698 "FROM pg_catalog.pg_opclass "
7699 "WHERE oid = '%u'::pg_catalog.oid",
7700 opcinfo->dobj.catId.oid);
7703 res = PQexec(g_conn, query->data);
7704 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7706 /* Expecting a single result only */
7707 ntups = PQntuples(res);
7708 if (ntups != 1)
7710 write_msg(NULL, "query returned %d rows instead of one: %s\n",
7711 ntups, query->data);
7712 exit_nicely();
7715 i_opcintype = PQfnumber(res, "opcintype");
7716 i_opckeytype = PQfnumber(res, "opckeytype");
7717 i_opcdefault = PQfnumber(res, "opcdefault");
7718 i_opcfamily = PQfnumber(res, "opcfamily");
7719 i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
7720 i_amname = PQfnumber(res, "amname");
7722 opcintype = PQgetvalue(res, 0, i_opcintype);
7723 opckeytype = PQgetvalue(res, 0, i_opckeytype);
7724 opcdefault = PQgetvalue(res, 0, i_opcdefault);
7725 opcfamily = PQgetvalue(res, 0, i_opcfamily);
7726 opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
7727 /* amname will still be needed after we PQclear res */
7728 amname = strdup(PQgetvalue(res, 0, i_amname));
7731 * DROP must be fully qualified in case same name appears in pg_catalog
7733 appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
7734 fmtId(opcinfo->dobj.namespace->dobj.name));
7735 appendPQExpBuffer(delq, ".%s",
7736 fmtId(opcinfo->dobj.name));
7737 appendPQExpBuffer(delq, " USING %s;\n",
7738 fmtId(amname));
7740 /* Build the fixed portion of the CREATE command */
7741 appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n ",
7742 fmtId(opcinfo->dobj.name));
7743 if (strcmp(opcdefault, "t") == 0)
7744 appendPQExpBuffer(q, "DEFAULT ");
7745 appendPQExpBuffer(q, "FOR TYPE %s USING %s",
7746 opcintype,
7747 fmtId(amname));
7748 if (strlen(opcfamily) > 0 &&
7749 (strcmp(opcfamily, opcinfo->dobj.name) != 0 ||
7750 strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
7752 appendPQExpBuffer(q, " FAMILY ");
7753 if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
7754 appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
7755 appendPQExpBuffer(q, "%s", fmtId(opcfamily));
7757 appendPQExpBuffer(q, " AS\n ");
7759 needComma = false;
7761 if (strcmp(opckeytype, "-") != 0)
7763 appendPQExpBuffer(q, "STORAGE %s",
7764 opckeytype);
7765 needComma = true;
7768 PQclear(res);
7771 * Now fetch and print the OPERATOR entries (pg_amop rows).
7773 resetPQExpBuffer(query);
7775 if (g_fout->remoteVersion >= 80400)
7778 * Print only those opfamily members that are tied to the opclass by
7779 * pg_depend entries.
7781 * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping
7782 * an older server's table in which it is used. Would it be better
7783 * to silently ignore it?
7785 appendPQExpBuffer(query, "SELECT amopstrategy, false as amopreqcheck, "
7786 "amopopr::pg_catalog.regoperator "
7787 "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
7788 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
7789 "AND refobjid = '%u'::pg_catalog.oid "
7790 "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
7791 "AND objid = ao.oid "
7792 "ORDER BY amopstrategy",
7793 opcinfo->dobj.catId.oid);
7795 else if (g_fout->remoteVersion >= 80300)
7798 * Print only those opfamily members that are tied to the opclass by
7799 * pg_depend entries.
7801 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
7802 "amopopr::pg_catalog.regoperator "
7803 "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
7804 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
7805 "AND refobjid = '%u'::pg_catalog.oid "
7806 "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
7807 "AND objid = ao.oid "
7808 "ORDER BY amopstrategy",
7809 opcinfo->dobj.catId.oid);
7811 else
7813 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
7814 "amopopr::pg_catalog.regoperator "
7815 "FROM pg_catalog.pg_amop "
7816 "WHERE amopclaid = '%u'::pg_catalog.oid "
7817 "ORDER BY amopstrategy",
7818 opcinfo->dobj.catId.oid);
7821 res = PQexec(g_conn, query->data);
7822 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7824 ntups = PQntuples(res);
7826 i_amopstrategy = PQfnumber(res, "amopstrategy");
7827 i_amopreqcheck = PQfnumber(res, "amopreqcheck");
7828 i_amopopr = PQfnumber(res, "amopopr");
7830 for (i = 0; i < ntups; i++)
7832 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
7833 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
7834 amopopr = PQgetvalue(res, i, i_amopopr);
7836 if (needComma)
7837 appendPQExpBuffer(q, " ,\n ");
7839 appendPQExpBuffer(q, "OPERATOR %s %s",
7840 amopstrategy, amopopr);
7841 if (strcmp(amopreqcheck, "t") == 0)
7842 appendPQExpBuffer(q, " RECHECK");
7844 needComma = true;
7847 PQclear(res);
7850 * Now fetch and print the FUNCTION entries (pg_amproc rows).
7852 resetPQExpBuffer(query);
7854 if (g_fout->remoteVersion >= 80300)
7857 * Print only those opfamily members that are tied to the opclass by
7858 * pg_depend entries.
7860 appendPQExpBuffer(query, "SELECT amprocnum, "
7861 "amproc::pg_catalog.regprocedure "
7862 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
7863 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
7864 "AND refobjid = '%u'::pg_catalog.oid "
7865 "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
7866 "AND objid = ap.oid "
7867 "ORDER BY amprocnum",
7868 opcinfo->dobj.catId.oid);
7870 else
7872 appendPQExpBuffer(query, "SELECT amprocnum, "
7873 "amproc::pg_catalog.regprocedure "
7874 "FROM pg_catalog.pg_amproc "
7875 "WHERE amopclaid = '%u'::pg_catalog.oid "
7876 "ORDER BY amprocnum",
7877 opcinfo->dobj.catId.oid);
7880 res = PQexec(g_conn, query->data);
7881 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7883 ntups = PQntuples(res);
7885 i_amprocnum = PQfnumber(res, "amprocnum");
7886 i_amproc = PQfnumber(res, "amproc");
7888 for (i = 0; i < ntups; i++)
7890 amprocnum = PQgetvalue(res, i, i_amprocnum);
7891 amproc = PQgetvalue(res, i, i_amproc);
7893 if (needComma)
7894 appendPQExpBuffer(q, " ,\n ");
7896 appendPQExpBuffer(q, "FUNCTION %s %s",
7897 amprocnum, amproc);
7899 needComma = true;
7902 PQclear(res);
7904 appendPQExpBuffer(q, ";\n");
7906 ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
7907 opcinfo->dobj.name,
7908 opcinfo->dobj.namespace->dobj.name,
7909 NULL,
7910 opcinfo->rolname,
7911 false, "OPERATOR CLASS", q->data, delq->data, NULL,
7912 opcinfo->dobj.dependencies, opcinfo->dobj.nDeps,
7913 NULL, NULL);
7915 /* Dump Operator Class Comments */
7916 resetPQExpBuffer(q);
7917 appendPQExpBuffer(q, "OPERATOR CLASS %s",
7918 fmtId(opcinfo->dobj.name));
7919 appendPQExpBuffer(q, " USING %s",
7920 fmtId(amname));
7921 dumpComment(fout, q->data,
7922 NULL, opcinfo->rolname,
7923 opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
7925 free(amname);
7926 destroyPQExpBuffer(query);
7927 destroyPQExpBuffer(q);
7928 destroyPQExpBuffer(delq);
7932 * dumpOpfamily
7933 * write out a single operator family definition
7935 static void
7936 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
7938 PQExpBuffer query;
7939 PQExpBuffer q;
7940 PQExpBuffer delq;
7941 PGresult *res;
7942 PGresult *res_ops;
7943 PGresult *res_procs;
7944 int ntups;
7945 int i_amname;
7946 int i_amopstrategy;
7947 int i_amopreqcheck;
7948 int i_amopopr;
7949 int i_amprocnum;
7950 int i_amproc;
7951 int i_amproclefttype;
7952 int i_amprocrighttype;
7953 char *amname;
7954 char *amopstrategy;
7955 char *amopreqcheck;
7956 char *amopopr;
7957 char *amprocnum;
7958 char *amproc;
7959 char *amproclefttype;
7960 char *amprocrighttype;
7961 bool needComma;
7962 int i;
7964 /* Skip if not to be dumped */
7965 if (!opfinfo->dobj.dump || dataOnly)
7966 return;
7969 * We want to dump the opfamily only if (1) it contains "loose" operators
7970 * or functions, or (2) it contains an opclass with a different name or
7971 * owner. Otherwise it's sufficient to let it be created during creation
7972 * of the contained opclass, and not dumping it improves portability of
7973 * the dump. Since we have to fetch the loose operators/funcs anyway, do
7974 * that first.
7977 query = createPQExpBuffer();
7978 q = createPQExpBuffer();
7979 delq = createPQExpBuffer();
7981 /* Make sure we are in proper schema so regoperator works correctly */
7982 selectSourceSchema(opfinfo->dobj.namespace->dobj.name);
7985 * Fetch only those opfamily members that are tied directly to the
7986 * opfamily by pg_depend entries.
7988 if (g_fout->remoteVersion >= 80400)
7991 * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping
7992 * an older server's table in which it is used. Would it be better
7993 * to silently ignore it?
7995 appendPQExpBuffer(query, "SELECT amopstrategy, false as amopreqcheck, "
7996 "amopopr::pg_catalog.regoperator "
7997 "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
7998 "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
7999 "AND refobjid = '%u'::pg_catalog.oid "
8000 "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
8001 "AND objid = ao.oid "
8002 "ORDER BY amopstrategy",
8003 opfinfo->dobj.catId.oid);
8005 else
8007 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
8008 "amopopr::pg_catalog.regoperator "
8009 "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
8010 "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8011 "AND refobjid = '%u'::pg_catalog.oid "
8012 "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
8013 "AND objid = ao.oid "
8014 "ORDER BY amopstrategy",
8015 opfinfo->dobj.catId.oid);
8018 res_ops = PQexec(g_conn, query->data);
8019 check_sql_result(res_ops, g_conn, query->data, PGRES_TUPLES_OK);
8021 resetPQExpBuffer(query);
8023 appendPQExpBuffer(query, "SELECT amprocnum, "
8024 "amproc::pg_catalog.regprocedure, "
8025 "amproclefttype::pg_catalog.regtype, "
8026 "amprocrighttype::pg_catalog.regtype "
8027 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
8028 "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8029 "AND refobjid = '%u'::pg_catalog.oid "
8030 "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
8031 "AND objid = ap.oid "
8032 "ORDER BY amprocnum",
8033 opfinfo->dobj.catId.oid);
8035 res_procs = PQexec(g_conn, query->data);
8036 check_sql_result(res_procs, g_conn, query->data, PGRES_TUPLES_OK);
8038 if (PQntuples(res_ops) == 0 && PQntuples(res_procs) == 0)
8040 /* No loose members, so check contained opclasses */
8041 resetPQExpBuffer(query);
8043 appendPQExpBuffer(query, "SELECT 1 "
8044 "FROM pg_catalog.pg_opclass c, pg_catalog.pg_opfamily f, pg_catalog.pg_depend "
8045 "WHERE f.oid = '%u'::pg_catalog.oid "
8046 "AND refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8047 "AND refobjid = f.oid "
8048 "AND classid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
8049 "AND objid = c.oid "
8050 "AND (opcname != opfname OR opcnamespace != opfnamespace OR opcowner != opfowner) "
8051 "LIMIT 1",
8052 opfinfo->dobj.catId.oid);
8054 res = PQexec(g_conn, query->data);
8055 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8057 if (PQntuples(res) == 0)
8059 /* no need to dump it, so bail out */
8060 PQclear(res);
8061 PQclear(res_ops);
8062 PQclear(res_procs);
8063 destroyPQExpBuffer(query);
8064 destroyPQExpBuffer(q);
8065 destroyPQExpBuffer(delq);
8066 return;
8069 PQclear(res);
8072 /* Get additional fields from the pg_opfamily row */
8073 resetPQExpBuffer(query);
8075 appendPQExpBuffer(query, "SELECT "
8076 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
8077 "FROM pg_catalog.pg_opfamily "
8078 "WHERE oid = '%u'::pg_catalog.oid",
8079 opfinfo->dobj.catId.oid);
8081 res = PQexec(g_conn, query->data);
8082 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8084 /* Expecting a single result only */
8085 ntups = PQntuples(res);
8086 if (ntups != 1)
8088 write_msg(NULL, "query returned %d rows instead of one: %s\n",
8089 ntups, query->data);
8090 exit_nicely();
8093 i_amname = PQfnumber(res, "amname");
8095 /* amname will still be needed after we PQclear res */
8096 amname = strdup(PQgetvalue(res, 0, i_amname));
8099 * DROP must be fully qualified in case same name appears in pg_catalog
8101 appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
8102 fmtId(opfinfo->dobj.namespace->dobj.name));
8103 appendPQExpBuffer(delq, ".%s",
8104 fmtId(opfinfo->dobj.name));
8105 appendPQExpBuffer(delq, " USING %s;\n",
8106 fmtId(amname));
8108 /* Build the fixed portion of the CREATE command */
8109 appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
8110 fmtId(opfinfo->dobj.name));
8111 appendPQExpBuffer(q, " USING %s;\n",
8112 fmtId(amname));
8114 PQclear(res);
8116 /* Do we need an ALTER to add loose members? */
8117 if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
8119 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
8120 fmtId(opfinfo->dobj.name));
8121 appendPQExpBuffer(q, " USING %s ADD\n ",
8122 fmtId(amname));
8124 needComma = false;
8127 * Now fetch and print the OPERATOR entries (pg_amop rows).
8129 ntups = PQntuples(res_ops);
8131 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
8132 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
8133 i_amopopr = PQfnumber(res_ops, "amopopr");
8135 for (i = 0; i < ntups; i++)
8137 amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
8138 amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
8139 amopopr = PQgetvalue(res_ops, i, i_amopopr);
8141 if (needComma)
8142 appendPQExpBuffer(q, " ,\n ");
8144 appendPQExpBuffer(q, "OPERATOR %s %s",
8145 amopstrategy, amopopr);
8146 if (strcmp(amopreqcheck, "t") == 0)
8147 appendPQExpBuffer(q, " RECHECK");
8149 needComma = true;
8153 * Now fetch and print the FUNCTION entries (pg_amproc rows).
8155 ntups = PQntuples(res_procs);
8157 i_amprocnum = PQfnumber(res_procs, "amprocnum");
8158 i_amproc = PQfnumber(res_procs, "amproc");
8159 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
8160 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
8162 for (i = 0; i < ntups; i++)
8164 amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
8165 amproc = PQgetvalue(res_procs, i, i_amproc);
8166 amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
8167 amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
8169 if (needComma)
8170 appendPQExpBuffer(q, " ,\n ");
8172 appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
8173 amprocnum, amproclefttype, amprocrighttype,
8174 amproc);
8176 needComma = true;
8179 appendPQExpBuffer(q, ";\n");
8182 ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
8183 opfinfo->dobj.name,
8184 opfinfo->dobj.namespace->dobj.name,
8185 NULL,
8186 opfinfo->rolname,
8187 false, "OPERATOR FAMILY", q->data, delq->data, NULL,
8188 opfinfo->dobj.dependencies, opfinfo->dobj.nDeps,
8189 NULL, NULL);
8191 /* Dump Operator Family Comments */
8192 resetPQExpBuffer(q);
8193 appendPQExpBuffer(q, "OPERATOR FAMILY %s",
8194 fmtId(opfinfo->dobj.name));
8195 appendPQExpBuffer(q, " USING %s",
8196 fmtId(amname));
8197 dumpComment(fout, q->data,
8198 NULL, opfinfo->rolname,
8199 opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
8201 free(amname);
8202 PQclear(res_ops);
8203 PQclear(res_procs);
8204 destroyPQExpBuffer(query);
8205 destroyPQExpBuffer(q);
8206 destroyPQExpBuffer(delq);
8210 * dumpConversion
8211 * write out a single conversion definition
8213 static void
8214 dumpConversion(Archive *fout, ConvInfo *convinfo)
8216 PQExpBuffer query;
8217 PQExpBuffer q;
8218 PQExpBuffer delq;
8219 PQExpBuffer details;
8220 PGresult *res;
8221 int ntups;
8222 int i_conname;
8223 int i_conforencoding;
8224 int i_contoencoding;
8225 int i_conproc;
8226 int i_condefault;
8227 const char *conname;
8228 const char *conforencoding;
8229 const char *contoencoding;
8230 const char *conproc;
8231 bool condefault;
8233 /* Skip if not to be dumped */
8234 if (!convinfo->dobj.dump || dataOnly)
8235 return;
8237 query = createPQExpBuffer();
8238 q = createPQExpBuffer();
8239 delq = createPQExpBuffer();
8240 details = createPQExpBuffer();
8242 /* Make sure we are in proper schema */
8243 selectSourceSchema(convinfo->dobj.namespace->dobj.name);
8245 /* Get conversion-specific details */
8246 appendPQExpBuffer(query, "SELECT conname, "
8247 "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
8248 "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
8249 "conproc, condefault "
8250 "FROM pg_catalog.pg_conversion c "
8251 "WHERE c.oid = '%u'::pg_catalog.oid",
8252 convinfo->dobj.catId.oid);
8254 res = PQexec(g_conn, query->data);
8255 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8257 /* Expecting a single result only */
8258 ntups = PQntuples(res);
8259 if (ntups != 1)
8261 write_msg(NULL, "query returned %d rows instead of one: %s\n",
8262 ntups, query->data);
8263 exit_nicely();
8266 i_conname = PQfnumber(res, "conname");
8267 i_conforencoding = PQfnumber(res, "conforencoding");
8268 i_contoencoding = PQfnumber(res, "contoencoding");
8269 i_conproc = PQfnumber(res, "conproc");
8270 i_condefault = PQfnumber(res, "condefault");
8272 conname = PQgetvalue(res, 0, i_conname);
8273 conforencoding = PQgetvalue(res, 0, i_conforencoding);
8274 contoencoding = PQgetvalue(res, 0, i_contoencoding);
8275 conproc = PQgetvalue(res, 0, i_conproc);
8276 condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
8279 * DROP must be fully qualified in case same name appears in pg_catalog
8281 appendPQExpBuffer(delq, "DROP CONVERSION %s",
8282 fmtId(convinfo->dobj.namespace->dobj.name));
8283 appendPQExpBuffer(delq, ".%s;\n",
8284 fmtId(convinfo->dobj.name));
8286 appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
8287 (condefault) ? "DEFAULT " : "",
8288 fmtId(convinfo->dobj.name));
8289 appendStringLiteralAH(q, conforencoding, fout);
8290 appendPQExpBuffer(q, " TO ");
8291 appendStringLiteralAH(q, contoencoding, fout);
8292 /* regproc is automatically quoted in 7.3 and above */
8293 appendPQExpBuffer(q, " FROM %s;\n", conproc);
8295 ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
8296 convinfo->dobj.name,
8297 convinfo->dobj.namespace->dobj.name,
8298 NULL,
8299 convinfo->rolname,
8300 false, "CONVERSION", q->data, delq->data, NULL,
8301 convinfo->dobj.dependencies, convinfo->dobj.nDeps,
8302 NULL, NULL);
8304 /* Dump Conversion Comments */
8305 resetPQExpBuffer(q);
8306 appendPQExpBuffer(q, "CONVERSION %s", fmtId(convinfo->dobj.name));
8307 dumpComment(fout, q->data,
8308 convinfo->dobj.namespace->dobj.name, convinfo->rolname,
8309 convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
8311 PQclear(res);
8313 destroyPQExpBuffer(query);
8314 destroyPQExpBuffer(q);
8315 destroyPQExpBuffer(delq);
8316 destroyPQExpBuffer(details);
8320 * format_aggregate_signature: generate aggregate name and argument list
8322 * The argument type names are qualified if needed. The aggregate name
8323 * is never qualified.
8325 static char *
8326 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
8328 PQExpBufferData buf;
8329 int j;
8331 initPQExpBuffer(&buf);
8332 if (honor_quotes)
8333 appendPQExpBuffer(&buf, "%s",
8334 fmtId(agginfo->aggfn.dobj.name));
8335 else
8336 appendPQExpBuffer(&buf, "%s", agginfo->aggfn.dobj.name);
8338 if (agginfo->aggfn.nargs == 0)
8339 appendPQExpBuffer(&buf, "(*)");
8340 else
8342 appendPQExpBuffer(&buf, "(");
8343 for (j = 0; j < agginfo->aggfn.nargs; j++)
8345 char *typname;
8347 typname = getFormattedTypeName(agginfo->aggfn.argtypes[j], zeroAsOpaque);
8349 appendPQExpBuffer(&buf, "%s%s",
8350 (j > 0) ? ", " : "",
8351 typname);
8352 free(typname);
8354 appendPQExpBuffer(&buf, ")");
8356 return buf.data;
8360 * dumpAgg
8361 * write out a single aggregate definition
8363 static void
8364 dumpAgg(Archive *fout, AggInfo *agginfo)
8366 PQExpBuffer query;
8367 PQExpBuffer q;
8368 PQExpBuffer delq;
8369 PQExpBuffer details;
8370 char *aggsig;
8371 char *aggsig_tag;
8372 PGresult *res;
8373 int ntups;
8374 int i_aggtransfn;
8375 int i_aggfinalfn;
8376 int i_aggsortop;
8377 int i_aggtranstype;
8378 int i_agginitval;
8379 int i_convertok;
8380 const char *aggtransfn;
8381 const char *aggfinalfn;
8382 const char *aggsortop;
8383 const char *aggtranstype;
8384 const char *agginitval;
8385 bool convertok;
8387 /* Skip if not to be dumped */
8388 if (!agginfo->aggfn.dobj.dump || dataOnly)
8389 return;
8391 query = createPQExpBuffer();
8392 q = createPQExpBuffer();
8393 delq = createPQExpBuffer();
8394 details = createPQExpBuffer();
8396 /* Make sure we are in proper schema */
8397 selectSourceSchema(agginfo->aggfn.dobj.namespace->dobj.name);
8399 /* Get aggregate-specific details */
8400 if (g_fout->remoteVersion >= 80100)
8402 appendPQExpBuffer(query, "SELECT aggtransfn, "
8403 "aggfinalfn, aggtranstype::pg_catalog.regtype, "
8404 "aggsortop::pg_catalog.regoperator, "
8405 "agginitval, "
8406 "'t'::boolean as convertok "
8407 "from pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
8408 "where a.aggfnoid = p.oid "
8409 "and p.oid = '%u'::pg_catalog.oid",
8410 agginfo->aggfn.dobj.catId.oid);
8412 else if (g_fout->remoteVersion >= 70300)
8414 appendPQExpBuffer(query, "SELECT aggtransfn, "
8415 "aggfinalfn, aggtranstype::pg_catalog.regtype, "
8416 "0 as aggsortop, "
8417 "agginitval, "
8418 "'t'::boolean as convertok "
8419 "from pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
8420 "where a.aggfnoid = p.oid "
8421 "and p.oid = '%u'::pg_catalog.oid",
8422 agginfo->aggfn.dobj.catId.oid);
8424 else if (g_fout->remoteVersion >= 70100)
8426 appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
8427 "format_type(aggtranstype, NULL) as aggtranstype, "
8428 "0 as aggsortop, "
8429 "agginitval, "
8430 "'t'::boolean as convertok "
8431 "from pg_aggregate "
8432 "where oid = '%u'::oid",
8433 agginfo->aggfn.dobj.catId.oid);
8435 else
8437 appendPQExpBuffer(query, "SELECT aggtransfn1 as aggtransfn, "
8438 "aggfinalfn, "
8439 "(select typname from pg_type where oid = aggtranstype1) as aggtranstype, "
8440 "0 as aggsortop, "
8441 "agginitval1 as agginitval, "
8442 "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) as convertok "
8443 "from pg_aggregate "
8444 "where oid = '%u'::oid",
8445 agginfo->aggfn.dobj.catId.oid);
8448 res = PQexec(g_conn, query->data);
8449 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8451 /* Expecting a single result only */
8452 ntups = PQntuples(res);
8453 if (ntups != 1)
8455 write_msg(NULL, "query returned %d rows instead of one: %s\n",
8456 ntups, query->data);
8457 exit_nicely();
8460 i_aggtransfn = PQfnumber(res, "aggtransfn");
8461 i_aggfinalfn = PQfnumber(res, "aggfinalfn");
8462 i_aggsortop = PQfnumber(res, "aggsortop");
8463 i_aggtranstype = PQfnumber(res, "aggtranstype");
8464 i_agginitval = PQfnumber(res, "agginitval");
8465 i_convertok = PQfnumber(res, "convertok");
8467 aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
8468 aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
8469 aggsortop = PQgetvalue(res, 0, i_aggsortop);
8470 aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
8471 agginitval = PQgetvalue(res, 0, i_agginitval);
8472 convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
8474 aggsig = format_aggregate_signature(agginfo, fout, true);
8475 aggsig_tag = format_aggregate_signature(agginfo, fout, false);
8477 if (!convertok)
8479 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
8480 aggsig);
8481 return;
8484 if (g_fout->remoteVersion >= 70300)
8486 /* If using 7.3's regproc or regtype, data is already quoted */
8487 appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
8488 aggtransfn,
8489 aggtranstype);
8491 else if (g_fout->remoteVersion >= 70100)
8493 /* format_type quotes, regproc does not */
8494 appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
8495 fmtId(aggtransfn),
8496 aggtranstype);
8498 else
8500 /* need quotes all around */
8501 appendPQExpBuffer(details, " SFUNC = %s,\n",
8502 fmtId(aggtransfn));
8503 appendPQExpBuffer(details, " STYPE = %s",
8504 fmtId(aggtranstype));
8507 if (!PQgetisnull(res, 0, i_agginitval))
8509 appendPQExpBuffer(details, ",\n INITCOND = ");
8510 appendStringLiteralAH(details, agginitval, fout);
8513 if (strcmp(aggfinalfn, "-") != 0)
8515 appendPQExpBuffer(details, ",\n FINALFUNC = %s",
8516 aggfinalfn);
8519 aggsortop = convertOperatorReference(aggsortop);
8520 if (aggsortop)
8522 appendPQExpBuffer(details, ",\n SORTOP = %s",
8523 aggsortop);
8527 * DROP must be fully qualified in case same name appears in pg_catalog
8529 appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
8530 fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
8531 aggsig);
8533 appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
8534 aggsig, details->data);
8536 ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
8537 aggsig_tag,
8538 agginfo->aggfn.dobj.namespace->dobj.name,
8539 NULL,
8540 agginfo->aggfn.rolname,
8541 false, "AGGREGATE", q->data, delq->data, NULL,
8542 agginfo->aggfn.dobj.dependencies, agginfo->aggfn.dobj.nDeps,
8543 NULL, NULL);
8545 /* Dump Aggregate Comments */
8546 resetPQExpBuffer(q);
8547 appendPQExpBuffer(q, "AGGREGATE %s", aggsig);
8548 dumpComment(fout, q->data,
8549 agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
8550 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
8553 * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
8554 * command look like a function's GRANT; in particular this affects the
8555 * syntax for zero-argument aggregates.
8557 free(aggsig);
8558 free(aggsig_tag);
8560 aggsig = format_function_signature(&agginfo->aggfn, true);
8561 aggsig_tag = format_function_signature(&agginfo->aggfn, false);
8563 dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
8564 "FUNCTION",
8565 aggsig, aggsig_tag,
8566 agginfo->aggfn.dobj.namespace->dobj.name,
8567 agginfo->aggfn.rolname, agginfo->aggfn.proacl);
8569 free(aggsig);
8570 free(aggsig_tag);
8572 PQclear(res);
8574 destroyPQExpBuffer(query);
8575 destroyPQExpBuffer(q);
8576 destroyPQExpBuffer(delq);
8577 destroyPQExpBuffer(details);
8581 * dumpTSParser
8582 * write out a single text search parser
8584 static void
8585 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
8587 PQExpBuffer q;
8588 PQExpBuffer delq;
8590 /* Skip if not to be dumped */
8591 if (!prsinfo->dobj.dump || dataOnly)
8592 return;
8594 q = createPQExpBuffer();
8595 delq = createPQExpBuffer();
8597 /* Make sure we are in proper schema */
8598 selectSourceSchema(prsinfo->dobj.namespace->dobj.name);
8600 appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
8601 fmtId(prsinfo->dobj.name));
8603 appendPQExpBuffer(q, " START = %s,\n",
8604 convertTSFunction(prsinfo->prsstart));
8605 appendPQExpBuffer(q, " GETTOKEN = %s,\n",
8606 convertTSFunction(prsinfo->prstoken));
8607 appendPQExpBuffer(q, " END = %s,\n",
8608 convertTSFunction(prsinfo->prsend));
8609 if (prsinfo->prsheadline != InvalidOid)
8610 appendPQExpBuffer(q, " HEADLINE = %s,\n",
8611 convertTSFunction(prsinfo->prsheadline));
8612 appendPQExpBuffer(q, " LEXTYPES = %s );\n",
8613 convertTSFunction(prsinfo->prslextype));
8616 * DROP must be fully qualified in case same name appears in pg_catalog
8618 appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s",
8619 fmtId(prsinfo->dobj.namespace->dobj.name));
8620 appendPQExpBuffer(delq, ".%s;\n",
8621 fmtId(prsinfo->dobj.name));
8623 ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
8624 prsinfo->dobj.name,
8625 prsinfo->dobj.namespace->dobj.name,
8626 NULL,
8628 false, "TEXT SEARCH PARSER", q->data, delq->data, NULL,
8629 prsinfo->dobj.dependencies, prsinfo->dobj.nDeps,
8630 NULL, NULL);
8632 /* Dump Parser Comments */
8633 resetPQExpBuffer(q);
8634 appendPQExpBuffer(q, "TEXT SEARCH PARSER %s",
8635 fmtId(prsinfo->dobj.name));
8636 dumpComment(fout, q->data,
8637 NULL, "",
8638 prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
8640 destroyPQExpBuffer(q);
8641 destroyPQExpBuffer(delq);
8645 * dumpTSDictionary
8646 * write out a single text search dictionary
8648 static void
8649 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
8651 PQExpBuffer q;
8652 PQExpBuffer delq;
8653 PQExpBuffer query;
8654 PGresult *res;
8655 int ntups;
8656 char *nspname;
8657 char *tmplname;
8659 /* Skip if not to be dumped */
8660 if (!dictinfo->dobj.dump || dataOnly)
8661 return;
8663 q = createPQExpBuffer();
8664 delq = createPQExpBuffer();
8665 query = createPQExpBuffer();
8667 /* Fetch name and namespace of the dictionary's template */
8668 selectSourceSchema("pg_catalog");
8669 appendPQExpBuffer(query, "SELECT nspname, tmplname "
8670 "FROM pg_ts_template p, pg_namespace n "
8671 "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
8672 dictinfo->dicttemplate);
8673 res = PQexec(g_conn, query->data);
8674 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8675 ntups = PQntuples(res);
8676 if (ntups != 1)
8678 write_msg(NULL, "query returned %d rows instead of one: %s\n",
8679 ntups, query->data);
8680 exit_nicely();
8682 nspname = PQgetvalue(res, 0, 0);
8683 tmplname = PQgetvalue(res, 0, 1);
8685 /* Make sure we are in proper schema */
8686 selectSourceSchema(dictinfo->dobj.namespace->dobj.name);
8688 appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
8689 fmtId(dictinfo->dobj.name));
8691 appendPQExpBuffer(q, " TEMPLATE = ");
8692 if (strcmp(nspname, dictinfo->dobj.namespace->dobj.name) != 0)
8693 appendPQExpBuffer(q, "%s.", fmtId(nspname));
8694 appendPQExpBuffer(q, "%s", fmtId(tmplname));
8696 PQclear(res);
8698 /* the dictinitoption can be dumped straight into the command */
8699 if (dictinfo->dictinitoption)
8700 appendPQExpBuffer(q, ",\n %s", dictinfo->dictinitoption);
8702 appendPQExpBuffer(q, " );\n");
8705 * DROP must be fully qualified in case same name appears in pg_catalog
8707 appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s",
8708 fmtId(dictinfo->dobj.namespace->dobj.name));
8709 appendPQExpBuffer(delq, ".%s;\n",
8710 fmtId(dictinfo->dobj.name));
8712 ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
8713 dictinfo->dobj.name,
8714 dictinfo->dobj.namespace->dobj.name,
8715 NULL,
8716 dictinfo->rolname,
8717 false, "TEXT SEARCH DICTIONARY", q->data, delq->data, NULL,
8718 dictinfo->dobj.dependencies, dictinfo->dobj.nDeps,
8719 NULL, NULL);
8721 /* Dump Dictionary Comments */
8722 resetPQExpBuffer(q);
8723 appendPQExpBuffer(q, "TEXT SEARCH DICTIONARY %s",
8724 fmtId(dictinfo->dobj.name));
8725 dumpComment(fout, q->data,
8726 NULL, dictinfo->rolname,
8727 dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
8729 destroyPQExpBuffer(q);
8730 destroyPQExpBuffer(delq);
8731 destroyPQExpBuffer(query);
8735 * dumpTSTemplate
8736 * write out a single text search template
8738 static void
8739 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
8741 PQExpBuffer q;
8742 PQExpBuffer delq;
8744 /* Skip if not to be dumped */
8745 if (!tmplinfo->dobj.dump || dataOnly)
8746 return;
8748 q = createPQExpBuffer();
8749 delq = createPQExpBuffer();
8751 /* Make sure we are in proper schema */
8752 selectSourceSchema(tmplinfo->dobj.namespace->dobj.name);
8754 appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
8755 fmtId(tmplinfo->dobj.name));
8757 if (tmplinfo->tmplinit != InvalidOid)
8758 appendPQExpBuffer(q, " INIT = %s,\n",
8759 convertTSFunction(tmplinfo->tmplinit));
8760 appendPQExpBuffer(q, " LEXIZE = %s );\n",
8761 convertTSFunction(tmplinfo->tmpllexize));
8764 * DROP must be fully qualified in case same name appears in pg_catalog
8766 appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s",
8767 fmtId(tmplinfo->dobj.namespace->dobj.name));
8768 appendPQExpBuffer(delq, ".%s;\n",
8769 fmtId(tmplinfo->dobj.name));
8771 ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
8772 tmplinfo->dobj.name,
8773 tmplinfo->dobj.namespace->dobj.name,
8774 NULL,
8776 false, "TEXT SEARCH TEMPLATE", q->data, delq->data, NULL,
8777 tmplinfo->dobj.dependencies, tmplinfo->dobj.nDeps,
8778 NULL, NULL);
8780 /* Dump Template Comments */
8781 resetPQExpBuffer(q);
8782 appendPQExpBuffer(q, "TEXT SEARCH TEMPLATE %s",
8783 fmtId(tmplinfo->dobj.name));
8784 dumpComment(fout, q->data,
8785 NULL, "",
8786 tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
8788 destroyPQExpBuffer(q);
8789 destroyPQExpBuffer(delq);
8793 * dumpTSConfig
8794 * write out a single text search configuration
8796 static void
8797 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
8799 PQExpBuffer q;
8800 PQExpBuffer delq;
8801 PQExpBuffer query;
8802 PGresult *res;
8803 char *nspname;
8804 char *prsname;
8805 int ntups,
8807 int i_tokenname;
8808 int i_dictname;
8810 /* Skip if not to be dumped */
8811 if (!cfginfo->dobj.dump || dataOnly)
8812 return;
8814 q = createPQExpBuffer();
8815 delq = createPQExpBuffer();
8816 query = createPQExpBuffer();
8818 /* Fetch name and namespace of the config's parser */
8819 selectSourceSchema("pg_catalog");
8820 appendPQExpBuffer(query, "SELECT nspname, prsname "
8821 "FROM pg_ts_parser p, pg_namespace n "
8822 "WHERE p.oid = '%u' AND n.oid = prsnamespace",
8823 cfginfo->cfgparser);
8824 res = PQexec(g_conn, query->data);
8825 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8826 ntups = PQntuples(res);
8827 if (ntups != 1)
8829 write_msg(NULL, "query returned %d rows instead of one: %s\n",
8830 ntups, query->data);
8831 exit_nicely();
8833 nspname = PQgetvalue(res, 0, 0);
8834 prsname = PQgetvalue(res, 0, 1);
8836 /* Make sure we are in proper schema */
8837 selectSourceSchema(cfginfo->dobj.namespace->dobj.name);
8839 appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
8840 fmtId(cfginfo->dobj.name));
8842 appendPQExpBuffer(q, " PARSER = ");
8843 if (strcmp(nspname, cfginfo->dobj.namespace->dobj.name) != 0)
8844 appendPQExpBuffer(q, "%s.", fmtId(nspname));
8845 appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
8847 PQclear(res);
8849 resetPQExpBuffer(query);
8850 appendPQExpBuffer(query,
8851 "SELECT \n"
8852 " ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t \n"
8853 " WHERE t.tokid = m.maptokentype ) AS tokenname, \n"
8854 " m.mapdict::pg_catalog.regdictionary AS dictname \n"
8855 "FROM pg_catalog.pg_ts_config_map AS m \n"
8856 "WHERE m.mapcfg = '%u' \n"
8857 "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
8858 cfginfo->cfgparser, cfginfo->dobj.catId.oid);
8860 res = PQexec(g_conn, query->data);
8861 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8862 ntups = PQntuples(res);
8864 i_tokenname = PQfnumber(res, "tokenname");
8865 i_dictname = PQfnumber(res, "dictname");
8867 for (i = 0; i < ntups; i++)
8869 char *tokenname = PQgetvalue(res, i, i_tokenname);
8870 char *dictname = PQgetvalue(res, i, i_dictname);
8872 if (i == 0 ||
8873 strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
8875 /* starting a new token type, so start a new command */
8876 if (i > 0)
8877 appendPQExpBuffer(q, ";\n");
8878 appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
8879 fmtId(cfginfo->dobj.name));
8880 /* tokenname needs quoting, dictname does NOT */
8881 appendPQExpBuffer(q, " ADD MAPPING FOR %s WITH %s",
8882 fmtId(tokenname), dictname);
8884 else
8885 appendPQExpBuffer(q, ", %s", dictname);
8888 if (ntups > 0)
8889 appendPQExpBuffer(q, ";\n");
8891 PQclear(res);
8894 * DROP must be fully qualified in case same name appears in pg_catalog
8896 appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s",
8897 fmtId(cfginfo->dobj.namespace->dobj.name));
8898 appendPQExpBuffer(delq, ".%s;\n",
8899 fmtId(cfginfo->dobj.name));
8901 ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
8902 cfginfo->dobj.name,
8903 cfginfo->dobj.namespace->dobj.name,
8904 NULL,
8905 cfginfo->rolname,
8906 false, "TEXT SEARCH CONFIGURATION", q->data, delq->data, NULL,
8907 cfginfo->dobj.dependencies, cfginfo->dobj.nDeps,
8908 NULL, NULL);
8910 /* Dump Configuration Comments */
8911 resetPQExpBuffer(q);
8912 appendPQExpBuffer(q, "TEXT SEARCH CONFIGURATION %s",
8913 fmtId(cfginfo->dobj.name));
8914 dumpComment(fout, q->data,
8915 NULL, cfginfo->rolname,
8916 cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
8918 destroyPQExpBuffer(q);
8919 destroyPQExpBuffer(delq);
8920 destroyPQExpBuffer(query);
8924 /*----------
8925 * Write out grant/revoke information
8927 * 'objCatId' is the catalog ID of the underlying object.
8928 * 'objDumpId' is the dump ID of the underlying object.
8929 * 'type' must be TABLE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, or TABLESPACE.
8930 * 'name' is the formatted name of the object. Must be quoted etc. already.
8931 * 'tag' is the tag for the archive entry (typ. unquoted name of object).
8932 * 'nspname' is the namespace the object is in (NULL if none).
8933 * 'owner' is the owner, NULL if there is no owner (for languages).
8934 * 'acls' is the string read out of the fooacl system catalog field;
8935 * it will be parsed here.
8936 *----------
8938 static void
8939 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
8940 const char *type, const char *name,
8941 const char *tag, const char *nspname, const char *owner,
8942 const char *acls)
8944 PQExpBuffer sql;
8946 /* Do nothing if ACL dump is not enabled */
8947 if (dataOnly || aclsSkip)
8948 return;
8950 sql = createPQExpBuffer();
8952 if (!buildACLCommands(name, type, acls, owner, fout->remoteVersion, sql))
8954 write_msg(NULL, "could not parse ACL list (%s) for object \"%s\" (%s)\n",
8955 acls, name, type);
8956 exit_nicely();
8959 if (sql->len > 0)
8960 ArchiveEntry(fout, nilCatalogId, createDumpId(),
8961 tag, nspname,
8962 NULL,
8963 owner ? owner : "",
8964 false, "ACL", sql->data, "", NULL,
8965 &(objDumpId), 1,
8966 NULL, NULL);
8968 destroyPQExpBuffer(sql);
8972 * dumpTable
8973 * write out to fout the declarations (not data) of a user-defined table
8975 static void
8976 dumpTable(Archive *fout, TableInfo *tbinfo)
8978 char *namecopy;
8980 if (tbinfo->dobj.dump)
8982 if (tbinfo->relkind == RELKIND_SEQUENCE)
8983 dumpSequence(fout, tbinfo);
8984 else if (!dataOnly)
8985 dumpTableSchema(fout, tbinfo);
8987 /* Handle the ACL here */
8988 namecopy = strdup(fmtId(tbinfo->dobj.name));
8989 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
8990 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE",
8991 namecopy, tbinfo->dobj.name,
8992 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
8993 tbinfo->relacl);
8994 free(namecopy);
8999 * dumpTableSchema
9000 * write the declaration (not data) of one user-defined table or view
9002 static void
9003 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
9005 PQExpBuffer query = createPQExpBuffer();
9006 PQExpBuffer q = createPQExpBuffer();
9007 PQExpBuffer delq = createPQExpBuffer();
9008 PGresult *res;
9009 int numParents;
9010 TableInfo **parents;
9011 int actual_atts; /* number of attrs in this CREATE statment */
9012 char *reltypename;
9013 char *storage;
9014 int j,
9017 /* Make sure we are in proper schema */
9018 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
9020 /* Is it a table or a view? */
9021 if (tbinfo->relkind == RELKIND_VIEW)
9023 char *viewdef;
9025 reltypename = "VIEW";
9027 /* Fetch the view definition */
9028 if (g_fout->remoteVersion >= 70300)
9030 /* Beginning in 7.3, viewname is not unique; rely on OID */
9031 appendPQExpBuffer(query,
9032 "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) as viewdef",
9033 tbinfo->dobj.catId.oid);
9035 else
9037 appendPQExpBuffer(query, "SELECT definition as viewdef "
9038 " from pg_views where viewname = ");
9039 appendStringLiteralAH(query, tbinfo->dobj.name, fout);
9040 appendPQExpBuffer(query, ";");
9043 res = PQexec(g_conn, query->data);
9044 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9046 if (PQntuples(res) != 1)
9048 if (PQntuples(res) < 1)
9049 write_msg(NULL, "query to obtain definition of view \"%s\" returned no data\n",
9050 tbinfo->dobj.name);
9051 else
9052 write_msg(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
9053 tbinfo->dobj.name);
9054 exit_nicely();
9057 viewdef = PQgetvalue(res, 0, 0);
9059 if (strlen(viewdef) == 0)
9061 write_msg(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
9062 tbinfo->dobj.name);
9063 exit_nicely();
9067 * DROP must be fully qualified in case same name appears in
9068 * pg_catalog
9070 appendPQExpBuffer(delq, "DROP VIEW %s.",
9071 fmtId(tbinfo->dobj.namespace->dobj.name));
9072 appendPQExpBuffer(delq, "%s;\n",
9073 fmtId(tbinfo->dobj.name));
9075 appendPQExpBuffer(q, "CREATE VIEW %s AS\n %s\n",
9076 fmtId(tbinfo->dobj.name), viewdef);
9078 PQclear(res);
9080 else
9082 reltypename = "TABLE";
9083 numParents = tbinfo->numParents;
9084 parents = tbinfo->parents;
9087 * DROP must be fully qualified in case same name appears in
9088 * pg_catalog
9090 appendPQExpBuffer(delq, "DROP TABLE %s.",
9091 fmtId(tbinfo->dobj.namespace->dobj.name));
9092 appendPQExpBuffer(delq, "%s;\n",
9093 fmtId(tbinfo->dobj.name));
9095 appendPQExpBuffer(q, "CREATE TABLE %s (",
9096 fmtId(tbinfo->dobj.name));
9097 actual_atts = 0;
9098 for (j = 0; j < tbinfo->numatts; j++)
9100 /* Is this one of the table's own attrs, and not dropped ? */
9101 if (!tbinfo->inhAttrs[j] && !tbinfo->attisdropped[j])
9103 /* Format properly if not first attr */
9104 if (actual_atts > 0)
9105 appendPQExpBuffer(q, ",");
9106 appendPQExpBuffer(q, "\n ");
9108 /* Attribute name */
9109 appendPQExpBuffer(q, "%s ",
9110 fmtId(tbinfo->attnames[j]));
9112 /* Attribute type */
9113 if (g_fout->remoteVersion >= 70100)
9115 appendPQExpBuffer(q, "%s",
9116 tbinfo->atttypnames[j]);
9118 else
9120 /* If no format_type, fake it */
9121 appendPQExpBuffer(q, "%s",
9122 myFormatType(tbinfo->atttypnames[j],
9123 tbinfo->atttypmod[j]));
9127 * Default value --- suppress if inherited or to be printed
9128 * separately.
9130 if (tbinfo->attrdefs[j] != NULL &&
9131 !tbinfo->inhAttrDef[j] &&
9132 !tbinfo->attrdefs[j]->separate)
9133 appendPQExpBuffer(q, " DEFAULT %s",
9134 tbinfo->attrdefs[j]->adef_expr);
9137 * Not Null constraint --- suppress if inherited
9139 if (tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
9140 appendPQExpBuffer(q, " NOT NULL");
9142 actual_atts++;
9147 * Add non-inherited CHECK constraints, if any.
9149 for (j = 0; j < tbinfo->ncheck; j++)
9151 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
9153 if (constr->separate || !constr->conislocal)
9154 continue;
9156 if (actual_atts > 0)
9157 appendPQExpBuffer(q, ",\n ");
9159 appendPQExpBuffer(q, "CONSTRAINT %s ",
9160 fmtId(constr->dobj.name));
9161 appendPQExpBuffer(q, "%s", constr->condef);
9163 actual_atts++;
9166 appendPQExpBuffer(q, "\n)");
9168 if (numParents > 0)
9170 appendPQExpBuffer(q, "\nINHERITS (");
9171 for (k = 0; k < numParents; k++)
9173 TableInfo *parentRel = parents[k];
9175 if (k > 0)
9176 appendPQExpBuffer(q, ", ");
9177 if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
9178 appendPQExpBuffer(q, "%s.",
9179 fmtId(parentRel->dobj.namespace->dobj.name));
9180 appendPQExpBuffer(q, "%s",
9181 fmtId(parentRel->dobj.name));
9183 appendPQExpBuffer(q, ")");
9186 if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
9187 appendPQExpBuffer(q, "\nWITH (%s)", tbinfo->reloptions);
9189 appendPQExpBuffer(q, ";\n");
9191 /* Loop dumping statistics and storage statements */
9192 for (j = 0; j < tbinfo->numatts; j++)
9195 * Dump per-column statistics information. We only issue an ALTER
9196 * TABLE statement if the attstattarget entry for this column is
9197 * non-negative (i.e. it's not the default value)
9199 if (tbinfo->attstattarget[j] >= 0 &&
9200 !tbinfo->attisdropped[j])
9202 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
9203 fmtId(tbinfo->dobj.name));
9204 appendPQExpBuffer(q, "ALTER COLUMN %s ",
9205 fmtId(tbinfo->attnames[j]));
9206 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
9207 tbinfo->attstattarget[j]);
9211 * Dump per-column storage information. The statement is only
9212 * dumped if the storage has been changed from the type's default.
9214 if (!tbinfo->attisdropped[j] && tbinfo->attstorage[j] != tbinfo->typstorage[j])
9216 switch (tbinfo->attstorage[j])
9218 case 'p':
9219 storage = "PLAIN";
9220 break;
9221 case 'e':
9222 storage = "EXTERNAL";
9223 break;
9224 case 'm':
9225 storage = "MAIN";
9226 break;
9227 case 'x':
9228 storage = "EXTENDED";
9229 break;
9230 default:
9231 storage = NULL;
9235 * Only dump the statement if it's a storage type we recognize
9237 if (storage != NULL)
9239 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
9240 fmtId(tbinfo->dobj.name));
9241 appendPQExpBuffer(q, "ALTER COLUMN %s ",
9242 fmtId(tbinfo->attnames[j]));
9243 appendPQExpBuffer(q, "SET STORAGE %s;\n",
9244 storage);
9250 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
9251 tbinfo->dobj.name,
9252 tbinfo->dobj.namespace->dobj.name,
9253 (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
9254 tbinfo->rolname,
9255 (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
9256 reltypename, q->data, delq->data, NULL,
9257 tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
9258 NULL, NULL);
9260 /* Dump Table Comments */
9261 dumpTableComment(fout, tbinfo, reltypename);
9263 /* Dump comments on inlined table constraints */
9264 for (j = 0; j < tbinfo->ncheck; j++)
9266 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
9268 if (constr->separate || !constr->conislocal)
9269 continue;
9271 dumpTableConstraintComment(fout, constr);
9274 destroyPQExpBuffer(query);
9275 destroyPQExpBuffer(q);
9276 destroyPQExpBuffer(delq);
9280 * dumpAttrDef --- dump an attribute's default-value declaration
9282 static void
9283 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
9285 TableInfo *tbinfo = adinfo->adtable;
9286 int adnum = adinfo->adnum;
9287 PQExpBuffer q;
9288 PQExpBuffer delq;
9290 /* Only print it if "separate" mode is selected */
9291 if (!tbinfo->dobj.dump || !adinfo->separate || dataOnly)
9292 return;
9294 /* Don't print inherited defaults, either */
9295 if (tbinfo->inhAttrDef[adnum - 1])
9296 return;
9298 q = createPQExpBuffer();
9299 delq = createPQExpBuffer();
9301 appendPQExpBuffer(q, "ALTER TABLE %s ",
9302 fmtId(tbinfo->dobj.name));
9303 appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
9304 fmtId(tbinfo->attnames[adnum - 1]),
9305 adinfo->adef_expr);
9308 * DROP must be fully qualified in case same name appears in pg_catalog
9310 appendPQExpBuffer(delq, "ALTER TABLE %s.",
9311 fmtId(tbinfo->dobj.namespace->dobj.name));
9312 appendPQExpBuffer(delq, "%s ",
9313 fmtId(tbinfo->dobj.name));
9314 appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
9315 fmtId(tbinfo->attnames[adnum - 1]));
9317 ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
9318 tbinfo->attnames[adnum - 1],
9319 tbinfo->dobj.namespace->dobj.name,
9320 NULL,
9321 tbinfo->rolname,
9322 false, "DEFAULT", q->data, delq->data, NULL,
9323 adinfo->dobj.dependencies, adinfo->dobj.nDeps,
9324 NULL, NULL);
9326 destroyPQExpBuffer(q);
9327 destroyPQExpBuffer(delq);
9331 * getAttrName: extract the correct name for an attribute
9333 * The array tblInfo->attnames[] only provides names of user attributes;
9334 * if a system attribute number is supplied, we have to fake it.
9335 * We also do a little bit of bounds checking for safety's sake.
9337 static const char *
9338 getAttrName(int attrnum, TableInfo *tblInfo)
9340 if (attrnum > 0 && attrnum <= tblInfo->numatts)
9341 return tblInfo->attnames[attrnum - 1];
9342 switch (attrnum)
9344 case SelfItemPointerAttributeNumber:
9345 return "ctid";
9346 case ObjectIdAttributeNumber:
9347 return "oid";
9348 case MinTransactionIdAttributeNumber:
9349 return "xmin";
9350 case MinCommandIdAttributeNumber:
9351 return "cmin";
9352 case MaxTransactionIdAttributeNumber:
9353 return "xmax";
9354 case MaxCommandIdAttributeNumber:
9355 return "cmax";
9356 case TableOidAttributeNumber:
9357 return "tableoid";
9359 write_msg(NULL, "invalid column number %d for table \"%s\"\n",
9360 attrnum, tblInfo->dobj.name);
9361 exit_nicely();
9362 return NULL; /* keep compiler quiet */
9366 * dumpIndex
9367 * write out to fout a user-defined index
9369 static void
9370 dumpIndex(Archive *fout, IndxInfo *indxinfo)
9372 TableInfo *tbinfo = indxinfo->indextable;
9373 PQExpBuffer q;
9374 PQExpBuffer delq;
9376 if (dataOnly)
9377 return;
9379 q = createPQExpBuffer();
9380 delq = createPQExpBuffer();
9383 * If there's an associated constraint, don't dump the index per se, but
9384 * do dump any comment for it. (This is safe because dependency ordering
9385 * will have ensured the constraint is emitted first.)
9387 if (indxinfo->indexconstraint == 0)
9389 /* Plain secondary index */
9390 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
9392 /* If the index is clustered, we need to record that. */
9393 if (indxinfo->indisclustered)
9395 appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
9396 fmtId(tbinfo->dobj.name));
9397 appendPQExpBuffer(q, " ON %s;\n",
9398 fmtId(indxinfo->dobj.name));
9402 * DROP must be fully qualified in case same name appears in
9403 * pg_catalog
9405 appendPQExpBuffer(delq, "DROP INDEX %s.",
9406 fmtId(tbinfo->dobj.namespace->dobj.name));
9407 appendPQExpBuffer(delq, "%s;\n",
9408 fmtId(indxinfo->dobj.name));
9410 ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
9411 indxinfo->dobj.name,
9412 tbinfo->dobj.namespace->dobj.name,
9413 indxinfo->tablespace,
9414 tbinfo->rolname, false,
9415 "INDEX", q->data, delq->data, NULL,
9416 indxinfo->dobj.dependencies, indxinfo->dobj.nDeps,
9417 NULL, NULL);
9420 /* Dump Index Comments */
9421 resetPQExpBuffer(q);
9422 appendPQExpBuffer(q, "INDEX %s",
9423 fmtId(indxinfo->dobj.name));
9424 dumpComment(fout, q->data,
9425 tbinfo->dobj.namespace->dobj.name,
9426 tbinfo->rolname,
9427 indxinfo->dobj.catId, 0, indxinfo->dobj.dumpId);
9429 destroyPQExpBuffer(q);
9430 destroyPQExpBuffer(delq);
9434 * dumpConstraint
9435 * write out to fout a user-defined constraint
9437 static void
9438 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
9440 TableInfo *tbinfo = coninfo->contable;
9441 PQExpBuffer q;
9442 PQExpBuffer delq;
9444 /* Skip if not to be dumped */
9445 if (!coninfo->dobj.dump || dataOnly)
9446 return;
9448 q = createPQExpBuffer();
9449 delq = createPQExpBuffer();
9451 if (coninfo->contype == 'p' || coninfo->contype == 'u')
9453 /* Index-related constraint */
9454 IndxInfo *indxinfo;
9455 int k;
9457 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
9459 if (indxinfo == NULL)
9461 write_msg(NULL, "missing index for constraint \"%s\"\n",
9462 coninfo->dobj.name);
9463 exit_nicely();
9466 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
9467 fmtId(tbinfo->dobj.name));
9468 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s (",
9469 fmtId(coninfo->dobj.name),
9470 coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
9472 for (k = 0; k < indxinfo->indnkeys; k++)
9474 int indkey = (int) indxinfo->indkeys[k];
9475 const char *attname;
9477 if (indkey == InvalidAttrNumber)
9478 break;
9479 attname = getAttrName(indkey, tbinfo);
9481 appendPQExpBuffer(q, "%s%s",
9482 (k == 0) ? "" : ", ",
9483 fmtId(attname));
9486 appendPQExpBuffer(q, ")");
9488 if (indxinfo->options && strlen(indxinfo->options) > 0)
9489 appendPQExpBuffer(q, " WITH (%s)", indxinfo->options);
9491 appendPQExpBuffer(q, ";\n");
9493 /* If the index is clustered, we need to record that. */
9494 if (indxinfo->indisclustered)
9496 appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
9497 fmtId(tbinfo->dobj.name));
9498 appendPQExpBuffer(q, " ON %s;\n",
9499 fmtId(indxinfo->dobj.name));
9503 * DROP must be fully qualified in case same name appears in
9504 * pg_catalog
9506 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
9507 fmtId(tbinfo->dobj.namespace->dobj.name));
9508 appendPQExpBuffer(delq, "%s ",
9509 fmtId(tbinfo->dobj.name));
9510 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
9511 fmtId(coninfo->dobj.name));
9513 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
9514 coninfo->dobj.name,
9515 tbinfo->dobj.namespace->dobj.name,
9516 indxinfo->tablespace,
9517 tbinfo->rolname, false,
9518 "CONSTRAINT", q->data, delq->data, NULL,
9519 coninfo->dobj.dependencies, coninfo->dobj.nDeps,
9520 NULL, NULL);
9522 else if (coninfo->contype == 'f')
9525 * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
9526 * current table data is not processed
9528 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
9529 fmtId(tbinfo->dobj.name));
9530 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
9531 fmtId(coninfo->dobj.name),
9532 coninfo->condef);
9535 * DROP must be fully qualified in case same name appears in
9536 * pg_catalog
9538 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
9539 fmtId(tbinfo->dobj.namespace->dobj.name));
9540 appendPQExpBuffer(delq, "%s ",
9541 fmtId(tbinfo->dobj.name));
9542 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
9543 fmtId(coninfo->dobj.name));
9545 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
9546 coninfo->dobj.name,
9547 tbinfo->dobj.namespace->dobj.name,
9548 NULL,
9549 tbinfo->rolname, false,
9550 "FK CONSTRAINT", q->data, delq->data, NULL,
9551 coninfo->dobj.dependencies, coninfo->dobj.nDeps,
9552 NULL, NULL);
9554 else if (coninfo->contype == 'c' && tbinfo)
9556 /* CHECK constraint on a table */
9558 /* Ignore if not to be dumped separately */
9559 if (coninfo->separate)
9561 /* not ONLY since we want it to propagate to children */
9562 appendPQExpBuffer(q, "ALTER TABLE %s\n",
9563 fmtId(tbinfo->dobj.name));
9564 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
9565 fmtId(coninfo->dobj.name),
9566 coninfo->condef);
9569 * DROP must be fully qualified in case same name appears in
9570 * pg_catalog
9572 appendPQExpBuffer(delq, "ALTER TABLE %s.",
9573 fmtId(tbinfo->dobj.namespace->dobj.name));
9574 appendPQExpBuffer(delq, "%s ",
9575 fmtId(tbinfo->dobj.name));
9576 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
9577 fmtId(coninfo->dobj.name));
9579 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
9580 coninfo->dobj.name,
9581 tbinfo->dobj.namespace->dobj.name,
9582 NULL,
9583 tbinfo->rolname, false,
9584 "CHECK CONSTRAINT", q->data, delq->data, NULL,
9585 coninfo->dobj.dependencies, coninfo->dobj.nDeps,
9586 NULL, NULL);
9589 else if (coninfo->contype == 'c' && tbinfo == NULL)
9591 /* CHECK constraint on a domain */
9592 TypeInfo *tinfo = coninfo->condomain;
9594 /* Ignore if not to be dumped separately */
9595 if (coninfo->separate)
9597 appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
9598 fmtId(tinfo->dobj.name));
9599 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
9600 fmtId(coninfo->dobj.name),
9601 coninfo->condef);
9604 * DROP must be fully qualified in case same name appears in
9605 * pg_catalog
9607 appendPQExpBuffer(delq, "ALTER DOMAIN %s.",
9608 fmtId(tinfo->dobj.namespace->dobj.name));
9609 appendPQExpBuffer(delq, "%s ",
9610 fmtId(tinfo->dobj.name));
9611 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
9612 fmtId(coninfo->dobj.name));
9614 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
9615 coninfo->dobj.name,
9616 tinfo->dobj.namespace->dobj.name,
9617 NULL,
9618 tinfo->rolname, false,
9619 "CHECK CONSTRAINT", q->data, delq->data, NULL,
9620 coninfo->dobj.dependencies, coninfo->dobj.nDeps,
9621 NULL, NULL);
9624 else
9626 write_msg(NULL, "unrecognized constraint type: %c\n", coninfo->contype);
9627 exit_nicely();
9630 /* Dump Constraint Comments --- only works for table constraints */
9631 if (tbinfo && coninfo->separate)
9632 dumpTableConstraintComment(fout, coninfo);
9634 destroyPQExpBuffer(q);
9635 destroyPQExpBuffer(delq);
9639 * dumpTableConstraintComment --- dump a constraint's comment if any
9641 * This is split out because we need the function in two different places
9642 * depending on whether the constraint is dumped as part of CREATE TABLE
9643 * or as a separate ALTER command.
9645 static void
9646 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
9648 TableInfo *tbinfo = coninfo->contable;
9649 PQExpBuffer q = createPQExpBuffer();
9651 appendPQExpBuffer(q, "CONSTRAINT %s ",
9652 fmtId(coninfo->dobj.name));
9653 appendPQExpBuffer(q, "ON %s",
9654 fmtId(tbinfo->dobj.name));
9655 dumpComment(fout, q->data,
9656 tbinfo->dobj.namespace->dobj.name,
9657 tbinfo->rolname,
9658 coninfo->dobj.catId, 0,
9659 coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
9661 destroyPQExpBuffer(q);
9665 * findLastBuiltInOid -
9666 * find the last built in oid
9668 * For 7.1 and 7.2, we do this by retrieving datlastsysoid from the
9669 * pg_database entry for the current database
9671 static Oid
9672 findLastBuiltinOid_V71(const char *dbname)
9674 PGresult *res;
9675 int ntups;
9676 Oid last_oid;
9677 PQExpBuffer query = createPQExpBuffer();
9679 resetPQExpBuffer(query);
9680 appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
9681 appendStringLiteralAH(query, dbname, g_fout);
9683 res = PQexec(g_conn, query->data);
9684 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9686 ntups = PQntuples(res);
9687 if (ntups < 1)
9689 write_msg(NULL, "missing pg_database entry for this database\n");
9690 exit_nicely();
9692 if (ntups > 1)
9694 write_msg(NULL, "found more than one pg_database entry for this database\n");
9695 exit_nicely();
9697 last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
9698 PQclear(res);
9699 destroyPQExpBuffer(query);
9700 return last_oid;
9704 * findLastBuiltInOid -
9705 * find the last built in oid
9707 * For 7.0, we do this by assuming that the last thing that initdb does is to
9708 * create the pg_indexes view. This sucks in general, but seeing that 7.0.x
9709 * initdb won't be changing anymore, it'll do.
9711 static Oid
9712 findLastBuiltinOid_V70(void)
9714 PGresult *res;
9715 int ntups;
9716 int last_oid;
9718 res = PQexec(g_conn,
9719 "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'");
9720 check_sql_result(res, g_conn,
9721 "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'",
9722 PGRES_TUPLES_OK);
9723 ntups = PQntuples(res);
9724 if (ntups < 1)
9726 write_msg(NULL, "could not find entry for pg_indexes in pg_class\n");
9727 exit_nicely();
9729 if (ntups > 1)
9731 write_msg(NULL, "found more than one entry for pg_indexes in pg_class\n");
9732 exit_nicely();
9734 last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
9735 PQclear(res);
9736 return last_oid;
9739 static void
9740 dumpSequence(Archive *fout, TableInfo *tbinfo)
9742 PGresult *res;
9743 char *startv,
9744 *last,
9745 *incby,
9746 *maxv = NULL,
9747 *minv = NULL,
9748 *cache;
9749 char bufm[100],
9750 bufx[100];
9751 bool cycled,
9752 called;
9753 PQExpBuffer query = createPQExpBuffer();
9754 PQExpBuffer delqry = createPQExpBuffer();
9756 /* Make sure we are in proper schema */
9757 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
9759 snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
9760 snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
9762 if (g_fout->remoteVersion >= 80400)
9764 appendPQExpBuffer(query,
9765 "SELECT sequence_name, "
9766 "start_value, last_value, increment_by, "
9767 "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
9768 " WHEN increment_by < 0 AND max_value = -1 THEN NULL "
9769 " ELSE max_value "
9770 "END AS max_value, "
9771 "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
9772 " WHEN increment_by < 0 AND min_value = %s THEN NULL "
9773 " ELSE min_value "
9774 "END AS min_value, "
9775 "cache_value, is_cycled, is_called from %s",
9776 bufx, bufm,
9777 fmtId(tbinfo->dobj.name));
9779 else
9781 appendPQExpBuffer(query,
9782 "SELECT sequence_name, "
9783 "0 as start_value, last_value, increment_by, "
9784 "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
9785 " WHEN increment_by < 0 AND max_value = -1 THEN NULL "
9786 " ELSE max_value "
9787 "END AS max_value, "
9788 "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
9789 " WHEN increment_by < 0 AND min_value = %s THEN NULL "
9790 " ELSE min_value "
9791 "END AS min_value, "
9792 "cache_value, is_cycled, is_called from %s",
9793 bufx, bufm,
9794 fmtId(tbinfo->dobj.name));
9797 res = PQexec(g_conn, query->data);
9798 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9800 if (PQntuples(res) != 1)
9802 write_msg(NULL, "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
9803 tbinfo->dobj.name, PQntuples(res));
9804 exit_nicely();
9807 /* Disable this check: it fails if sequence has been renamed */
9808 #ifdef NOT_USED
9809 if (strcmp(PQgetvalue(res, 0, 0), tbinfo->dobj.name) != 0)
9811 write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
9812 tbinfo->dobj.name, PQgetvalue(res, 0, 0));
9813 exit_nicely();
9815 #endif
9817 startv = PQgetvalue(res, 0, 1);
9818 last = PQgetvalue(res, 0, 2);
9819 incby = PQgetvalue(res, 0, 3);
9820 if (!PQgetisnull(res, 0, 4))
9821 maxv = PQgetvalue(res, 0, 4);
9822 if (!PQgetisnull(res, 0, 5))
9823 minv = PQgetvalue(res, 0, 5);
9824 cache = PQgetvalue(res, 0, 6);
9825 cycled = (strcmp(PQgetvalue(res, 0, 7), "t") == 0);
9826 called = (strcmp(PQgetvalue(res, 0, 8), "t") == 0);
9829 * The logic we use for restoring sequences is as follows:
9831 * Add a CREATE SEQUENCE statement as part of a "schema" dump (use
9832 * last_val for start if called is false, else use min_val for start_val).
9833 * Also, if the sequence is owned by a column, add an ALTER SEQUENCE OWNED
9834 * BY command for it.
9836 * Add a 'SETVAL(seq, last_val, iscalled)' as part of a "data" dump.
9838 if (!dataOnly)
9840 resetPQExpBuffer(delqry);
9843 * DROP must be fully qualified in case same name appears in
9844 * pg_catalog
9846 appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
9847 fmtId(tbinfo->dobj.namespace->dobj.name));
9848 appendPQExpBuffer(delqry, "%s;\n",
9849 fmtId(tbinfo->dobj.name));
9851 resetPQExpBuffer(query);
9852 appendPQExpBuffer(query,
9853 "CREATE SEQUENCE %s\n",
9854 fmtId(tbinfo->dobj.name));
9856 if (g_fout->remoteVersion >= 80400)
9857 appendPQExpBuffer(query, " START WITH %s\n", startv);
9858 else
9861 * Versions before 8.4 did not remember the true start value. If
9862 * is_called is false then the sequence has never been incremented
9863 * so we can use last_val. Otherwise punt and let it default.
9865 if (!called)
9866 appendPQExpBuffer(query, " START WITH %s\n", last);
9869 appendPQExpBuffer(query, " INCREMENT BY %s\n", incby);
9871 if (maxv)
9872 appendPQExpBuffer(query, " MAXVALUE %s\n", maxv);
9873 else
9874 appendPQExpBuffer(query, " NO MAXVALUE\n");
9876 if (minv)
9877 appendPQExpBuffer(query, " MINVALUE %s\n", minv);
9878 else
9879 appendPQExpBuffer(query, " NO MINVALUE\n");
9881 appendPQExpBuffer(query,
9882 " CACHE %s%s",
9883 cache, (cycled ? "\n CYCLE" : ""));
9885 appendPQExpBuffer(query, ";\n");
9887 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
9888 tbinfo->dobj.name,
9889 tbinfo->dobj.namespace->dobj.name,
9890 NULL,
9891 tbinfo->rolname,
9892 false, "SEQUENCE", query->data, delqry->data, NULL,
9893 tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
9894 NULL, NULL);
9897 * If the sequence is owned by a table column, emit the ALTER for it
9898 * as a separate TOC entry immediately following the sequence's own
9899 * entry. It's OK to do this rather than using full sorting logic,
9900 * because the dependency that tells us it's owned will have forced
9901 * the table to be created first. We can't just include the ALTER in
9902 * the TOC entry because it will fail if we haven't reassigned the
9903 * sequence owner to match the table's owner.
9905 * We need not schema-qualify the table reference because both
9906 * sequence and table must be in the same schema.
9908 if (OidIsValid(tbinfo->owning_tab))
9910 TableInfo *owning_tab = findTableByOid(tbinfo->owning_tab);
9912 if (owning_tab && owning_tab->dobj.dump)
9914 resetPQExpBuffer(query);
9915 appendPQExpBuffer(query, "ALTER SEQUENCE %s",
9916 fmtId(tbinfo->dobj.name));
9917 appendPQExpBuffer(query, " OWNED BY %s",
9918 fmtId(owning_tab->dobj.name));
9919 appendPQExpBuffer(query, ".%s;\n",
9920 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
9922 ArchiveEntry(fout, nilCatalogId, createDumpId(),
9923 tbinfo->dobj.name,
9924 tbinfo->dobj.namespace->dobj.name,
9925 NULL,
9926 tbinfo->rolname,
9927 false, "SEQUENCE OWNED BY", query->data, "", NULL,
9928 &(tbinfo->dobj.dumpId), 1,
9929 NULL, NULL);
9933 /* Dump Sequence Comments */
9934 resetPQExpBuffer(query);
9935 appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
9936 dumpComment(fout, query->data,
9937 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
9938 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
9941 if (!schemaOnly)
9943 resetPQExpBuffer(query);
9944 appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
9945 appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
9946 appendPQExpBuffer(query, ", %s, %s);\n",
9947 last, (called ? "true" : "false"));
9949 ArchiveEntry(fout, nilCatalogId, createDumpId(),
9950 tbinfo->dobj.name,
9951 tbinfo->dobj.namespace->dobj.name,
9952 NULL,
9953 tbinfo->rolname,
9954 false, "SEQUENCE SET", query->data, "", NULL,
9955 &(tbinfo->dobj.dumpId), 1,
9956 NULL, NULL);
9959 PQclear(res);
9961 destroyPQExpBuffer(query);
9962 destroyPQExpBuffer(delqry);
9965 static void
9966 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
9968 TableInfo *tbinfo = tginfo->tgtable;
9969 PQExpBuffer query;
9970 PQExpBuffer delqry;
9971 const char *p;
9972 int findx;
9974 if (dataOnly)
9975 return;
9977 query = createPQExpBuffer();
9978 delqry = createPQExpBuffer();
9981 * DROP must be fully qualified in case same name appears in pg_catalog
9983 appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
9984 fmtId(tginfo->dobj.name));
9985 appendPQExpBuffer(delqry, "ON %s.",
9986 fmtId(tbinfo->dobj.namespace->dobj.name));
9987 appendPQExpBuffer(delqry, "%s;\n",
9988 fmtId(tbinfo->dobj.name));
9990 if (tginfo->tgisconstraint)
9992 appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
9993 appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
9995 else
9997 appendPQExpBuffer(query, "CREATE TRIGGER ");
9998 appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
10000 appendPQExpBuffer(query, "\n ");
10002 /* Trigger type */
10003 findx = 0;
10004 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
10005 appendPQExpBuffer(query, "BEFORE");
10006 else
10007 appendPQExpBuffer(query, "AFTER");
10008 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
10010 appendPQExpBuffer(query, " INSERT");
10011 findx++;
10013 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
10015 if (findx > 0)
10016 appendPQExpBuffer(query, " OR DELETE");
10017 else
10018 appendPQExpBuffer(query, " DELETE");
10019 findx++;
10021 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
10023 if (findx > 0)
10024 appendPQExpBuffer(query, " OR UPDATE");
10025 else
10026 appendPQExpBuffer(query, " UPDATE");
10028 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
10030 if (findx > 0)
10031 appendPQExpBuffer(query, " OR TRUNCATE");
10032 else
10033 appendPQExpBuffer(query, " TRUNCATE");
10035 appendPQExpBuffer(query, " ON %s\n",
10036 fmtId(tbinfo->dobj.name));
10038 if (tginfo->tgisconstraint)
10040 if (OidIsValid(tginfo->tgconstrrelid))
10042 /* If we are using regclass, name is already quoted */
10043 if (g_fout->remoteVersion >= 70300)
10044 appendPQExpBuffer(query, " FROM %s\n ",
10045 tginfo->tgconstrrelname);
10046 else
10047 appendPQExpBuffer(query, " FROM %s\n ",
10048 fmtId(tginfo->tgconstrrelname));
10050 if (!tginfo->tgdeferrable)
10051 appendPQExpBuffer(query, "NOT ");
10052 appendPQExpBuffer(query, "DEFERRABLE INITIALLY ");
10053 if (tginfo->tginitdeferred)
10054 appendPQExpBuffer(query, "DEFERRED\n");
10055 else
10056 appendPQExpBuffer(query, "IMMEDIATE\n");
10059 if (TRIGGER_FOR_ROW(tginfo->tgtype))
10060 appendPQExpBuffer(query, " FOR EACH ROW\n ");
10061 else
10062 appendPQExpBuffer(query, " FOR EACH STATEMENT\n ");
10064 /* In 7.3, result of regproc is already quoted */
10065 if (g_fout->remoteVersion >= 70300)
10066 appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
10067 tginfo->tgfname);
10068 else
10069 appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
10070 fmtId(tginfo->tgfname));
10072 p = tginfo->tgargs;
10073 for (findx = 0; findx < tginfo->tgnargs; findx++)
10075 const char *s = p;
10077 /* Set 'p' to end of arg string. marked by '\000' */
10078 for (;;)
10080 p = strchr(p, '\\');
10081 if (p == NULL)
10083 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
10084 tginfo->tgargs,
10085 tginfo->dobj.name,
10086 tbinfo->dobj.name);
10087 exit_nicely();
10089 p++;
10090 if (*p == '\\') /* is it '\\'? */
10092 p++;
10093 continue;
10095 if (p[0] == '0' && p[1] == '0' && p[2] == '0') /* is it '\000'? */
10096 break;
10098 p--;
10100 appendPQExpBufferChar(query, '\'');
10101 while (s < p)
10103 if (*s == '\'')
10104 appendPQExpBufferChar(query, '\'');
10107 * bytea unconditionally doubles backslashes, so we suppress the
10108 * doubling for standard_conforming_strings.
10110 if (fout->std_strings && *s == '\\' && s[1] == '\\')
10111 s++;
10112 appendPQExpBufferChar(query, *s++);
10114 appendPQExpBufferChar(query, '\'');
10115 appendPQExpBuffer(query,
10116 (findx < tginfo->tgnargs - 1) ? ", " : "");
10117 p = p + 4;
10119 appendPQExpBuffer(query, ");\n");
10121 if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
10123 appendPQExpBuffer(query, "\nALTER TABLE %s ",
10124 fmtId(tbinfo->dobj.name));
10125 switch (tginfo->tgenabled)
10127 case 'D':
10128 case 'f':
10129 appendPQExpBuffer(query, "DISABLE");
10130 break;
10131 case 'A':
10132 appendPQExpBuffer(query, "ENABLE ALWAYS");
10133 break;
10134 case 'R':
10135 appendPQExpBuffer(query, "ENABLE REPLICA");
10136 break;
10137 default:
10138 appendPQExpBuffer(query, "ENABLE");
10139 break;
10141 appendPQExpBuffer(query, " TRIGGER %s;\n",
10142 fmtId(tginfo->dobj.name));
10145 ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
10146 tginfo->dobj.name,
10147 tbinfo->dobj.namespace->dobj.name,
10148 NULL,
10149 tbinfo->rolname, false,
10150 "TRIGGER", query->data, delqry->data, NULL,
10151 tginfo->dobj.dependencies, tginfo->dobj.nDeps,
10152 NULL, NULL);
10154 resetPQExpBuffer(query);
10155 appendPQExpBuffer(query, "TRIGGER %s ",
10156 fmtId(tginfo->dobj.name));
10157 appendPQExpBuffer(query, "ON %s",
10158 fmtId(tbinfo->dobj.name));
10160 dumpComment(fout, query->data,
10161 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
10162 tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
10164 destroyPQExpBuffer(query);
10165 destroyPQExpBuffer(delqry);
10169 * dumpRule
10170 * Dump a rule
10172 static void
10173 dumpRule(Archive *fout, RuleInfo *rinfo)
10175 TableInfo *tbinfo = rinfo->ruletable;
10176 PQExpBuffer query;
10177 PQExpBuffer cmd;
10178 PQExpBuffer delcmd;
10179 PGresult *res;
10181 /* Skip if not to be dumped */
10182 if (!rinfo->dobj.dump || dataOnly)
10183 return;
10186 * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
10187 * we do not want to dump it as a separate object.
10189 if (!rinfo->separate)
10190 return;
10193 * Make sure we are in proper schema.
10195 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
10197 query = createPQExpBuffer();
10198 cmd = createPQExpBuffer();
10199 delcmd = createPQExpBuffer();
10201 if (g_fout->remoteVersion >= 70300)
10203 appendPQExpBuffer(query,
10204 "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid) AS definition",
10205 rinfo->dobj.catId.oid);
10207 else
10209 /* Rule name was unique before 7.3 ... */
10210 appendPQExpBuffer(query,
10211 "SELECT pg_get_ruledef('%s') AS definition",
10212 rinfo->dobj.name);
10215 res = PQexec(g_conn, query->data);
10216 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10218 if (PQntuples(res) != 1)
10220 write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
10221 rinfo->dobj.name, tbinfo->dobj.name);
10222 exit_nicely();
10225 printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
10228 * Add the command to alter the rules replication firing semantics if it
10229 * differs from the default.
10231 if (rinfo->ev_enabled != 'O')
10233 appendPQExpBuffer(cmd, "ALTER TABLE %s.",
10234 fmtId(tbinfo->dobj.namespace->dobj.name));
10235 appendPQExpBuffer(cmd, "%s ",
10236 fmtId(tbinfo->dobj.name));
10237 switch (rinfo->ev_enabled)
10239 case 'A':
10240 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
10241 fmtId(rinfo->dobj.name));
10242 break;
10243 case 'R':
10244 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
10245 fmtId(rinfo->dobj.name));
10246 break;
10247 case 'D':
10248 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
10249 fmtId(rinfo->dobj.name));
10250 break;
10255 * DROP must be fully qualified in case same name appears in pg_catalog
10257 appendPQExpBuffer(delcmd, "DROP RULE %s ",
10258 fmtId(rinfo->dobj.name));
10259 appendPQExpBuffer(delcmd, "ON %s.",
10260 fmtId(tbinfo->dobj.namespace->dobj.name));
10261 appendPQExpBuffer(delcmd, "%s;\n",
10262 fmtId(tbinfo->dobj.name));
10264 ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
10265 rinfo->dobj.name,
10266 tbinfo->dobj.namespace->dobj.name,
10267 NULL,
10268 tbinfo->rolname, false,
10269 "RULE", cmd->data, delcmd->data, NULL,
10270 rinfo->dobj.dependencies, rinfo->dobj.nDeps,
10271 NULL, NULL);
10273 /* Dump rule comments */
10274 resetPQExpBuffer(query);
10275 appendPQExpBuffer(query, "RULE %s",
10276 fmtId(rinfo->dobj.name));
10277 appendPQExpBuffer(query, " ON %s",
10278 fmtId(tbinfo->dobj.name));
10279 dumpComment(fout, query->data,
10280 tbinfo->dobj.namespace->dobj.name,
10281 tbinfo->rolname,
10282 rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
10284 PQclear(res);
10286 destroyPQExpBuffer(query);
10287 destroyPQExpBuffer(cmd);
10288 destroyPQExpBuffer(delcmd);
10292 * getDependencies --- obtain available dependency data
10294 static void
10295 getDependencies(void)
10297 PQExpBuffer query;
10298 PGresult *res;
10299 int ntups,
10301 int i_classid,
10302 i_objid,
10303 i_refclassid,
10304 i_refobjid,
10305 i_deptype;
10306 DumpableObject *dobj,
10307 *refdobj;
10309 /* No dependency info available before 7.3 */
10310 if (g_fout->remoteVersion < 70300)
10311 return;
10313 if (g_verbose)
10314 write_msg(NULL, "reading dependency data\n");
10316 /* Make sure we are in proper schema */
10317 selectSourceSchema("pg_catalog");
10319 query = createPQExpBuffer();
10321 appendPQExpBuffer(query, "SELECT "
10322 "classid, objid, refclassid, refobjid, deptype "
10323 "FROM pg_depend "
10324 "WHERE deptype != 'p' "
10325 "ORDER BY 1,2");
10327 res = PQexec(g_conn, query->data);
10328 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10330 ntups = PQntuples(res);
10332 i_classid = PQfnumber(res, "classid");
10333 i_objid = PQfnumber(res, "objid");
10334 i_refclassid = PQfnumber(res, "refclassid");
10335 i_refobjid = PQfnumber(res, "refobjid");
10336 i_deptype = PQfnumber(res, "deptype");
10339 * Since we ordered the SELECT by referencing ID, we can expect that
10340 * multiple entries for the same object will appear together; this saves
10341 * on searches.
10343 dobj = NULL;
10345 for (i = 0; i < ntups; i++)
10347 CatalogId objId;
10348 CatalogId refobjId;
10349 char deptype;
10351 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
10352 objId.oid = atooid(PQgetvalue(res, i, i_objid));
10353 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
10354 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
10355 deptype = *(PQgetvalue(res, i, i_deptype));
10357 if (dobj == NULL ||
10358 dobj->catId.tableoid != objId.tableoid ||
10359 dobj->catId.oid != objId.oid)
10360 dobj = findObjectByCatalogId(objId);
10363 * Failure to find objects mentioned in pg_depend is not unexpected,
10364 * since for example we don't collect info about TOAST tables.
10366 if (dobj == NULL)
10368 #ifdef NOT_USED
10369 fprintf(stderr, "no referencing object %u %u\n",
10370 objId.tableoid, objId.oid);
10371 #endif
10372 continue;
10375 refdobj = findObjectByCatalogId(refobjId);
10377 if (refdobj == NULL)
10379 #ifdef NOT_USED
10380 fprintf(stderr, "no referenced object %u %u\n",
10381 refobjId.tableoid, refobjId.oid);
10382 #endif
10383 continue;
10387 * Ordinarily, table rowtypes have implicit dependencies on their
10388 * tables. However, for a composite type the implicit dependency goes
10389 * the other way in pg_depend; which is the right thing for DROP but
10390 * it doesn't produce the dependency ordering we need. So in that one
10391 * case, we reverse the direction of the dependency.
10393 if (deptype == 'i' &&
10394 dobj->objType == DO_TABLE &&
10395 refdobj->objType == DO_TYPE)
10396 addObjectDependency(refdobj, dobj->dumpId);
10397 else
10398 /* normal case */
10399 addObjectDependency(dobj, refdobj->dumpId);
10402 PQclear(res);
10404 destroyPQExpBuffer(query);
10409 * selectSourceSchema - make the specified schema the active search path
10410 * in the source database.
10412 * NB: pg_catalog is explicitly searched after the specified schema;
10413 * so user names are only qualified if they are cross-schema references,
10414 * and system names are only qualified if they conflict with a user name
10415 * in the current schema.
10417 * Whenever the selected schema is not pg_catalog, be careful to qualify
10418 * references to system catalogs and types in our emitted commands!
10420 static void
10421 selectSourceSchema(const char *schemaName)
10423 static char *curSchemaName = NULL;
10424 PQExpBuffer query;
10426 /* Not relevant if fetching from pre-7.3 DB */
10427 if (g_fout->remoteVersion < 70300)
10428 return;
10429 /* Ignore null schema names */
10430 if (schemaName == NULL || *schemaName == '\0')
10431 return;
10432 /* Optimize away repeated selection of same schema */
10433 if (curSchemaName && strcmp(curSchemaName, schemaName) == 0)
10434 return;
10436 query = createPQExpBuffer();
10437 appendPQExpBuffer(query, "SET search_path = %s",
10438 fmtId(schemaName));
10439 if (strcmp(schemaName, "pg_catalog") != 0)
10440 appendPQExpBuffer(query, ", pg_catalog");
10442 do_sql_command(g_conn, query->data);
10444 destroyPQExpBuffer(query);
10445 if (curSchemaName)
10446 free(curSchemaName);
10447 curSchemaName = strdup(schemaName);
10451 * getFormattedTypeName - retrieve a nicely-formatted type name for the
10452 * given type name.
10454 * NB: in 7.3 and up the result may depend on the currently-selected
10455 * schema; this is why we don't try to cache the names.
10457 static char *
10458 getFormattedTypeName(Oid oid, OidOptions opts)
10460 char *result;
10461 PQExpBuffer query;
10462 PGresult *res;
10463 int ntups;
10465 if (oid == 0)
10467 if ((opts & zeroAsOpaque) != 0)
10468 return strdup(g_opaque_type);
10469 else if ((opts & zeroAsAny) != 0)
10470 return strdup("'any'");
10471 else if ((opts & zeroAsStar) != 0)
10472 return strdup("*");
10473 else if ((opts & zeroAsNone) != 0)
10474 return strdup("NONE");
10477 query = createPQExpBuffer();
10478 if (g_fout->remoteVersion >= 70300)
10480 appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
10481 oid);
10483 else if (g_fout->remoteVersion >= 70100)
10485 appendPQExpBuffer(query, "SELECT format_type('%u'::oid, NULL)",
10486 oid);
10488 else
10490 appendPQExpBuffer(query, "SELECT typname "
10491 "FROM pg_type "
10492 "WHERE oid = '%u'::oid",
10493 oid);
10496 res = PQexec(g_conn, query->data);
10497 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10499 /* Expecting a single result only */
10500 ntups = PQntuples(res);
10501 if (ntups != 1)
10503 write_msg(NULL, "query returned %d rows instead of one: %s\n",
10504 ntups, query->data);
10505 exit_nicely();
10508 if (g_fout->remoteVersion >= 70100)
10510 /* already quoted */
10511 result = strdup(PQgetvalue(res, 0, 0));
10513 else
10515 /* may need to quote it */
10516 result = strdup(fmtId(PQgetvalue(res, 0, 0)));
10519 PQclear(res);
10520 destroyPQExpBuffer(query);
10522 return result;
10526 * myFormatType --- local implementation of format_type for use with 7.0.
10528 static char *
10529 myFormatType(const char *typname, int32 typmod)
10531 char *result;
10532 bool isarray = false;
10533 PQExpBuffer buf = createPQExpBuffer();
10535 /* Handle array types */
10536 if (typname[0] == '_')
10538 isarray = true;
10539 typname++;
10542 /* Show lengths on bpchar and varchar */
10543 if (!strcmp(typname, "bpchar"))
10545 int len = (typmod - VARHDRSZ);
10547 appendPQExpBuffer(buf, "character");
10548 if (len > 1)
10549 appendPQExpBuffer(buf, "(%d)",
10550 typmod - VARHDRSZ);
10552 else if (!strcmp(typname, "varchar"))
10554 appendPQExpBuffer(buf, "character varying");
10555 if (typmod != -1)
10556 appendPQExpBuffer(buf, "(%d)",
10557 typmod - VARHDRSZ);
10559 else if (!strcmp(typname, "numeric"))
10561 appendPQExpBuffer(buf, "numeric");
10562 if (typmod != -1)
10564 int32 tmp_typmod;
10565 int precision;
10566 int scale;
10568 tmp_typmod = typmod - VARHDRSZ;
10569 precision = (tmp_typmod >> 16) & 0xffff;
10570 scale = tmp_typmod & 0xffff;
10571 appendPQExpBuffer(buf, "(%d,%d)",
10572 precision, scale);
10577 * char is an internal single-byte data type; Let's make sure we force it
10578 * through with quotes. - thomas 1998-12-13
10580 else if (strcmp(typname, "char") == 0)
10581 appendPQExpBuffer(buf, "\"char\"");
10582 else
10583 appendPQExpBuffer(buf, "%s", fmtId(typname));
10585 /* Append array qualifier for array types */
10586 if (isarray)
10587 appendPQExpBuffer(buf, "[]");
10589 result = strdup(buf->data);
10590 destroyPQExpBuffer(buf);
10592 return result;
10596 * fmtQualifiedId - convert a qualified name to the proper format for
10597 * the source database.
10599 * Like fmtId, use the result before calling again.
10601 static const char *
10602 fmtQualifiedId(const char *schema, const char *id)
10604 static PQExpBuffer id_return = NULL;
10606 if (id_return) /* first time through? */
10607 resetPQExpBuffer(id_return);
10608 else
10609 id_return = createPQExpBuffer();
10611 /* Suppress schema name if fetching from pre-7.3 DB */
10612 if (g_fout->remoteVersion >= 70300 && schema && *schema)
10614 appendPQExpBuffer(id_return, "%s.",
10615 fmtId(schema));
10617 appendPQExpBuffer(id_return, "%s",
10618 fmtId(id));
10620 return id_return->data;
10624 * Return a column list clause for the given relation.
10626 * Special case: if there are no undropped columns in the relation, return
10627 * "", not an invalid "()" column list.
10629 static const char *
10630 fmtCopyColumnList(const TableInfo *ti)
10632 static PQExpBuffer q = NULL;
10633 int numatts = ti->numatts;
10634 char **attnames = ti->attnames;
10635 bool *attisdropped = ti->attisdropped;
10636 bool needComma;
10637 int i;
10639 if (q) /* first time through? */
10640 resetPQExpBuffer(q);
10641 else
10642 q = createPQExpBuffer();
10644 appendPQExpBuffer(q, "(");
10645 needComma = false;
10646 for (i = 0; i < numatts; i++)
10648 if (attisdropped[i])
10649 continue;
10650 if (needComma)
10651 appendPQExpBuffer(q, ", ");
10652 appendPQExpBuffer(q, "%s", fmtId(attnames[i]));
10653 needComma = true;
10656 if (!needComma)
10657 return ""; /* no undropped columns */
10659 appendPQExpBuffer(q, ")");
10660 return q->data;
10664 * Convenience subroutine to execute a SQL command and check for
10665 * COMMAND_OK status.
10667 static void
10668 do_sql_command(PGconn *conn, const char *query)
10670 PGresult *res;
10672 res = PQexec(conn, query);
10673 check_sql_result(res, conn, query, PGRES_COMMAND_OK);
10674 PQclear(res);
10678 * Convenience subroutine to verify a SQL command succeeded,
10679 * and exit with a useful error message if not.
10681 static void
10682 check_sql_result(PGresult *res, PGconn *conn, const char *query,
10683 ExecStatusType expected)
10685 const char *err;
10687 if (res && PQresultStatus(res) == expected)
10688 return; /* A-OK */
10690 write_msg(NULL, "SQL command failed\n");
10691 if (res)
10692 err = PQresultErrorMessage(res);
10693 else
10694 err = PQerrorMessage(conn);
10695 write_msg(NULL, "Error message from server: %s", err);
10696 write_msg(NULL, "The command was: %s\n", query);
10697 exit_nicely();