1 /*-------------------------------------------------------------------------
4 * pg_dump is a utility for dumping out a postgres database
7 * Portions Copyright (c) 1996-2017, 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
14 * Note that pg_dump runs in a transaction-snapshot mode transaction,
15 * so it sees a consistent snapshot of the database including system
16 * catalogs. However, it relies in part on various specialized backend
17 * functions like pg_get_indexdef(), and those things tend to look at
18 * the currently committed state. So it is possible to get 'cache
19 * lookup failed' error if someone performs DDL changes while a dump is
20 * happening. The window for this sort of thing is from the acquisition
21 * of the transaction snapshot to getSchemaData() (when pg_dump acquires
22 * AccessShareLock on every table it intends to dump). It isn't very large,
25 * http://archives.postgresql.org/pgsql-bugs/2010-02/msg00187.php
28 * src/bin/pg_dump/pg_dump.c
30 *-------------------------------------------------------------------------
32 #include "postgres_fe.h"
40 #include "getopt_long.h"
42 #include "access/attnum.h"
43 #include "access/sysattr.h"
44 #include "access/transam.h"
45 #include "catalog/pg_am.h"
46 #include "catalog/pg_attribute.h"
47 #include "catalog/pg_cast.h"
48 #include "catalog/pg_class.h"
49 #include "catalog/pg_default_acl.h"
50 #include "catalog/pg_largeobject.h"
51 #include "catalog/pg_largeobject_metadata.h"
52 #include "catalog/pg_proc.h"
53 #include "catalog/pg_trigger.h"
54 #include "catalog/pg_type.h"
55 #include "libpq/libpq-fs.h"
57 #include "dumputils.h"
59 #include "pg_backup_db.h"
60 #include "pg_backup_utils.h"
62 #include "fe_utils/string_utils.h"
67 const char *descr; /* comment for an object */
68 Oid classoid; /* object class (catalog OID) */
69 Oid objoid; /* object OID */
70 int objsubid; /* subobject (table column #) */
75 const char *provider; /* label provider of this security label */
76 const char *label; /* security label for an object */
77 Oid classoid; /* object class (catalog OID) */
78 Oid objoid; /* object OID */
79 int objsubid; /* subobject (table column #) */
82 typedef enum OidOptions
91 bool g_verbose; /* User wants verbose narration of our
93 static bool dosync = true; /* Issue fsync() to make dump durable on disk. */
95 /* subquery used to convert user ID (eg, datdba) to user name */
96 static const char *username_subquery;
99 * For 8.0 and earlier servers, pulled from pg_database, for 8.1+ we use
100 * FirstNormalObjectId - 1.
102 static Oid g_last_builtin_oid; /* value of the last builtin oid */
104 /* The specified names/patterns should to match at least one entity */
105 static int strict_names = 0;
108 * Object inclusion/exclusion lists
110 * The string lists record the patterns given by command-line switches,
111 * which we then convert to lists of OIDs of matching objects.
113 static SimpleStringList schema_include_patterns = {NULL, NULL};
114 static SimpleOidList schema_include_oids = {NULL, NULL};
115 static SimpleStringList schema_exclude_patterns = {NULL, NULL};
116 static SimpleOidList schema_exclude_oids = {NULL, NULL};
118 static SimpleStringList table_include_patterns = {NULL, NULL};
119 static SimpleOidList table_include_oids = {NULL, NULL};
120 static SimpleStringList table_exclude_patterns = {NULL, NULL};
121 static SimpleOidList table_exclude_oids = {NULL, NULL};
122 static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
123 static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
126 char g_opaque_type[10]; /* name for the opaque type */
128 /* placeholders for the delimiters for comments */
129 char g_comment_start[10];
130 char g_comment_end[10];
132 static const CatalogId nilCatalogId = {0, 0};
134 static void help(const char *progname);
135 static void setup_connection(Archive *AH,
136 const char *dumpencoding, const char *dumpsnapshot,
138 static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
139 static void expand_schema_name_patterns(Archive *fout,
140 SimpleStringList *patterns,
143 static void expand_table_name_patterns(Archive *fout,
144 SimpleStringList *patterns,
147 static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid);
148 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
149 static void refreshMatViewData(Archive *fout, TableDataInfo *tdinfo);
150 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
151 static void dumpComment(Archive *fout, const char *target,
152 const char *namespace, const char *owner,
153 CatalogId catalogId, int subid, DumpId dumpId);
154 static int findComments(Archive *fout, Oid classoid, Oid objoid,
155 CommentItem **items);
156 static int collectComments(Archive *fout, CommentItem **items);
157 static void dumpSecLabel(Archive *fout, const char *target,
158 const char *namespace, const char *owner,
159 CatalogId catalogId, int subid, DumpId dumpId);
160 static int findSecLabels(Archive *fout, Oid classoid, Oid objoid,
161 SecLabelItem **items);
162 static int collectSecLabels(Archive *fout, SecLabelItem **items);
163 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
164 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
165 static void dumpExtension(Archive *fout, ExtensionInfo *extinfo);
166 static void dumpType(Archive *fout, TypeInfo *tyinfo);
167 static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
168 static void dumpEnumType(Archive *fout, TypeInfo *tyinfo);
169 static void dumpRangeType(Archive *fout, TypeInfo *tyinfo);
170 static void dumpUndefinedType(Archive *fout, TypeInfo *tyinfo);
171 static void dumpDomain(Archive *fout, TypeInfo *tyinfo);
172 static void dumpCompositeType(Archive *fout, TypeInfo *tyinfo);
173 static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
174 static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
175 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
176 static void dumpFunc(Archive *fout, FuncInfo *finfo);
177 static void dumpCast(Archive *fout, CastInfo *cast);
178 static void dumpTransform(Archive *fout, TransformInfo *transform);
179 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
180 static void dumpAccessMethod(Archive *fout, AccessMethodInfo *oprinfo);
181 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
182 static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
183 static void dumpCollation(Archive *fout, CollInfo *collinfo);
184 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
185 static void dumpRule(Archive *fout, RuleInfo *rinfo);
186 static void dumpAgg(Archive *fout, AggInfo *agginfo);
187 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
188 static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
189 static void dumpTable(Archive *fout, TableInfo *tbinfo);
190 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
191 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
192 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
193 static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo);
194 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
195 static void dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo);
196 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
197 static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
198 static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
199 static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
200 static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
201 static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
202 static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
203 static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
204 static void dumpUserMappings(Archive *fout,
205 const char *servername, const char *namespace,
206 const char *owner, CatalogId catalogId, DumpId dumpId);
207 static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
209 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
210 const char *type, const char *name, const char *subname,
211 const char *tag, const char *nspname, const char *owner,
212 const char *acls, const char *racls,
213 const char *initacls, const char *initracls);
215 static void getDependencies(Archive *fout);
216 static void BuildArchiveDependencies(Archive *fout);
217 static void findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
218 DumpId **dependencies, int *nDeps, int *allocDeps);
220 static DumpableObject *createBoundaryObjects(void);
221 static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
222 DumpableObject *boundaryObjs);
224 static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
225 static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, bool oids, char relkind);
226 static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo, bool oids);
227 static void buildMatViewRefreshDependencies(Archive *fout);
228 static void getTableDataFKConstraints(void);
229 static char *format_function_arguments(FuncInfo *finfo, char *funcargs,
231 static char *format_function_arguments_old(Archive *fout,
232 FuncInfo *finfo, int nallargs,
236 static char *format_function_signature(Archive *fout,
237 FuncInfo *finfo, bool honor_quotes);
238 static char *convertRegProcReference(Archive *fout,
240 static char *convertOperatorReference(Archive *fout, const char *opr);
241 static char *convertTSFunction(Archive *fout, Oid funcOid);
242 static Oid findLastBuiltinOid_V71(Archive *fout, const char *);
243 static void selectSourceSchema(Archive *fout, const char *schemaName);
244 static char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
245 static void getBlobs(Archive *fout);
246 static void dumpBlob(Archive *fout, BlobInfo *binfo);
247 static int dumpBlobs(Archive *fout, void *arg);
248 static void dumpPolicy(Archive *fout, PolicyInfo *polinfo);
249 static void dumpPublication(Archive *fout, PublicationInfo *pubinfo);
250 static void dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo);
251 static void dumpSubscription(Archive *fout, SubscriptionInfo *subinfo);
252 static void dumpDatabase(Archive *AH);
253 static void dumpEncoding(Archive *AH);
254 static void dumpStdStrings(Archive *AH);
255 static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
256 PQExpBuffer upgrade_buffer, Oid pg_type_oid);
257 static bool binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
258 PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
259 static void binary_upgrade_set_pg_class_oids(Archive *fout,
260 PQExpBuffer upgrade_buffer,
261 Oid pg_class_oid, bool is_index);
262 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
263 DumpableObject *dobj,
264 const char *objlabel);
265 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
266 static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
267 static bool nonemptyReloptions(const char *reloptions);
268 static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
269 const char *prefix, Archive *fout);
270 static char *get_synchronized_snapshot(Archive *fout);
271 static void setupDumpWorker(Archive *AHX);
272 static TableInfo *getRootTableInfo(TableInfo *tbinfo);
276 main(int argc, char **argv)
279 const char *filename = NULL;
280 const char *format = "p";
283 DumpableObject **dobjs;
285 DumpableObject *boundaryObjs;
288 RestoreOptions *ropt;
289 Archive *fout; /* the script file */
290 const char *dumpencoding = NULL;
291 const char *dumpsnapshot = NULL;
292 char *use_role = NULL;
294 trivalue prompt_password = TRI_DEFAULT;
295 int compressLevel = -1;
297 ArchiveFormat archiveFormat = archUnknown;
298 ArchiveMode archiveMode;
300 static DumpOptions dopt;
302 static struct option long_options[] = {
303 {"data-only", no_argument, NULL, 'a'},
304 {"blobs", no_argument, NULL, 'b'},
305 {"no-blobs", no_argument, NULL, 'B'},
306 {"clean", no_argument, NULL, 'c'},
307 {"create", no_argument, NULL, 'C'},
308 {"dbname", required_argument, NULL, 'd'},
309 {"file", required_argument, NULL, 'f'},
310 {"format", required_argument, NULL, 'F'},
311 {"host", required_argument, NULL, 'h'},
312 {"jobs", 1, NULL, 'j'},
313 {"no-reconnect", no_argument, NULL, 'R'},
314 {"oids", no_argument, NULL, 'o'},
315 {"no-owner", no_argument, NULL, 'O'},
316 {"port", required_argument, NULL, 'p'},
317 {"schema", required_argument, NULL, 'n'},
318 {"exclude-schema", required_argument, NULL, 'N'},
319 {"schema-only", no_argument, NULL, 's'},
320 {"superuser", required_argument, NULL, 'S'},
321 {"table", required_argument, NULL, 't'},
322 {"exclude-table", required_argument, NULL, 'T'},
323 {"no-password", no_argument, NULL, 'w'},
324 {"password", no_argument, NULL, 'W'},
325 {"username", required_argument, NULL, 'U'},
326 {"verbose", no_argument, NULL, 'v'},
327 {"no-privileges", no_argument, NULL, 'x'},
328 {"no-acl", no_argument, NULL, 'x'},
329 {"compress", required_argument, NULL, 'Z'},
330 {"encoding", required_argument, NULL, 'E'},
331 {"help", no_argument, NULL, '?'},
332 {"version", no_argument, NULL, 'V'},
335 * the following options don't have an equivalent short option letter
337 {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
338 {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
339 {"column-inserts", no_argument, &dopt.column_inserts, 1},
340 {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
341 {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
342 {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
343 {"exclude-table-data", required_argument, NULL, 4},
344 {"if-exists", no_argument, &dopt.if_exists, 1},
345 {"inserts", no_argument, &dopt.dump_inserts, 1},
346 {"lock-wait-timeout", required_argument, NULL, 2},
347 {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
348 {"quote-all-identifiers", no_argument, "e_all_identifiers, 1},
349 {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
350 {"role", required_argument, NULL, 3},
351 {"section", required_argument, NULL, 5},
352 {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
353 {"snapshot", required_argument, NULL, 6},
354 {"strict-names", no_argument, &strict_names, 1},
355 {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
356 {"no-publications", no_argument, &dopt.no_publications, 1},
357 {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
358 {"no-synchronized-snapshots", no_argument, &dopt.no_synchronized_snapshots, 1},
359 {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
360 {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
361 {"no-sync", no_argument, NULL, 7},
366 set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
369 * Initialize what we need for parallel execution, especially for thread
370 * support on Windows.
372 init_parallel_dump_utils();
376 strcpy(g_comment_start, "-- ");
377 g_comment_end[0] = '\0';
378 strcpy(g_opaque_type, "opaque");
380 progname = get_progname(argv[0]);
384 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
389 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
391 puts("pg_dump (PostgreSQL) " PG_VERSION);
396 InitDumpOptions(&dopt);
398 while ((c = getopt_long(argc, argv, "abBcCd:E:f:F:h:j:n:N:oOp:RsS:t:T:U:vwWxZ:",
399 long_options, &optindex)) != -1)
403 case 'a': /* Dump data only */
404 dopt.dataOnly = true;
407 case 'b': /* Dump blobs */
408 dopt.outputBlobs = true;
411 case 'B': /* Don't dump blobs */
412 dopt.dontOutputBlobs = true;
415 case 'c': /* clean (i.e., drop) schema prior to create */
416 dopt.outputClean = 1;
419 case 'C': /* Create DB */
420 dopt.outputCreateDB = 1;
423 case 'd': /* database name */
424 dopt.dbname = pg_strdup(optarg);
427 case 'E': /* Dump encoding */
428 dumpencoding = pg_strdup(optarg);
432 filename = pg_strdup(optarg);
436 format = pg_strdup(optarg);
439 case 'h': /* server host */
440 dopt.pghost = pg_strdup(optarg);
443 case 'j': /* number of dump jobs */
444 numWorkers = atoi(optarg);
447 case 'n': /* include schema(s) */
448 simple_string_list_append(&schema_include_patterns, optarg);
449 dopt.include_everything = false;
452 case 'N': /* exclude schema(s) */
453 simple_string_list_append(&schema_exclude_patterns, optarg);
456 case 'o': /* Dump oids */
460 case 'O': /* Don't reconnect to match owner */
461 dopt.outputNoOwner = 1;
464 case 'p': /* server port */
465 dopt.pgport = pg_strdup(optarg);
469 /* no-op, still accepted for backwards compatibility */
472 case 's': /* dump schema only */
473 dopt.schemaOnly = true;
476 case 'S': /* Username for superuser in plain text output */
477 dopt.outputSuperuser = pg_strdup(optarg);
480 case 't': /* include table(s) */
481 simple_string_list_append(&table_include_patterns, optarg);
482 dopt.include_everything = false;
485 case 'T': /* exclude table(s) */
486 simple_string_list_append(&table_exclude_patterns, optarg);
490 dopt.username = pg_strdup(optarg);
493 case 'v': /* verbose */
498 prompt_password = TRI_NO;
502 prompt_password = TRI_YES;
505 case 'x': /* skip ACL dump */
506 dopt.aclsSkip = true;
509 case 'Z': /* Compression Level */
510 compressLevel = atoi(optarg);
511 if (compressLevel < 0 || compressLevel > 9)
513 write_msg(NULL, "compression level must be in range 0..9\n");
519 /* This covers the long options. */
522 case 2: /* lock-wait-timeout */
523 dopt.lockWaitTimeout = pg_strdup(optarg);
526 case 3: /* SET ROLE */
527 use_role = pg_strdup(optarg);
530 case 4: /* exclude table(s) data */
531 simple_string_list_append(&tabledata_exclude_patterns, optarg);
534 case 5: /* section */
535 set_dump_section(optarg, &dopt.dumpSections);
538 case 6: /* snapshot */
539 dumpsnapshot = pg_strdup(optarg);
542 case 7: /* no-sync */
547 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
553 * Non-option argument specifies database name as long as it wasn't
554 * already specified with -d / --dbname
556 if (optind < argc && dopt.dbname == NULL)
557 dopt.dbname = argv[optind++];
559 /* Complain if any arguments remain */
562 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
563 progname, argv[optind]);
564 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
569 /* --column-inserts implies --inserts */
570 if (dopt.column_inserts)
571 dopt.dump_inserts = 1;
574 * Binary upgrade mode implies dumping sequence data even in schema-only
575 * mode. This is not exposed as a separate option, but kept separate
576 * internally for clarity.
578 if (dopt.binary_upgrade)
579 dopt.sequence_data = 1;
581 if (dopt.dataOnly && dopt.schemaOnly)
583 write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
587 if (dopt.dataOnly && dopt.outputClean)
589 write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
593 if (dopt.dump_inserts && dopt.oids)
595 write_msg(NULL, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
596 write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
600 if (dopt.if_exists && !dopt.outputClean)
601 exit_horribly(NULL, "option --if-exists requires option -c/--clean\n");
603 /* Identify archive format to emit */
604 archiveFormat = parseArchiveFormat(format, &archiveMode);
606 /* archiveFormat specific setup */
607 if (archiveFormat == archNull)
610 /* Custom and directory formats are compressed by default, others not */
611 if (compressLevel == -1)
614 if (archiveFormat == archCustom || archiveFormat == archDirectory)
615 compressLevel = Z_DEFAULT_COMPRESSION;
622 if (compressLevel != 0)
623 write_msg(NULL, "WARNING: requested compression not available in this "
624 "installation -- archive will be uncompressed\n");
629 * On Windows we can only have at most MAXIMUM_WAIT_OBJECTS (= 64 usually)
630 * parallel jobs because that's the maximum limit for the
631 * WaitForMultipleObjects() call.
635 || numWorkers > MAXIMUM_WAIT_OBJECTS
638 exit_horribly(NULL, "invalid number of parallel jobs\n");
640 /* Parallel backup only in the directory archive format so far */
641 if (archiveFormat != archDirectory && numWorkers > 1)
642 exit_horribly(NULL, "parallel backup only supported by the directory format\n");
644 /* Open the output file */
645 fout = CreateArchive(filename, archiveFormat, compressLevel, dosync,
646 archiveMode, setupDumpWorker);
648 /* Make dump options accessible right away */
649 SetArchiveOptions(fout, &dopt, NULL);
651 /* Register the cleanup hook */
652 on_exit_close_archive(fout);
654 /* Let the archiver know how noisy to be */
655 fout->verbose = g_verbose;
658 * We allow the server to be back to 8.0, and up to any minor release of
659 * our own major version. (See also version check in pg_dumpall.c.)
661 fout->minRemoteVersion = 80000;
662 fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
664 fout->numWorkers = numWorkers;
667 * Open the database using the Archiver, so it knows about it. Errors mean
670 ConnectDatabase(fout, dopt.dbname, dopt.pghost, dopt.pgport, dopt.username, prompt_password);
671 setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
674 * Disable security label support if server version < v9.1.x (prevents
675 * access to nonexistent pg_seclabel catalog)
677 if (fout->remoteVersion < 90100)
678 dopt.no_security_labels = 1;
681 * On hot standbys, never try to dump unlogged table data, since it will
682 * just throw an error.
685 dopt.no_unlogged_table_data = true;
687 /* Select the appropriate subquery to convert user IDs to names */
688 if (fout->remoteVersion >= 80100)
689 username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
691 username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
693 /* check the version for the synchronized snapshots feature */
694 if (numWorkers > 1 && fout->remoteVersion < 90200
695 && !dopt.no_synchronized_snapshots)
697 "Synchronized snapshots are not supported by this server version.\n"
698 "Run with --no-synchronized-snapshots instead if you do not need\n"
699 "synchronized snapshots.\n");
701 /* check the version when a snapshot is explicitly specified by user */
702 if (dumpsnapshot && fout->remoteVersion < 90200)
704 "Exported snapshots are not supported by this server version.\n");
707 * Find the last built-in OID, if needed (prior to 8.1)
709 * With 8.1 and above, we can just use FirstNormalObjectId - 1.
711 if (fout->remoteVersion < 80100)
712 g_last_builtin_oid = findLastBuiltinOid_V71(fout,
713 PQdb(GetConnection(fout)));
715 g_last_builtin_oid = FirstNormalObjectId - 1;
718 write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
720 /* Expand schema selection patterns into OID lists */
721 if (schema_include_patterns.head != NULL)
723 expand_schema_name_patterns(fout, &schema_include_patterns,
724 &schema_include_oids,
726 if (schema_include_oids.head == NULL)
727 exit_horribly(NULL, "no matching schemas were found\n");
729 expand_schema_name_patterns(fout, &schema_exclude_patterns,
730 &schema_exclude_oids,
732 /* non-matching exclusion patterns aren't an error */
734 /* Expand table selection patterns into OID lists */
735 if (table_include_patterns.head != NULL)
737 expand_table_name_patterns(fout, &table_include_patterns,
740 if (table_include_oids.head == NULL)
741 exit_horribly(NULL, "no matching tables were found\n");
743 expand_table_name_patterns(fout, &table_exclude_patterns,
747 expand_table_name_patterns(fout, &tabledata_exclude_patterns,
748 &tabledata_exclude_oids,
751 /* non-matching exclusion patterns aren't an error */
754 * Dumping blobs is the default for dumps where an inclusion switch is not
755 * used (an "include everything" dump). -B can be used to exclude blobs
756 * from those dumps. -b can be used to include blobs even when an
757 * inclusion switch is used.
759 * -s means "schema only" and blobs are data, not schema, so we never
760 * include blobs when -s is used.
762 if (dopt.include_everything && !dopt.schemaOnly && !dopt.dontOutputBlobs)
763 dopt.outputBlobs = true;
766 * Now scan the database and create DumpableObject structs for all the
767 * objects we intend to dump.
769 tblinfo = getSchemaData(fout, &numTables);
771 if (fout->remoteVersion < 80400)
772 guessConstraintInheritance(tblinfo, numTables);
774 if (!dopt.schemaOnly)
776 getTableData(&dopt, tblinfo, numTables, dopt.oids, 0);
777 buildMatViewRefreshDependencies(fout);
779 getTableDataFKConstraints();
782 if (dopt.schemaOnly && dopt.sequence_data)
783 getTableData(&dopt, tblinfo, numTables, dopt.oids, RELKIND_SEQUENCE);
786 * In binary-upgrade mode, we do not have to worry about the actual blob
787 * data or the associated metadata that resides in the pg_largeobject and
788 * pg_largeobject_metadata tables, respectivly.
790 * However, we do need to collect blob information as there may be
791 * comments or other information on blobs that we do need to dump out.
793 if (dopt.outputBlobs || dopt.binary_upgrade)
797 * Collect dependency data to assist in ordering the objects.
799 getDependencies(fout);
801 /* Lastly, create dummy objects to represent the section boundaries */
802 boundaryObjs = createBoundaryObjects();
804 /* Get pointers to all the known DumpableObjects */
805 getDumpableObjects(&dobjs, &numObjs);
808 * Add dummy dependencies to enforce the dump section ordering.
810 addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
813 * Sort the objects into a safe dump order (no forward references).
815 * We rely on dependency information to help us determine a safe order, so
816 * the initial sort is mostly for cosmetic purposes: we sort by name to
817 * ensure that logically identical schemas will dump identically.
819 sortDumpableObjectsByTypeName(dobjs, numObjs);
821 /* If we do a parallel dump, we want the largest tables to go first */
822 if (archiveFormat == archDirectory && numWorkers > 1)
823 sortDataAndIndexObjectsBySize(dobjs, numObjs);
825 sortDumpableObjects(dobjs, numObjs,
826 boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
829 * Create archive TOC entries for all the objects to be dumped, in a safe
833 /* First the special ENCODING and STDSTRINGS entries. */
835 dumpStdStrings(fout);
837 /* The database item is always next, unless we don't want it at all */
838 if (dopt.include_everything && !dopt.dataOnly)
841 /* Now the rearrangeable objects. */
842 for (i = 0; i < numObjs; i++)
843 dumpDumpableObject(fout, dobjs[i]);
846 * Set up options info to ensure we dump what we want.
848 ropt = NewRestoreOptions();
849 ropt->filename = filename;
851 /* if you change this list, see dumpOptionsFromRestoreOptions */
852 ropt->dropSchema = dopt.outputClean;
853 ropt->dataOnly = dopt.dataOnly;
854 ropt->schemaOnly = dopt.schemaOnly;
855 ropt->if_exists = dopt.if_exists;
856 ropt->column_inserts = dopt.column_inserts;
857 ropt->dumpSections = dopt.dumpSections;
858 ropt->aclsSkip = dopt.aclsSkip;
859 ropt->superuser = dopt.outputSuperuser;
860 ropt->createDB = dopt.outputCreateDB;
861 ropt->noOwner = dopt.outputNoOwner;
862 ropt->noTablespace = dopt.outputNoTablespaces;
863 ropt->disable_triggers = dopt.disable_triggers;
864 ropt->use_setsessauth = dopt.use_setsessauth;
865 ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
866 ropt->dump_inserts = dopt.dump_inserts;
867 ropt->no_publications = dopt.no_publications;
868 ropt->no_security_labels = dopt.no_security_labels;
869 ropt->no_subscriptions = dopt.no_subscriptions;
870 ropt->lockWaitTimeout = dopt.lockWaitTimeout;
871 ropt->include_everything = dopt.include_everything;
872 ropt->enable_row_security = dopt.enable_row_security;
873 ropt->sequence_data = dopt.sequence_data;
874 ropt->binary_upgrade = dopt.binary_upgrade;
876 if (compressLevel == -1)
877 ropt->compression = 0;
879 ropt->compression = compressLevel;
881 ropt->suppressDumpWarnings = true; /* We've already shown them */
883 SetArchiveOptions(fout, &dopt, ropt);
885 /* Mark which entries should be output */
886 ProcessArchiveRestoreOptions(fout);
889 * The archive's TOC entries are now marked as to which ones will actually
890 * be output, so we can set up their dependency lists properly. This isn't
891 * necessary for plain-text output, though.
894 BuildArchiveDependencies(fout);
897 * And finally we can do the actual output.
899 * Note: for non-plain-text output formats, the output file is written
900 * inside CloseArchive(). This is, um, bizarre; but not worth changing
904 RestoreArchive(fout);
913 help(const char *progname)
915 printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
916 printf(_("Usage:\n"));
917 printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
919 printf(_("\nGeneral options:\n"));
920 printf(_(" -f, --file=FILENAME output file or directory name\n"));
921 printf(_(" -F, --format=c|d|t|p output file format (custom, directory, tar,\n"
922 " plain text (default))\n"));
923 printf(_(" -j, --jobs=NUM use this many parallel jobs to dump\n"));
924 printf(_(" -v, --verbose verbose mode\n"));
925 printf(_(" -V, --version output version information, then exit\n"));
926 printf(_(" -Z, --compress=0-9 compression level for compressed formats\n"));
927 printf(_(" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
928 printf(_(" --no-sync do not wait for changes to be written safely to disk\n"));
929 printf(_(" -?, --help show this help, then exit\n"));
931 printf(_("\nOptions controlling the output content:\n"));
932 printf(_(" -a, --data-only dump only the data, not the schema\n"));
933 printf(_(" -b, --blobs include large objects in dump\n"));
934 printf(_(" -B, --no-blobs exclude large objects in dump\n"));
935 printf(_(" -c, --clean clean (drop) database objects before recreating\n"));
936 printf(_(" -C, --create include commands to create database in dump\n"));
937 printf(_(" -E, --encoding=ENCODING dump the data in encoding ENCODING\n"));
938 printf(_(" -n, --schema=SCHEMA dump the named schema(s) only\n"));
939 printf(_(" -N, --exclude-schema=SCHEMA do NOT dump the named schema(s)\n"));
940 printf(_(" -o, --oids include OIDs in dump\n"));
941 printf(_(" -O, --no-owner skip restoration of object ownership in\n"
942 " plain-text format\n"));
943 printf(_(" -s, --schema-only dump only the schema, no data\n"));
944 printf(_(" -S, --superuser=NAME superuser user name to use in plain-text format\n"));
945 printf(_(" -t, --table=TABLE dump the named table(s) only\n"));
946 printf(_(" -T, --exclude-table=TABLE do NOT dump the named table(s)\n"));
947 printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
948 printf(_(" --binary-upgrade for use by upgrade utilities only\n"));
949 printf(_(" --column-inserts dump data as INSERT commands with column names\n"));
950 printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n"));
951 printf(_(" --disable-triggers disable triggers during data-only restore\n"));
952 printf(_(" --enable-row-security enable row security (dump only content user has\n"
954 printf(_(" --exclude-table-data=TABLE do NOT dump data for the named table(s)\n"));
955 printf(_(" --if-exists use IF EXISTS when dropping objects\n"));
956 printf(_(" --inserts dump data as INSERT commands, rather than COPY\n"));
957 printf(_(" --no-publications do not dump publications\n"));
958 printf(_(" --no-security-labels do not dump security label assignments\n"));
959 printf(_(" --no-subscriptions do not dump subscriptions\n"));
960 printf(_(" --no-synchronized-snapshots do not use synchronized snapshots in parallel jobs\n"));
961 printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
962 printf(_(" --no-unlogged-table-data do not dump unlogged table data\n"));
963 printf(_(" --quote-all-identifiers quote all identifiers, even if not key words\n"));
964 printf(_(" --load-via-partition-root load partitions via the root table\n"));
965 printf(_(" --section=SECTION dump named section (pre-data, data, or post-data)\n"));
966 printf(_(" --serializable-deferrable wait until the dump can run without anomalies\n"));
967 printf(_(" --snapshot=SNAPSHOT use given snapshot for the dump\n"));
968 printf(_(" --strict-names require table and/or schema include patterns to\n"
969 " match at least one entity each\n"));
970 printf(_(" --use-set-session-authorization\n"
971 " use SET SESSION AUTHORIZATION commands instead of\n"
972 " ALTER OWNER commands to set ownership\n"));
974 printf(_("\nConnection options:\n"));
975 printf(_(" -d, --dbname=DBNAME database to dump\n"));
976 printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
977 printf(_(" -p, --port=PORT database server port number\n"));
978 printf(_(" -U, --username=NAME connect as specified database user\n"));
979 printf(_(" -w, --no-password never prompt for password\n"));
980 printf(_(" -W, --password force password prompt (should happen automatically)\n"));
981 printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
983 printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
984 "variable value is used.\n\n"));
985 printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
989 setup_connection(Archive *AH, const char *dumpencoding,
990 const char *dumpsnapshot, char *use_role)
992 DumpOptions *dopt = AH->dopt;
993 PGconn *conn = GetConnection(AH);
994 const char *std_strings;
997 * Set the client encoding if requested.
1001 if (PQsetClientEncoding(conn, dumpencoding) < 0)
1002 exit_horribly(NULL, "invalid client encoding \"%s\" specified\n",
1007 * Get the active encoding and the standard_conforming_strings setting, so
1008 * we know how to escape strings.
1010 AH->encoding = PQclientEncoding(conn);
1012 std_strings = PQparameterStatus(conn, "standard_conforming_strings");
1013 AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
1016 * Set the role if requested. In a parallel dump worker, we'll be passed
1017 * use_role == NULL, but AH->use_role is already set (if user specified it
1018 * originally) and we should use that.
1020 if (!use_role && AH->use_role)
1021 use_role = AH->use_role;
1023 /* Set the role if requested */
1024 if (use_role && AH->remoteVersion >= 80100)
1026 PQExpBuffer query = createPQExpBuffer();
1028 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
1029 ExecuteSqlStatement(AH, query->data);
1030 destroyPQExpBuffer(query);
1032 /* save it for possible later use by parallel workers */
1034 AH->use_role = pg_strdup(use_role);
1037 /* Set the datestyle to ISO to ensure the dump's portability */
1038 ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
1040 /* Likewise, avoid using sql_standard intervalstyle */
1041 if (AH->remoteVersion >= 80400)
1042 ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
1045 * Set extra_float_digits so that we can dump float data exactly (given
1046 * correctly implemented float I/O code, anyway)
1048 if (AH->remoteVersion >= 90000)
1049 ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
1051 ExecuteSqlStatement(AH, "SET extra_float_digits TO 2");
1054 * If synchronized scanning is supported, disable it, to prevent
1055 * unpredictable changes in row ordering across a dump and reload.
1057 if (AH->remoteVersion >= 80300)
1058 ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
1061 * Disable timeouts if supported.
1063 ExecuteSqlStatement(AH, "SET statement_timeout = 0");
1064 if (AH->remoteVersion >= 90300)
1065 ExecuteSqlStatement(AH, "SET lock_timeout = 0");
1066 if (AH->remoteVersion >= 90600)
1067 ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
1070 * Quote all identifiers, if requested.
1072 if (quote_all_identifiers && AH->remoteVersion >= 90100)
1073 ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1076 * Adjust row-security mode, if supported.
1078 if (AH->remoteVersion >= 90500)
1080 if (dopt->enable_row_security)
1081 ExecuteSqlStatement(AH, "SET row_security = on");
1083 ExecuteSqlStatement(AH, "SET row_security = off");
1087 * Start transaction-snapshot mode transaction to dump consistent data.
1089 ExecuteSqlStatement(AH, "BEGIN");
1090 if (AH->remoteVersion >= 90100)
1093 * To support the combination of serializable_deferrable with the jobs
1094 * option we use REPEATABLE READ for the worker connections that are
1095 * passed a snapshot. As long as the snapshot is acquired in a
1096 * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
1097 * REPEATABLE READ transaction provides the appropriate integrity
1098 * guarantees. This is a kluge, but safe for back-patching.
1100 if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
1101 ExecuteSqlStatement(AH,
1102 "SET TRANSACTION ISOLATION LEVEL "
1103 "SERIALIZABLE, READ ONLY, DEFERRABLE");
1105 ExecuteSqlStatement(AH,
1106 "SET TRANSACTION ISOLATION LEVEL "
1107 "REPEATABLE READ, READ ONLY");
1111 ExecuteSqlStatement(AH,
1112 "SET TRANSACTION ISOLATION LEVEL "
1113 "SERIALIZABLE, READ ONLY");
1117 * If user specified a snapshot to use, select that. In a parallel dump
1118 * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
1119 * is already set (if the server can handle it) and we should use that.
1122 AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
1124 if (AH->sync_snapshot_id)
1126 PQExpBuffer query = createPQExpBuffer();
1128 appendPQExpBuffer(query, "SET TRANSACTION SNAPSHOT ");
1129 appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
1130 ExecuteSqlStatement(AH, query->data);
1131 destroyPQExpBuffer(query);
1133 else if (AH->numWorkers > 1 &&
1134 AH->remoteVersion >= 90200 &&
1135 !dopt->no_synchronized_snapshots)
1139 "Synchronized snapshots are not supported on standby servers.\n"
1140 "Run with --no-synchronized-snapshots instead if you do not need\n"
1141 "synchronized snapshots.\n");
1144 AH->sync_snapshot_id = get_synchronized_snapshot(AH);
1148 /* Set up connection for a parallel worker process */
1150 setupDumpWorker(Archive *AH)
1153 * We want to re-select all the same values the master connection is
1154 * using. We'll have inherited directly-usable values in
1155 * AH->sync_snapshot_id and AH->use_role, but we need to translate the
1156 * inherited encoding value back to a string to pass to setup_connection.
1158 setup_connection(AH,
1159 pg_encoding_to_char(AH->encoding),
1165 get_synchronized_snapshot(Archive *fout)
1167 char *query = "SELECT pg_catalog.pg_export_snapshot()";
1171 res = ExecuteSqlQueryForSingleRow(fout, query);
1172 result = pg_strdup(PQgetvalue(res, 0, 0));
1178 static ArchiveFormat
1179 parseArchiveFormat(const char *format, ArchiveMode *mode)
1181 ArchiveFormat archiveFormat;
1183 *mode = archModeWrite;
1185 if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1187 /* This is used by pg_dumpall, and is not documented */
1188 archiveFormat = archNull;
1189 *mode = archModeAppend;
1191 else if (pg_strcasecmp(format, "c") == 0)
1192 archiveFormat = archCustom;
1193 else if (pg_strcasecmp(format, "custom") == 0)
1194 archiveFormat = archCustom;
1195 else if (pg_strcasecmp(format, "d") == 0)
1196 archiveFormat = archDirectory;
1197 else if (pg_strcasecmp(format, "directory") == 0)
1198 archiveFormat = archDirectory;
1199 else if (pg_strcasecmp(format, "p") == 0)
1200 archiveFormat = archNull;
1201 else if (pg_strcasecmp(format, "plain") == 0)
1202 archiveFormat = archNull;
1203 else if (pg_strcasecmp(format, "t") == 0)
1204 archiveFormat = archTar;
1205 else if (pg_strcasecmp(format, "tar") == 0)
1206 archiveFormat = archTar;
1208 exit_horribly(NULL, "invalid output format \"%s\" specified\n", format);
1209 return archiveFormat;
1213 * Find the OIDs of all schemas matching the given list of patterns,
1214 * and append them to the given OID list.
1217 expand_schema_name_patterns(Archive *fout,
1218 SimpleStringList *patterns,
1219 SimpleOidList *oids,
1224 SimpleStringListCell *cell;
1227 if (patterns->head == NULL)
1228 return; /* nothing to do */
1230 query = createPQExpBuffer();
1233 * The loop below runs multiple SELECTs might sometimes result in
1234 * duplicate entries in the OID list, but we don't care.
1237 for (cell = patterns->head; cell; cell = cell->next)
1239 appendPQExpBuffer(query,
1240 "SELECT oid FROM pg_catalog.pg_namespace n\n");
1241 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1242 false, NULL, "n.nspname", NULL, NULL);
1244 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1245 if (strict_names && PQntuples(res) == 0)
1246 exit_horribly(NULL, "no matching schemas were found for pattern \"%s\"\n", cell->val);
1248 for (i = 0; i < PQntuples(res); i++)
1250 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1254 resetPQExpBuffer(query);
1257 destroyPQExpBuffer(query);
1261 * Find the OIDs of all tables matching the given list of patterns,
1262 * and append them to the given OID list.
1265 expand_table_name_patterns(Archive *fout,
1266 SimpleStringList *patterns, SimpleOidList *oids,
1271 SimpleStringListCell *cell;
1274 if (patterns->head == NULL)
1275 return; /* nothing to do */
1277 query = createPQExpBuffer();
1280 * this might sometimes result in duplicate entries in the OID list, but
1284 for (cell = patterns->head; cell; cell = cell->next)
1286 appendPQExpBuffer(query,
1288 "\nFROM pg_catalog.pg_class c"
1289 "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
1290 "\nWHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c')\n",
1291 RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1292 RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
1293 RELKIND_PARTITIONED_TABLE);
1294 processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1295 false, "n.nspname", "c.relname", NULL,
1296 "pg_catalog.pg_table_is_visible(c.oid)");
1298 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1299 if (strict_names && PQntuples(res) == 0)
1300 exit_horribly(NULL, "no matching tables were found for pattern \"%s\"\n", cell->val);
1302 for (i = 0; i < PQntuples(res); i++)
1304 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1308 resetPQExpBuffer(query);
1311 destroyPQExpBuffer(query);
1315 * checkExtensionMembership
1316 * Determine whether object is an extension member, and if so,
1317 * record an appropriate dependency and set the object's dump flag.
1319 * It's important to call this for each object that could be an extension
1320 * member. Generally, we integrate this with determining the object's
1321 * to-be-dumped-ness, since extension membership overrides other rules for that.
1323 * Returns true if object is an extension member, else false.
1326 checkExtensionMembership(DumpableObject *dobj, Archive *fout)
1328 ExtensionInfo *ext = findOwningExtension(dobj->catId);
1333 dobj->ext_member = true;
1335 /* Record dependency so that getDependencies needn't deal with that */
1336 addObjectDependency(dobj, ext->dobj.dumpId);
1339 * In 9.6 and above, mark the member object to have any non-initial ACL,
1340 * policies, and security labels dumped.
1342 * Note that any initial ACLs (see pg_init_privs) will be removed when we
1343 * extract the information about the object. We don't provide support for
1344 * initial policies and security labels and it seems unlikely for those to
1345 * ever exist, but we may have to revisit this later.
1347 * Prior to 9.6, we do not include any extension member components.
1349 * In binary upgrades, we still dump all components of the members
1350 * individually, since the idea is to exactly reproduce the database
1351 * contents rather than replace the extension contents with something
1354 if (fout->dopt->binary_upgrade)
1355 dobj->dump = ext->dobj.dump;
1358 if (fout->remoteVersion < 90600)
1359 dobj->dump = DUMP_COMPONENT_NONE;
1361 dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL |
1362 DUMP_COMPONENT_SECLABEL |
1363 DUMP_COMPONENT_POLICY);
1370 * selectDumpableNamespace: policy-setting subroutine
1371 * Mark a namespace as to be dumped or not
1374 selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
1377 * If specific tables are being dumped, do not dump any complete
1378 * namespaces. If specific namespaces are being dumped, dump just those
1379 * namespaces. Otherwise, dump all non-system namespaces.
1381 if (table_include_oids.head != NULL)
1382 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1383 else if (schema_include_oids.head != NULL)
1384 nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
1385 simple_oid_list_member(&schema_include_oids,
1386 nsinfo->dobj.catId.oid) ?
1387 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1388 else if (fout->remoteVersion >= 90600 &&
1389 strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
1392 * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
1393 * they are interesting (and not the original ACLs which were set at
1394 * initdb time, see pg_init_privs).
1396 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1398 else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1399 strcmp(nsinfo->dobj.name, "information_schema") == 0)
1401 /* Other system schemas don't get dumped */
1402 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1405 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
1408 * In any case, a namespace can be excluded by an exclusion switch
1410 if (nsinfo->dobj.dump_contains &&
1411 simple_oid_list_member(&schema_exclude_oids,
1412 nsinfo->dobj.catId.oid))
1413 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1416 * If the schema belongs to an extension, allow extension membership to
1417 * override the dump decision for the schema itself. However, this does
1418 * not change dump_contains, so this won't change what we do with objects
1419 * within the schema. (If they belong to the extension, they'll get
1420 * suppressed by it, otherwise not.)
1422 (void) checkExtensionMembership(&nsinfo->dobj, fout);
1426 * selectDumpableTable: policy-setting subroutine
1427 * Mark a table as to be dumped or not
1430 selectDumpableTable(TableInfo *tbinfo, Archive *fout)
1432 if (checkExtensionMembership(&tbinfo->dobj, fout))
1433 return; /* extension membership overrides all else */
1436 * If specific tables are being dumped, dump just those tables; else, dump
1437 * according to the parent namespace's dump flag.
1439 if (table_include_oids.head != NULL)
1440 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1441 tbinfo->dobj.catId.oid) ?
1442 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1444 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
1447 * In any case, a table can be excluded by an exclusion switch
1449 if (tbinfo->dobj.dump &&
1450 simple_oid_list_member(&table_exclude_oids,
1451 tbinfo->dobj.catId.oid))
1452 tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
1456 * selectDumpableType: policy-setting subroutine
1457 * Mark a type as to be dumped or not
1459 * If it's a table's rowtype or an autogenerated array type, we also apply a
1460 * special type code to facilitate sorting into the desired order. (We don't
1461 * want to consider those to be ordinary types because that would bring tables
1462 * up into the datatype part of the dump order.) We still set the object's
1463 * dump flag; that's not going to cause the dummy type to be dumped, but we
1464 * need it so that casts involving such types will be dumped correctly -- see
1465 * dumpCast. This means the flag should be set the same as for the underlying
1466 * object (the table or base type).
1469 selectDumpableType(TypeInfo *tyinfo, Archive *fout)
1471 /* skip complex types, except for standalone composite types */
1472 if (OidIsValid(tyinfo->typrelid) &&
1473 tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1475 TableInfo *tytable = findTableByOid(tyinfo->typrelid);
1477 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1478 if (tytable != NULL)
1479 tyinfo->dobj.dump = tytable->dobj.dump;
1481 tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
1485 /* skip auto-generated array types */
1486 if (tyinfo->isArray)
1488 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1491 * Fall through to set the dump flag; we assume that the subsequent
1492 * rules will do the same thing as they would for the array's base
1493 * type. (We cannot reliably look up the base type here, since
1494 * getTypes may not have processed it yet.)
1498 if (checkExtensionMembership(&tyinfo->dobj, fout))
1499 return; /* extension membership overrides all else */
1501 /* Dump based on if the contents of the namespace are being dumped */
1502 tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
1506 * selectDumpableDefaultACL: policy-setting subroutine
1507 * Mark a default ACL as to be dumped or not
1509 * For per-schema default ACLs, dump if the schema is to be dumped.
1510 * Otherwise dump if we are dumping "everything". Note that dataOnly
1511 * and aclsSkip are checked separately.
1514 selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
1516 /* Default ACLs can't be extension members */
1518 if (dinfo->dobj.namespace)
1519 /* default ACLs are considered part of the namespace */
1520 dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
1522 dinfo->dobj.dump = dopt->include_everything ?
1523 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1527 * selectDumpableCast: policy-setting subroutine
1528 * Mark a cast as to be dumped or not
1530 * Casts do not belong to any particular namespace (since they haven't got
1531 * names), nor do they have identifiable owners. To distinguish user-defined
1532 * casts from built-in ones, we must resort to checking whether the cast's
1533 * OID is in the range reserved for initdb.
1536 selectDumpableCast(CastInfo *cast, Archive *fout)
1538 if (checkExtensionMembership(&cast->dobj, fout))
1539 return; /* extension membership overrides all else */
1542 * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
1543 * support ACLs currently.
1545 if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1546 cast->dobj.dump = DUMP_COMPONENT_NONE;
1548 cast->dobj.dump = fout->dopt->include_everything ?
1549 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1553 * selectDumpableProcLang: policy-setting subroutine
1554 * Mark a procedural language as to be dumped or not
1556 * Procedural languages do not belong to any particular namespace. To
1557 * identify built-in languages, we must resort to checking whether the
1558 * language's OID is in the range reserved for initdb.
1561 selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
1563 if (checkExtensionMembership(&plang->dobj, fout))
1564 return; /* extension membership overrides all else */
1567 * Only include procedural languages when we are dumping everything.
1569 * For from-initdb procedural languages, only include ACLs, as we do for
1570 * the pg_catalog namespace. We need this because procedural languages do
1571 * not live in any namespace.
1573 if (!fout->dopt->include_everything)
1574 plang->dobj.dump = DUMP_COMPONENT_NONE;
1577 if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1578 plang->dobj.dump = fout->remoteVersion < 90600 ?
1579 DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
1581 plang->dobj.dump = DUMP_COMPONENT_ALL;
1586 * selectDumpableAccessMethod: policy-setting subroutine
1587 * Mark an access method as to be dumped or not
1589 * Access methods do not belong to any particular namespace. To identify
1590 * built-in access methods, we must resort to checking whether the
1591 * method's OID is in the range reserved for initdb.
1594 selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
1596 if (checkExtensionMembership(&method->dobj, fout))
1597 return; /* extension membership overrides all else */
1600 * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
1601 * they do not support ACLs currently.
1603 if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1604 method->dobj.dump = DUMP_COMPONENT_NONE;
1606 method->dobj.dump = fout->dopt->include_everything ?
1607 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1611 * selectDumpableExtension: policy-setting subroutine
1612 * Mark an extension as to be dumped or not
1614 * Normally, we dump all extensions, or none of them if include_everything
1615 * is false (i.e., a --schema or --table switch was given). However, in
1616 * binary-upgrade mode it's necessary to skip built-in extensions, since we
1617 * assume those will already be installed in the target database. We identify
1618 * such extensions by their having OIDs in the range reserved for initdb.
1621 selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
1624 * Use DUMP_COMPONENT_ACL for from-initdb extensions, to allow users to
1625 * change permissions on those objects, if they wish to, and have those
1626 * changes preserved.
1628 if (dopt->binary_upgrade && extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1629 extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
1631 extinfo->dobj.dump = extinfo->dobj.dump_contains =
1632 dopt->include_everything ? DUMP_COMPONENT_ALL :
1633 DUMP_COMPONENT_NONE;
1637 * selectDumpablePublicationTable: policy-setting subroutine
1638 * Mark a publication table as to be dumped or not
1640 * Publication tables have schemas, but those are ignored in decision making,
1641 * because publications are only dumped when we are dumping everything.
1644 selectDumpablePublicationTable(DumpableObject *dobj, Archive *fout)
1646 if (checkExtensionMembership(dobj, fout))
1647 return; /* extension membership overrides all else */
1649 dobj->dump = fout->dopt->include_everything ?
1650 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1654 * selectDumpableObject: policy-setting subroutine
1655 * Mark a generic dumpable object as to be dumped or not
1657 * Use this only for object types without a special-case routine above.
1660 selectDumpableObject(DumpableObject *dobj, Archive *fout)
1662 if (checkExtensionMembership(dobj, fout))
1663 return; /* extension membership overrides all else */
1666 * Default policy is to dump if parent namespace is dumpable, or for
1667 * non-namespace-associated items, dump if we're dumping "everything".
1669 if (dobj->namespace)
1670 dobj->dump = dobj->namespace->dobj.dump_contains;
1672 dobj->dump = fout->dopt->include_everything ?
1673 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1677 * Dump a table's contents for loading using the COPY command
1678 * - this routine is called by the Archiver when it wants the table
1683 dumpTableData_copy(Archive *fout, void *dcontext)
1685 TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1686 TableInfo *tbinfo = tdinfo->tdtable;
1687 const char *classname = tbinfo->dobj.name;
1688 const bool hasoids = tbinfo->hasoids;
1689 const bool oids = tdinfo->oids;
1690 PQExpBuffer q = createPQExpBuffer();
1693 * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
1694 * which uses it already.
1696 PQExpBuffer clistBuf = createPQExpBuffer();
1697 PGconn *conn = GetConnection(fout);
1701 const char *column_list;
1704 write_msg(NULL, "dumping contents of table \"%s.%s\"\n",
1705 tbinfo->dobj.namespace->dobj.name, classname);
1708 * Make sure we are in proper schema. We will qualify the table name
1709 * below anyway (in case its name conflicts with a pg_catalog table); but
1710 * this ensures reproducible results in case the table contains regproc,
1711 * regclass, etc columns.
1713 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
1716 * Specify the column list explicitly so that we have no possibility of
1717 * retrieving data in the wrong column order. (The default column
1718 * ordering of COPY will not be what we want in certain corner cases
1719 * involving ADD COLUMN and inheritance.)
1721 column_list = fmtCopyColumnList(tbinfo, clistBuf);
1723 if (oids && hasoids)
1725 appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
1726 fmtQualifiedId(fout->remoteVersion,
1727 tbinfo->dobj.namespace->dobj.name,
1731 else if (tdinfo->filtercond)
1733 /* Note: this syntax is only supported in 8.2 and up */
1734 appendPQExpBufferStr(q, "COPY (SELECT ");
1735 /* klugery to get rid of parens in column list */
1736 if (strlen(column_list) > 2)
1738 appendPQExpBufferStr(q, column_list + 1);
1739 q->data[q->len - 1] = ' ';
1742 appendPQExpBufferStr(q, "* ");
1743 appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
1744 fmtQualifiedId(fout->remoteVersion,
1745 tbinfo->dobj.namespace->dobj.name,
1747 tdinfo->filtercond);
1751 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1752 fmtQualifiedId(fout->remoteVersion,
1753 tbinfo->dobj.namespace->dobj.name,
1757 res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
1759 destroyPQExpBuffer(clistBuf);
1763 ret = PQgetCopyData(conn, ©buf, 0);
1766 break; /* done or error */
1770 WriteData(fout, copybuf, ret);
1777 * There was considerable discussion in late July, 2000 regarding
1778 * slowing down pg_dump when backing up large tables. Users with both
1779 * slow & fast (multi-processor) machines experienced performance
1780 * degradation when doing a backup.
1782 * Initial attempts based on sleeping for a number of ms for each ms
1783 * of work were deemed too complex, then a simple 'sleep in each loop'
1784 * implementation was suggested. The latter failed because the loop
1785 * was too tight. Finally, the following was implemented:
1787 * If throttle is non-zero, then
1788 * See how long since the last sleep.
1789 * Work out how long to sleep (based on ratio).
1790 * If sleep is more than 100ms, then
1796 * where the throttle value was the number of ms to sleep per ms of
1797 * work. The calculation was done in each loop.
1799 * Most of the hard work is done in the backend, and this solution
1800 * still did not work particularly well: on slow machines, the ratio
1801 * was 50:1, and on medium paced machines, 1:1, and on fast
1802 * multi-processor machines, it had little or no effect, for reasons
1803 * that were unclear.
1805 * Further discussion ensued, and the proposal was dropped.
1807 * For those people who want this feature, it can be implemented using
1808 * gettimeofday in each loop, calculating the time since last sleep,
1809 * multiplying that by the sleep ratio, then if the result is more
1810 * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1811 * function to sleep for a subsecond period ie.
1813 * select(0, NULL, NULL, NULL, &tvi);
1815 * This will return after the interval specified in the structure tvi.
1816 * Finally, call gettimeofday again to save the 'last sleep time'.
1820 archprintf(fout, "\\.\n\n\n");
1824 /* copy data transfer failed */
1825 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
1826 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1827 write_msg(NULL, "The command was: %s\n", q->data);
1831 /* Check command status and return to normal libpq state */
1832 res = PQgetResult(conn);
1833 if (PQresultStatus(res) != PGRES_COMMAND_OK)
1835 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetResult() failed.\n", classname);
1836 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1837 write_msg(NULL, "The command was: %s\n", q->data);
1842 /* Do this to ensure we've pumped libpq back to idle state */
1843 if (PQgetResult(conn) != NULL)
1844 write_msg(NULL, "WARNING: unexpected extra results during COPY of table \"%s\"\n",
1847 destroyPQExpBuffer(q);
1852 * Dump table data using INSERT commands.
1854 * Caution: when we restore from an archive file direct to database, the
1855 * INSERT commands emitted by this function have to be parsed by
1856 * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
1857 * E'' strings, or dollar-quoted strings. So don't emit anything like that.
1860 dumpTableData_insert(Archive *fout, void *dcontext)
1862 TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1863 TableInfo *tbinfo = tdinfo->tdtable;
1864 const char *classname = tbinfo->dobj.name;
1865 DumpOptions *dopt = fout->dopt;
1866 PQExpBuffer q = createPQExpBuffer();
1867 PQExpBuffer insertStmt = NULL;
1874 * Make sure we are in proper schema. We will qualify the table name
1875 * below anyway (in case its name conflicts with a pg_catalog table); but
1876 * this ensures reproducible results in case the table contains regproc,
1877 * regclass, etc columns.
1879 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
1881 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1882 "SELECT * FROM ONLY %s",
1883 fmtQualifiedId(fout->remoteVersion,
1884 tbinfo->dobj.namespace->dobj.name,
1886 if (tdinfo->filtercond)
1887 appendPQExpBuffer(q, " %s", tdinfo->filtercond);
1889 ExecuteSqlStatement(fout, q->data);
1893 res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
1895 nfields = PQnfields(res);
1896 for (tuple = 0; tuple < PQntuples(res); tuple++)
1899 * First time through, we build as much of the INSERT statement as
1900 * possible in "insertStmt", which we can then just print for each
1901 * line. If the table happens to have zero columns then this will
1902 * be a complete statement, otherwise it will end in "VALUES(" and
1903 * be ready to have the row's column values appended.
1905 if (insertStmt == NULL)
1907 insertStmt = createPQExpBuffer();
1910 * When load-via-partition-root is set, get the root table
1911 * name for the partition table, so that we can reload data
1912 * through the root table.
1914 if (dopt->load_via_partition_root && tbinfo->ispartition)
1916 TableInfo *parentTbinfo;
1918 parentTbinfo = getRootTableInfo(tbinfo);
1921 * When we loading data through the root, we will qualify
1922 * the table name. This is needed because earlier
1923 * search_path will be set for the partition table.
1925 classname = (char *) fmtQualifiedId(fout->remoteVersion,
1926 parentTbinfo->dobj.namespace->dobj.name,
1927 parentTbinfo->dobj.name);
1930 classname = fmtId(tbinfo->dobj.name);
1932 appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
1935 /* corner case for zero-column table */
1938 appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
1942 /* append the list of column names if required */
1943 if (dopt->column_inserts)
1945 appendPQExpBufferChar(insertStmt, '(');
1946 for (field = 0; field < nfields; field++)
1949 appendPQExpBufferStr(insertStmt, ", ");
1950 appendPQExpBufferStr(insertStmt,
1951 fmtId(PQfname(res, field)));
1953 appendPQExpBufferStr(insertStmt, ") ");
1956 if (tbinfo->needs_override)
1957 appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
1959 appendPQExpBufferStr(insertStmt, "VALUES (");
1963 archputs(insertStmt->data, fout);
1965 /* if it is zero-column table then we're done */
1969 for (field = 0; field < nfields; field++)
1972 archputs(", ", fout);
1973 if (PQgetisnull(res, tuple, field))
1975 archputs("NULL", fout);
1979 /* XXX This code is partially duplicated in ruleutils.c */
1980 switch (PQftype(res, field))
1991 * These types are printed without quotes unless
1992 * they contain values that aren't accepted by the
1993 * scanner unquoted (e.g., 'NaN'). Note that
1994 * strtod() and friends might accept NaN, so we
1995 * can't use that to test.
1997 * In reality we only need to defend against
1998 * infinity and NaN, so we need not get too crazy
1999 * about pattern matching here.
2001 const char *s = PQgetvalue(res, tuple, field);
2003 if (strspn(s, "0123456789 +-eE.") == strlen(s))
2006 archprintf(fout, "'%s'", s);
2012 archprintf(fout, "B'%s'",
2013 PQgetvalue(res, tuple, field));
2017 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
2018 archputs("true", fout);
2020 archputs("false", fout);
2024 /* All other types are printed as string literals. */
2025 resetPQExpBuffer(q);
2026 appendStringLiteralAH(q,
2027 PQgetvalue(res, tuple, field),
2029 archputs(q->data, fout);
2033 archputs(");\n", fout);
2036 if (PQntuples(res) <= 0)
2044 archputs("\n\n", fout);
2046 ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
2048 destroyPQExpBuffer(q);
2049 if (insertStmt != NULL)
2050 destroyPQExpBuffer(insertStmt);
2057 * get the root TableInfo for the given partition table.
2060 getRootTableInfo(TableInfo *tbinfo)
2062 TableInfo *parentTbinfo;
2064 Assert(tbinfo->ispartition);
2065 Assert(tbinfo->numParents == 1);
2067 parentTbinfo = tbinfo->parents[0];
2068 while (parentTbinfo->ispartition)
2070 Assert(parentTbinfo->numParents == 1);
2071 parentTbinfo = parentTbinfo->parents[0];
2074 return parentTbinfo;
2079 * dump the contents of a single table
2081 * Actually, this just makes an ArchiveEntry for the table contents.
2084 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
2086 DumpOptions *dopt = fout->dopt;
2087 TableInfo *tbinfo = tdinfo->tdtable;
2088 PQExpBuffer copyBuf = createPQExpBuffer();
2089 PQExpBuffer clistBuf = createPQExpBuffer();
2090 DataDumperPtr dumpFn;
2092 const char *copyFrom;
2094 if (!dopt->dump_inserts)
2096 /* Dump/restore using COPY */
2097 dumpFn = dumpTableData_copy;
2100 * When load-via-partition-root is set, get the root table name for
2101 * the partition table, so that we can reload data through the root
2104 if (dopt->load_via_partition_root && tbinfo->ispartition)
2106 TableInfo *parentTbinfo;
2108 parentTbinfo = getRootTableInfo(tbinfo);
2111 * When we load data through the root, we will qualify the table
2112 * name, because search_path is set for the partition.
2114 copyFrom = fmtQualifiedId(fout->remoteVersion,
2115 parentTbinfo->dobj.namespace->dobj.name,
2116 parentTbinfo->dobj.name);
2119 copyFrom = fmtId(tbinfo->dobj.name);
2121 /* must use 2 steps here 'cause fmtId is nonreentrant */
2122 appendPQExpBuffer(copyBuf, "COPY %s ",
2124 appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
2125 fmtCopyColumnList(tbinfo, clistBuf),
2126 (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
2127 copyStmt = copyBuf->data;
2131 /* Restore using INSERT */
2132 dumpFn = dumpTableData_insert;
2137 * Note: although the TableDataInfo is a full DumpableObject, we treat its
2138 * dependency on its table as "special" and pass it to ArchiveEntry now.
2139 * See comments for BuildArchiveDependencies.
2141 if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2142 ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
2143 tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
2144 NULL, tbinfo->rolname,
2145 false, "TABLE DATA", SECTION_DATA,
2147 &(tbinfo->dobj.dumpId), 1,
2150 destroyPQExpBuffer(copyBuf);
2151 destroyPQExpBuffer(clistBuf);
2155 * refreshMatViewData -
2156 * load or refresh the contents of a single materialized view
2158 * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
2162 refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
2164 TableInfo *tbinfo = tdinfo->tdtable;
2167 /* If the materialized view is not flagged as populated, skip this. */
2168 if (!tbinfo->relispopulated)
2171 q = createPQExpBuffer();
2173 appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
2174 fmtId(tbinfo->dobj.name));
2176 if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2178 tdinfo->dobj.catId, /* catalog ID */
2179 tdinfo->dobj.dumpId, /* dump ID */
2180 tbinfo->dobj.name, /* Name */
2181 tbinfo->dobj.namespace->dobj.name, /* Namespace */
2182 NULL, /* Tablespace */
2183 tbinfo->rolname, /* Owner */
2184 false, /* with oids */
2185 "MATERIALIZED VIEW DATA", /* Desc */
2186 SECTION_POST_DATA, /* Section */
2187 q->data, /* Create */
2190 tdinfo->dobj.dependencies, /* Deps */
2191 tdinfo->dobj.nDeps, /* # Deps */
2193 NULL); /* Dumper Arg */
2195 destroyPQExpBuffer(q);
2200 * set up dumpable objects representing the contents of tables
2203 getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, bool oids, char relkind)
2207 for (i = 0; i < numTables; i++)
2209 if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
2210 (!relkind || tblinfo[i].relkind == relkind))
2211 makeTableDataInfo(dopt, &(tblinfo[i]), oids);
2216 * Make a dumpable object for the data of this specific table
2218 * Note: we make a TableDataInfo if and only if we are going to dump the
2219 * table data; the "dump" flag in such objects isn't used.
2222 makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo, bool oids)
2224 TableDataInfo *tdinfo;
2227 * Nothing to do if we already decided to dump the table. This will
2228 * happen for "config" tables.
2230 if (tbinfo->dataObj != NULL)
2233 /* Skip VIEWs (no data to dump) */
2234 if (tbinfo->relkind == RELKIND_VIEW)
2236 /* Skip FOREIGN TABLEs (no data to dump) */
2237 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2239 /* Skip partitioned tables (data in partitions) */
2240 if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
2243 /* Don't dump data in unlogged tables, if so requested */
2244 if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
2245 dopt->no_unlogged_table_data)
2248 /* Check that the data is not explicitly excluded */
2249 if (simple_oid_list_member(&tabledata_exclude_oids,
2250 tbinfo->dobj.catId.oid))
2253 /* OK, let's dump it */
2254 tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
2256 if (tbinfo->relkind == RELKIND_MATVIEW)
2257 tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
2258 else if (tbinfo->relkind == RELKIND_SEQUENCE)
2259 tdinfo->dobj.objType = DO_SEQUENCE_SET;
2261 tdinfo->dobj.objType = DO_TABLE_DATA;
2264 * Note: use tableoid 0 so that this object won't be mistaken for
2265 * something that pg_depend entries apply to.
2267 tdinfo->dobj.catId.tableoid = 0;
2268 tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
2269 AssignDumpId(&tdinfo->dobj);
2270 tdinfo->dobj.name = tbinfo->dobj.name;
2271 tdinfo->dobj.namespace = tbinfo->dobj.namespace;
2272 tdinfo->tdtable = tbinfo;
2273 tdinfo->oids = oids;
2274 tdinfo->filtercond = NULL; /* might get set later */
2275 addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
2277 tbinfo->dataObj = tdinfo;
2281 * The refresh for a materialized view must be dependent on the refresh for
2282 * any materialized view that this one is dependent on.
2284 * This must be called after all the objects are created, but before they are
2288 buildMatViewRefreshDependencies(Archive *fout)
2298 /* No Mat Views before 9.3. */
2299 if (fout->remoteVersion < 90300)
2302 /* Make sure we are in proper schema */
2303 selectSourceSchema(fout, "pg_catalog");
2305 query = createPQExpBuffer();
2307 appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
2309 "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
2310 "FROM pg_depend d1 "
2311 "JOIN pg_class c1 ON c1.oid = d1.objid "
2312 "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
2313 " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
2314 "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
2315 "AND d2.objid = r1.oid "
2316 "AND d2.refobjid <> d1.objid "
2317 "JOIN pg_class c2 ON c2.oid = d2.refobjid "
2318 "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2319 CppAsString2(RELKIND_VIEW) ") "
2320 "WHERE d1.classid = 'pg_class'::regclass "
2322 "SELECT w.objid, d3.refobjid, c3.relkind "
2324 "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
2325 "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
2326 "AND d3.objid = r3.oid "
2327 "AND d3.refobjid <> w.refobjid "
2328 "JOIN pg_class c3 ON c3.oid = d3.refobjid "
2329 "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2330 CppAsString2(RELKIND_VIEW) ") "
2332 "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
2334 "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
2336 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2338 ntups = PQntuples(res);
2340 i_classid = PQfnumber(res, "classid");
2341 i_objid = PQfnumber(res, "objid");
2342 i_refobjid = PQfnumber(res, "refobjid");
2344 for (i = 0; i < ntups; i++)
2348 DumpableObject *dobj;
2349 DumpableObject *refdobj;
2351 TableInfo *reftbinfo;
2353 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
2354 objId.oid = atooid(PQgetvalue(res, i, i_objid));
2355 refobjId.tableoid = objId.tableoid;
2356 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
2358 dobj = findObjectByCatalogId(objId);
2362 Assert(dobj->objType == DO_TABLE);
2363 tbinfo = (TableInfo *) dobj;
2364 Assert(tbinfo->relkind == RELKIND_MATVIEW);
2365 dobj = (DumpableObject *) tbinfo->dataObj;
2368 Assert(dobj->objType == DO_REFRESH_MATVIEW);
2370 refdobj = findObjectByCatalogId(refobjId);
2371 if (refdobj == NULL)
2374 Assert(refdobj->objType == DO_TABLE);
2375 reftbinfo = (TableInfo *) refdobj;
2376 Assert(reftbinfo->relkind == RELKIND_MATVIEW);
2377 refdobj = (DumpableObject *) reftbinfo->dataObj;
2378 if (refdobj == NULL)
2380 Assert(refdobj->objType == DO_REFRESH_MATVIEW);
2382 addObjectDependency(dobj, refdobj->dumpId);
2384 if (!reftbinfo->relispopulated)
2385 tbinfo->relispopulated = false;
2390 destroyPQExpBuffer(query);
2394 * getTableDataFKConstraints -
2395 * add dump-order dependencies reflecting foreign key constraints
2397 * This code is executed only in a data-only dump --- in schema+data dumps
2398 * we handle foreign key issues by not creating the FK constraints until
2399 * after the data is loaded. In a data-only dump, however, we want to
2400 * order the table data objects in such a way that a table's referenced
2401 * tables are restored first. (In the presence of circular references or
2402 * self-references this may be impossible; we'll detect and complain about
2403 * that during the dependency sorting step.)
2406 getTableDataFKConstraints(void)
2408 DumpableObject **dobjs;
2412 /* Search through all the dumpable objects for FK constraints */
2413 getDumpableObjects(&dobjs, &numObjs);
2414 for (i = 0; i < numObjs; i++)
2416 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
2418 ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
2421 /* Not interesting unless both tables are to be dumped */
2422 if (cinfo->contable == NULL ||
2423 cinfo->contable->dataObj == NULL)
2425 ftable = findTableByOid(cinfo->confrelid);
2426 if (ftable == NULL ||
2427 ftable->dataObj == NULL)
2431 * Okay, make referencing table's TABLE_DATA object depend on the
2432 * referenced table's TABLE_DATA object.
2434 addObjectDependency(&cinfo->contable->dataObj->dobj,
2435 ftable->dataObj->dobj.dumpId);
2443 * guessConstraintInheritance:
2444 * In pre-8.4 databases, we can't tell for certain which constraints
2445 * are inherited. We assume a CHECK constraint is inherited if its name
2446 * matches the name of any constraint in the parent. Originally this code
2447 * tried to compare the expression texts, but that can fail for various
2448 * reasons --- for example, if the parent and child tables are in different
2449 * schemas, reverse-listing of function calls may produce different text
2450 * (schema-qualified or not) depending on search path.
2452 * In 8.4 and up we can rely on the conislocal field to decide which
2453 * constraints must be dumped; much safer.
2455 * This function assumes all conislocal flags were initialized to TRUE.
2456 * It clears the flag on anything that seems to be inherited.
2459 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
2465 for (i = 0; i < numTables; i++)
2467 TableInfo *tbinfo = &(tblinfo[i]);
2469 TableInfo **parents;
2472 /* Sequences and views never have parents */
2473 if (tbinfo->relkind == RELKIND_SEQUENCE ||
2474 tbinfo->relkind == RELKIND_VIEW)
2477 /* Don't bother computing anything for non-target tables, either */
2478 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
2481 numParents = tbinfo->numParents;
2482 parents = tbinfo->parents;
2484 if (numParents == 0)
2485 continue; /* nothing to see here, move along */
2487 /* scan for inherited CHECK constraints */
2488 for (j = 0; j < tbinfo->ncheck; j++)
2490 ConstraintInfo *constr;
2492 constr = &(tbinfo->checkexprs[j]);
2494 for (k = 0; k < numParents; k++)
2498 parent = parents[k];
2499 for (l = 0; l < parent->ncheck; l++)
2501 ConstraintInfo *pconstr = &(parent->checkexprs[l]);
2503 if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
2505 constr->conislocal = false;
2509 if (!constr->conislocal)
2519 * dump the database definition
2522 dumpDatabase(Archive *fout)
2524 DumpOptions *dopt = fout->dopt;
2525 PQExpBuffer dbQry = createPQExpBuffer();
2526 PQExpBuffer delQry = createPQExpBuffer();
2527 PQExpBuffer creaQry = createPQExpBuffer();
2528 PGconn *conn = GetConnection(fout);
2541 const char *datname,
2550 datname = PQdb(conn);
2553 write_msg(NULL, "saving database definition\n");
2555 /* Make sure we are in proper schema */
2556 selectSourceSchema(fout, "pg_catalog");
2558 /* Get the database owner and parameters from pg_database */
2559 if (fout->remoteVersion >= 90300)
2561 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2562 "(%s datdba) AS dba, "
2563 "pg_encoding_to_char(encoding) AS encoding, "
2564 "datcollate, datctype, datfrozenxid, datminmxid, "
2565 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2566 "shobj_description(oid, 'pg_database') AS description "
2571 appendStringLiteralAH(dbQry, datname, fout);
2573 else if (fout->remoteVersion >= 80400)
2575 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2576 "(%s datdba) AS dba, "
2577 "pg_encoding_to_char(encoding) AS encoding, "
2578 "datcollate, datctype, datfrozenxid, 0 AS datminmxid, "
2579 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2580 "shobj_description(oid, 'pg_database') AS description "
2585 appendStringLiteralAH(dbQry, datname, fout);
2587 else if (fout->remoteVersion >= 80200)
2589 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2590 "(%s datdba) AS dba, "
2591 "pg_encoding_to_char(encoding) AS encoding, "
2592 "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2593 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2594 "shobj_description(oid, 'pg_database') AS description "
2599 appendStringLiteralAH(dbQry, datname, fout);
2603 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2604 "(%s datdba) AS dba, "
2605 "pg_encoding_to_char(encoding) AS encoding, "
2606 "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2607 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
2611 appendStringLiteralAH(dbQry, datname, fout);
2614 res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
2616 i_tableoid = PQfnumber(res, "tableoid");
2617 i_oid = PQfnumber(res, "oid");
2618 i_dba = PQfnumber(res, "dba");
2619 i_encoding = PQfnumber(res, "encoding");
2620 i_collate = PQfnumber(res, "datcollate");
2621 i_ctype = PQfnumber(res, "datctype");
2622 i_frozenxid = PQfnumber(res, "datfrozenxid");
2623 i_minmxid = PQfnumber(res, "datminmxid");
2624 i_tablespace = PQfnumber(res, "tablespace");
2626 dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
2627 dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
2628 dba = PQgetvalue(res, 0, i_dba);
2629 encoding = PQgetvalue(res, 0, i_encoding);
2630 collate = PQgetvalue(res, 0, i_collate);
2631 ctype = PQgetvalue(res, 0, i_ctype);
2632 frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
2633 minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
2634 tablespace = PQgetvalue(res, 0, i_tablespace);
2636 appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
2638 if (strlen(encoding) > 0)
2640 appendPQExpBufferStr(creaQry, " ENCODING = ");
2641 appendStringLiteralAH(creaQry, encoding, fout);
2643 if (strlen(collate) > 0)
2645 appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
2646 appendStringLiteralAH(creaQry, collate, fout);
2648 if (strlen(ctype) > 0)
2650 appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
2651 appendStringLiteralAH(creaQry, ctype, fout);
2653 if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
2654 !dopt->outputNoTablespaces)
2655 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
2657 appendPQExpBufferStr(creaQry, ";\n");
2659 if (dopt->binary_upgrade)
2661 appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
2662 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
2663 "SET datfrozenxid = '%u', datminmxid = '%u'\n"
2665 frozenxid, minmxid);
2666 appendStringLiteralAH(creaQry, datname, fout);
2667 appendPQExpBufferStr(creaQry, ";\n");
2671 appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
2674 dbDumpId = createDumpId();
2677 dbCatId, /* catalog ID */
2678 dbDumpId, /* dump ID */
2680 NULL, /* Namespace */
2681 NULL, /* Tablespace */
2683 false, /* with oids */
2684 "DATABASE", /* Desc */
2685 SECTION_PRE_DATA, /* Section */
2686 creaQry->data, /* Create */
2687 delQry->data, /* Del */
2692 NULL); /* Dumper Arg */
2695 * pg_largeobject and pg_largeobject_metadata come from the old system
2696 * intact, so set their relfrozenxids and relminmxids.
2698 if (dopt->binary_upgrade)
2701 PQExpBuffer loFrozenQry = createPQExpBuffer();
2702 PQExpBuffer loOutQry = createPQExpBuffer();
2709 if (fout->remoteVersion >= 90300)
2710 appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
2711 "FROM pg_catalog.pg_class\n"
2712 "WHERE oid = %u;\n",
2713 LargeObjectRelationId);
2715 appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
2716 "FROM pg_catalog.pg_class\n"
2717 "WHERE oid = %u;\n",
2718 LargeObjectRelationId);
2720 lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2722 i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2723 i_relminmxid = PQfnumber(lo_res, "relminmxid");
2725 appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
2726 appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2727 "SET relfrozenxid = '%u', relminmxid = '%u'\n"
2728 "WHERE oid = %u;\n",
2729 atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2730 atoi(PQgetvalue(lo_res, 0, i_relminmxid)),
2731 LargeObjectRelationId);
2732 ArchiveEntry(fout, nilCatalogId, createDumpId(),
2733 "pg_largeobject", NULL, NULL, "",
2734 false, "pg_largeobject", SECTION_PRE_DATA,
2735 loOutQry->data, "", NULL,
2742 * pg_largeobject_metadata
2744 if (fout->remoteVersion >= 90000)
2746 resetPQExpBuffer(loFrozenQry);
2747 resetPQExpBuffer(loOutQry);
2749 if (fout->remoteVersion >= 90300)
2750 appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
2751 "FROM pg_catalog.pg_class\n"
2752 "WHERE oid = %u;\n",
2753 LargeObjectMetadataRelationId);
2755 appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
2756 "FROM pg_catalog.pg_class\n"
2757 "WHERE oid = %u;\n",
2758 LargeObjectMetadataRelationId);
2760 lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2762 i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2763 i_relminmxid = PQfnumber(lo_res, "relminmxid");
2765 appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject_metadata relfrozenxid and relminmxid\n");
2766 appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2767 "SET relfrozenxid = '%u', relminmxid = '%u'\n"
2768 "WHERE oid = %u;\n",
2769 atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2770 atoi(PQgetvalue(lo_res, 0, i_relminmxid)),
2771 LargeObjectMetadataRelationId);
2772 ArchiveEntry(fout, nilCatalogId, createDumpId(),
2773 "pg_largeobject_metadata", NULL, NULL, "",
2774 false, "pg_largeobject_metadata", SECTION_PRE_DATA,
2775 loOutQry->data, "", NULL,
2782 destroyPQExpBuffer(loFrozenQry);
2783 destroyPQExpBuffer(loOutQry);
2786 /* Dump DB comment if any */
2787 if (fout->remoteVersion >= 80200)
2790 * 8.2 keeps comments on shared objects in a shared table, so we
2791 * cannot use the dumpComment used for other database objects.
2793 char *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
2795 if (comment && strlen(comment))
2797 resetPQExpBuffer(dbQry);
2800 * Generates warning when loaded into a differently-named
2803 appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
2804 appendStringLiteralAH(dbQry, comment, fout);
2805 appendPQExpBufferStr(dbQry, ";\n");
2807 ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
2808 dba, false, "COMMENT", SECTION_NONE,
2809 dbQry->data, "", NULL,
2810 &dbDumpId, 1, NULL, NULL);
2815 resetPQExpBuffer(dbQry);
2816 appendPQExpBuffer(dbQry, "DATABASE %s", fmtId(datname));
2817 dumpComment(fout, dbQry->data, NULL, "",
2818 dbCatId, 0, dbDumpId);
2821 /* Dump shared security label. */
2822 if (!dopt->no_security_labels && fout->remoteVersion >= 90200)
2825 PQExpBuffer seclabelQry;
2827 seclabelQry = createPQExpBuffer();
2829 buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
2830 shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
2831 resetPQExpBuffer(seclabelQry);
2832 emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
2833 if (strlen(seclabelQry->data))
2834 ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
2835 dba, false, "SECURITY LABEL", SECTION_NONE,
2836 seclabelQry->data, "", NULL,
2837 &dbDumpId, 1, NULL, NULL);
2838 destroyPQExpBuffer(seclabelQry);
2844 destroyPQExpBuffer(dbQry);
2845 destroyPQExpBuffer(delQry);
2846 destroyPQExpBuffer(creaQry);
2850 * dumpEncoding: put the correct encoding into the archive
2853 dumpEncoding(Archive *AH)
2855 const char *encname = pg_encoding_to_char(AH->encoding);
2856 PQExpBuffer qry = createPQExpBuffer();
2859 write_msg(NULL, "saving encoding = %s\n", encname);
2861 appendPQExpBufferStr(qry, "SET client_encoding = ");
2862 appendStringLiteralAH(qry, encname, AH);
2863 appendPQExpBufferStr(qry, ";\n");
2865 ArchiveEntry(AH, nilCatalogId, createDumpId(),
2866 "ENCODING", NULL, NULL, "",
2867 false, "ENCODING", SECTION_PRE_DATA,
2868 qry->data, "", NULL,
2872 destroyPQExpBuffer(qry);
2877 * dumpStdStrings: put the correct escape string behavior into the archive
2880 dumpStdStrings(Archive *AH)
2882 const char *stdstrings = AH->std_strings ? "on" : "off";
2883 PQExpBuffer qry = createPQExpBuffer();
2886 write_msg(NULL, "saving standard_conforming_strings = %s\n",
2889 appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
2892 ArchiveEntry(AH, nilCatalogId, createDumpId(),
2893 "STDSTRINGS", NULL, NULL, "",
2894 false, "STDSTRINGS", SECTION_PRE_DATA,
2895 qry->data, "", NULL,
2899 destroyPQExpBuffer(qry);
2905 * Collect schema-level data about large objects
2908 getBlobs(Archive *fout)
2910 DumpOptions *dopt = fout->dopt;
2911 PQExpBuffer blobQry = createPQExpBuffer();
2913 DumpableObject *bdata;
2924 /* Verbose message */
2926 write_msg(NULL, "reading large objects\n");
2928 /* Make sure we are in proper schema */
2929 selectSourceSchema(fout, "pg_catalog");
2931 /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
2932 if (fout->remoteVersion >= 90600)
2934 PQExpBuffer acl_subquery = createPQExpBuffer();
2935 PQExpBuffer racl_subquery = createPQExpBuffer();
2936 PQExpBuffer init_acl_subquery = createPQExpBuffer();
2937 PQExpBuffer init_racl_subquery = createPQExpBuffer();
2939 buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
2940 init_racl_subquery, "l.lomacl", "l.lomowner", "'L'",
2941 dopt->binary_upgrade);
2943 appendPQExpBuffer(blobQry,
2944 "SELECT l.oid, (%s l.lomowner) AS rolname, "
2947 "%s AS initlomacl, "
2948 "%s AS initrlomacl "
2949 "FROM pg_largeobject_metadata l "
2950 "LEFT JOIN pg_init_privs pip ON "
2951 "(l.oid = pip.objoid "
2952 "AND pip.classoid = 'pg_largeobject'::regclass "
2953 "AND pip.objsubid = 0) ",
2956 racl_subquery->data,
2957 init_acl_subquery->data,
2958 init_racl_subquery->data);
2960 destroyPQExpBuffer(acl_subquery);
2961 destroyPQExpBuffer(racl_subquery);
2962 destroyPQExpBuffer(init_acl_subquery);
2963 destroyPQExpBuffer(init_racl_subquery);
2965 else if (fout->remoteVersion >= 90000)
2966 appendPQExpBuffer(blobQry,
2967 "SELECT oid, (%s lomowner) AS rolname, lomacl, "
2968 "NULL AS rlomacl, NULL AS initlomacl, "
2969 "NULL AS initrlomacl "
2970 " FROM pg_largeobject_metadata",
2973 appendPQExpBufferStr(blobQry,
2974 "SELECT DISTINCT loid AS oid, "
2975 "NULL::name AS rolname, NULL::oid AS lomacl, "
2976 "NULL::oid AS rlomacl, NULL::oid AS initlomacl, "
2977 "NULL::oid AS initrlomacl "
2978 " FROM pg_largeobject");
2980 res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
2982 i_oid = PQfnumber(res, "oid");
2983 i_lomowner = PQfnumber(res, "rolname");
2984 i_lomacl = PQfnumber(res, "lomacl");
2985 i_rlomacl = PQfnumber(res, "rlomacl");
2986 i_initlomacl = PQfnumber(res, "initlomacl");
2987 i_initrlomacl = PQfnumber(res, "initrlomacl");
2989 ntups = PQntuples(res);
2992 * Each large object has its own BLOB archive entry.
2994 binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
2996 for (i = 0; i < ntups; i++)
2998 binfo[i].dobj.objType = DO_BLOB;
2999 binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
3000 binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3001 AssignDumpId(&binfo[i].dobj);
3003 binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oid));
3004 binfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_lomowner));
3005 binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, i_lomacl));
3006 binfo[i].rblobacl = pg_strdup(PQgetvalue(res, i, i_rlomacl));
3007 binfo[i].initblobacl = pg_strdup(PQgetvalue(res, i, i_initlomacl));
3008 binfo[i].initrblobacl = pg_strdup(PQgetvalue(res, i, i_initrlomacl));
3010 if (PQgetisnull(res, i, i_lomacl) &&
3011 PQgetisnull(res, i, i_rlomacl) &&
3012 PQgetisnull(res, i, i_initlomacl) &&
3013 PQgetisnull(res, i, i_initrlomacl))
3014 binfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
3017 * In binary-upgrade mode for blobs, we do *not* dump out the data or
3018 * the ACLs, should any exist. The data and ACL (if any) will be
3019 * copied by pg_upgrade, which simply copies the pg_largeobject and
3020 * pg_largeobject_metadata tables.
3022 * We *do* dump out the definition of the blob because we need that to
3023 * make the restoration of the comments, and anything else, work since
3024 * pg_upgrade copies the files behind pg_largeobject and
3025 * pg_largeobject_metadata after the dump is restored.
3027 if (dopt->binary_upgrade)
3028 binfo[i].dobj.dump &= ~(DUMP_COMPONENT_DATA | DUMP_COMPONENT_ACL);
3032 * If we have any large objects, a "BLOBS" archive entry is needed. This
3033 * is just a placeholder for sorting; it carries no data now.
3037 bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
3038 bdata->objType = DO_BLOB_DATA;
3039 bdata->catId = nilCatalogId;
3040 AssignDumpId(bdata);
3041 bdata->name = pg_strdup("BLOBS");
3045 destroyPQExpBuffer(blobQry);
3051 * dump the definition (metadata) of the given large object
3054 dumpBlob(Archive *fout, BlobInfo *binfo)
3056 PQExpBuffer cquery = createPQExpBuffer();
3057 PQExpBuffer dquery = createPQExpBuffer();
3059 appendPQExpBuffer(cquery,
3060 "SELECT pg_catalog.lo_create('%s');\n",
3063 appendPQExpBuffer(dquery,
3064 "SELECT pg_catalog.lo_unlink('%s');\n",
3067 if (binfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
3068 ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
3071 binfo->rolname, false,
3072 "BLOB", SECTION_PRE_DATA,
3073 cquery->data, dquery->data, NULL,
3077 /* set up tag for comment and/or ACL */
3078 resetPQExpBuffer(cquery);
3079 appendPQExpBuffer(cquery, "LARGE OBJECT %s", binfo->dobj.name);
3081 /* Dump comment if any */
3082 if (binfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3083 dumpComment(fout, cquery->data,
3084 NULL, binfo->rolname,
3085 binfo->dobj.catId, 0, binfo->dobj.dumpId);
3087 /* Dump security label if any */
3088 if (binfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3089 dumpSecLabel(fout, cquery->data,
3090 NULL, binfo->rolname,
3091 binfo->dobj.catId, 0, binfo->dobj.dumpId);
3093 /* Dump ACL if any */
3094 if (binfo->blobacl && (binfo->dobj.dump & DUMP_COMPONENT_ACL))
3095 dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
3096 binfo->dobj.name, NULL, cquery->data,
3097 NULL, binfo->rolname, binfo->blobacl, binfo->rblobacl,
3098 binfo->initblobacl, binfo->initrblobacl);
3100 destroyPQExpBuffer(cquery);
3101 destroyPQExpBuffer(dquery);
3106 * dump the data contents of all large objects
3109 dumpBlobs(Archive *fout, void *arg)
3111 const char *blobQry;
3112 const char *blobFetchQry;
3113 PGconn *conn = GetConnection(fout);
3115 char buf[LOBBUFSIZE];
3121 write_msg(NULL, "saving large objects\n");
3123 /* Make sure we are in proper schema */
3124 selectSourceSchema(fout, "pg_catalog");
3127 * Currently, we re-fetch all BLOB OIDs using a cursor. Consider scanning
3128 * the already-in-memory dumpable objects instead...
3130 if (fout->remoteVersion >= 90000)
3131 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_largeobject_metadata";
3133 blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
3135 ExecuteSqlStatement(fout, blobQry);
3137 /* Command to fetch from cursor */
3138 blobFetchQry = "FETCH 1000 IN bloboid";
3143 res = ExecuteSqlQuery(fout, blobFetchQry, PGRES_TUPLES_OK);
3145 /* Process the tuples, if any */
3146 ntups = PQntuples(res);
3147 for (i = 0; i < ntups; i++)
3152 blobOid = atooid(PQgetvalue(res, i, 0));
3154 loFd = lo_open(conn, blobOid, INV_READ);
3156 exit_horribly(NULL, "could not open large object %u: %s",
3157 blobOid, PQerrorMessage(conn));
3159 StartBlob(fout, blobOid);
3161 /* Now read it in chunks, sending data to archive */
3164 cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
3166 exit_horribly(NULL, "error reading large object %u: %s",
3167 blobOid, PQerrorMessage(conn));
3169 WriteData(fout, buf, cnt);
3172 lo_close(conn, loFd);
3174 EndBlob(fout, blobOid);
3178 } while (ntups > 0);
3185 * get information about policies on a dumpable table.
3188 getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
3192 PolicyInfo *polinfo;
3197 int i_polpermissive;
3205 if (fout->remoteVersion < 90500)
3208 query = createPQExpBuffer();
3210 for (i = 0; i < numTables; i++)
3212 TableInfo *tbinfo = &tblinfo[i];
3214 /* Ignore row security on tables not to be dumped */
3215 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
3219 write_msg(NULL, "reading row security enabled for table \"%s.%s\"\n",
3220 tbinfo->dobj.namespace->dobj.name,
3224 * Get row security enabled information for the table. We represent
3225 * RLS enabled on a table by creating PolicyInfo object with an empty
3231 * Note: use tableoid 0 so that this object won't be mistaken for
3232 * something that pg_depend entries apply to.
3234 polinfo = pg_malloc(sizeof(PolicyInfo));
3235 polinfo->dobj.objType = DO_POLICY;
3236 polinfo->dobj.catId.tableoid = 0;
3237 polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
3238 AssignDumpId(&polinfo->dobj);
3239 polinfo->dobj.namespace = tbinfo->dobj.namespace;
3240 polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
3241 polinfo->poltable = tbinfo;
3242 polinfo->polname = NULL;
3243 polinfo->polcmd = '\0';
3244 polinfo->polpermissive = 0;
3245 polinfo->polroles = NULL;
3246 polinfo->polqual = NULL;
3247 polinfo->polwithcheck = NULL;
3251 write_msg(NULL, "reading policies for table \"%s.%s\"\n",
3252 tbinfo->dobj.namespace->dobj.name,
3256 * select table schema to ensure regproc name is qualified if needed
3258 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
3260 resetPQExpBuffer(query);
3262 /* Get the policies for the table. */
3263 if (fout->remoteVersion >= 100000)
3264 appendPQExpBuffer(query,
3265 "SELECT oid, tableoid, pol.polname, pol.polcmd, pol.polpermissive, "
3266 "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3267 " pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(rolname) from pg_catalog.pg_roles WHERE oid = ANY(pol.polroles)), ', ') END AS polroles, "
3268 "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3269 "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3270 "FROM pg_catalog.pg_policy pol "
3271 "WHERE polrelid = '%u'",
3272 tbinfo->dobj.catId.oid);
3274 appendPQExpBuffer(query,
3275 "SELECT oid, tableoid, pol.polname, pol.polcmd, 't' as polpermissive, "
3276 "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3277 " pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(rolname) from pg_catalog.pg_roles WHERE oid = ANY(pol.polroles)), ', ') END AS polroles, "
3278 "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3279 "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3280 "FROM pg_catalog.pg_policy pol "
3281 "WHERE polrelid = '%u'",
3282 tbinfo->dobj.catId.oid);
3283 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3285 ntups = PQntuples(res);
3290 * No explicit policies to handle (only the default-deny policy,
3291 * which is handled as part of the table definition). Clean up
3298 i_oid = PQfnumber(res, "oid");
3299 i_tableoid = PQfnumber(res, "tableoid");
3300 i_polname = PQfnumber(res, "polname");
3301 i_polcmd = PQfnumber(res, "polcmd");
3302 i_polpermissive = PQfnumber(res, "polpermissive");
3303 i_polroles = PQfnumber(res, "polroles");
3304 i_polqual = PQfnumber(res, "polqual");
3305 i_polwithcheck = PQfnumber(res, "polwithcheck");
3307 polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
3309 for (j = 0; j < ntups; j++)
3311 polinfo[j].dobj.objType = DO_POLICY;
3312 polinfo[j].dobj.catId.tableoid =
3313 atooid(PQgetvalue(res, j, i_tableoid));
3314 polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3315 AssignDumpId(&polinfo[j].dobj);
3316 polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3317 polinfo[j].poltable = tbinfo;
3318 polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
3319 polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
3321 polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
3322 polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
3324 if (PQgetisnull(res, j, i_polroles))
3325 polinfo[j].polroles = NULL;
3327 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
3329 if (PQgetisnull(res, j, i_polqual))
3330 polinfo[j].polqual = NULL;
3332 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
3334 if (PQgetisnull(res, j, i_polwithcheck))
3335 polinfo[j].polwithcheck = NULL;
3337 polinfo[j].polwithcheck
3338 = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
3342 destroyPQExpBuffer(query);
3347 * dump the definition of the given policy
3350 dumpPolicy(Archive *fout, PolicyInfo *polinfo)
3352 DumpOptions *dopt = fout->dopt;
3353 TableInfo *tbinfo = polinfo->poltable;
3363 * If polname is NULL, then this record is just indicating that ROW LEVEL
3364 * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
3365 * ROW LEVEL SECURITY.
3367 if (polinfo->polname == NULL)
3369 query = createPQExpBuffer();
3371 appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
3372 fmtId(polinfo->dobj.name));
3374 if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3375 ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3377 polinfo->dobj.namespace->dobj.name,
3379 tbinfo->rolname, false,
3380 "ROW SECURITY", SECTION_POST_DATA,
3381 query->data, "", NULL,
3385 destroyPQExpBuffer(query);
3389 if (polinfo->polcmd == '*')
3391 else if (polinfo->polcmd == 'r')
3392 cmd = " FOR SELECT";
3393 else if (polinfo->polcmd == 'a')
3394 cmd = " FOR INSERT";
3395 else if (polinfo->polcmd == 'w')
3396 cmd = " FOR UPDATE";
3397 else if (polinfo->polcmd == 'd')
3398 cmd = " FOR DELETE";
3401 write_msg(NULL, "unexpected policy command type: %c\n",
3406 query = createPQExpBuffer();
3407 delqry = createPQExpBuffer();
3409 appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
3411 appendPQExpBuffer(query, " ON %s%s%s", fmtId(tbinfo->dobj.name),
3412 !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
3414 if (polinfo->polroles != NULL)
3415 appendPQExpBuffer(query, " TO %s", polinfo->polroles);
3417 if (polinfo->polqual != NULL)
3418 appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
3420 if (polinfo->polwithcheck != NULL)
3421 appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
3423 appendPQExpBuffer(query, ";\n");
3425 appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
3426 appendPQExpBuffer(delqry, " ON %s;\n", fmtId(tbinfo->dobj.name));
3428 tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
3430 if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3431 ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3433 polinfo->dobj.namespace->dobj.name,
3435 tbinfo->rolname, false,
3436 "POLICY", SECTION_POST_DATA,
3437 query->data, delqry->data, NULL,
3442 destroyPQExpBuffer(query);
3443 destroyPQExpBuffer(delqry);
3448 * get information about publications
3451 getPublications(Archive *fout)
3453 DumpOptions *dopt = fout->dopt;
3456 PublicationInfo *pubinfo;
3468 if (dopt->no_publications || fout->remoteVersion < 100000)
3471 query = createPQExpBuffer();
3473 resetPQExpBuffer(query);
3475 /* Get the publications. */
3476 appendPQExpBuffer(query,
3477 "SELECT p.tableoid, p.oid, p.pubname, "
3478 "(%s p.pubowner) AS rolname, "
3479 "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete "
3480 "FROM pg_catalog.pg_publication p",
3483 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3485 ntups = PQntuples(res);
3487 i_tableoid = PQfnumber(res, "tableoid");
3488 i_oid = PQfnumber(res, "oid");
3489 i_pubname = PQfnumber(res, "pubname");
3490 i_rolname = PQfnumber(res, "rolname");
3491 i_puballtables = PQfnumber(res, "puballtables");
3492 i_pubinsert = PQfnumber(res, "pubinsert");
3493 i_pubupdate = PQfnumber(res, "pubupdate");
3494 i_pubdelete = PQfnumber(res, "pubdelete");
3496 pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
3498 for (i = 0; i < ntups; i++)
3500 pubinfo[i].dobj.objType = DO_PUBLICATION;
3501 pubinfo[i].dobj.catId.tableoid =
3502 atooid(PQgetvalue(res, i, i_tableoid));
3503 pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3504 AssignDumpId(&pubinfo[i].dobj);
3505 pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
3506 pubinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3507 pubinfo[i].puballtables =
3508 (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
3509 pubinfo[i].pubinsert =
3510 (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
3511 pubinfo[i].pubupdate =
3512 (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
3513 pubinfo[i].pubdelete =
3514 (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
3516 if (strlen(pubinfo[i].rolname) == 0)
3517 write_msg(NULL, "WARNING: owner of publication \"%s\" appears to be invalid\n",
3518 pubinfo[i].dobj.name);
3520 /* Decide whether we want to dump it */
3521 selectDumpableObject(&(pubinfo[i].dobj), fout);
3525 destroyPQExpBuffer(query);
3530 * dump the definition of the given publication
3533 dumpPublication(Archive *fout, PublicationInfo *pubinfo)
3540 if (!(pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3543 delq = createPQExpBuffer();
3544 query = createPQExpBuffer();
3545 labelq = createPQExpBuffer();
3547 appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
3548 fmtId(pubinfo->dobj.name));
3550 appendPQExpBuffer(query, "CREATE PUBLICATION %s",
3551 fmtId(pubinfo->dobj.name));
3553 appendPQExpBuffer(labelq, "PUBLICATION %s", fmtId(pubinfo->dobj.name));
3555 if (pubinfo->puballtables)
3556 appendPQExpBufferStr(query, " FOR ALL TABLES");
3558 appendPQExpBufferStr(query, " WITH (publish = '");
3559 if (pubinfo->pubinsert)
3561 appendPQExpBufferStr(query, "insert");
3565 if (pubinfo->pubupdate)
3568 appendPQExpBufferStr(query, ", ");
3570 appendPQExpBufferStr(query, "update");
3574 if (pubinfo->pubdelete)
3577 appendPQExpBufferStr(query, ", ");
3579 appendPQExpBufferStr(query, "delete");
3583 appendPQExpBufferStr(query, "');\n");
3585 ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
3589 pubinfo->rolname, false,
3590 "PUBLICATION", SECTION_POST_DATA,
3591 query->data, delq->data, NULL,
3595 if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3596 dumpComment(fout, labelq->data,
3597 NULL, pubinfo->rolname,
3598 pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
3600 if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3601 dumpSecLabel(fout, labelq->data,
3602 NULL, pubinfo->rolname,
3603 pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
3605 destroyPQExpBuffer(delq);
3606 destroyPQExpBuffer(query);
3610 * getPublicationTables
3611 * get information about publication membership for dumpable tables.
3614 getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
3618 PublicationRelInfo *pubrinfo;
3626 if (fout->remoteVersion < 100000)
3629 query = createPQExpBuffer();
3631 for (i = 0; i < numTables; i++)
3633 TableInfo *tbinfo = &tblinfo[i];
3635 /* Only plain tables can be aded to publications. */
3636 if (tbinfo->relkind != RELKIND_RELATION)
3640 * Ignore publication membership of tables whose definitions are not
3643 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3647 write_msg(NULL, "reading publication membership for table \"%s.%s\"\n",
3648 tbinfo->dobj.namespace->dobj.name,
3651 resetPQExpBuffer(query);
3653 /* Get the publication membership for the table. */
3654 appendPQExpBuffer(query,
3655 "SELECT pr.tableoid, pr.oid, p.pubname "
3656 "FROM pg_catalog.pg_publication_rel pr,"
3657 " pg_catalog.pg_publication p "
3658 "WHERE pr.prrelid = '%u'"
3659 " AND p.oid = pr.prpubid",
3660 tbinfo->dobj.catId.oid);
3661 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3663 ntups = PQntuples(res);
3668 * Table is not member of any publications. Clean up and return.
3674 i_tableoid = PQfnumber(res, "tableoid");
3675 i_oid = PQfnumber(res, "oid");
3676 i_pubname = PQfnumber(res, "pubname");
3678 pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
3680 for (j = 0; j < ntups; j++)
3682 pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
3683 pubrinfo[j].dobj.catId.tableoid =
3684 atooid(PQgetvalue(res, j, i_tableoid));
3685 pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3686 AssignDumpId(&pubrinfo[j].dobj);
3687 pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3688 pubrinfo[j].dobj.name = tbinfo->dobj.name;
3689 pubrinfo[j].pubname = pg_strdup(PQgetvalue(res, j, i_pubname));
3690 pubrinfo[j].pubtable = tbinfo;
3692 /* Decide whether we want to dump it */
3693 selectDumpablePublicationTable(&(pubrinfo[j].dobj), fout);
3697 destroyPQExpBuffer(query);
3701 * dumpPublicationTable
3702 * dump the definition of the given publication table mapping
3705 dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo)
3707 TableInfo *tbinfo = pubrinfo->pubtable;
3711 if (!(pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3714 tag = psprintf("%s %s", pubrinfo->pubname, tbinfo->dobj.name);
3716 query = createPQExpBuffer();
3718 appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
3719 fmtId(pubrinfo->pubname));
3720 appendPQExpBuffer(query, " %s;",
3721 fmtId(tbinfo->dobj.name));
3724 * There is no point in creating drop query as drop query as the drop is
3725 * done by table drop.
3727 ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
3729 tbinfo->dobj.namespace->dobj.name,
3732 "PUBLICATION TABLE", SECTION_POST_DATA,
3733 query->data, "", NULL,
3738 destroyPQExpBuffer(query);
3742 * Is the currently connected user a superuser?
3745 is_superuser(Archive *fout)
3747 ArchiveHandle *AH = (ArchiveHandle *) fout;
3750 val = PQparameterStatus(AH->connection, "is_superuser");
3752 if (val && strcmp(val, "on") == 0)
3760 * get information about subscriptions
3763 getSubscriptions(Archive *fout)
3765 DumpOptions *dopt = fout->dopt;
3768 SubscriptionInfo *subinfo;
3775 int i_subsynccommit;
3776 int i_subpublications;
3780 if (dopt->no_subscriptions || fout->remoteVersion < 100000)
3783 if (!is_superuser(fout))
3787 res = ExecuteSqlQuery(fout,
3788 "SELECT count(*) FROM pg_subscription "
3789 "WHERE subdbid = (SELECT oid FROM pg_catalog.pg_database"
3790 " WHERE datname = current_database())",
3792 n = atoi(PQgetvalue(res, 0, 0));
3794 write_msg(NULL, "WARNING: subscriptions not dumped because current user is not a superuser\n");
3799 query = createPQExpBuffer();
3801 resetPQExpBuffer(query);
3803 /* Get the subscriptions in current database. */
3804 appendPQExpBuffer(query,
3805 "SELECT s.tableoid, s.oid, s.subname,"
3806 "(%s s.subowner) AS rolname, "
3807 " s.subconninfo, s.subslotname, s.subsynccommit, "
3808 " s.subpublications "
3809 "FROM pg_catalog.pg_subscription s "
3810 "WHERE s.subdbid = (SELECT oid FROM pg_catalog.pg_database"
3811 " WHERE datname = current_database())",
3813 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3815 ntups = PQntuples(res);
3817 i_tableoid = PQfnumber(res, "tableoid");
3818 i_oid = PQfnumber(res, "oid");
3819 i_subname = PQfnumber(res, "subname");
3820 i_rolname = PQfnumber(res, "rolname");
3821 i_subconninfo = PQfnumber(res, "subconninfo");
3822 i_subslotname = PQfnumber(res, "subslotname");
3823 i_subsynccommit = PQfnumber(res, "subsynccommit");
3824 i_subpublications = PQfnumber(res, "subpublications");
3826 subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
3828 for (i = 0; i < ntups; i++)
3830 subinfo[i].dobj.objType = DO_SUBSCRIPTION;
3831 subinfo[i].dobj.catId.tableoid =
3832 atooid(PQgetvalue(res, i, i_tableoid));
3833 subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3834 AssignDumpId(&subinfo[i].dobj);
3835 subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
3836 subinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3837 subinfo[i].subconninfo = pg_strdup(PQgetvalue(res, i, i_subconninfo));
3838 if (PQgetisnull(res, i, i_subslotname))
3839 subinfo[i].subslotname = NULL;
3841 subinfo[i].subslotname = pg_strdup(PQgetvalue(res, i, i_subslotname));
3842 subinfo[i].subsynccommit =
3843 pg_strdup(PQgetvalue(res, i, i_subsynccommit));
3844 subinfo[i].subpublications =
3845 pg_strdup(PQgetvalue(res, i, i_subpublications));
3847 if (strlen(subinfo[i].rolname) == 0)
3848 write_msg(NULL, "WARNING: owner of subscription \"%s\" appears to be invalid\n",
3849 subinfo[i].dobj.name);
3851 /* Decide whether we want to dump it */
3852 selectDumpableObject(&(subinfo[i].dobj), fout);
3856 destroyPQExpBuffer(query);
3861 * dump the definition of the given subscription
3864 dumpSubscription(Archive *fout, SubscriptionInfo *subinfo)
3869 PQExpBuffer publications;
3870 char **pubnames = NULL;
3874 if (!(subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3877 delq = createPQExpBuffer();
3878 query = createPQExpBuffer();
3879 labelq = createPQExpBuffer();
3881 appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
3882 fmtId(subinfo->dobj.name));
3884 appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
3885 fmtId(subinfo->dobj.name));
3886 appendStringLiteralAH(query, subinfo->subconninfo, fout);
3888 /* Build list of quoted publications and append them to query. */
3889 if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
3892 "WARNING: could not parse subpublications array\n");
3899 publications = createPQExpBuffer();
3900 for (i = 0; i < npubnames; i++)
3903 appendPQExpBufferStr(publications, ", ");
3905 appendPQExpBufferStr(publications, fmtId(pubnames[i]));
3908 appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
3909 if (subinfo->subslotname)
3910 appendStringLiteralAH(query, subinfo->subslotname, fout);
3912 appendPQExpBufferStr(query, "NONE");
3914 if (strcmp(subinfo->subsynccommit, "off") != 0)
3915 appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
3917 appendPQExpBufferStr(query, ");\n");
3919 appendPQExpBuffer(labelq, "SUBSCRIPTION %s", fmtId(subinfo->dobj.name));
3921 ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
3925 subinfo->rolname, false,
3926 "SUBSCRIPTION", SECTION_POST_DATA,
3927 query->data, delq->data, NULL,
3931 if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3932 dumpComment(fout, labelq->data,
3933 NULL, subinfo->rolname,
3934 subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
3936 if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3937 dumpSecLabel(fout, labelq->data,
3938 NULL, subinfo->rolname,
3939 subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
3941 destroyPQExpBuffer(publications);
3945 destroyPQExpBuffer(delq);
3946 destroyPQExpBuffer(query);
3950 binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
3951 PQExpBuffer upgrade_buffer,
3954 PQExpBuffer upgrade_query = createPQExpBuffer();
3955 PGresult *upgrade_res;
3956 Oid pg_type_array_oid;
3958 appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
3959 appendPQExpBuffer(upgrade_buffer,
3960 "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
3963 /* we only support old >= 8.3 for binary upgrades */
3964 appendPQExpBuffer(upgrade_query,
3966 "FROM pg_catalog.pg_type "
3967 "WHERE pg_type.oid = '%u'::pg_catalog.oid;",
3970 upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
3972 pg_type_array_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "typarray")));
3974 if (OidIsValid(pg_type_array_oid))
3976 appendPQExpBufferStr(upgrade_buffer,
3977 "\n-- For binary upgrade, must preserve pg_type array oid\n");
3978 appendPQExpBuffer(upgrade_buffer,
3979 "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
3983 PQclear(upgrade_res);
3984 destroyPQExpBuffer(upgrade_query);
3988 binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
3989 PQExpBuffer upgrade_buffer,
3992 PQExpBuffer upgrade_query = createPQExpBuffer();
3993 PGresult *upgrade_res;
3995 bool toast_set = false;
3997 /* we only support old >= 8.3 for binary upgrades */
3998 appendPQExpBuffer(upgrade_query,
3999 "SELECT c.reltype AS crel, t.reltype AS trel "
4000 "FROM pg_catalog.pg_class c "
4001 "LEFT JOIN pg_catalog.pg_class t ON "
4002 " (c.reltoastrelid = t.oid) "
4003 "WHERE c.oid = '%u'::pg_catalog.oid;",
4006 upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4008 pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
4010 binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
4013 if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
4015 /* Toast tables do not have pg_type array rows */
4016 Oid pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
4017 PQfnumber(upgrade_res, "trel")));
4019 appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
4020 appendPQExpBuffer(upgrade_buffer,
4021 "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4027 PQclear(upgrade_res);
4028 destroyPQExpBuffer(upgrade_query);
4034 binary_upgrade_set_pg_class_oids(Archive *fout,
4035 PQExpBuffer upgrade_buffer, Oid pg_class_oid,
4038 PQExpBuffer upgrade_query = createPQExpBuffer();
4039 PGresult *upgrade_res;
4040 Oid pg_class_reltoastrelid;
4041 Oid pg_index_indexrelid;
4043 appendPQExpBuffer(upgrade_query,
4044 "SELECT c.reltoastrelid, i.indexrelid "
4045 "FROM pg_catalog.pg_class c LEFT JOIN "
4046 "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
4047 "WHERE c.oid = '%u'::pg_catalog.oid;",
4050 upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4052 pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
4053 pg_index_indexrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "indexrelid")));
4055 appendPQExpBufferStr(upgrade_buffer,
4056 "\n-- For binary upgrade, must preserve pg_class oids\n");
4060 appendPQExpBuffer(upgrade_buffer,
4061 "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
4063 /* only tables have toast tables, not indexes */
4064 if (OidIsValid(pg_class_reltoastrelid))
4067 * One complexity is that the table definition might not require
4068 * the creation of a TOAST table, and the TOAST table might have
4069 * been created long after table creation, when the table was
4070 * loaded with wide data. By setting the TOAST oid we force
4071 * creation of the TOAST heap and TOAST index by the backend so we
4072 * can cleanly copy the files during binary upgrade.
4075 appendPQExpBuffer(upgrade_buffer,
4076 "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
4077 pg_class_reltoastrelid);
4079 /* every toast table has an index */
4080 appendPQExpBuffer(upgrade_buffer,
4081 "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
4082 pg_index_indexrelid);
4086 appendPQExpBuffer(upgrade_buffer,
4087 "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
4090 appendPQExpBufferChar(upgrade_buffer, '\n');
4092 PQclear(upgrade_res);
4093 destroyPQExpBuffer(upgrade_query);
4097 * If the DumpableObject is a member of an extension, add a suitable
4098 * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
4101 binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
4102 DumpableObject *dobj,
4103 const char *objlabel)
4105 DumpableObject *extobj = NULL;
4108 if (!dobj->ext_member)
4112 * Find the parent extension. We could avoid this search if we wanted to
4113 * add a link field to DumpableObject, but the space costs of that would
4114 * be considerable. We assume that member objects could only have a
4115 * direct dependency on their own extension, not any others.
4117 for (i = 0; i < dobj->nDeps; i++)
4119 extobj = findObjectByDumpId(dobj->dependencies[i]);
4120 if (extobj && extobj->objType == DO_EXTENSION)
4125 exit_horribly(NULL, "could not find parent extension for %s\n", objlabel);
4127 appendPQExpBufferStr(upgrade_buffer,
4128 "\n-- For binary upgrade, handle extension membership the hard way\n");
4129 appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s;\n",
4130 fmtId(extobj->name),
4136 * read all namespaces in the system catalogs and return them in the
4137 * NamespaceInfo* structure
4139 * numNamespaces is set to the number of namespaces read in
4142 getNamespaces(Archive *fout, int *numNamespaces)
4144 DumpOptions *dopt = fout->dopt;
4149 NamespaceInfo *nsinfo;
4159 query = createPQExpBuffer();
4161 /* Make sure we are in proper schema */
4162 selectSourceSchema(fout, "pg_catalog");
4165 * we fetch all namespaces including system ones, so that every object we
4166 * read in can be linked to a containing namespace.
4168 if (fout->remoteVersion >= 90600)
4170 PQExpBuffer acl_subquery = createPQExpBuffer();
4171 PQExpBuffer racl_subquery = createPQExpBuffer();
4172 PQExpBuffer init_acl_subquery = createPQExpBuffer();
4173 PQExpBuffer init_racl_subquery = createPQExpBuffer();
4175 buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
4176 init_racl_subquery, "n.nspacl", "n.nspowner", "'n'",
4177 dopt->binary_upgrade);
4179 appendPQExpBuffer(query, "SELECT n.tableoid, n.oid, n.nspname, "
4180 "(%s nspowner) AS rolname, "
4183 "%s as initnspacl, "
4184 "%s as initrnspacl "
4185 "FROM pg_namespace n "
4186 "LEFT JOIN pg_init_privs pip "
4187 "ON (n.oid = pip.objoid "
4188 "AND pip.classoid = 'pg_namespace'::regclass "
4189 "AND pip.objsubid = 0",
4192 racl_subquery->data,
4193 init_acl_subquery->data,
4194 init_racl_subquery->data);
4197 * When we are doing a 'clean' run, we will be dropping and recreating
4198 * the 'public' schema (the only object which has that kind of
4199 * treatment in the backend and which has an entry in pg_init_privs)
4200 * and therefore we should not consider any initial privileges in
4201 * pg_init_privs in that case.
4203 * See pg_backup_archiver.c:_printTocEntry() for the details on why
4204 * the public schema is special in this regard.
4206 * Note that if the public schema is dropped and re-created, this is
4207 * essentially a no-op because the new public schema won't have an
4208 * entry in pg_init_privs anyway, as the entry will be removed when
4209 * the public schema is dropped.
4211 * Further, we have to handle the case where the public schema does
4214 if (dopt->outputClean)
4215 appendPQExpBuffer(query, " AND pip.objoid <> "
4216 "coalesce((select oid from pg_namespace "
4217 "where nspname = 'public'),0)");
4219 appendPQExpBuffer(query, ") ");
4221 destroyPQExpBuffer(acl_subquery);
4222 destroyPQExpBuffer(racl_subquery);
4223 destroyPQExpBuffer(init_acl_subquery);
4224 destroyPQExpBuffer(init_racl_subquery);
4227 appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
4228 "(%s nspowner) AS rolname, "
4229 "nspacl, NULL as rnspacl, "
4230 "NULL AS initnspacl, NULL as initrnspacl "
4231 "FROM pg_namespace",
4234 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4236 ntups = PQntuples(res);
4238 nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
4240 i_tableoid = PQfnumber(res, "tableoid");
4241 i_oid = PQfnumber(res, "oid");
4242 i_nspname = PQfnumber(res, "nspname");
4243 i_rolname = PQfnumber(res, "rolname");
4244 i_nspacl = PQfnumber(res, "nspacl");
4245 i_rnspacl = PQfnumber(res, "rnspacl");
4246 i_initnspacl = PQfnumber(res, "initnspacl");
4247 i_initrnspacl = PQfnumber(res, "initrnspacl");
4249 for (i = 0; i < ntups; i++)
4251 nsinfo[i].dobj.objType = DO_NAMESPACE;
4252 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4253 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4254 AssignDumpId(&nsinfo[i].dobj);
4255 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
4256 nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4257 nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
4258 nsinfo[i].rnspacl = pg_strdup(PQgetvalue(res, i, i_rnspacl));
4259 nsinfo[i].initnspacl = pg_strdup(PQgetvalue(res, i, i_initnspacl));
4260 nsinfo[i].initrnspacl = pg_strdup(PQgetvalue(res, i, i_initrnspacl));
4262 /* Decide whether to dump this namespace */
4263 selectDumpableNamespace(&nsinfo[i], fout);
4266 * Do not try to dump ACL if the ACL is empty or the default.
4268 * This is useful because, for some schemas/objects, the only
4269 * component we are going to try and dump is the ACL and if we can
4270 * remove that then 'dump' goes to zero/false and we don't consider
4271 * this object for dumping at all later on.
4273 if (PQgetisnull(res, i, i_nspacl) && PQgetisnull(res, i, i_rnspacl) &&
4274 PQgetisnull(res, i, i_initnspacl) &&
4275 PQgetisnull(res, i, i_initrnspacl))
4276 nsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4278 if (strlen(nsinfo[i].rolname) == 0)
4279 write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
4280 nsinfo[i].dobj.name);
4284 destroyPQExpBuffer(query);
4286 *numNamespaces = ntups;
4293 * given a namespace OID, look up the info read by getNamespaces
4295 static NamespaceInfo *
4296 findNamespace(Archive *fout, Oid nsoid)
4298 NamespaceInfo *nsinfo;
4300 nsinfo = findNamespaceByOid(nsoid);
4302 exit_horribly(NULL, "schema with OID %u does not exist\n", nsoid);
4308 * read all extensions in the system catalogs and return them in the
4309 * ExtensionInfo* structure
4311 * numExtensions is set to the number of extensions read in
4314 getExtensions(Archive *fout, int *numExtensions)
4316 DumpOptions *dopt = fout->dopt;
4321 ExtensionInfo *extinfo;
4326 int i_extrelocatable;
4332 * Before 9.1, there are no extensions.
4334 if (fout->remoteVersion < 90100)
4340 query = createPQExpBuffer();
4342 /* Make sure we are in proper schema */
4343 selectSourceSchema(fout, "pg_catalog");
4345 appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
4346 "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
4347 "FROM pg_extension x "
4348 "JOIN pg_namespace n ON n.oid = x.extnamespace");
4350 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4352 ntups = PQntuples(res);
4354 extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
4356 i_tableoid = PQfnumber(res, "tableoid");
4357 i_oid = PQfnumber(res, "oid");
4358 i_extname = PQfnumber(res, "extname");
4359 i_nspname = PQfnumber(res, "nspname");
4360 i_extrelocatable = PQfnumber(res, "extrelocatable");
4361 i_extversion = PQfnumber(res, "extversion");
4362 i_extconfig = PQfnumber(res, "extconfig");
4363 i_extcondition = PQfnumber(res, "extcondition");
4365 for (i = 0; i < ntups; i++)
4367 extinfo[i].dobj.objType = DO_EXTENSION;
4368 extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4369 extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4370 AssignDumpId(&extinfo[i].dobj);
4371 extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
4372 extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
4373 extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
4374 extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
4375 extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
4376 extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
4378 /* Decide whether we want to dump it */
4379 selectDumpableExtension(&(extinfo[i]), dopt);
4383 destroyPQExpBuffer(query);
4385 *numExtensions = ntups;
4392 * read all types in the system catalogs and return them in the
4393 * TypeInfo* structure
4395 * numTypes is set to the number of types read in
4397 * NB: this must run after getFuncs() because we assume we can do
4401 getTypes(Archive *fout, int *numTypes)
4403 DumpOptions *dopt = fout->dopt;
4407 PQExpBuffer query = createPQExpBuffer();
4409 ShellTypeInfo *stinfo;
4427 * we include even the built-in types because those may be used as array
4428 * elements by user-defined types
4430 * we filter out the built-in types when we dump out the types
4432 * same approach for undefined (shell) types and array types
4434 * Note: as of 8.3 we can reliably detect whether a type is an
4435 * auto-generated array type by checking the element type's typarray.
4436 * (Before that the test is capable of generating false positives.) We
4437 * still check for name beginning with '_', though, so as to avoid the
4438 * cost of the subselect probe for all standard types. This would have to
4439 * be revisited if the backend ever allows renaming of array types.
4442 /* Make sure we are in proper schema */
4443 selectSourceSchema(fout, "pg_catalog");
4445 if (fout->remoteVersion >= 90600)
4447 PQExpBuffer acl_subquery = createPQExpBuffer();
4448 PQExpBuffer racl_subquery = createPQExpBuffer();
4449 PQExpBuffer initacl_subquery = createPQExpBuffer();
4450 PQExpBuffer initracl_subquery = createPQExpBuffer();
4452 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
4453 initracl_subquery, "t.typacl", "t.typowner", "'T'",
4454 dopt->binary_upgrade);
4456 appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, t.typname, "
4460 "%s AS inittypacl, "
4461 "%s AS initrtypacl, "
4462 "(%s t.typowner) AS rolname, "
4463 "t.typelem, t.typrelid, "
4464 "CASE WHEN t.typrelid = 0 THEN ' '::\"char\" "
4465 "ELSE (SELECT relkind FROM pg_class WHERE oid = t.typrelid) END AS typrelkind, "
4466 "t.typtype, t.typisdefined, "
4467 "t.typname[0] = '_' AND t.typelem != 0 AND "
4468 "(SELECT typarray FROM pg_type te WHERE oid = t.typelem) = t.oid AS isarray "
4470 "LEFT JOIN pg_init_privs pip ON "
4471 "(t.oid = pip.objoid "
4472 "AND pip.classoid = 'pg_type'::regclass "
4473 "AND pip.objsubid = 0) ",
4475 racl_subquery->data,
4476 initacl_subquery->data,
4477 initracl_subquery->data,
4480 destroyPQExpBuffer(acl_subquery);
4481 destroyPQExpBuffer(racl_subquery);
4482 destroyPQExpBuffer(initacl_subquery);
4483 destroyPQExpBuffer(initracl_subquery);
4485 else if (fout->remoteVersion >= 90200)
4487 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4488 "typnamespace, typacl, NULL as rtypacl, "
4489 "NULL AS inittypacl, NULL AS initrtypacl, "
4490 "(%s typowner) AS rolname, "
4491 "typelem, typrelid, "
4492 "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4493 "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4494 "typtype, typisdefined, "
4495 "typname[0] = '_' AND typelem != 0 AND "
4496 "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4500 else if (fout->remoteVersion >= 80300)
4502 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4503 "typnamespace, NULL AS typacl, NULL as rtypacl, "
4504 "NULL AS inittypacl, NULL AS initrtypacl, "
4505 "(%s typowner) AS rolname, "
4506 "typelem, typrelid, "
4507 "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4508 "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4509 "typtype, typisdefined, "
4510 "typname[0] = '_' AND typelem != 0 AND "
4511 "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4517 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4518 "typnamespace, NULL AS typacl, NULL as rtypacl, "
4519 "NULL AS inittypacl, NULL AS initrtypacl, "
4520 "(%s typowner) AS rolname, "
4521 "typelem, typrelid, "
4522 "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4523 "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4524 "typtype, typisdefined, "
4525 "typname[0] = '_' AND typelem != 0 AS isarray "
4530 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4532 ntups = PQntuples(res);
4534 tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
4536 i_tableoid = PQfnumber(res, "tableoid");
4537 i_oid = PQfnumber(res, "oid");
4538 i_typname = PQfnumber(res, "typname");
4539 i_typnamespace = PQfnumber(res, "typnamespace");
4540 i_typacl = PQfnumber(res, "typacl");
4541 i_rtypacl = PQfnumber(res, "rtypacl");
4542 i_inittypacl = PQfnumber(res, "inittypacl");
4543 i_initrtypacl = PQfnumber(res, "initrtypacl");
4544 i_rolname = PQfnumber(res, "rolname");
4545 i_typelem = PQfnumber(res, "typelem");
4546 i_typrelid = PQfnumber(res, "typrelid");
4547 i_typrelkind = PQfnumber(res, "typrelkind");
4548 i_typtype = PQfnumber(res, "typtype");
4549 i_typisdefined = PQfnumber(res, "typisdefined");
4550 i_isarray = PQfnumber(res, "isarray");
4552 for (i = 0; i < ntups; i++)
4554 tyinfo[i].dobj.objType = DO_TYPE;
4555 tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4556 tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4557 AssignDumpId(&tyinfo[i].dobj);
4558 tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
4559 tyinfo[i].dobj.namespace =
4561 atooid(PQgetvalue(res, i, i_typnamespace)));
4562 tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4563 tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
4564 tyinfo[i].rtypacl = pg_strdup(PQgetvalue(res, i, i_rtypacl));
4565 tyinfo[i].inittypacl = pg_strdup(PQgetvalue(res, i, i_inittypacl));
4566 tyinfo[i].initrtypacl = pg_strdup(PQgetvalue(res, i, i_initrtypacl));
4567 tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
4568 tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
4569 tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
4570 tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
4571 tyinfo[i].shellType = NULL;
4573 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
4574 tyinfo[i].isDefined = true;
4576 tyinfo[i].isDefined = false;
4578 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
4579 tyinfo[i].isArray = true;
4581 tyinfo[i].isArray = false;
4583 /* Decide whether we want to dump it */
4584 selectDumpableType(&tyinfo[i], fout);
4586 /* Do not try to dump ACL if no ACL exists. */
4587 if (PQgetisnull(res, i, i_typacl) && PQgetisnull(res, i, i_rtypacl) &&
4588 PQgetisnull(res, i, i_inittypacl) &&
4589 PQgetisnull(res, i, i_initrtypacl))
4590 tyinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4593 * If it's a domain, fetch info about its constraints, if any
4595 tyinfo[i].nDomChecks = 0;
4596 tyinfo[i].domChecks = NULL;
4597 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4598 tyinfo[i].typtype == TYPTYPE_DOMAIN)
4599 getDomainConstraints(fout, &(tyinfo[i]));
4602 * If it's a base type, make a DumpableObject representing a shell
4603 * definition of the type. We will need to dump that ahead of the I/O
4604 * functions for the type. Similarly, range types need a shell
4605 * definition in case they have a canonicalize function.
4607 * Note: the shell type doesn't have a catId. You might think it
4608 * should copy the base type's catId, but then it might capture the
4609 * pg_depend entries for the type, which we don't want.
4611 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4612 (tyinfo[i].typtype == TYPTYPE_BASE ||
4613 tyinfo[i].typtype == TYPTYPE_RANGE))
4615 stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
4616 stinfo->dobj.objType = DO_SHELL_TYPE;
4617 stinfo->dobj.catId = nilCatalogId;
4618 AssignDumpId(&stinfo->dobj);
4619 stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
4620 stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
4621 stinfo->baseType = &(tyinfo[i]);
4622 tyinfo[i].shellType = stinfo;
4625 * Initially mark the shell type as not to be dumped. We'll only
4626 * dump it if the I/O or canonicalize functions need to be dumped;
4627 * this is taken care of while sorting dependencies.
4629 stinfo->dobj.dump = DUMP_COMPONENT_NONE;
4632 if (strlen(tyinfo[i].rolname) == 0)
4633 write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
4634 tyinfo[i].dobj.name);
4641 destroyPQExpBuffer(query);
4648 * read all operators in the system catalogs and return them in the
4649 * OprInfo* structure
4651 * numOprs is set to the number of operators read in
4654 getOperators(Archive *fout, int *numOprs)
4659 PQExpBuffer query = createPQExpBuffer();
4670 * find all operators, including builtin operators; we filter out
4671 * system-defined operators at dump-out time.
4674 /* Make sure we are in proper schema */
4675 selectSourceSchema(fout, "pg_catalog");
4677 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
4679 "(%s oprowner) AS rolname, "
4681 "oprcode::oid AS oprcode "
4685 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4687 ntups = PQntuples(res);
4690 oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
4692 i_tableoid = PQfnumber(res, "tableoid");
4693 i_oid = PQfnumber(res, "oid");
4694 i_oprname = PQfnumber(res, "oprname");
4695 i_oprnamespace = PQfnumber(res, "oprnamespace");
4696 i_rolname = PQfnumber(res, "rolname");
4697 i_oprkind = PQfnumber(res, "oprkind");
4698 i_oprcode = PQfnumber(res, "oprcode");
4700 for (i = 0; i < ntups; i++)
4702 oprinfo[i].dobj.objType = DO_OPERATOR;
4703 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4704 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4705 AssignDumpId(&oprinfo[i].dobj);
4706 oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
4707 oprinfo[i].dobj.namespace =
4709 atooid(PQgetvalue(res, i, i_oprnamespace)));
4710 oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4711 oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
4712 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
4714 /* Decide whether we want to dump it */
4715 selectDumpableObject(&(oprinfo[i].dobj), fout);
4717 /* Operators do not currently have ACLs. */
4718 oprinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4720 if (strlen(oprinfo[i].rolname) == 0)
4721 write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
4722 oprinfo[i].dobj.name);
4727 destroyPQExpBuffer(query);
4734 * read all collations in the system catalogs and return them in the
4735 * CollInfo* structure
4737 * numCollations is set to the number of collations read in
4740 getCollations(Archive *fout, int *numCollations)
4750 int i_collnamespace;
4753 /* Collations didn't exist pre-9.1 */
4754 if (fout->remoteVersion < 90100)
4760 query = createPQExpBuffer();
4763 * find all collations, including builtin collations; we filter out
4764 * system-defined collations at dump-out time.
4767 /* Make sure we are in proper schema */
4768 selectSourceSchema(fout, "pg_catalog");
4770 appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
4772 "(%s collowner) AS rolname "
4773 "FROM pg_collation",
4776 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4778 ntups = PQntuples(res);
4779 *numCollations = ntups;
4781 collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
4783 i_tableoid = PQfnumber(res, "tableoid");
4784 i_oid = PQfnumber(res, "oid");
4785 i_collname = PQfnumber(res, "collname");
4786 i_collnamespace = PQfnumber(res, "collnamespace");
4787 i_rolname = PQfnumber(res, "rolname");
4789 for (i = 0; i < ntups; i++)
4791 collinfo[i].dobj.objType = DO_COLLATION;
4792 collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4793 collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4794 AssignDumpId(&collinfo[i].dobj);
4795 collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
4796 collinfo[i].dobj.namespace =
4798 atooid(PQgetvalue(res, i, i_collnamespace)));
4799 collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4801 /* Decide whether we want to dump it */
4802 selectDumpableObject(&(collinfo[i].dobj), fout);
4804 /* Collations do not currently have ACLs. */
4805 collinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4810 destroyPQExpBuffer(query);
4817 * read all conversions in the system catalogs and return them in the
4818 * ConvInfo* structure
4820 * numConversions is set to the number of conversions read in
4823 getConversions(Archive *fout, int *numConversions)
4836 query = createPQExpBuffer();
4839 * find all conversions, including builtin conversions; we filter out
4840 * system-defined conversions at dump-out time.
4843 /* Make sure we are in proper schema */
4844 selectSourceSchema(fout, "pg_catalog");
4846 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
4848 "(%s conowner) AS rolname "
4849 "FROM pg_conversion",
4852 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4854 ntups = PQntuples(res);
4855 *numConversions = ntups;
4857 convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
4859 i_tableoid = PQfnumber(res, "tableoid");
4860 i_oid = PQfnumber(res, "oid");
4861 i_conname = PQfnumber(res, "conname");
4862 i_connamespace = PQfnumber(res, "connamespace");
4863 i_rolname = PQfnumber(res, "rolname");
4865 for (i = 0; i < ntups; i++)
4867 convinfo[i].dobj.objType = DO_CONVERSION;
4868 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4869 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4870 AssignDumpId(&convinfo[i].dobj);
4871 convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
4872 convinfo[i].dobj.namespace =
4874 atooid(PQgetvalue(res, i, i_connamespace)));
4875 convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4877 /* Decide whether we want to dump it */
4878 selectDumpableObject(&(convinfo[i].dobj), fout);
4880 /* Conversions do not currently have ACLs. */
4881 convinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4886 destroyPQExpBuffer(query);
4893 * read all user-defined access methods in the system catalogs and return
4894 * them in the AccessMethodInfo* structure
4896 * numAccessMethods is set to the number of access methods read in
4899 getAccessMethods(Archive *fout, int *numAccessMethods)
4905 AccessMethodInfo *aminfo;
4912 /* Before 9.6, there are no user-defined access methods */
4913 if (fout->remoteVersion < 90600)
4915 *numAccessMethods = 0;
4919 query = createPQExpBuffer();
4921 /* Make sure we are in proper schema */
4922 selectSourceSchema(fout, "pg_catalog");
4924 /* Select all access methods from pg_am table */
4925 appendPQExpBuffer(query, "SELECT tableoid, oid, amname, amtype, "
4926 "amhandler::pg_catalog.regproc AS amhandler "
4929 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4931 ntups = PQntuples(res);
4932 *numAccessMethods = ntups;
4934 aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
4936 i_tableoid = PQfnumber(res, "tableoid");
4937 i_oid = PQfnumber(res, "oid");
4938 i_amname = PQfnumber(res, "amname");
4939 i_amhandler = PQfnumber(res, "amhandler");
4940 i_amtype = PQfnumber(res, "amtype");
4942 for (i = 0; i < ntups; i++)
4944 aminfo[i].dobj.objType = DO_ACCESS_METHOD;
4945 aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4946 aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4947 AssignDumpId(&aminfo[i].dobj);
4948 aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
4949 aminfo[i].dobj.namespace = NULL;
4950 aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
4951 aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
4953 /* Decide whether we want to dump it */
4954 selectDumpableAccessMethod(&(aminfo[i]), fout);
4956 /* Access methods do not currently have ACLs. */
4957 aminfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4962 destroyPQExpBuffer(query);
4970 * read all opclasses in the system catalogs and return them in the
4971 * OpclassInfo* structure
4973 * numOpclasses is set to the number of opclasses read in
4976 getOpclasses(Archive *fout, int *numOpclasses)
4981 PQExpBuffer query = createPQExpBuffer();
4982 OpclassInfo *opcinfo;
4990 * find all opclasses, including builtin opclasses; we filter out
4991 * system-defined opclasses at dump-out time.
4994 /* Make sure we are in proper schema */
4995 selectSourceSchema(fout, "pg_catalog");
4997 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
4999 "(%s opcowner) AS rolname "
5003 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5005 ntups = PQntuples(res);
5006 *numOpclasses = ntups;
5008 opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
5010 i_tableoid = PQfnumber(res, "tableoid");
5011 i_oid = PQfnumber(res, "oid");
5012 i_opcname = PQfnumber(res, "opcname");
5013 i_opcnamespace = PQfnumber(res, "opcnamespace");
5014 i_rolname = PQfnumber(res, "rolname");
5016 for (i = 0; i < ntups; i++)
5018 opcinfo[i].dobj.objType = DO_OPCLASS;
5019 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5020 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5021 AssignDumpId(&opcinfo[i].dobj);
5022 opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
5023 opcinfo[i].dobj.namespace =
5025 atooid(PQgetvalue(res, i, i_opcnamespace)));
5026 opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5028 /* Decide whether we want to dump it */
5029 selectDumpableObject(&(opcinfo[i].dobj), fout);
5031 /* Op Classes do not currently have ACLs. */
5032 opcinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5034 if (strlen(opcinfo[i].rolname) == 0)
5035 write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
5036 opcinfo[i].dobj.name);
5041 destroyPQExpBuffer(query);
5048 * read all opfamilies in the system catalogs and return them in the
5049 * OpfamilyInfo* structure
5051 * numOpfamilies is set to the number of opfamilies read in
5054 getOpfamilies(Archive *fout, int *numOpfamilies)
5060 OpfamilyInfo *opfinfo;
5067 /* Before 8.3, there is no separate concept of opfamilies */
5068 if (fout->remoteVersion < 80300)
5074 query = createPQExpBuffer();
5077 * find all opfamilies, including builtin opfamilies; we filter out
5078 * system-defined opfamilies at dump-out time.
5081 /* Make sure we are in proper schema */
5082 selectSourceSchema(fout, "pg_catalog");
5084 appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
5086 "(%s opfowner) AS rolname "
5090 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5092 ntups = PQntuples(res);
5093 *numOpfamilies = ntups;
5095 opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
5097 i_tableoid = PQfnumber(res, "tableoid");
5098 i_oid = PQfnumber(res, "oid");
5099 i_opfname = PQfnumber(res, "opfname");
5100 i_opfnamespace = PQfnumber(res, "opfnamespace");
5101 i_rolname = PQfnumber(res, "rolname");
5103 for (i = 0; i < ntups; i++)
5105 opfinfo[i].dobj.objType = DO_OPFAMILY;
5106 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5107 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5108 AssignDumpId(&opfinfo[i].dobj);
5109 opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
5110 opfinfo[i].dobj.namespace =
5112 atooid(PQgetvalue(res, i, i_opfnamespace)));
5113 opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5115 /* Decide whether we want to dump it */
5116 selectDumpableObject(&(opfinfo[i].dobj), fout);
5118 /* Extensions do not currently have ACLs. */
5119 opfinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5121 if (strlen(opfinfo[i].rolname) == 0)
5122 write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
5123 opfinfo[i].dobj.name);
5128 destroyPQExpBuffer(query);
5135 * read all the user-defined aggregates in the system catalogs and
5136 * return them in the AggInfo* structure
5138 * numAggs is set to the number of aggregates read in
5141 getAggregates(Archive *fout, int *numAggs)
5143 DumpOptions *dopt = fout->dopt;
5147 PQExpBuffer query = createPQExpBuffer();
5161 /* Make sure we are in proper schema */
5162 selectSourceSchema(fout, "pg_catalog");
5165 * Find all interesting aggregates. See comment in getFuncs() for the
5166 * rationale behind the filtering logic.
5168 if (fout->remoteVersion >= 90600)
5170 PQExpBuffer acl_subquery = createPQExpBuffer();
5171 PQExpBuffer racl_subquery = createPQExpBuffer();
5172 PQExpBuffer initacl_subquery = createPQExpBuffer();
5173 PQExpBuffer initracl_subquery = createPQExpBuffer();
5175 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5176 initracl_subquery, "p.proacl", "p.proowner", "'f'",
5177 dopt->binary_upgrade);
5179 appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
5180 "p.proname AS aggname, "
5181 "p.pronamespace AS aggnamespace, "
5182 "p.pronargs, p.proargtypes, "
5183 "(%s p.proowner) AS rolname, "
5186 "%s AS initaggacl, "
5187 "%s AS initraggacl "
5189 "LEFT JOIN pg_init_privs pip ON "
5190 "(p.oid = pip.objoid "
5191 "AND pip.classoid = 'pg_proc'::regclass "
5192 "AND pip.objsubid = 0) "
5193 "WHERE p.proisagg AND ("
5194 "p.pronamespace != "
5195 "(SELECT oid FROM pg_namespace "
5196 "WHERE nspname = 'pg_catalog') OR "
5197 "p.proacl IS DISTINCT FROM pip.initprivs",
5200 racl_subquery->data,
5201 initacl_subquery->data,
5202 initracl_subquery->data);
5203 if (dopt->binary_upgrade)
5204 appendPQExpBufferStr(query,
5205 " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5206 "classid = 'pg_proc'::regclass AND "
5207 "objid = p.oid AND "
5208 "refclassid = 'pg_extension'::regclass AND "
5210 appendPQExpBufferChar(query, ')');
5212 destroyPQExpBuffer(acl_subquery);
5213 destroyPQExpBuffer(racl_subquery);
5214 destroyPQExpBuffer(initacl_subquery);
5215 destroyPQExpBuffer(initracl_subquery);
5217 else if (fout->remoteVersion >= 80200)
5219 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
5220 "pronamespace AS aggnamespace, "
5221 "pronargs, proargtypes, "
5222 "(%s proowner) AS rolname, "
5223 "proacl AS aggacl, "
5225 "NULL AS initaggacl, NULL AS initraggacl "
5227 "WHERE proisagg AND ("
5229 "(SELECT oid FROM pg_namespace "
5230 "WHERE nspname = 'pg_catalog')",
5232 if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
5233 appendPQExpBufferStr(query,
5234 " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5235 "classid = 'pg_proc'::regclass AND "
5236 "objid = p.oid AND "
5237 "refclassid = 'pg_extension'::regclass AND "
5239 appendPQExpBufferChar(query, ')');
5243 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
5244 "pronamespace AS aggnamespace, "
5245 "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
5247 "(%s proowner) AS rolname, "
5248 "proacl AS aggacl, "
5250 "NULL AS initaggacl, NULL AS initraggacl "
5253 "AND pronamespace != "
5254 "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
5258 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5260 ntups = PQntuples(res);
5263 agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
5265 i_tableoid = PQfnumber(res, "tableoid");
5266 i_oid = PQfnumber(res, "oid");
5267 i_aggname = PQfnumber(res, "aggname");
5268 i_aggnamespace = PQfnumber(res, "aggnamespace");
5269 i_pronargs = PQfnumber(res, "pronargs");
5270 i_proargtypes = PQfnumber(res, "proargtypes");
5271 i_rolname = PQfnumber(res, "rolname");
5272 i_aggacl = PQfnumber(res, "aggacl");
5273 i_raggacl = PQfnumber(res, "raggacl");
5274 i_initaggacl = PQfnumber(res, "initaggacl");
5275 i_initraggacl = PQfnumber(res, "initraggacl");
5277 for (i = 0; i < ntups; i++)
5279 agginfo[i].aggfn.dobj.objType = DO_AGG;
5280 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5281 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5282 AssignDumpId(&agginfo[i].aggfn.dobj);
5283 agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
5284 agginfo[i].aggfn.dobj.namespace =
5286 atooid(PQgetvalue(res, i, i_aggnamespace)));
5287 agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5288 if (strlen(agginfo[i].aggfn.rolname) == 0)
5289 write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
5290 agginfo[i].aggfn.dobj.name);
5291 agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
5292 agginfo[i].aggfn.prorettype = InvalidOid; /* not saved */
5293 agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
5294 agginfo[i].aggfn.rproacl = pg_strdup(PQgetvalue(res, i, i_raggacl));
5295 agginfo[i].aggfn.initproacl = pg_strdup(PQgetvalue(res, i, i_initaggacl));
5296 agginfo[i].aggfn.initrproacl = pg_strdup(PQgetvalue(res, i, i_initraggacl));
5297 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
5298 if (agginfo[i].aggfn.nargs == 0)
5299 agginfo[i].aggfn.argtypes = NULL;
5302 agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
5303 parseOidArray(PQgetvalue(res, i, i_proargtypes),
5304 agginfo[i].aggfn.argtypes,
5305 agginfo[i].aggfn.nargs);
5308 /* Decide whether we want to dump it */
5309 selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
5311 /* Do not try to dump ACL if no ACL exists. */
5312 if (PQgetisnull(res, i, i_aggacl) && PQgetisnull(res, i, i_raggacl) &&
5313 PQgetisnull(res, i, i_initaggacl) &&
5314 PQgetisnull(res, i, i_initraggacl))
5315 agginfo[i].aggfn.dobj.dump &= ~DUMP_COMPONENT_ACL;
5320 destroyPQExpBuffer(query);
5327 * read all the user-defined functions in the system catalogs and
5328 * return them in the FuncInfo* structure
5330 * numFuncs is set to the number of functions read in
5333 getFuncs(Archive *fout, int *numFuncs)
5335 DumpOptions *dopt = fout->dopt;
5339 PQExpBuffer query = createPQExpBuffer();
5355 /* Make sure we are in proper schema */
5356 selectSourceSchema(fout, "pg_catalog");
5359 * Find all interesting functions. This is a bit complicated:
5361 * 1. Always exclude aggregates; those are handled elsewhere.
5363 * 2. Always exclude functions that are internally dependent on something
5364 * else, since presumably those will be created as a result of creating
5365 * the something else. This currently acts only to suppress constructor
5366 * functions for range types (so we only need it in 9.2 and up). Note
5367 * this is OK only because the constructors don't have any dependencies
5368 * the range type doesn't have; otherwise we might not get creation
5371 * 3. Otherwise, we normally exclude functions in pg_catalog. However, if
5372 * they're members of extensions and we are in binary-upgrade mode then
5373 * include them, since we want to dump extension members individually in
5374 * that mode. Also, if they are used by casts or transforms then we need
5375 * to gather the information about them, though they won't be dumped if
5376 * they are built-in. Also, in 9.6 and up, include functions in
5377 * pg_catalog if they have an ACL different from what's shown in
5380 if (fout->remoteVersion >= 90600)
5382 PQExpBuffer acl_subquery = createPQExpBuffer();
5383 PQExpBuffer racl_subquery = createPQExpBuffer();
5384 PQExpBuffer initacl_subquery = createPQExpBuffer();
5385 PQExpBuffer initracl_subquery = createPQExpBuffer();
5387 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5388 initracl_subquery, "p.proacl", "p.proowner", "'f'",
5389 dopt->binary_upgrade);
5391 appendPQExpBuffer(query,
5392 "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
5393 "p.pronargs, p.proargtypes, p.prorettype, "
5396 "%s AS initproacl, "
5397 "%s AS initrproacl, "
5399 "(%s p.proowner) AS rolname "
5401 "LEFT JOIN pg_init_privs pip ON "
5402 "(p.oid = pip.objoid "
5403 "AND pip.classoid = 'pg_proc'::regclass "
5404 "AND pip.objsubid = 0) "
5405 "WHERE NOT proisagg"
5406 "\n AND NOT EXISTS (SELECT 1 FROM pg_depend "
5407 "WHERE classid = 'pg_proc'::regclass AND "
5408 "objid = p.oid AND deptype = 'i')"
5410 "\n pronamespace != "
5411 "(SELECT oid FROM pg_namespace "
5412 "WHERE nspname = 'pg_catalog')"
5413 "\n OR EXISTS (SELECT 1 FROM pg_cast"
5414 "\n WHERE pg_cast.oid > %u "
5415 "\n AND p.oid = pg_cast.castfunc)"
5416 "\n OR EXISTS (SELECT 1 FROM pg_transform"
5417 "\n WHERE pg_transform.oid > %u AND "
5418 "\n (p.oid = pg_transform.trffromsql"
5419 "\n OR p.oid = pg_transform.trftosql))",
5421 racl_subquery->data,
5422 initacl_subquery->data,
5423 initracl_subquery->data,
5426 g_last_builtin_oid);
5427 if (dopt->binary_upgrade)
5428 appendPQExpBufferStr(query,
5429 "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5430 "classid = 'pg_proc'::regclass AND "
5431 "objid = p.oid AND "
5432 "refclassid = 'pg_extension'::regclass AND "
5434 appendPQExpBufferStr(query,
5435 "\n OR p.proacl IS DISTINCT FROM pip.initprivs");
5436 appendPQExpBufferChar(query, ')');
5438 destroyPQExpBuffer(acl_subquery);
5439 destroyPQExpBuffer(racl_subquery);
5440 destroyPQExpBuffer(initacl_subquery);
5441 destroyPQExpBuffer(initracl_subquery);
5445 appendPQExpBuffer(query,
5446 "SELECT tableoid, oid, proname, prolang, "
5447 "pronargs, proargtypes, prorettype, proacl, "
5449 "NULL as initproacl, NULL AS initrproacl, "
5451 "(%s proowner) AS rolname "
5453 "WHERE NOT proisagg",
5455 if (fout->remoteVersion >= 90200)
5456 appendPQExpBufferStr(query,
5457 "\n AND NOT EXISTS (SELECT 1 FROM pg_depend "
5458 "WHERE classid = 'pg_proc'::regclass AND "
5459 "objid = p.oid AND deptype = 'i')");
5460 appendPQExpBuffer(query,
5462 "\n pronamespace != "
5463 "(SELECT oid FROM pg_namespace "
5464 "WHERE nspname = 'pg_catalog')"
5465 "\n OR EXISTS (SELECT 1 FROM pg_cast"
5466 "\n WHERE pg_cast.oid > '%u'::oid"
5467 "\n AND p.oid = pg_cast.castfunc)",
5468 g_last_builtin_oid);
5470 if (fout->remoteVersion >= 90500)
5471 appendPQExpBuffer(query,
5472 "\n OR EXISTS (SELECT 1 FROM pg_transform"
5473 "\n WHERE pg_transform.oid > '%u'::oid"
5474 "\n AND (p.oid = pg_transform.trffromsql"
5475 "\n OR p.oid = pg_transform.trftosql))",
5476 g_last_builtin_oid);
5478 if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
5479 appendPQExpBufferStr(query,
5480 "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5481 "classid = 'pg_proc'::regclass AND "
5482 "objid = p.oid AND "
5483 "refclassid = 'pg_extension'::regclass AND "
5485 appendPQExpBufferChar(query, ')');
5488 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5490 ntups = PQntuples(res);
5494 finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
5496 i_tableoid = PQfnumber(res, "tableoid");
5497 i_oid = PQfnumber(res, "oid");
5498 i_proname = PQfnumber(res, "proname");
5499 i_pronamespace = PQfnumber(res, "pronamespace");
5500 i_rolname = PQfnumber(res, "rolname");
5501 i_prolang = PQfnumber(res, "prolang");
5502 i_pronargs = PQfnumber(res, "pronargs");
5503 i_proargtypes = PQfnumber(res, "proargtypes");
5504 i_prorettype = PQfnumber(res, "prorettype");
5505 i_proacl = PQfnumber(res, "proacl");
5506 i_rproacl = PQfnumber(res, "rproacl");
5507 i_initproacl = PQfnumber(res, "initproacl");
5508 i_initrproacl = PQfnumber(res, "initrproacl");
5510 for (i = 0; i < ntups; i++)
5512 finfo[i].dobj.objType = DO_FUNC;
5513 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5514 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5515 AssignDumpId(&finfo[i].dobj);
5516 finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
5517 finfo[i].dobj.namespace =
5519 atooid(PQgetvalue(res, i, i_pronamespace)));
5520 finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5521 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
5522 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
5523 finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
5524 finfo[i].rproacl = pg_strdup(PQgetvalue(res, i, i_rproacl));
5525 finfo[i].initproacl = pg_strdup(PQgetvalue(res, i, i_initproacl));
5526 finfo[i].initrproacl = pg_strdup(PQgetvalue(res, i, i_initrproacl));
5527 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
5528 if (finfo[i].nargs == 0)
5529 finfo[i].argtypes = NULL;
5532 finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
5533 parseOidArray(PQgetvalue(res, i, i_proargtypes),
5534 finfo[i].argtypes, finfo[i].nargs);
5537 /* Decide whether we want to dump it */
5538 selectDumpableObject(&(finfo[i].dobj), fout);
5540 /* Do not try to dump ACL if no ACL exists. */
5541 if (PQgetisnull(res, i, i_proacl) && PQgetisnull(res, i, i_rproacl) &&
5542 PQgetisnull(res, i, i_initproacl) &&
5543 PQgetisnull(res, i, i_initrproacl))
5544 finfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5546 if (strlen(finfo[i].rolname) == 0)
5548 "WARNING: owner of function \"%s\" appears to be invalid\n",
5549 finfo[i].dobj.name);
5554 destroyPQExpBuffer(query);
5561 * read all the tables (no indexes)
5562 * in the system catalogs return them in the TableInfo* structure
5564 * numTables is set to the number of tables read in
5567 getTables(Archive *fout, int *numTables)
5569 DumpOptions *dopt = fout->dopt;
5573 PQExpBuffer query = createPQExpBuffer();
5586 int i_relhastriggers;
5590 int i_relforcerowsec;
5595 int i_toastfrozenxid;
5597 int i_relpersistence;
5598 int i_relispopulated;
5602 int i_reltablespace;
5605 int i_toastreloptions;
5608 int i_is_identity_sequence;
5614 /* Make sure we are in proper schema */
5615 selectSourceSchema(fout, "pg_catalog");
5618 * Find all the tables and table-like objects.
5620 * We include system catalogs, so that we can work if a user table is
5621 * defined to inherit from a system catalog (pretty weird, but...)
5623 * We ignore relations that are not ordinary tables, sequences, views,
5624 * materialized views, composite types, or foreign tables.
5626 * Composite-type table entries won't be dumped as such, but we have to
5627 * make a DumpableObject for them so that we can track dependencies of the
5628 * composite type (pg_depend entries for columns of the composite type
5629 * link to the pg_class entry not the pg_type entry).
5631 * Note: in this phase we should collect only a minimal amount of
5632 * information about each table, basically just enough to decide if it is
5633 * interesting. We must fetch all tables in this phase because otherwise
5634 * we cannot correctly identify inherited columns, owned sequences, etc.
5637 if (fout->remoteVersion >= 90600)
5639 char *partkeydef = "NULL";
5640 char *ispartition = "false";
5641 char *partbound = "NULL";
5643 PQExpBuffer acl_subquery = createPQExpBuffer();
5644 PQExpBuffer racl_subquery = createPQExpBuffer();
5645 PQExpBuffer initacl_subquery = createPQExpBuffer();
5646 PQExpBuffer initracl_subquery = createPQExpBuffer();
5648 PQExpBuffer attacl_subquery = createPQExpBuffer();
5649 PQExpBuffer attracl_subquery = createPQExpBuffer();
5650 PQExpBuffer attinitacl_subquery = createPQExpBuffer();
5651 PQExpBuffer attinitracl_subquery = createPQExpBuffer();
5654 * Collect the information about any partitioned tables, which were
5658 if (fout->remoteVersion >= 100000)
5660 partkeydef = "pg_get_partkeydef(c.oid)";
5661 ispartition = "c.relispartition";
5662 partbound = "pg_get_expr(c.relpartbound, c.oid)";
5666 * Left join to pick up dependency info linking sequences to their
5667 * owning column, if any (note this dependency is AUTO as of 8.2)
5669 * Left join to detect if any privileges are still as-set-at-init, in
5670 * which case we won't dump out ACL commands for those.
5673 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5674 initracl_subquery, "c.relacl", "c.relowner",
5675 "CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
5676 " THEN 's' ELSE 'r' END::\"char\"",
5677 dopt->binary_upgrade);
5679 buildACLQueries(attacl_subquery, attracl_subquery, attinitacl_subquery,
5680 attinitracl_subquery, "at.attacl", "c.relowner", "'c'",
5681 dopt->binary_upgrade);
5683 appendPQExpBuffer(query,
5684 "SELECT c.tableoid, c.oid, c.relname, "
5685 "%s AS relacl, %s as rrelacl, "
5686 "%s AS initrelacl, %s as initrrelacl, "
5687 "c.relkind, c.relnamespace, "
5688 "(%s c.relowner) AS rolname, "
5689 "c.relchecks, c.relhastriggers, "
5690 "c.relhasindex, c.relhasrules, c.relhasoids, "
5691 "c.relrowsecurity, c.relforcerowsecurity, "
5692 "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
5693 "tc.relfrozenxid AS tfrozenxid, "
5694 "tc.relminmxid AS tminmxid, "
5695 "c.relpersistence, c.relispopulated, "
5696 "c.relreplident, c.relpages, "
5697 "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
5698 "d.refobjid AS owning_tab, "
5699 "d.refobjsubid AS owning_col, "
5700 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
5701 "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
5702 "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
5703 "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
5704 "tc.reloptions AS toast_reloptions, "
5705 "c.relkind = '%c' AND EXISTS (SELECT 1 FROM pg_depend WHERE classid = 'pg_class'::regclass AND objid = c.oid AND objsubid = 0 AND refclassid = 'pg_class'::regclass AND deptype = 'i') AS is_identity_sequence, "
5706 "EXISTS (SELECT 1 FROM pg_attribute at LEFT JOIN pg_init_privs pip ON "
5707 "(c.oid = pip.objoid "
5708 "AND pip.classoid = 'pg_class'::regclass "
5709 "AND pip.objsubid = at.attnum)"
5710 "WHERE at.attrelid = c.oid AND ("
5712 "OR %s IS NOT NULL "
5713 "OR %s IS NOT NULL "
5717 "%s AS partkeydef, "
5718 "%s AS ispartition, "
5721 "LEFT JOIN pg_depend d ON "
5722 "(c.relkind = '%c' AND "
5723 "d.classid = c.tableoid AND d.objid = c.oid AND "
5724 "d.objsubid = 0 AND "
5725 "d.refclassid = c.tableoid AND d.deptype IN ('a', 'i')) "
5726 "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
5727 "LEFT JOIN pg_init_privs pip ON "
5728 "(c.oid = pip.objoid "
5729 "AND pip.classoid = 'pg_class'::regclass "
5730 "AND pip.objsubid = 0) "
5731 "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c', '%c') "
5734 racl_subquery->data,
5735 initacl_subquery->data,
5736 initracl_subquery->data,
5739 attacl_subquery->data,
5740 attracl_subquery->data,
5741 attinitacl_subquery->data,
5742 attinitracl_subquery->data,
5747 RELKIND_RELATION, RELKIND_SEQUENCE,
5748 RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
5749 RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
5750 RELKIND_PARTITIONED_TABLE);
5752 destroyPQExpBuffer(acl_subquery);
5753 destroyPQExpBuffer(racl_subquery);
5754 destroyPQExpBuffer(initacl_subquery);
5755 destroyPQExpBuffer(initracl_subquery);
5757 destroyPQExpBuffer(attacl_subquery);
5758 destroyPQExpBuffer(attracl_subquery);
5759 destroyPQExpBuffer(attinitacl_subquery);
5760 destroyPQExpBuffer(attinitracl_subquery);
5762 else if (fout->remoteVersion >= 90500)
5765 * Left join to pick up dependency info linking sequences to their
5766 * owning column, if any (note this dependency is AUTO as of 8.2)
5768 appendPQExpBuffer(query,
5769 "SELECT c.tableoid, c.oid, c.relname, "
5770 "c.relacl, NULL as rrelacl, "
5771 "NULL AS initrelacl, NULL AS initrrelacl, "
5774 "(%s c.relowner) AS rolname, "
5775 "c.relchecks, c.relhastriggers, "
5776 "c.relhasindex, c.relhasrules, c.relhasoids, "
5777 "c.relrowsecurity, c.relforcerowsecurity, "
5778 "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
5779 "tc.relfrozenxid AS tfrozenxid, "
5780 "tc.relminmxid AS tminmxid, "
5781 "c.relpersistence, c.relispopulated, "
5782 "c.relreplident, c.relpages, "
5783 "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
5784 "d.refobjid AS owning_tab, "
5785 "d.refobjsubid AS owning_col, "
5786 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
5787 "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
5788 "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
5789 "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
5790 "tc.reloptions AS toast_reloptions, "
5791 "NULL AS changed_acl, "
5792 "NULL AS partkeydef, "
5793 "false AS ispartition, "
5794 "NULL AS partbound "
5796 "LEFT JOIN pg_depend d ON "
5797 "(c.relkind = '%c' AND "
5798 "d.classid = c.tableoid AND d.objid = c.oid AND "
5799 "d.objsubid = 0 AND "
5800 "d.refclassid = c.tableoid AND d.deptype = 'a') "
5801 "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
5802 "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
5806 RELKIND_RELATION, RELKIND_SEQUENCE,
5807 RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
5808 RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
5810 else if (fout->remoteVersion >= 90400)
5813 * Left join to pick up dependency info linking sequences to their
5814 * owning column, if any (note this dependency is AUTO as of 8.2)
5816 appendPQExpBuffer(query,
5817 "SELECT c.tableoid, c.oid, c.relname, "
5818 "c.relacl, NULL as rrelacl, "
5819 "NULL AS initrelacl, NULL AS initrrelacl, "
5822 "(%s c.relowner) AS rolname, "
5823 "c.relchecks, c.relhastriggers, "
5824 "c.relhasindex, c.relhasrules, c.relhasoids, "
5825 "'f'::bool AS relrowsecurity, "
5826 "'f'::bool AS relforcerowsecurity, "
5827 "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
5828 "tc.relfrozenxid AS tfrozenxid, "
5829 "tc.relminmxid AS tminmxid, "
5830 "c.relpersistence, c.relispopulated, "
5831 "c.relreplident, c.relpages, "
5832 "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
5833 "d.refobjid AS owning_tab, "
5834 "d.refobjsubid AS owning_col, "
5835 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
5836 "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
5837 "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
5838 "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
5839 "tc.reloptions AS toast_reloptions, "
5840 "NULL AS changed_acl, "
5841 "NULL AS partkeydef, "
5842 "false AS ispartition, "
5843 "NULL AS partbound "
5845 "LEFT JOIN pg_depend d ON "
5846 "(c.relkind = '%c' AND "
5847 "d.classid = c.tableoid AND d.objid = c.oid AND "
5848 "d.objsubid = 0 AND "
5849 "d.refclassid = c.tableoid AND d.deptype = 'a') "
5850 "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
5851 "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
5855 RELKIND_RELATION, RELKIND_SEQUENCE,
5856 RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
5857 RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
5859 else if (fout->remoteVersion >= 90300)
5862 * Left join to pick up dependency info linking sequences to their
5863 * owning column, if any (note this dependency is AUTO as of 8.2)
5865 appendPQExpBuffer(query,
5866 "SELECT c.tableoid, c.oid, c.relname, "
5867 "c.relacl, NULL as rrelacl, "
5868 "NULL AS initrelacl, NULL AS initrrelacl, "
5871 "(%s c.relowner) AS rolname, "
5872 "c.relchecks, c.relhastriggers, "
5873 "c.relhasindex, c.relhasrules, c.relhasoids, "
5874 "'f'::bool AS relrowsecurity, "
5875 "'f'::bool AS relforcerowsecurity, "
5876 "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
5877 "tc.relfrozenxid AS tfrozenxid, "
5878 "tc.relminmxid AS tminmxid, "
5879 "c.relpersistence, c.relispopulated, "
5880 "'d' AS relreplident, c.relpages, "
5881 "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
5882 "d.refobjid AS owning_tab, "
5883 "d.refobjsubid AS owning_col, "
5884 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
5885 "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
5886 "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
5887 "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
5888 "tc.reloptions AS toast_reloptions, "
5889 "NULL AS changed_acl, "
5890 "NULL AS partkeydef, "
5891 "false AS ispartition, "
5892 "NULL AS partbound "
5894 "LEFT JOIN pg_depend d ON "
5895 "(c.relkind = '%c' AND "
5896 "d.classid = c.tableoid AND d.objid = c.oid AND "
5897 "d.objsubid = 0 AND "
5898 "d.refclassid = c.tableoid AND d.deptype = 'a') "
5899 "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
5900 "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
5904 RELKIND_RELATION, RELKIND_SEQUENCE,
5905 RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
5906 RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
5908 else if (fout->remoteVersion >= 90100)
5911 * Left join to pick up dependency info linking sequences to their
5912 * owning column, if any (note this dependency is AUTO as of 8.2)
5914 appendPQExpBuffer(query,
5915 "SELECT c.tableoid, c.oid, c.relname, "
5916 "c.relacl, NULL as rrelacl, "
5917 "NULL AS initrelacl, NULL AS initrrelacl, "
5920 "(%s c.relowner) AS rolname, "
5921 "c.relchecks, c.relhastriggers, "
5922 "c.relhasindex, c.relhasrules, c.relhasoids, "
5923 "'f'::bool AS relrowsecurity, "
5924 "'f'::bool AS relforcerowsecurity, "
5925 "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
5926 "tc.relfrozenxid AS tfrozenxid, "
5928 "c.relpersistence, 't' as relispopulated, "
5929 "'d' AS relreplident, c.relpages, "
5930 "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
5931 "d.refobjid AS owning_tab, "
5932 "d.refobjsubid AS owning_col, "
5933 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
5934 "c.reloptions AS reloptions, "
5935 "tc.reloptions AS toast_reloptions, "
5936 "NULL AS changed_acl, "
5937 "NULL AS partkeydef, "
5938 "false AS ispartition, "
5939 "NULL AS partbound "
5941 "LEFT JOIN pg_depend d ON "
5942 "(c.relkind = '%c' AND "
5943 "d.classid = c.tableoid AND d.objid = c.oid AND "
5944 "d.objsubid = 0 AND "
5945 "d.refclassid = c.tableoid AND d.deptype = 'a') "
5946 "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
5947 "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
5951 RELKIND_RELATION, RELKIND_SEQUENCE,
5952 RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
5953 RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
5955 else if (fout->remoteVersion >= 90000)
5958 * Left join to pick up dependency info linking sequences to their
5959 * owning column, if any (note this dependency is AUTO as of 8.2)
5961 appendPQExpBuffer(query,
5962 "SELECT c.tableoid, c.oid, c.relname, "
5963 "c.relacl, NULL as rrelacl, "
5964 "NULL AS initrelacl, NULL AS initrrelacl, "
5967 "(%s c.relowner) AS rolname, "
5968 "c.relchecks, c.relhastriggers, "
5969 "c.relhasindex, c.relhasrules, c.relhasoids, "
5970 "'f'::bool AS relrowsecurity, "
5971 "'f'::bool AS relforcerowsecurity, "
5972 "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
5973 "tc.relfrozenxid AS tfrozenxid, "
5975 "'p' AS relpersistence, 't' as relispopulated, "
5976 "'d' AS relreplident, c.relpages, "
5977 "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
5978 "d.refobjid AS owning_tab, "
5979 "d.refobjsubid AS owning_col, "
5980 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
5981 "c.reloptions AS reloptions, "
5982 "tc.reloptions AS toast_reloptions, "
5983 "NULL AS changed_acl, "
5984 "NULL AS partkeydef, "
5985 "false AS ispartition, "
5986 "NULL AS partbound "
5988 "LEFT JOIN pg_depend d ON "
5989 "(c.relkind = '%c' AND "
5990 "d.classid = c.tableoid AND d.objid = c.oid AND "
5991 "d.objsubid = 0 AND "
5992 "d.refclassid = c.tableoid AND d.deptype = 'a') "
5993 "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
5994 "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
5998 RELKIND_RELATION, RELKIND_SEQUENCE,
5999 RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6001 else if (fout->remoteVersion >= 80400)
6004 * Left join to pick up dependency info linking sequences to their
6005 * owning column, if any (note this dependency is AUTO as of 8.2)
6007 appendPQExpBuffer(query,
6008 "SELECT c.tableoid, c.oid, c.relname, "
6009 "c.relacl, NULL as rrelacl, "
6010 "NULL AS initrelacl, NULL AS initrrelacl, "
6013 "(%s c.relowner) AS rolname, "
6014 "c.relchecks, c.relhastriggers, "
6015 "c.relhasindex, c.relhasrules, c.relhasoids, "
6016 "'f'::bool AS relrowsecurity, "
6017 "'f'::bool AS relforcerowsecurity, "
6018 "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6019 "tc.relfrozenxid AS tfrozenxid, "
6021 "'p' AS relpersistence, 't' as relispopulated, "
6022 "'d' AS relreplident, c.relpages, "
6023 "NULL AS reloftype, "
6024 "d.refobjid AS owning_tab, "
6025 "d.refobjsubid AS owning_col, "
6026 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6027 "c.reloptions AS reloptions, "
6028 "tc.reloptions AS toast_reloptions, "
6029 "NULL AS changed_acl, "
6030 "NULL AS partkeydef, "
6031 "false AS ispartition, "
6032 "NULL AS partbound "
6034 "LEFT JOIN pg_depend d ON "
6035 "(c.relkind = '%c' AND "
6036 "d.classid = c.tableoid AND d.objid = c.oid AND "
6037 "d.objsubid = 0 AND "
6038 "d.refclassid = c.tableoid AND d.deptype = 'a') "
6039 "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6040 "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6044 RELKIND_RELATION, RELKIND_SEQUENCE,
6045 RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6047 else if (fout->remoteVersion >= 80200)
6050 * Left join to pick up dependency info linking sequences to their
6051 * owning column, if any (note this dependency is AUTO as of 8.2)
6053 appendPQExpBuffer(query,
6054 "SELECT c.tableoid, c.oid, c.relname, "
6055 "c.relacl, NULL as rrelacl, "
6056 "NULL AS initrelacl, NULL AS initrrelacl, "
6059 "(%s c.relowner) AS rolname, "
6060 "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
6061 "c.relhasindex, c.relhasrules, c.relhasoids, "
6062 "'f'::bool AS relrowsecurity, "
6063 "'f'::bool AS relforcerowsecurity, "
6064 "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6065 "tc.relfrozenxid AS tfrozenxid, "
6067 "'p' AS relpersistence, 't' as relispopulated, "
6068 "'d' AS relreplident, c.relpages, "
6069 "NULL AS reloftype, "
6070 "d.refobjid AS owning_tab, "
6071 "d.refobjsubid AS owning_col, "
6072 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6073 "c.reloptions AS reloptions, "
6074 "NULL AS toast_reloptions, "
6075 "NULL AS changed_acl, "
6076 "NULL AS partkeydef, "
6077 "false AS ispartition, "
6078 "NULL AS partbound "
6080 "LEFT JOIN pg_depend d ON "
6081 "(c.relkind = '%c' AND "
6082 "d.classid = c.tableoid AND d.objid = c.oid AND "
6083 "d.objsubid = 0 AND "
6084 "d.refclassid = c.tableoid AND d.deptype = 'a') "
6085 "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6086 "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6090 RELKIND_RELATION, RELKIND_SEQUENCE,
6091 RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6096 * Left join to pick up dependency info linking sequences to their
6097 * owning column, if any
6099 appendPQExpBuffer(query,
6100 "SELECT c.tableoid, c.oid, relname, "
6101 "relacl, NULL as rrelacl, "
6102 "NULL AS initrelacl, NULL AS initrrelacl, "
6103 "relkind, relnamespace, "
6104 "(%s relowner) AS rolname, "
6105 "relchecks, (reltriggers <> 0) AS relhastriggers, "
6106 "relhasindex, relhasrules, relhasoids, "
6107 "'f'::bool AS relrowsecurity, "
6108 "'f'::bool AS relforcerowsecurity, "
6109 "0 AS relfrozenxid, 0 AS relminmxid,"
6111 "0 AS tfrozenxid, 0 AS tminmxid,"
6112 "'p' AS relpersistence, 't' as relispopulated, "
6113 "'d' AS relreplident, relpages, "
6114 "NULL AS reloftype, "
6115 "d.refobjid AS owning_tab, "
6116 "d.refobjsubid AS owning_col, "
6117 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6118 "NULL AS reloptions, "
6119 "NULL AS toast_reloptions, "
6120 "NULL AS changed_acl, "
6121 "NULL AS partkeydef, "
6122 "false AS ispartition, "
6123 "NULL AS partbound "
6125 "LEFT JOIN pg_depend d ON "
6126 "(c.relkind = '%c' AND "
6127 "d.classid = c.tableoid AND d.objid = c.oid AND "
6128 "d.objsubid = 0 AND "
6129 "d.refclassid = c.tableoid AND d.deptype = 'i') "
6130 "WHERE relkind in ('%c', '%c', '%c', '%c') "
6134 RELKIND_RELATION, RELKIND_SEQUENCE,
6135 RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6138 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6140 ntups = PQntuples(res);
6145 * Extract data from result and lock dumpable tables. We do the locking
6146 * before anything else, to minimize the window wherein a table could
6147 * disappear under us.
6149 * Note that we have to save info about all tables here, even when dumping
6150 * only one, because we don't yet know which tables might be inheritance
6151 * ancestors of the target table.
6153 tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
6155 i_reltableoid = PQfnumber(res, "tableoid");
6156 i_reloid = PQfnumber(res, "oid");
6157 i_relname = PQfnumber(res, "relname");
6158 i_relnamespace = PQfnumber(res, "relnamespace");
6159 i_relacl = PQfnumber(res, "relacl");
6160 i_rrelacl = PQfnumber(res, "rrelacl");
6161 i_initrelacl = PQfnumber(res, "initrelacl");
6162 i_initrrelacl = PQfnumber(res, "initrrelacl");
6163 i_relkind = PQfnumber(res, "relkind");
6164 i_rolname = PQfnumber(res, "rolname");
6165 i_relchecks = PQfnumber(res, "relchecks");
6166 i_relhastriggers = PQfnumber(res, "relhastriggers");
6167 i_relhasindex = PQfnumber(res, "relhasindex");
6168 i_relhasrules = PQfnumber(res, "relhasrules");
6169 i_relrowsec = PQfnumber(res, "relrowsecurity");
6170 i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
6171 i_relhasoids = PQfnumber(res, "relhasoids");
6172 i_relfrozenxid = PQfnumber(res, "relfrozenxid");
6173 i_relminmxid = PQfnumber(res, "relminmxid");
6174 i_toastoid = PQfnumber(res, "toid");
6175 i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
6176 i_toastminmxid = PQfnumber(res, "tminmxid");
6177 i_relpersistence = PQfnumber(res, "relpersistence");
6178 i_relispopulated = PQfnumber(res, "relispopulated");
6179 i_relreplident = PQfnumber(res, "relreplident");
6180 i_relpages = PQfnumber(res, "relpages");
6181 i_owning_tab = PQfnumber(res, "owning_tab");
6182 i_owning_col = PQfnumber(res, "owning_col");
6183 i_reltablespace = PQfnumber(res, "reltablespace");
6184 i_reloptions = PQfnumber(res, "reloptions");
6185 i_checkoption = PQfnumber(res, "checkoption");
6186 i_toastreloptions = PQfnumber(res, "toast_reloptions");
6187 i_reloftype = PQfnumber(res, "reloftype");
6188 i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
6189 i_changed_acl = PQfnumber(res, "changed_acl");
6190 i_partkeydef = PQfnumber(res, "partkeydef");
6191 i_ispartition = PQfnumber(res, "ispartition");
6192 i_partbound = PQfnumber(res, "partbound");
6194 if (dopt->lockWaitTimeout)
6197 * Arrange to fail instead of waiting forever for a table lock.
6199 * NB: this coding assumes that the only queries issued within the
6200 * following loop are LOCK TABLEs; else the timeout may be undesirably
6201 * applied to other things too.
6203 resetPQExpBuffer(query);
6204 appendPQExpBufferStr(query, "SET statement_timeout = ");
6205 appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
6206 ExecuteSqlStatement(fout, query->data);
6209 for (i = 0; i < ntups; i++)
6211 tblinfo[i].dobj.objType = DO_TABLE;
6212 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
6213 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
6214 AssignDumpId(&tblinfo[i].dobj);
6215 tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
6216 tblinfo[i].dobj.namespace =
6218 atooid(PQgetvalue(res, i, i_relnamespace)));
6219 tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6220 tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
6221 tblinfo[i].rrelacl = pg_strdup(PQgetvalue(res, i, i_rrelacl));
6222 tblinfo[i].initrelacl = pg_strdup(PQgetvalue(res, i, i_initrelacl));
6223 tblinfo[i].initrrelacl = pg_strdup(PQgetvalue(res, i, i_initrrelacl));
6224 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
6225 tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
6226 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
6227 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
6228 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
6229 tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
6230 tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
6231 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
6232 tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
6233 tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
6234 tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
6235 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
6236 tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
6237 tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
6238 tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
6239 tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
6240 if (PQgetisnull(res, i, i_reloftype))
6241 tblinfo[i].reloftype = NULL;
6243 tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
6244 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
6245 if (PQgetisnull(res, i, i_owning_tab))
6247 tblinfo[i].owning_tab = InvalidOid;
6248 tblinfo[i].owning_col = 0;
6252 tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
6253 tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
6255 tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
6256 tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
6257 if (i_checkoption == -1 || PQgetisnull(res, i, i_checkoption))
6258 tblinfo[i].checkoption = NULL;
6260 tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
6261 tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
6263 /* other fields were zeroed above */
6266 * Decide whether we want to dump this table.
6268 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
6269 tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
6271 selectDumpableTable(&tblinfo[i], fout);
6274 * If the table-level and all column-level ACLs for this table are
6275 * unchanged, then we don't need to worry about including the ACLs for
6276 * this table. If any column-level ACLs have been changed, the
6277 * 'changed_acl' column from the query will indicate that.
6279 * This can result in a significant performance improvement in cases
6280 * where we are only looking to dump out the ACL (eg: pg_catalog).
6282 if (PQgetisnull(res, i, i_relacl) && PQgetisnull(res, i, i_rrelacl) &&
6283 PQgetisnull(res, i, i_initrelacl) &&
6284 PQgetisnull(res, i, i_initrrelacl) &&
6285 strcmp(PQgetvalue(res, i, i_changed_acl), "f") == 0)
6286 tblinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
6288 tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
6289 tblinfo[i].dummy_view = false; /* might get set during sort */
6290 tblinfo[i].postponed_def = false; /* might get set during sort */
6292 tblinfo[i].is_identity_sequence = (i_is_identity_sequence >= 0 &&
6293 strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
6295 /* Partition key string or NULL */
6296 tblinfo[i].partkeydef = pg_strdup(PQgetvalue(res, i, i_partkeydef));
6297 tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
6298 tblinfo[i].partbound = pg_strdup(PQgetvalue(res, i, i_partbound));
6301 * Read-lock target tables to make sure they aren't DROPPED or altered
6302 * in schema before we get around to dumping them.
6304 * Note that we don't explicitly lock parents of the target tables; we
6305 * assume our lock on the child is enough to prevent schema
6306 * alterations to parent tables.
6308 * NOTE: it'd be kinda nice to lock other relations too, not only
6309 * plain tables, but the backend doesn't presently allow that.
6311 * We only need to lock the table for certain components; see
6314 if (tblinfo[i].dobj.dump &&
6315 (tblinfo[i].relkind == RELKIND_RELATION ||
6316 tblinfo->relkind == RELKIND_PARTITIONED_TABLE) &&
6317 (tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK))
6319 resetPQExpBuffer(query);
6320 appendPQExpBuffer(query,
6321 "LOCK TABLE %s IN ACCESS SHARE MODE",
6322 fmtQualifiedId(fout->remoteVersion,
6323 tblinfo[i].dobj.namespace->dobj.name,
6324 tblinfo[i].dobj.name));
6325 ExecuteSqlStatement(fout, query->data);
6328 /* Emit notice if join for owner failed */
6329 if (strlen(tblinfo[i].rolname) == 0)
6330 write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
6331 tblinfo[i].dobj.name);
6334 if (dopt->lockWaitTimeout)
6336 ExecuteSqlStatement(fout, "SET statement_timeout = 0");
6341 destroyPQExpBuffer(query);
6348 * identify owned sequences and mark them as dumpable if owning table is
6350 * We used to do this in getTables(), but it's better to do it after the
6351 * index used by findTableByOid() has been set up.
6354 getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
6359 * Force sequences that are "owned" by table columns to be dumped whenever
6360 * their owning table is being dumped.
6362 for (i = 0; i < numTables; i++)
6364 TableInfo *seqinfo = &tblinfo[i];
6365 TableInfo *owning_tab;
6367 if (!OidIsValid(seqinfo->owning_tab))
6368 continue; /* not an owned sequence */
6370 owning_tab = findTableByOid(seqinfo->owning_tab);
6371 if (owning_tab == NULL)
6372 exit_horribly(NULL, "failed sanity check, parent table with OID %u of sequence with OID %u not found\n",
6373 seqinfo->owning_tab, seqinfo->dobj.catId.oid);
6376 * We need to dump the components that are being dumped for the table
6377 * and any components which the sequence is explicitly marked with.
6379 * We can't simply use the set of components which are being dumped
6380 * for the table as the table might be in an extension (and only the
6381 * non-extension components, eg: ACLs if changed, security labels, and
6382 * policies, are being dumped) while the sequence is not (and
6383 * therefore the definition and other components should also be
6386 * If the sequence is part of the extension then it should be properly
6387 * marked by checkExtensionMembership() and this will be a no-op as
6388 * the table will be equivalently marked.
6390 seqinfo->dobj.dump = seqinfo->dobj.dump | owning_tab->dobj.dump;
6392 if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
6393 seqinfo->interesting = true;
6399 * read all the inheritance information
6400 * from the system catalogs return them in the InhInfo* structure
6402 * numInherits is set to the number of pairs read in
6405 getInherits(Archive *fout, int *numInherits)
6410 PQExpBuffer query = createPQExpBuffer();
6416 /* Make sure we are in proper schema */
6417 selectSourceSchema(fout, "pg_catalog");
6420 * Find all the inheritance information, excluding implicit inheritance
6421 * via partitioning. We handle that case using getPartitions(), because
6422 * we want more information about partitions than just the parent-child
6425 appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
6427 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6429 ntups = PQntuples(res);
6431 *numInherits = ntups;
6433 inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
6435 i_inhrelid = PQfnumber(res, "inhrelid");
6436 i_inhparent = PQfnumber(res, "inhparent");
6438 for (i = 0; i < ntups; i++)
6440 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
6441 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
6446 destroyPQExpBuffer(query);
6453 * get information about every index on a dumpable table
6455 * Note: index data is not returned directly to the caller, but it
6456 * does get entered into the DumpableObject tables.
6459 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
6463 PQExpBuffer query = createPQExpBuffer();
6466 ConstraintInfo *constrinfo;
6487 for (i = 0; i < numTables; i++)
6489 TableInfo *tbinfo = &tblinfo[i];
6491 /* Only plain tables and materialized views have indexes. */
6492 if (tbinfo->relkind != RELKIND_RELATION &&
6493 tbinfo->relkind != RELKIND_MATVIEW)
6495 if (!tbinfo->hasindex)
6498 /* Ignore indexes of tables whose definitions are not to be dumped */
6499 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
6503 write_msg(NULL, "reading indexes for table \"%s.%s\"\n",
6504 tbinfo->dobj.namespace->dobj.name,
6507 /* Make sure we are in proper schema so indexdef is right */
6508 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
6511 * The point of the messy-looking outer join is to find a constraint
6512 * that is related by an internal dependency link to the index. If we
6513 * find one, create a CONSTRAINT entry linked to the INDEX entry. We
6514 * assume an index won't have more than one internal dependency.
6516 * As of 9.0 we don't need to look at pg_depend but can check for a
6517 * match to pg_constraint.conindid. The check on conrelid is
6518 * redundant but useful because that column is indexed while conindid
6521 resetPQExpBuffer(query);
6522 if (fout->remoteVersion >= 90400)
6525 * the test on indisready is necessary in 9.2, and harmless in
6526 * earlier/later versions
6528 appendPQExpBuffer(query,
6529 "SELECT t.tableoid, t.oid, "
6530 "t.relname AS indexname, "
6531 "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6532 "t.relnatts AS indnkeys, "
6533 "i.indkey, i.indisclustered, "
6534 "i.indisreplident, t.relpages, "
6535 "c.contype, c.conname, "
6536 "c.condeferrable, c.condeferred, "
6537 "c.tableoid AS contableoid, "
6539 "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6540 "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6541 "t.reloptions AS indreloptions "
6542 "FROM pg_catalog.pg_index i "
6543 "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6544 "LEFT JOIN pg_catalog.pg_constraint c "
6545 "ON (i.indrelid = c.conrelid AND "
6546 "i.indexrelid = c.conindid AND "
6547 "c.contype IN ('p','u','x')) "
6548 "WHERE i.indrelid = '%u'::pg_catalog.oid "
6549 "AND i.indisvalid AND i.indisready "
6550 "ORDER BY indexname",
6551 tbinfo->dobj.catId.oid);
6553 else if (fout->remoteVersion >= 90000)
6556 * the test on indisready is necessary in 9.2, and harmless in
6557 * earlier/later versions
6559 appendPQExpBuffer(query,
6560 "SELECT t.tableoid, t.oid, "
6561 "t.relname AS indexname, "
6562 "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6563 "t.relnatts AS indnkeys, "
6564 "i.indkey, i.indisclustered, "
6565 "false AS indisreplident, t.relpages, "
6566 "c.contype, c.conname, "
6567 "c.condeferrable, c.condeferred, "
6568 "c.tableoid AS contableoid, "
6570 "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6571 "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6572 "t.reloptions AS indreloptions "
6573 "FROM pg_catalog.pg_index i "
6574 "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6575 "LEFT JOIN pg_catalog.pg_constraint c "
6576 "ON (i.indrelid = c.conrelid AND "
6577 "i.indexrelid = c.conindid AND "
6578 "c.contype IN ('p','u','x')) "
6579 "WHERE i.indrelid = '%u'::pg_catalog.oid "
6580 "AND i.indisvalid AND i.indisready "
6581 "ORDER BY indexname",
6582 tbinfo->dobj.catId.oid);
6584 else if (fout->remoteVersion >= 80200)
6586 appendPQExpBuffer(query,
6587 "SELECT t.tableoid, t.oid, "
6588 "t.relname AS indexname, "
6589 "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6590 "t.relnatts AS indnkeys, "
6591 "i.indkey, i.indisclustered, "
6592 "false AS indisreplident, t.relpages, "
6593 "c.contype, c.conname, "
6594 "c.condeferrable, c.condeferred, "
6595 "c.tableoid AS contableoid, "
6598 "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6599 "t.reloptions AS indreloptions "
6600 "FROM pg_catalog.pg_index i "
6601 "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6602 "LEFT JOIN pg_catalog.pg_depend d "
6603 "ON (d.classid = t.tableoid "
6604 "AND d.objid = t.oid "
6605 "AND d.deptype = 'i') "
6606 "LEFT JOIN pg_catalog.pg_constraint c "
6607 "ON (d.refclassid = c.tableoid "
6608 "AND d.refobjid = c.oid) "
6609 "WHERE i.indrelid = '%u'::pg_catalog.oid "
6611 "ORDER BY indexname",
6612 tbinfo->dobj.catId.oid);
6616 appendPQExpBuffer(query,
6617 "SELECT t.tableoid, t.oid, "
6618 "t.relname AS indexname, "
6619 "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6620 "t.relnatts AS indnkeys, "
6621 "i.indkey, i.indisclustered, "
6622 "false AS indisreplident, t.relpages, "
6623 "c.contype, c.conname, "
6624 "c.condeferrable, c.condeferred, "
6625 "c.tableoid AS contableoid, "
6628 "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6629 "null AS indreloptions "
6630 "FROM pg_catalog.pg_index i "
6631 "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6632 "LEFT JOIN pg_catalog.pg_depend d "
6633 "ON (d.classid = t.tableoid "
6634 "AND d.objid = t.oid "
6635 "AND d.deptype = 'i') "
6636 "LEFT JOIN pg_catalog.pg_constraint c "
6637 "ON (d.refclassid = c.tableoid "
6638 "AND d.refobjid = c.oid) "
6639 "WHERE i.indrelid = '%u'::pg_catalog.oid "
6640 "ORDER BY indexname",
6641 tbinfo->dobj.catId.oid);
6644 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6646 ntups = PQntuples(res);
6648 i_tableoid = PQfnumber(res, "tableoid");
6649 i_oid = PQfnumber(res, "oid");
6650 i_indexname = PQfnumber(res, "indexname");
6651 i_indexdef = PQfnumber(res, "indexdef");
6652 i_indnkeys = PQfnumber(res, "indnkeys");
6653 i_indkey = PQfnumber(res, "indkey");
6654 i_indisclustered = PQfnumber(res, "indisclustered");
6655 i_indisreplident = PQfnumber(res, "indisreplident");
6656 i_relpages = PQfnumber(res, "relpages");
6657 i_contype = PQfnumber(res, "contype");
6658 i_conname = PQfnumber(res, "conname");
6659 i_condeferrable = PQfnumber(res, "condeferrable");
6660 i_condeferred = PQfnumber(res, "condeferred");
6661 i_contableoid = PQfnumber(res, "contableoid");
6662 i_conoid = PQfnumber(res, "conoid");
6663 i_condef = PQfnumber(res, "condef");
6664 i_tablespace = PQfnumber(res, "tablespace");
6665 i_indreloptions = PQfnumber(res, "indreloptions");
6667 indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
6668 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
6670 for (j = 0; j < ntups; j++)
6674 indxinfo[j].dobj.objType = DO_INDEX;
6675 indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
6676 indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
6677 AssignDumpId(&indxinfo[j].dobj);
6678 indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
6679 indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
6680 indxinfo[j].indextable = tbinfo;
6681 indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
6682 indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
6683 indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
6684 indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
6685 indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnkeys * sizeof(Oid));
6686 parseOidArray(PQgetvalue(res, j, i_indkey),
6687 indxinfo[j].indkeys, indxinfo[j].indnkeys);
6688 indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
6689 indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
6690 indxinfo[j].relpages = atoi(PQgetvalue(res, j, i_relpages));
6691 contype = *(PQgetvalue(res, j, i_contype));
6693 if (contype == 'p' || contype == 'u' || contype == 'x')
6696 * If we found a constraint matching the index, create an
6699 constrinfo[j].dobj.objType = DO_CONSTRAINT;
6700 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
6701 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
6702 AssignDumpId(&constrinfo[j].dobj);
6703 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
6704 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
6705 constrinfo[j].contable = tbinfo;
6706 constrinfo[j].condomain = NULL;
6707 constrinfo[j].contype = contype;
6709 constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
6711 constrinfo[j].condef = NULL;
6712 constrinfo[j].confrelid = InvalidOid;
6713 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
6714 constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
6715 constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
6716 constrinfo[j].conislocal = true;
6717 constrinfo[j].separate = true;
6719 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
6723 /* Plain secondary index */
6724 indxinfo[j].indexconstraint = 0;
6731 destroyPQExpBuffer(query);
6735 * getExtendedStatistics
6736 * get information about extended statistics on a dumpable table
6737 * or materialized view.
6739 * Note: extended statistics data is not returned directly to the caller, but
6740 * it does get entered into the DumpableObject tables.
6743 getExtendedStatistics(Archive *fout, TableInfo tblinfo[], int numTables)
6749 StatsExtInfo *statsextinfo;
6756 /* Extended statistics were new in v10 */
6757 if (fout->remoteVersion < 100000)
6760 query = createPQExpBuffer();
6762 for (i = 0; i < numTables; i++)
6764 TableInfo *tbinfo = &tblinfo[i];
6767 * Only plain tables, materialized views, foreign tables and
6768 * partitioned tables can have extended statistics.
6770 if (tbinfo->relkind != RELKIND_RELATION &&
6771 tbinfo->relkind != RELKIND_MATVIEW &&
6772 tbinfo->relkind != RELKIND_FOREIGN_TABLE &&
6773 tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
6777 * Ignore extended statistics of tables whose definitions are not to
6780 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
6784 write_msg(NULL, "reading extended statistics for table \"%s.%s\"\n",
6785 tbinfo->dobj.namespace->dobj.name,
6788 /* Make sure we are in proper schema so stadef is right */
6789 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
6791 resetPQExpBuffer(query);
6793 appendPQExpBuffer(query,
6798 "pg_catalog.pg_get_statisticsobjdef(oid) AS stxdef "
6799 "FROM pg_statistic_ext "
6800 "WHERE stxrelid = '%u' "
6801 "ORDER BY stxname", tbinfo->dobj.catId.oid);
6803 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6805 ntups = PQntuples(res);
6807 i_tableoid = PQfnumber(res, "tableoid");
6808 i_oid = PQfnumber(res, "oid");
6809 i_stxname = PQfnumber(res, "stxname");
6810 i_stxdef = PQfnumber(res, "stxdef");
6812 statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
6814 for (j = 0; j < ntups; j++)
6816 statsextinfo[j].dobj.objType = DO_STATSEXT;
6817 statsextinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
6818 statsextinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
6819 AssignDumpId(&statsextinfo[j].dobj);
6820 statsextinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_stxname));
6821 statsextinfo[j].dobj.namespace = tbinfo->dobj.namespace;
6822 statsextinfo[j].statsexttable = tbinfo;
6823 statsextinfo[j].statsextdef = pg_strdup(PQgetvalue(res, j, i_stxdef));
6829 destroyPQExpBuffer(query);
6835 * Get info about constraints on dumpable tables.
6837 * Currently handles foreign keys only.
6838 * Unique and primary key constraints are handled with indexes,
6839 * while check constraints are processed in getTableAttrs().
6842 getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
6846 ConstraintInfo *constrinfo;
6856 query = createPQExpBuffer();
6858 for (i = 0; i < numTables; i++)
6860 TableInfo *tbinfo = &tblinfo[i];
6862 if (!tbinfo->hastriggers ||
6863 !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
6867 write_msg(NULL, "reading foreign key constraints for table \"%s.%s\"\n",
6868 tbinfo->dobj.namespace->dobj.name,
6872 * select table schema to ensure constraint expr is qualified if
6875 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
6877 resetPQExpBuffer(query);
6878 appendPQExpBuffer(query,
6879 "SELECT tableoid, oid, conname, confrelid, "
6880 "pg_catalog.pg_get_constraintdef(oid) AS condef "
6881 "FROM pg_catalog.pg_constraint "
6882 "WHERE conrelid = '%u'::pg_catalog.oid "
6883 "AND contype = 'f'",
6884 tbinfo->dobj.catId.oid);
6885 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6887 ntups = PQntuples(res);
6889 i_contableoid = PQfnumber(res, "tableoid");
6890 i_conoid = PQfnumber(res, "oid");
6891 i_conname = PQfnumber(res, "conname");
6892 i_confrelid = PQfnumber(res, "confrelid");
6893 i_condef = PQfnumber(res, "condef");
6895 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
6897 for (j = 0; j < ntups; j++)
6899 constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
6900 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
6901 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
6902 AssignDumpId(&constrinfo[j].dobj);
6903 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
6904 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
6905 constrinfo[j].contable = tbinfo;
6906 constrinfo[j].condomain = NULL;
6907 constrinfo[j].contype = 'f';
6908 constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
6909 constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
6910 constrinfo[j].conindex = 0;
6911 constrinfo[j].condeferrable = false;
6912 constrinfo[j].condeferred = false;
6913 constrinfo[j].conislocal = true;
6914 constrinfo[j].separate = true;
6920 destroyPQExpBuffer(query);
6924 * getDomainConstraints
6926 * Get info about constraints on a domain.
6929 getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
6932 ConstraintInfo *constrinfo;
6942 * select appropriate schema to ensure names in constraint are properly
6945 selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
6947 query = createPQExpBuffer();
6949 if (fout->remoteVersion >= 90100)
6950 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
6951 "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6953 "FROM pg_catalog.pg_constraint "
6954 "WHERE contypid = '%u'::pg_catalog.oid "
6956 tyinfo->dobj.catId.oid);
6959 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
6960 "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6961 "true as convalidated "
6962 "FROM pg_catalog.pg_constraint "
6963 "WHERE contypid = '%u'::pg_catalog.oid "
6965 tyinfo->dobj.catId.oid);
6967 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6969 ntups = PQntuples(res);
6971 i_tableoid = PQfnumber(res, "tableoid");
6972 i_oid = PQfnumber(res, "oid");
6973 i_conname = PQfnumber(res, "conname");
6974 i_consrc = PQfnumber(res, "consrc");
6976 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
6978 tyinfo->nDomChecks = ntups;
6979 tyinfo->domChecks = constrinfo;
6981 for (i = 0; i < ntups; i++)
6983 bool validated = PQgetvalue(res, i, 4)[0] == 't';
6985 constrinfo[i].dobj.objType = DO_CONSTRAINT;
6986 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6987 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6988 AssignDumpId(&constrinfo[i].dobj);
6989 constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
6990 constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
6991 constrinfo[i].contable = NULL;
6992 constrinfo[i].condomain = tyinfo;
6993 constrinfo[i].contype = 'c';
6994 constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
6995 constrinfo[i].confrelid = InvalidOid;
6996 constrinfo[i].conindex = 0;
6997 constrinfo[i].condeferrable = false;
6998 constrinfo[i].condeferred = false;
6999 constrinfo[i].conislocal = true;
7001 constrinfo[i].separate = !validated;
7004 * Make the domain depend on the constraint, ensuring it won't be
7005 * output till any constraint dependencies are OK. If the constraint
7006 * has not been validated, it's going to be dumped after the domain
7007 * anyway, so this doesn't matter.
7010 addObjectDependency(&tyinfo->dobj,
7011 constrinfo[i].dobj.dumpId);
7016 destroyPQExpBuffer(query);
7021 * get basic information about every rule in the system
7023 * numRules is set to the number of rules read in
7026 getRules(Archive *fout, int *numRules)
7031 PQExpBuffer query = createPQExpBuffer();
7041 /* Make sure we are in proper schema */
7042 selectSourceSchema(fout, "pg_catalog");
7044 if (fout->remoteVersion >= 80300)
7046 appendPQExpBufferStr(query, "SELECT "
7047 "tableoid, oid, rulename, "
7048 "ev_class AS ruletable, ev_type, is_instead, "
7055 appendPQExpBufferStr(query, "SELECT "
7056 "tableoid, oid, rulename, "
7057 "ev_class AS ruletable, ev_type, is_instead, "
7058 "'O'::char AS ev_enabled "
7063 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7065 ntups = PQntuples(res);
7069 ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
7071 i_tableoid = PQfnumber(res, "tableoid");
7072 i_oid = PQfnumber(res, "oid");
7073 i_rulename = PQfnumber(res, "rulename");
7074 i_ruletable = PQfnumber(res, "ruletable");
7075 i_ev_type = PQfnumber(res, "ev_type");
7076 i_is_instead = PQfnumber(res, "is_instead");
7077 i_ev_enabled = PQfnumber(res, "ev_enabled");
7079 for (i = 0; i < ntups; i++)
7083 ruleinfo[i].dobj.objType = DO_RULE;
7084 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7085 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7086 AssignDumpId(&ruleinfo[i].dobj);
7087 ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
7088 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
7089 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
7090 if (ruleinfo[i].ruletable == NULL)
7091 exit_horribly(NULL, "failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found\n",
7092 ruletableoid, ruleinfo[i].dobj.catId.oid);
7093 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
7094 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
7095 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
7096 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
7097 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
7098 if (ruleinfo[i].ruletable)
7101 * If the table is a view or materialized view, force its ON
7102 * SELECT rule to be sorted before the view itself --- this
7103 * ensures that any dependencies for the rule affect the table's
7104 * positioning. Other rules are forced to appear after their
7107 if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
7108 ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
7109 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
7111 addObjectDependency(&ruleinfo[i].ruletable->dobj,
7112 ruleinfo[i].dobj.dumpId);
7113 /* We'll merge the rule into CREATE VIEW, if possible */
7114 ruleinfo[i].separate = false;
7118 addObjectDependency(&ruleinfo[i].dobj,
7119 ruleinfo[i].ruletable->dobj.dumpId);
7120 ruleinfo[i].separate = true;
7124 ruleinfo[i].separate = true;
7129 destroyPQExpBuffer(query);
7136 * get information about every trigger on a dumpable table
7138 * Note: trigger data is not returned directly to the caller, but it
7139 * does get entered into the DumpableObject tables.
7142 getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
7146 PQExpBuffer query = createPQExpBuffer();
7148 TriggerInfo *tginfo;
7166 for (i = 0; i < numTables; i++)
7168 TableInfo *tbinfo = &tblinfo[i];
7170 if (!tbinfo->hastriggers ||
7171 !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7175 write_msg(NULL, "reading triggers for table \"%s.%s\"\n",
7176 tbinfo->dobj.namespace->dobj.name,
7180 * select table schema to ensure regproc name is qualified if needed
7182 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
7184 resetPQExpBuffer(query);
7185 if (fout->remoteVersion >= 90000)
7188 * NB: think not to use pretty=true in pg_get_triggerdef. It
7189 * could result in non-forward-compatible dumps of WHEN clauses
7190 * due to under-parenthesization.
7192 appendPQExpBuffer(query,
7194 "tgfoid::pg_catalog.regproc AS tgfname, "
7195 "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
7196 "tgenabled, tableoid, oid "
7197 "FROM pg_catalog.pg_trigger t "
7198 "WHERE tgrelid = '%u'::pg_catalog.oid "
7199 "AND NOT tgisinternal",
7200 tbinfo->dobj.catId.oid);
7202 else if (fout->remoteVersion >= 80300)
7205 * We ignore triggers that are tied to a foreign-key constraint
7207 appendPQExpBuffer(query,
7209 "tgfoid::pg_catalog.regproc AS tgfname, "
7210 "tgtype, tgnargs, tgargs, tgenabled, "
7211 "tgisconstraint, tgconstrname, tgdeferrable, "
7212 "tgconstrrelid, tginitdeferred, tableoid, oid, "
7213 "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
7214 "FROM pg_catalog.pg_trigger t "
7215 "WHERE tgrelid = '%u'::pg_catalog.oid "
7216 "AND tgconstraint = 0",
7217 tbinfo->dobj.catId.oid);
7222 * We ignore triggers that are tied to a foreign-key constraint,
7223 * but in these versions we have to grovel through pg_constraint
7226 appendPQExpBuffer(query,
7228 "tgfoid::pg_catalog.regproc AS tgfname, "
7229 "tgtype, tgnargs, tgargs, tgenabled, "
7230 "tgisconstraint, tgconstrname, tgdeferrable, "
7231 "tgconstrrelid, tginitdeferred, tableoid, oid, "
7232 "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
7233 "FROM pg_catalog.pg_trigger t "
7234 "WHERE tgrelid = '%u'::pg_catalog.oid "
7235 "AND (NOT tgisconstraint "
7237 " (SELECT 1 FROM pg_catalog.pg_depend d "
7238 " JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
7239 " WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
7240 tbinfo->dobj.catId.oid);
7243 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7245 ntups = PQntuples(res);
7247 i_tableoid = PQfnumber(res, "tableoid");
7248 i_oid = PQfnumber(res, "oid");
7249 i_tgname = PQfnumber(res, "tgname");
7250 i_tgfname = PQfnumber(res, "tgfname");
7251 i_tgtype = PQfnumber(res, "tgtype");
7252 i_tgnargs = PQfnumber(res, "tgnargs");
7253 i_tgargs = PQfnumber(res, "tgargs");
7254 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
7255 i_tgconstrname = PQfnumber(res, "tgconstrname");
7256 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
7257 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
7258 i_tgenabled = PQfnumber(res, "tgenabled");
7259 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
7260 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
7261 i_tgdef = PQfnumber(res, "tgdef");
7263 tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
7265 tbinfo->numTriggers = ntups;
7266 tbinfo->triggers = tginfo;
7268 for (j = 0; j < ntups; j++)
7270 tginfo[j].dobj.objType = DO_TRIGGER;
7271 tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
7272 tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7273 AssignDumpId(&tginfo[j].dobj);
7274 tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
7275 tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
7276 tginfo[j].tgtable = tbinfo;
7277 tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
7280 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
7282 /* remaining fields are not valid if we have tgdef */
7283 tginfo[j].tgfname = NULL;
7284 tginfo[j].tgtype = 0;
7285 tginfo[j].tgnargs = 0;
7286 tginfo[j].tgargs = NULL;
7287 tginfo[j].tgisconstraint = false;
7288 tginfo[j].tgdeferrable = false;
7289 tginfo[j].tginitdeferred = false;
7290 tginfo[j].tgconstrname = NULL;
7291 tginfo[j].tgconstrrelid = InvalidOid;
7292 tginfo[j].tgconstrrelname = NULL;
7296 tginfo[j].tgdef = NULL;
7298 tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
7299 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
7300 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
7301 tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
7302 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
7303 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
7304 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
7306 if (tginfo[j].tgisconstraint)
7308 tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
7309 tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
7310 if (OidIsValid(tginfo[j].tgconstrrelid))
7312 if (PQgetisnull(res, j, i_tgconstrrelname))
7313 exit_horribly(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
7314 tginfo[j].dobj.name,
7316 tginfo[j].tgconstrrelid);
7317 tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
7320 tginfo[j].tgconstrrelname = NULL;
7324 tginfo[j].tgconstrname = NULL;
7325 tginfo[j].tgconstrrelid = InvalidOid;
7326 tginfo[j].tgconstrrelname = NULL;
7334 destroyPQExpBuffer(query);
7339 * get information about event triggers
7342 getEventTriggers(Archive *fout, int *numEventTriggers)
7347 EventTriggerInfo *evtinfo;
7358 /* Before 9.3, there are no event triggers */
7359 if (fout->remoteVersion < 90300)
7361 *numEventTriggers = 0;
7365 query = createPQExpBuffer();
7367 /* Make sure we are in proper schema */
7368 selectSourceSchema(fout, "pg_catalog");
7370 appendPQExpBuffer(query,
7371 "SELECT e.tableoid, e.oid, evtname, evtenabled, "
7372 "evtevent, (%s evtowner) AS evtowner, "
7373 "array_to_string(array("
7374 "select quote_literal(x) "
7375 " from unnest(evttags) as t(x)), ', ') as evttags, "
7376 "e.evtfoid::regproc as evtfname "
7377 "FROM pg_event_trigger e "
7381 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7383 ntups = PQntuples(res);
7385 *numEventTriggers = ntups;
7387 evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
7389 i_tableoid = PQfnumber(res, "tableoid");
7390 i_oid = PQfnumber(res, "oid");
7391 i_evtname = PQfnumber(res, "evtname");
7392 i_evtevent = PQfnumber(res, "evtevent");
7393 i_evtowner = PQfnumber(res, "evtowner");
7394 i_evttags = PQfnumber(res, "evttags");
7395 i_evtfname = PQfnumber(res, "evtfname");
7396 i_evtenabled = PQfnumber(res, "evtenabled");
7398 for (i = 0; i < ntups; i++)
7400 evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
7401 evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7402 evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7403 AssignDumpId(&evtinfo[i].dobj);
7404 evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
7405 evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
7406 evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
7407 evtinfo[i].evtowner = pg_strdup(PQgetvalue(res, i, i_evtowner));
7408 evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
7409 evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
7410 evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
7412 /* Decide whether we want to dump it */
7413 selectDumpableObject(&(evtinfo[i].dobj), fout);
7415 /* Event Triggers do not currently have ACLs. */
7416 evtinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7421 destroyPQExpBuffer(query);
7428 * get basic information about every procedural language in the system
7430 * numProcLangs is set to the number of langs read in
7432 * NB: this must run after getFuncs() because we assume we can do
7436 getProcLangs(Archive *fout, int *numProcLangs)
7438 DumpOptions *dopt = fout->dopt;
7442 PQExpBuffer query = createPQExpBuffer();
7443 ProcLangInfo *planginfo;
7448 int i_lanplcallfoid;
7457 /* Make sure we are in proper schema */
7458 selectSourceSchema(fout, "pg_catalog");
7460 if (fout->remoteVersion >= 90600)
7462 PQExpBuffer acl_subquery = createPQExpBuffer();
7463 PQExpBuffer racl_subquery = createPQExpBuffer();
7464 PQExpBuffer initacl_subquery = createPQExpBuffer();
7465 PQExpBuffer initracl_subquery = createPQExpBuffer();
7467 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
7468 initracl_subquery, "l.lanacl", "l.lanowner", "'l'",
7469 dopt->binary_upgrade);
7471 /* pg_language has a laninline column */
7472 appendPQExpBuffer(query, "SELECT l.tableoid, l.oid, "
7473 "l.lanname, l.lanpltrusted, l.lanplcallfoid, "
7474 "l.laninline, l.lanvalidator, "
7477 "%s AS initlanacl, "
7478 "%s AS initrlanacl, "
7479 "(%s l.lanowner) AS lanowner "
7480 "FROM pg_language l "
7481 "LEFT JOIN pg_init_privs pip ON "
7482 "(l.oid = pip.objoid "
7483 "AND pip.classoid = 'pg_language'::regclass "
7484 "AND pip.objsubid = 0) "
7488 racl_subquery->data,
7489 initacl_subquery->data,
7490 initracl_subquery->data,
7493 destroyPQExpBuffer(acl_subquery);
7494 destroyPQExpBuffer(racl_subquery);
7495 destroyPQExpBuffer(initacl_subquery);
7496 destroyPQExpBuffer(initracl_subquery);
7498 else if (fout->remoteVersion >= 90000)
7500 /* pg_language has a laninline column */
7501 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7502 "lanname, lanpltrusted, lanplcallfoid, "
7503 "laninline, lanvalidator, lanacl, NULL AS rlanacl, "
7504 "NULL AS initlanacl, NULL AS initrlanacl, "
7505 "(%s lanowner) AS lanowner "
7511 else if (fout->remoteVersion >= 80300)
7513 /* pg_language has a lanowner column */
7514 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7515 "lanname, lanpltrusted, lanplcallfoid, "
7516 "0 AS laninline, lanvalidator, lanacl, "
7518 "NULL AS initlanacl, NULL AS initrlanacl, "
7519 "(%s lanowner) AS lanowner "
7525 else if (fout->remoteVersion >= 80100)
7527 /* Languages are owned by the bootstrap superuser, OID 10 */
7528 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7529 "lanname, lanpltrusted, lanplcallfoid, "
7530 "0 AS laninline, lanvalidator, lanacl, "
7532 "NULL AS initlanacl, NULL AS initrlanacl, "
7533 "(%s '10') AS lanowner "
7541 /* Languages are owned by the bootstrap superuser, sysid 1 */
7542 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7543 "lanname, lanpltrusted, lanplcallfoid, "
7544 "0 AS laninline, lanvalidator, lanacl, "
7546 "NULL AS initlanacl, NULL AS initrlanacl, "
7547 "(%s '1') AS lanowner "
7554 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7556 ntups = PQntuples(res);
7558 *numProcLangs = ntups;
7560 planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
7562 i_tableoid = PQfnumber(res, "tableoid");
7563 i_oid = PQfnumber(res, "oid");
7564 i_lanname = PQfnumber(res, "lanname");
7565 i_lanpltrusted = PQfnumber(res, "lanpltrusted");
7566 i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
7567 i_laninline = PQfnumber(res, "laninline");
7568 i_lanvalidator = PQfnumber(res, "lanvalidator");
7569 i_lanacl = PQfnumber(res, "lanacl");
7570 i_rlanacl = PQfnumber(res, "rlanacl");
7571 i_initlanacl = PQfnumber(res, "initlanacl");
7572 i_initrlanacl = PQfnumber(res, "initrlanacl");
7573 i_lanowner = PQfnumber(res, "lanowner");
7575 for (i = 0; i < ntups; i++)
7577 planginfo[i].dobj.objType = DO_PROCLANG;
7578 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7579 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7580 AssignDumpId(&planginfo[i].dobj);
7582 planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
7583 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
7584 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
7585 planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
7586 planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
7587 planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
7588 planginfo[i].rlanacl = pg_strdup(PQgetvalue(res, i, i_rlanacl));
7589 planginfo[i].initlanacl = pg_strdup(PQgetvalue(res, i, i_initlanacl));
7590 planginfo[i].initrlanacl = pg_strdup(PQgetvalue(res, i, i_initrlanacl));
7591 planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
7593 /* Decide whether we want to dump it */
7594 selectDumpableProcLang(&(planginfo[i]), fout);
7596 /* Do not try to dump ACL if no ACL exists. */
7597 if (PQgetisnull(res, i, i_lanacl) && PQgetisnull(res, i, i_rlanacl) &&
7598 PQgetisnull(res, i, i_initlanacl) &&
7599 PQgetisnull(res, i, i_initrlanacl))
7600 planginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7605 destroyPQExpBuffer(query);
7612 * get basic information about every cast in the system
7614 * numCasts is set to the number of casts read in
7617 getCasts(Archive *fout, int *numCasts)
7622 PQExpBuffer query = createPQExpBuffer();
7632 /* Make sure we are in proper schema */
7633 selectSourceSchema(fout, "pg_catalog");
7635 if (fout->remoteVersion >= 80400)
7637 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
7638 "castsource, casttarget, castfunc, castcontext, "
7640 "FROM pg_cast ORDER BY 3,4");
7644 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
7645 "castsource, casttarget, castfunc, castcontext, "
7646 "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
7647 "FROM pg_cast ORDER BY 3,4");
7650 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7652 ntups = PQntuples(res);
7656 castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
7658 i_tableoid = PQfnumber(res, "tableoid");
7659 i_oid = PQfnumber(res, "oid");
7660 i_castsource = PQfnumber(res, "castsource");
7661 i_casttarget = PQfnumber(res, "casttarget");
7662 i_castfunc = PQfnumber(res, "castfunc");
7663 i_castcontext = PQfnumber(res, "castcontext");
7664 i_castmethod = PQfnumber(res, "castmethod");
7666 for (i = 0; i < ntups; i++)
7668 PQExpBufferData namebuf;
7669 TypeInfo *sTypeInfo;
7670 TypeInfo *tTypeInfo;
7672 castinfo[i].dobj.objType = DO_CAST;
7673 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7674 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7675 AssignDumpId(&castinfo[i].dobj);
7676 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
7677 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
7678 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
7679 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
7680 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
7683 * Try to name cast as concatenation of typnames. This is only used
7684 * for purposes of sorting. If we fail to find either type, the name
7685 * will be an empty string.
7687 initPQExpBuffer(&namebuf);
7688 sTypeInfo = findTypeByOid(castinfo[i].castsource);
7689 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
7690 if (sTypeInfo && tTypeInfo)
7691 appendPQExpBuffer(&namebuf, "%s %s",
7692 sTypeInfo->dobj.name, tTypeInfo->dobj.name);
7693 castinfo[i].dobj.name = namebuf.data;
7695 /* Decide whether we want to dump it */
7696 selectDumpableCast(&(castinfo[i]), fout);
7698 /* Casts do not currently have ACLs. */
7699 castinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7704 destroyPQExpBuffer(query);
7710 get_language_name(Archive *fout, Oid langid)
7716 query = createPQExpBuffer();
7717 appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
7718 res = ExecuteSqlQueryForSingleRow(fout, query->data);
7719 lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
7720 destroyPQExpBuffer(query);
7728 * get basic information about every transform in the system
7730 * numTransforms is set to the number of transforms read in
7733 getTransforms(Archive *fout, int *numTransforms)
7739 TransformInfo *transforminfo;
7747 /* Transforms didn't exist pre-9.5 */
7748 if (fout->remoteVersion < 90500)
7754 query = createPQExpBuffer();
7756 /* Make sure we are in proper schema */
7757 selectSourceSchema(fout, "pg_catalog");
7759 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7760 "trftype, trflang, trffromsql::oid, trftosql::oid "
7761 "FROM pg_transform "
7764 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7766 ntups = PQntuples(res);
7768 *numTransforms = ntups;
7770 transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
7772 i_tableoid = PQfnumber(res, "tableoid");
7773 i_oid = PQfnumber(res, "oid");
7774 i_trftype = PQfnumber(res, "trftype");
7775 i_trflang = PQfnumber(res, "trflang");
7776 i_trffromsql = PQfnumber(res, "trffromsql");
7777 i_trftosql = PQfnumber(res, "trftosql");
7779 for (i = 0; i < ntups; i++)
7781 PQExpBufferData namebuf;
7785 transforminfo[i].dobj.objType = DO_TRANSFORM;
7786 transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7787 transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7788 AssignDumpId(&transforminfo[i].dobj);
7789 transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
7790 transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
7791 transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
7792 transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
7795 * Try to name transform as concatenation of type and language name.
7796 * This is only used for purposes of sorting. If we fail to find
7797 * either, the name will be an empty string.
7799 initPQExpBuffer(&namebuf);
7800 typeInfo = findTypeByOid(transforminfo[i].trftype);
7801 lanname = get_language_name(fout, transforminfo[i].trflang);
7802 if (typeInfo && lanname)
7803 appendPQExpBuffer(&namebuf, "%s %s",
7804 typeInfo->dobj.name, lanname);
7805 transforminfo[i].dobj.name = namebuf.data;
7808 /* Decide whether we want to dump it */
7809 selectDumpableObject(&(transforminfo[i].dobj), fout);
7814 destroyPQExpBuffer(query);
7816 return transforminfo;
7821 * for each interesting table, read info about its attributes
7822 * (names, types, default values, CHECK constraints, etc)
7824 * This is implemented in a very inefficient way right now, looping
7825 * through the tblinfo and doing a join per table to find the attrs and their
7826 * types. However, because we want type names and so forth to be named
7827 * relative to the schema of each table, we couldn't do it in just one
7828 * query. (Maybe one query per schema?)
7833 getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
7835 DumpOptions *dopt = fout->dopt;
7838 PQExpBuffer q = createPQExpBuffer();
7843 int i_attstattarget;
7855 int i_attfdwoptions;
7860 for (i = 0; i < numTables; i++)
7862 TableInfo *tbinfo = &tblinfo[i];
7864 /* Don't bother to collect info for sequences */
7865 if (tbinfo->relkind == RELKIND_SEQUENCE)
7868 /* Don't bother with uninteresting tables, either */
7869 if (!tbinfo->interesting)
7873 * Make sure we are in proper schema for this table; this allows
7874 * correct retrieval of formatted type names and default exprs
7876 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
7878 /* find all the user attributes and their types */
7881 * we must read the attribute names in attribute number order! because
7882 * we will use the attnum to index into the attnames array later.
7885 write_msg(NULL, "finding the columns and types of table \"%s.%s\"\n",
7886 tbinfo->dobj.namespace->dobj.name,
7889 resetPQExpBuffer(q);
7891 if (fout->remoteVersion >= 100000)
7894 * attidentity is new in version 10.
7896 appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
7897 "a.attstattarget, a.attstorage, t.typstorage, "
7898 "a.attnotnull, a.atthasdef, a.attisdropped, "
7899 "a.attlen, a.attalign, a.attislocal, "
7900 "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
7901 "array_to_string(a.attoptions, ', ') AS attoptions, "
7902 "CASE WHEN a.attcollation <> t.typcollation "
7903 "THEN a.attcollation ELSE 0 END AS attcollation, "
7905 "pg_catalog.array_to_string(ARRAY("
7906 "SELECT pg_catalog.quote_ident(option_name) || "
7907 "' ' || pg_catalog.quote_literal(option_value) "
7908 "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
7909 "ORDER BY option_name"
7910 "), E',\n ') AS attfdwoptions "
7911 "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
7912 "ON a.atttypid = t.oid "
7913 "WHERE a.attrelid = '%u'::pg_catalog.oid "
7914 "AND a.attnum > 0::pg_catalog.int2 "
7915 "ORDER BY a.attnum",
7916 tbinfo->dobj.catId.oid);
7918 else if (fout->remoteVersion >= 90200)
7921 * attfdwoptions is new in 9.2.
7923 appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
7924 "a.attstattarget, a.attstorage, t.typstorage, "
7925 "a.attnotnull, a.atthasdef, a.attisdropped, "
7926 "a.attlen, a.attalign, a.attislocal, "
7927 "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
7928 "array_to_string(a.attoptions, ', ') AS attoptions, "
7929 "CASE WHEN a.attcollation <> t.typcollation "
7930 "THEN a.attcollation ELSE 0 END AS attcollation, "
7931 "pg_catalog.array_to_string(ARRAY("
7932 "SELECT pg_catalog.quote_ident(option_name) || "
7933 "' ' || pg_catalog.quote_literal(option_value) "
7934 "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
7935 "ORDER BY option_name"
7936 "), E',\n ') AS attfdwoptions "
7937 "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
7938 "ON a.atttypid = t.oid "
7939 "WHERE a.attrelid = '%u'::pg_catalog.oid "
7940 "AND a.attnum > 0::pg_catalog.int2 "
7941 "ORDER BY a.attnum",
7942 tbinfo->dobj.catId.oid);
7944 else if (fout->remoteVersion >= 90100)
7947 * attcollation is new in 9.1. Since we only want to dump COLLATE
7948 * clauses for attributes whose collation is different from their
7949 * type's default, we use a CASE here to suppress uninteresting
7950 * attcollations cheaply.
7952 appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
7953 "a.attstattarget, a.attstorage, t.typstorage, "
7954 "a.attnotnull, a.atthasdef, a.attisdropped, "
7955 "a.attlen, a.attalign, a.attislocal, "
7956 "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
7957 "array_to_string(a.attoptions, ', ') AS attoptions, "
7958 "CASE WHEN a.attcollation <> t.typcollation "
7959 "THEN a.attcollation ELSE 0 END AS attcollation, "
7960 "NULL AS attfdwoptions "
7961 "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
7962 "ON a.atttypid = t.oid "
7963 "WHERE a.attrelid = '%u'::pg_catalog.oid "
7964 "AND a.attnum > 0::pg_catalog.int2 "
7965 "ORDER BY a.attnum",
7966 tbinfo->dobj.catId.oid);
7968 else if (fout->remoteVersion >= 90000)
7970 /* attoptions is new in 9.0 */
7971 appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
7972 "a.attstattarget, a.attstorage, t.typstorage, "
7973 "a.attnotnull, a.atthasdef, a.attisdropped, "
7974 "a.attlen, a.attalign, a.attislocal, "
7975 "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
7976 "array_to_string(a.attoptions, ', ') AS attoptions, "
7977 "0 AS attcollation, "
7978 "NULL AS attfdwoptions "
7979 "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
7980 "ON a.atttypid = t.oid "
7981 "WHERE a.attrelid = '%u'::pg_catalog.oid "
7982 "AND a.attnum > 0::pg_catalog.int2 "
7983 "ORDER BY a.attnum",
7984 tbinfo->dobj.catId.oid);
7988 /* need left join here to not fail on dropped columns ... */
7989 appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
7990 "a.attstattarget, a.attstorage, t.typstorage, "
7991 "a.attnotnull, a.atthasdef, a.attisdropped, "
7992 "a.attlen, a.attalign, a.attislocal, "
7993 "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
7994 "'' AS attoptions, 0 AS attcollation, "
7995 "NULL AS attfdwoptions "
7996 "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
7997 "ON a.atttypid = t.oid "
7998 "WHERE a.attrelid = '%u'::pg_catalog.oid "
7999 "AND a.attnum > 0::pg_catalog.int2 "
8000 "ORDER BY a.attnum",
8001 tbinfo->dobj.catId.oid);
8004 res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8006 ntups = PQntuples(res);
8008 i_attnum = PQfnumber(res, "attnum");
8009 i_attname = PQfnumber(res, "attname");
8010 i_atttypname = PQfnumber(res, "atttypname");
8011 i_atttypmod = PQfnumber(res, "atttypmod");
8012 i_attstattarget = PQfnumber(res, "attstattarget");
8013 i_attstorage = PQfnumber(res, "attstorage");
8014 i_typstorage = PQfnumber(res, "typstorage");
8015 i_attnotnull = PQfnumber(res, "attnotnull");
8016 i_atthasdef = PQfnumber(res, "atthasdef");
8017 i_attidentity = PQfnumber(res, "attidentity");
8018 i_attisdropped = PQfnumber(res, "attisdropped");
8019 i_attlen = PQfnumber(res, "attlen");
8020 i_attalign = PQfnumber(res, "attalign");
8021 i_attislocal = PQfnumber(res, "attislocal");
8022 i_attoptions = PQfnumber(res, "attoptions");
8023 i_attcollation = PQfnumber(res, "attcollation");
8024 i_attfdwoptions = PQfnumber(res, "attfdwoptions");
8026 tbinfo->numatts = ntups;
8027 tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
8028 tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
8029 tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
8030 tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
8031 tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
8032 tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
8033 tbinfo->attidentity = (char *) pg_malloc(ntups * sizeof(char));
8034 tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
8035 tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
8036 tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
8037 tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
8038 tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
8039 tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
8040 tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
8041 tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
8042 tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
8043 tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
8044 hasdefaults = false;
8046 for (j = 0; j < ntups; j++)
8048 if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
8050 "invalid column numbering in table \"%s\"\n",
8052 tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
8053 tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
8054 tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
8055 tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
8056 tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
8057 tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
8058 tbinfo->attidentity[j] = (i_attidentity >= 0 ? *(PQgetvalue(res, j, i_attidentity)) : '\0');
8059 tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
8060 tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
8061 tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
8062 tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
8063 tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
8064 tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
8065 tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
8066 tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
8067 tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
8068 tbinfo->attrdefs[j] = NULL; /* fix below */
8069 if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
8071 /* these flags will be set in flagInhAttrs() */
8072 tbinfo->inhNotNull[j] = false;
8078 * Get info about column defaults
8082 AttrDefInfo *attrdefs;
8086 write_msg(NULL, "finding default expressions of table \"%s.%s\"\n",
8087 tbinfo->dobj.namespace->dobj.name,
8090 printfPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
8091 "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
8092 "FROM pg_catalog.pg_attrdef "
8093 "WHERE adrelid = '%u'::pg_catalog.oid",
8094 tbinfo->dobj.catId.oid);
8096 res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8098 numDefaults = PQntuples(res);
8099 attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
8101 for (j = 0; j < numDefaults; j++)
8105 adnum = atoi(PQgetvalue(res, j, 2));
8107 if (adnum <= 0 || adnum > ntups)
8109 "invalid adnum value %d for table \"%s\"\n",
8110 adnum, tbinfo->dobj.name);
8113 * dropped columns shouldn't have defaults, but just in case,
8116 if (tbinfo->attisdropped[adnum - 1])
8119 attrdefs[j].dobj.objType = DO_ATTRDEF;
8120 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
8121 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
8122 AssignDumpId(&attrdefs[j].dobj);
8123 attrdefs[j].adtable = tbinfo;
8124 attrdefs[j].adnum = adnum;
8125 attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
8127 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
8128 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
8130 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
8133 * Defaults on a VIEW must always be dumped as separate ALTER
8134 * TABLE commands. Defaults on regular tables are dumped as
8135 * part of the CREATE TABLE if possible, which it won't be if
8136 * the column is not going to be emitted explicitly.
8138 if (tbinfo->relkind == RELKIND_VIEW)
8140 attrdefs[j].separate = true;
8142 else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
8144 /* column will be suppressed, print default separately */
8145 attrdefs[j].separate = true;
8149 attrdefs[j].separate = false;
8152 * Mark the default as needing to appear before the table,
8153 * so that any dependencies it has must be emitted before
8154 * the CREATE TABLE. If this is not possible, we'll
8155 * change to "separate" mode while sorting dependencies.
8157 addObjectDependency(&tbinfo->dobj,
8158 attrdefs[j].dobj.dumpId);
8161 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
8167 * Get info about table CHECK constraints
8169 if (tbinfo->ncheck > 0)
8171 ConstraintInfo *constrs;
8175 write_msg(NULL, "finding check constraints for table \"%s.%s\"\n",
8176 tbinfo->dobj.namespace->dobj.name,
8179 resetPQExpBuffer(q);
8180 if (fout->remoteVersion >= 90200)
8183 * convalidated is new in 9.2 (actually, it is there in 9.1,
8184 * but it wasn't ever false for check constraints until 9.2).
8186 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8187 "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8188 "conislocal, convalidated "
8189 "FROM pg_catalog.pg_constraint "
8190 "WHERE conrelid = '%u'::pg_catalog.oid "
8191 " AND contype = 'c' "
8193 tbinfo->dobj.catId.oid);
8195 else if (fout->remoteVersion >= 80400)
8197 /* conislocal is new in 8.4 */
8198 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8199 "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8200 "conislocal, true AS convalidated "
8201 "FROM pg_catalog.pg_constraint "
8202 "WHERE conrelid = '%u'::pg_catalog.oid "
8203 " AND contype = 'c' "
8205 tbinfo->dobj.catId.oid);
8209 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8210 "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8211 "true AS conislocal, true AS convalidated "
8212 "FROM pg_catalog.pg_constraint "
8213 "WHERE conrelid = '%u'::pg_catalog.oid "
8214 " AND contype = 'c' "
8216 tbinfo->dobj.catId.oid);
8219 res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8221 numConstrs = PQntuples(res);
8222 if (numConstrs != tbinfo->ncheck)
8224 write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
8225 "expected %d check constraints on table \"%s\" but found %d\n",
8227 tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
8228 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
8232 constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
8233 tbinfo->checkexprs = constrs;
8235 for (j = 0; j < numConstrs; j++)
8237 bool validated = PQgetvalue(res, j, 5)[0] == 't';
8239 constrs[j].dobj.objType = DO_CONSTRAINT;
8240 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
8241 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
8242 AssignDumpId(&constrs[j].dobj);
8243 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
8244 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
8245 constrs[j].contable = tbinfo;
8246 constrs[j].condomain = NULL;
8247 constrs[j].contype = 'c';
8248 constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
8249 constrs[j].confrelid = InvalidOid;
8250 constrs[j].conindex = 0;
8251 constrs[j].condeferrable = false;
8252 constrs[j].condeferred = false;
8253 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
8256 * An unvalidated constraint needs to be dumped separately, so
8257 * that potentially-violating existing data is loaded before
8260 constrs[j].separate = !validated;
8262 constrs[j].dobj.dump = tbinfo->dobj.dump;
8265 * Mark the constraint as needing to appear before the table
8266 * --- this is so that any other dependencies of the
8267 * constraint will be emitted before we try to create the
8268 * table. If the constraint is to be dumped separately, it
8269 * will be dumped after data is loaded anyway, so don't do it.
8270 * (There's an automatic dependency in the opposite direction
8271 * anyway, so don't need to add one manually here.)
8273 if (!constrs[j].separate)
8274 addObjectDependency(&tbinfo->dobj,
8275 constrs[j].dobj.dumpId);
8278 * If the constraint is inherited, this will be detected later
8279 * (in pre-8.4 databases). We also detect later if the
8280 * constraint must be split out from the table definition.
8287 destroyPQExpBuffer(q);
8291 * Test whether a column should be printed as part of table's CREATE TABLE.
8292 * Column number is zero-based.
8294 * Normally this is always true, but it's false for dropped columns, as well
8295 * as those that were inherited without any local definition. (If we print
8296 * such a column it will mistakenly get pg_attribute.attislocal set to true.)
8297 * However, in binary_upgrade mode, we must print all such columns anyway and
8298 * fix the attislocal/attisdropped state later, so as to keep control of the
8299 * physical column order.
8301 * This function exists because there are scattered nonobvious places that
8302 * must be kept in sync with this decision.
8305 shouldPrintColumn(DumpOptions *dopt, TableInfo *tbinfo, int colno)
8307 if (dopt->binary_upgrade)
8309 return (tbinfo->attislocal[colno] && !tbinfo->attisdropped[colno]);
8315 * read all text search parsers in the system catalogs and return them
8316 * in the TSParserInfo* structure
8318 * numTSParsers is set to the number of parsers read in
8321 getTSParsers(Archive *fout, int *numTSParsers)
8327 TSParserInfo *prsinfo;
8338 /* Before 8.3, there is no built-in text search support */
8339 if (fout->remoteVersion < 80300)
8345 query = createPQExpBuffer();
8348 * find all text search objects, including builtin ones; we filter out
8349 * system-defined objects at dump-out time.
8352 /* Make sure we are in proper schema */
8353 selectSourceSchema(fout, "pg_catalog");
8355 appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
8356 "prsstart::oid, prstoken::oid, "
8357 "prsend::oid, prsheadline::oid, prslextype::oid "
8358 "FROM pg_ts_parser");
8360 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8362 ntups = PQntuples(res);
8363 *numTSParsers = ntups;
8365 prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
8367 i_tableoid = PQfnumber(res, "tableoid");
8368 i_oid = PQfnumber(res, "oid");
8369 i_prsname = PQfnumber(res, "prsname");
8370 i_prsnamespace = PQfnumber(res, "prsnamespace");
8371 i_prsstart = PQfnumber(res, "prsstart");
8372 i_prstoken = PQfnumber(res, "prstoken");
8373 i_prsend = PQfnumber(res, "prsend");
8374 i_prsheadline = PQfnumber(res, "prsheadline");
8375 i_prslextype = PQfnumber(res, "prslextype");
8377 for (i = 0; i < ntups; i++)
8379 prsinfo[i].dobj.objType = DO_TSPARSER;
8380 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8381 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8382 AssignDumpId(&prsinfo[i].dobj);
8383 prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
8384 prsinfo[i].dobj.namespace =
8386 atooid(PQgetvalue(res, i, i_prsnamespace)));
8387 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
8388 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
8389 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
8390 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
8391 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
8393 /* Decide whether we want to dump it */
8394 selectDumpableObject(&(prsinfo[i].dobj), fout);
8396 /* Text Search Parsers do not currently have ACLs. */
8397 prsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8402 destroyPQExpBuffer(query);
8408 * getTSDictionaries:
8409 * read all text search dictionaries in the system catalogs and return them
8410 * in the TSDictInfo* structure
8412 * numTSDicts is set to the number of dictionaries read in
8415 getTSDictionaries(Archive *fout, int *numTSDicts)
8421 TSDictInfo *dictinfo;
8425 int i_dictnamespace;
8428 int i_dictinitoption;
8430 /* Before 8.3, there is no built-in text search support */
8431 if (fout->remoteVersion < 80300)
8437 query = createPQExpBuffer();
8439 /* Make sure we are in proper schema */
8440 selectSourceSchema(fout, "pg_catalog");
8442 appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
8443 "dictnamespace, (%s dictowner) AS rolname, "
8444 "dicttemplate, dictinitoption "
8448 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8450 ntups = PQntuples(res);
8451 *numTSDicts = ntups;
8453 dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
8455 i_tableoid = PQfnumber(res, "tableoid");
8456 i_oid = PQfnumber(res, "oid");
8457 i_dictname = PQfnumber(res, "dictname");
8458 i_dictnamespace = PQfnumber(res, "dictnamespace");
8459 i_rolname = PQfnumber(res, "rolname");
8460 i_dictinitoption = PQfnumber(res, "dictinitoption");
8461 i_dicttemplate = PQfnumber(res, "dicttemplate");
8463 for (i = 0; i < ntups; i++)
8465 dictinfo[i].dobj.objType = DO_TSDICT;
8466 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8467 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8468 AssignDumpId(&dictinfo[i].dobj);
8469 dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
8470 dictinfo[i].dobj.namespace =
8472 atooid(PQgetvalue(res, i, i_dictnamespace)));
8473 dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8474 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
8475 if (PQgetisnull(res, i, i_dictinitoption))
8476 dictinfo[i].dictinitoption = NULL;
8478 dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
8480 /* Decide whether we want to dump it */
8481 selectDumpableObject(&(dictinfo[i].dobj), fout);
8483 /* Text Search Dictionaries do not currently have ACLs. */
8484 dictinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8489 destroyPQExpBuffer(query);
8496 * read all text search templates in the system catalogs and return them
8497 * in the TSTemplateInfo* structure
8499 * numTSTemplates is set to the number of templates read in
8502 getTSTemplates(Archive *fout, int *numTSTemplates)
8508 TSTemplateInfo *tmplinfo;
8512 int i_tmplnamespace;
8516 /* Before 8.3, there is no built-in text search support */
8517 if (fout->remoteVersion < 80300)
8519 *numTSTemplates = 0;
8523 query = createPQExpBuffer();
8525 /* Make sure we are in proper schema */
8526 selectSourceSchema(fout, "pg_catalog");
8528 appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
8529 "tmplnamespace, tmplinit::oid, tmpllexize::oid "
8530 "FROM pg_ts_template");
8532 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8534 ntups = PQntuples(res);
8535 *numTSTemplates = ntups;
8537 tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
8539 i_tableoid = PQfnumber(res, "tableoid");
8540 i_oid = PQfnumber(res, "oid");
8541 i_tmplname = PQfnumber(res, "tmplname");
8542 i_tmplnamespace = PQfnumber(res, "tmplnamespace");
8543 i_tmplinit = PQfnumber(res, "tmplinit");
8544 i_tmpllexize = PQfnumber(res, "tmpllexize");
8546 for (i = 0; i < ntups; i++)
8548 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
8549 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8550 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8551 AssignDumpId(&tmplinfo[i].dobj);
8552 tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
8553 tmplinfo[i].dobj.namespace =
8555 atooid(PQgetvalue(res, i, i_tmplnamespace)));
8556 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
8557 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
8559 /* Decide whether we want to dump it */
8560 selectDumpableObject(&(tmplinfo[i].dobj), fout);
8562 /* Text Search Templates do not currently have ACLs. */
8563 tmplinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8568 destroyPQExpBuffer(query);
8574 * getTSConfigurations:
8575 * read all text search configurations in the system catalogs and return
8576 * them in the TSConfigInfo* structure
8578 * numTSConfigs is set to the number of configurations read in
8581 getTSConfigurations(Archive *fout, int *numTSConfigs)
8587 TSConfigInfo *cfginfo;
8595 /* Before 8.3, there is no built-in text search support */
8596 if (fout->remoteVersion < 80300)
8602 query = createPQExpBuffer();
8604 /* Make sure we are in proper schema */
8605 selectSourceSchema(fout, "pg_catalog");
8607 appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
8608 "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
8609 "FROM pg_ts_config",
8612 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8614 ntups = PQntuples(res);
8615 *numTSConfigs = ntups;
8617 cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
8619 i_tableoid = PQfnumber(res, "tableoid");
8620 i_oid = PQfnumber(res, "oid");
8621 i_cfgname = PQfnumber(res, "cfgname");
8622 i_cfgnamespace = PQfnumber(res, "cfgnamespace");
8623 i_rolname = PQfnumber(res, "rolname");
8624 i_cfgparser = PQfnumber(res, "cfgparser");
8626 for (i = 0; i < ntups; i++)
8628 cfginfo[i].dobj.objType = DO_TSCONFIG;
8629 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8630 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8631 AssignDumpId(&cfginfo[i].dobj);
8632 cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
8633 cfginfo[i].dobj.namespace =
8635 atooid(PQgetvalue(res, i, i_cfgnamespace)));
8636 cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8637 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
8639 /* Decide whether we want to dump it */
8640 selectDumpableObject(&(cfginfo[i].dobj), fout);
8642 /* Text Search Configurations do not currently have ACLs. */
8643 cfginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8648 destroyPQExpBuffer(query);
8654 * getForeignDataWrappers:
8655 * read all foreign-data wrappers in the system catalogs and return
8656 * them in the FdwInfo* structure
8658 * numForeignDataWrappers is set to the number of fdws read in
8661 getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
8663 DumpOptions *dopt = fout->dopt;
8681 /* Before 8.4, there are no foreign-data wrappers */
8682 if (fout->remoteVersion < 80400)
8684 *numForeignDataWrappers = 0;
8688 query = createPQExpBuffer();
8690 /* Make sure we are in proper schema */
8691 selectSourceSchema(fout, "pg_catalog");
8693 if (fout->remoteVersion >= 90600)
8695 PQExpBuffer acl_subquery = createPQExpBuffer();
8696 PQExpBuffer racl_subquery = createPQExpBuffer();
8697 PQExpBuffer initacl_subquery = createPQExpBuffer();
8698 PQExpBuffer initracl_subquery = createPQExpBuffer();
8700 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
8701 initracl_subquery, "f.fdwacl", "f.fdwowner", "'F'",
8702 dopt->binary_upgrade);
8704 appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.fdwname, "
8705 "(%s f.fdwowner) AS rolname, "
8706 "f.fdwhandler::pg_catalog.regproc, "
8707 "f.fdwvalidator::pg_catalog.regproc, "
8710 "%s AS initfdwacl, "
8711 "%s AS initrfdwacl, "
8712 "array_to_string(ARRAY("
8713 "SELECT quote_ident(option_name) || ' ' || "
8714 "quote_literal(option_value) "
8715 "FROM pg_options_to_table(f.fdwoptions) "
8716 "ORDER BY option_name"
8717 "), E',\n ') AS fdwoptions "
8718 "FROM pg_foreign_data_wrapper f "
8719 "LEFT JOIN pg_init_privs pip ON "
8720 "(f.oid = pip.objoid "
8721 "AND pip.classoid = 'pg_foreign_data_wrapper'::regclass "
8722 "AND pip.objsubid = 0) ",
8725 racl_subquery->data,
8726 initacl_subquery->data,
8727 initracl_subquery->data);
8729 destroyPQExpBuffer(acl_subquery);
8730 destroyPQExpBuffer(racl_subquery);
8731 destroyPQExpBuffer(initacl_subquery);
8732 destroyPQExpBuffer(initracl_subquery);
8734 else if (fout->remoteVersion >= 90100)
8736 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
8737 "(%s fdwowner) AS rolname, "
8738 "fdwhandler::pg_catalog.regproc, "
8739 "fdwvalidator::pg_catalog.regproc, fdwacl, "
8741 "NULL as initfdwacl, NULL AS initrfdwacl, "
8742 "array_to_string(ARRAY("
8743 "SELECT quote_ident(option_name) || ' ' || "
8744 "quote_literal(option_value) "
8745 "FROM pg_options_to_table(fdwoptions) "
8746 "ORDER BY option_name"
8747 "), E',\n ') AS fdwoptions "
8748 "FROM pg_foreign_data_wrapper",
8753 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
8754 "(%s fdwowner) AS rolname, "
8755 "'-' AS fdwhandler, "
8756 "fdwvalidator::pg_catalog.regproc, fdwacl, "
8758 "NULL as initfdwacl, NULL AS initrfdwacl, "
8759 "array_to_string(ARRAY("
8760 "SELECT quote_ident(option_name) || ' ' || "
8761 "quote_literal(option_value) "
8762 "FROM pg_options_to_table(fdwoptions) "
8763 "ORDER BY option_name"
8764 "), E',\n ') AS fdwoptions "
8765 "FROM pg_foreign_data_wrapper",
8769 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8771 ntups = PQntuples(res);
8772 *numForeignDataWrappers = ntups;
8774 fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
8776 i_tableoid = PQfnumber(res, "tableoid");
8777 i_oid = PQfnumber(res, "oid");
8778 i_fdwname = PQfnumber(res, "fdwname");
8779 i_rolname = PQfnumber(res, "rolname");
8780 i_fdwhandler = PQfnumber(res, "fdwhandler");
8781 i_fdwvalidator = PQfnumber(res, "fdwvalidator");
8782 i_fdwacl = PQfnumber(res, "fdwacl");
8783 i_rfdwacl = PQfnumber(res, "rfdwacl");
8784 i_initfdwacl = PQfnumber(res, "initfdwacl");
8785 i_initrfdwacl = PQfnumber(res, "initrfdwacl");
8786 i_fdwoptions = PQfnumber(res, "fdwoptions");
8788 for (i = 0; i < ntups; i++)
8790 fdwinfo[i].dobj.objType = DO_FDW;
8791 fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8792 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8793 AssignDumpId(&fdwinfo[i].dobj);
8794 fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
8795 fdwinfo[i].dobj.namespace = NULL;
8796 fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8797 fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
8798 fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
8799 fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
8800 fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
8801 fdwinfo[i].rfdwacl = pg_strdup(PQgetvalue(res, i, i_rfdwacl));
8802 fdwinfo[i].initfdwacl = pg_strdup(PQgetvalue(res, i, i_initfdwacl));
8803 fdwinfo[i].initrfdwacl = pg_strdup(PQgetvalue(res, i, i_initrfdwacl));
8805 /* Decide whether we want to dump it */
8806 selectDumpableObject(&(fdwinfo[i].dobj), fout);
8808 /* Do not try to dump ACL if no ACL exists. */
8809 if (PQgetisnull(res, i, i_fdwacl) && PQgetisnull(res, i, i_rfdwacl) &&
8810 PQgetisnull(res, i, i_initfdwacl) &&
8811 PQgetisnull(res, i, i_initrfdwacl))
8812 fdwinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8817 destroyPQExpBuffer(query);
8823 * getForeignServers:
8824 * read all foreign servers in the system catalogs and return
8825 * them in the ForeignServerInfo * structure
8827 * numForeignServers is set to the number of servers read in
8830 getForeignServers(Archive *fout, int *numForeignServers)
8832 DumpOptions *dopt = fout->dopt;
8837 ForeignServerInfo *srvinfo;
8851 /* Before 8.4, there are no foreign servers */
8852 if (fout->remoteVersion < 80400)
8854 *numForeignServers = 0;
8858 query = createPQExpBuffer();
8860 /* Make sure we are in proper schema */
8861 selectSourceSchema(fout, "pg_catalog");
8863 if (fout->remoteVersion >= 90600)
8865 PQExpBuffer acl_subquery = createPQExpBuffer();
8866 PQExpBuffer racl_subquery = createPQExpBuffer();
8867 PQExpBuffer initacl_subquery = createPQExpBuffer();
8868 PQExpBuffer initracl_subquery = createPQExpBuffer();
8870 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
8871 initracl_subquery, "f.srvacl", "f.srvowner", "'S'",
8872 dopt->binary_upgrade);
8874 appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.srvname, "
8875 "(%s f.srvowner) AS rolname, "
8876 "f.srvfdw, f.srvtype, f.srvversion, "
8879 "%s AS initsrvacl, "
8880 "%s AS initrsrvacl, "
8881 "array_to_string(ARRAY("
8882 "SELECT quote_ident(option_name) || ' ' || "
8883 "quote_literal(option_value) "
8884 "FROM pg_options_to_table(f.srvoptions) "
8885 "ORDER BY option_name"
8886 "), E',\n ') AS srvoptions "
8887 "FROM pg_foreign_server f "
8888 "LEFT JOIN pg_init_privs pip "
8889 "ON (f.oid = pip.objoid "
8890 "AND pip.classoid = 'pg_foreign_server'::regclass "
8891 "AND pip.objsubid = 0) ",
8894 racl_subquery->data,
8895 initacl_subquery->data,
8896 initracl_subquery->data);
8898 destroyPQExpBuffer(acl_subquery);
8899 destroyPQExpBuffer(racl_subquery);
8900 destroyPQExpBuffer(initacl_subquery);
8901 destroyPQExpBuffer(initracl_subquery);
8905 appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
8906 "(%s srvowner) AS rolname, "
8907 "srvfdw, srvtype, srvversion, srvacl, "
8909 "NULL AS initsrvacl, NULL AS initrsrvacl, "
8910 "array_to_string(ARRAY("
8911 "SELECT quote_ident(option_name) || ' ' || "
8912 "quote_literal(option_value) "
8913 "FROM pg_options_to_table(srvoptions) "
8914 "ORDER BY option_name"
8915 "), E',\n ') AS srvoptions "
8916 "FROM pg_foreign_server",
8920 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8922 ntups = PQntuples(res);
8923 *numForeignServers = ntups;
8925 srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
8927 i_tableoid = PQfnumber(res, "tableoid");
8928 i_oid = PQfnumber(res, "oid");
8929 i_srvname = PQfnumber(res, "srvname");
8930 i_rolname = PQfnumber(res, "rolname");
8931 i_srvfdw = PQfnumber(res, "srvfdw");
8932 i_srvtype = PQfnumber(res, "srvtype");
8933 i_srvversion = PQfnumber(res, "srvversion");
8934 i_srvacl = PQfnumber(res, "srvacl");
8935 i_rsrvacl = PQfnumber(res, "rsrvacl");
8936 i_initsrvacl = PQfnumber(res, "initsrvacl");
8937 i_initrsrvacl = PQfnumber(res, "initrsrvacl");
8938 i_srvoptions = PQfnumber(res, "srvoptions");
8940 for (i = 0; i < ntups; i++)
8942 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
8943 srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8944 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8945 AssignDumpId(&srvinfo[i].dobj);
8946 srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
8947 srvinfo[i].dobj.namespace = NULL;
8948 srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8949 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
8950 srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
8951 srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
8952 srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
8953 srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
8954 srvinfo[i].rsrvacl = pg_strdup(PQgetvalue(res, i, i_rsrvacl));
8955 srvinfo[i].initsrvacl = pg_strdup(PQgetvalue(res, i, i_initsrvacl));
8956 srvinfo[i].initrsrvacl = pg_strdup(PQgetvalue(res, i, i_initrsrvacl));
8958 /* Decide whether we want to dump it */
8959 selectDumpableObject(&(srvinfo[i].dobj), fout);
8961 /* Do not try to dump ACL if no ACL exists. */
8962 if (PQgetisnull(res, i, i_srvacl) && PQgetisnull(res, i, i_rsrvacl) &&
8963 PQgetisnull(res, i, i_initsrvacl) &&
8964 PQgetisnull(res, i, i_initrsrvacl))
8965 srvinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8970 destroyPQExpBuffer(query);
8977 * read all default ACL information in the system catalogs and return
8978 * them in the DefaultACLInfo structure
8980 * numDefaultACLs is set to the number of ACLs read in
8983 getDefaultACLs(Archive *fout, int *numDefaultACLs)
8985 DumpOptions *dopt = fout->dopt;
8986 DefaultACLInfo *daclinfo;
8992 int i_defaclnamespace;
8993 int i_defaclobjtype;
8996 int i_initdefaclacl;
8997 int i_initrdefaclacl;
9001 if (fout->remoteVersion < 90000)
9003 *numDefaultACLs = 0;
9007 query = createPQExpBuffer();
9009 /* Make sure we are in proper schema */
9010 selectSourceSchema(fout, "pg_catalog");
9012 if (fout->remoteVersion >= 90600)
9014 PQExpBuffer acl_subquery = createPQExpBuffer();
9015 PQExpBuffer racl_subquery = createPQExpBuffer();
9016 PQExpBuffer initacl_subquery = createPQExpBuffer();
9017 PQExpBuffer initracl_subquery = createPQExpBuffer();
9019 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9020 initracl_subquery, "defaclacl", "defaclrole",
9021 "CASE WHEN defaclobjtype = 'S' THEN 's' ELSE defaclobjtype END::\"char\"",
9022 dopt->binary_upgrade);
9024 appendPQExpBuffer(query, "SELECT d.oid, d.tableoid, "
9025 "(%s d.defaclrole) AS defaclrole, "
9026 "d.defaclnamespace, "
9029 "%s AS rdefaclacl, "
9030 "%s AS initdefaclacl, "
9031 "%s AS initrdefaclacl "
9032 "FROM pg_default_acl d "
9033 "LEFT JOIN pg_init_privs pip ON "
9034 "(d.oid = pip.objoid "
9035 "AND pip.classoid = 'pg_default_acl'::regclass "
9036 "AND pip.objsubid = 0) ",
9039 racl_subquery->data,
9040 initacl_subquery->data,
9041 initracl_subquery->data);
9045 appendPQExpBuffer(query, "SELECT oid, tableoid, "
9046 "(%s defaclrole) AS defaclrole, "
9050 "NULL AS rdefaclacl, "
9051 "NULL AS initdefaclacl, "
9052 "NULL AS initrdefaclacl "
9053 "FROM pg_default_acl",
9057 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9059 ntups = PQntuples(res);
9060 *numDefaultACLs = ntups;
9062 daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
9064 i_oid = PQfnumber(res, "oid");
9065 i_tableoid = PQfnumber(res, "tableoid");
9066 i_defaclrole = PQfnumber(res, "defaclrole");
9067 i_defaclnamespace = PQfnumber(res, "defaclnamespace");
9068 i_defaclobjtype = PQfnumber(res, "defaclobjtype");
9069 i_defaclacl = PQfnumber(res, "defaclacl");
9070 i_rdefaclacl = PQfnumber(res, "rdefaclacl");
9071 i_initdefaclacl = PQfnumber(res, "initdefaclacl");
9072 i_initrdefaclacl = PQfnumber(res, "initrdefaclacl");
9074 for (i = 0; i < ntups; i++)
9076 Oid nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
9078 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
9079 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9080 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9081 AssignDumpId(&daclinfo[i].dobj);
9082 /* cheesy ... is it worth coming up with a better object name? */
9083 daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
9085 if (nspid != InvalidOid)
9086 daclinfo[i].dobj.namespace = findNamespace(fout, nspid);
9088 daclinfo[i].dobj.namespace = NULL;
9090 daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
9091 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
9092 daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
9093 daclinfo[i].rdefaclacl = pg_strdup(PQgetvalue(res, i, i_rdefaclacl));
9094 daclinfo[i].initdefaclacl = pg_strdup(PQgetvalue(res, i, i_initdefaclacl));
9095 daclinfo[i].initrdefaclacl = pg_strdup(PQgetvalue(res, i, i_initrdefaclacl));
9097 /* Decide whether we want to dump it */
9098 selectDumpableDefaultACL(&(daclinfo[i]), dopt);
9103 destroyPQExpBuffer(query);
9111 * This routine is used to dump any comments associated with the
9112 * object handed to this routine. The routine takes a constant character
9113 * string for the target part of the comment-creation command, plus
9114 * the namespace and owner of the object (for labeling the ArchiveEntry),
9115 * plus catalog ID and subid which are the lookup key for pg_description,
9116 * plus the dump ID for the object (for setting a dependency).
9117 * If a matching pg_description entry is found, it is dumped.
9119 * Note: although this routine takes a dumpId for dependency purposes,
9120 * that purpose is just to mark the dependency in the emitted dump file
9121 * for possible future use by pg_restore. We do NOT use it for determining
9122 * ordering of the comment in the dump file, because this routine is called
9123 * after dependency sorting occurs. This routine should be called just after
9124 * calling ArchiveEntry() for the specified object.
9127 dumpComment(Archive *fout, const char *target,
9128 const char *namespace, const char *owner,
9129 CatalogId catalogId, int subid, DumpId dumpId)
9131 DumpOptions *dopt = fout->dopt;
9132 CommentItem *comments;
9135 /* Comments are schema not data ... except blob comments are data */
9136 if (strncmp(target, "LARGE OBJECT ", 13) != 0)
9143 /* We do dump blob comments in binary-upgrade mode */
9144 if (dopt->schemaOnly && !dopt->binary_upgrade)
9148 /* Search for comments associated with catalogId, using table */
9149 ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
9152 /* Is there one matching the subid? */
9153 while (ncomments > 0)
9155 if (comments->objsubid == subid)
9161 /* If a comment exists, build COMMENT ON statement */
9164 PQExpBuffer query = createPQExpBuffer();
9166 appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
9167 appendStringLiteralAH(query, comments->descr, fout);
9168 appendPQExpBufferStr(query, ";\n");
9171 * We mark comments as SECTION_NONE because they really belong in the
9172 * same section as their parent, whether that is pre-data or
9175 ArchiveEntry(fout, nilCatalogId, createDumpId(),
9176 target, namespace, NULL, owner,
9177 false, "COMMENT", SECTION_NONE,
9178 query->data, "", NULL,
9182 destroyPQExpBuffer(query);
9187 * dumpTableComment --
9189 * As above, but dump comments for both the specified table (or view)
9193 dumpTableComment(Archive *fout, TableInfo *tbinfo,
9194 const char *reltypename)
9196 DumpOptions *dopt = fout->dopt;
9197 CommentItem *comments;
9202 /* Comments are SCHEMA not data */
9206 /* Search for comments associated with relation, using table */
9207 ncomments = findComments(fout,
9208 tbinfo->dobj.catId.tableoid,
9209 tbinfo->dobj.catId.oid,
9212 /* If comments exist, build COMMENT ON statements */
9216 query = createPQExpBuffer();
9217 target = createPQExpBuffer();
9219 while (ncomments > 0)
9221 const char *descr = comments->descr;
9222 int objsubid = comments->objsubid;
9226 resetPQExpBuffer(target);
9227 appendPQExpBuffer(target, "%s %s", reltypename,
9228 fmtId(tbinfo->dobj.name));
9230 resetPQExpBuffer(query);
9231 appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
9232 appendStringLiteralAH(query, descr, fout);
9233 appendPQExpBufferStr(query, ";\n");
9235 ArchiveEntry(fout, nilCatalogId, createDumpId(),
9237 tbinfo->dobj.namespace->dobj.name,
9238 NULL, tbinfo->rolname,
9239 false, "COMMENT", SECTION_NONE,
9240 query->data, "", NULL,
9241 &(tbinfo->dobj.dumpId), 1,
9244 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
9246 resetPQExpBuffer(target);
9247 appendPQExpBuffer(target, "COLUMN %s.",
9248 fmtId(tbinfo->dobj.name));
9249 appendPQExpBufferStr(target, fmtId(tbinfo->attnames[objsubid - 1]));
9251 resetPQExpBuffer(query);
9252 appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
9253 appendStringLiteralAH(query, descr, fout);
9254 appendPQExpBufferStr(query, ";\n");
9256 ArchiveEntry(fout, nilCatalogId, createDumpId(),
9258 tbinfo->dobj.namespace->dobj.name,
9259 NULL, tbinfo->rolname,
9260 false, "COMMENT", SECTION_NONE,
9261 query->data, "", NULL,
9262 &(tbinfo->dobj.dumpId), 1,
9270 destroyPQExpBuffer(query);
9271 destroyPQExpBuffer(target);
9277 * Find the comment(s), if any, associated with the given object. All the
9278 * objsubid values associated with the given classoid/objoid are found with
9282 findComments(Archive *fout, Oid classoid, Oid objoid,
9283 CommentItem **items)
9285 /* static storage for table of comments */
9286 static CommentItem *comments = NULL;
9287 static int ncomments = -1;
9289 CommentItem *middle = NULL;
9294 /* Get comments if we didn't already */
9296 ncomments = collectComments(fout, &comments);
9299 * Do binary search to find some item matching the object.
9302 high = &comments[ncomments - 1];
9305 middle = low + (high - low) / 2;
9307 if (classoid < middle->classoid)
9309 else if (classoid > middle->classoid)
9311 else if (objoid < middle->objoid)
9313 else if (objoid > middle->objoid)
9316 break; /* found a match */
9319 if (low > high) /* no matches */
9326 * Now determine how many items match the object. The search loop
9327 * invariant still holds: only items between low and high inclusive could
9331 while (middle > low)
9333 if (classoid != middle[-1].classoid ||
9334 objoid != middle[-1].objoid)
9343 while (middle <= high)
9345 if (classoid != middle->classoid ||
9346 objoid != middle->objoid)
9356 * collectComments --
9358 * Construct a table of all comments available for database objects.
9359 * We used to do per-object queries for the comments, but it's much faster
9360 * to pull them all over at once, and on most databases the memory cost
9363 * The table is sorted by classoid/objid/objsubid for speed in lookup.
9366 collectComments(Archive *fout, CommentItem **items)
9376 CommentItem *comments;
9379 * Note we do NOT change source schema here; preserve the caller's
9383 query = createPQExpBuffer();
9385 appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
9386 "FROM pg_catalog.pg_description "
9387 "ORDER BY classoid, objoid, objsubid");
9389 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9391 /* Construct lookup table containing OIDs in numeric form */
9393 i_description = PQfnumber(res, "description");
9394 i_classoid = PQfnumber(res, "classoid");
9395 i_objoid = PQfnumber(res, "objoid");
9396 i_objsubid = PQfnumber(res, "objsubid");
9398 ntups = PQntuples(res);
9400 comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
9402 for (i = 0; i < ntups; i++)
9404 comments[i].descr = PQgetvalue(res, i, i_description);
9405 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
9406 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
9407 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
9410 /* Do NOT free the PGresult since we are keeping pointers into it */
9411 destroyPQExpBuffer(query);
9418 * dumpDumpableObject
9420 * This routine and its subsidiaries are responsible for creating
9421 * ArchiveEntries (TOC objects) for each object to be dumped.
9424 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
9426 switch (dobj->objType)
9429 dumpNamespace(fout, (NamespaceInfo *) dobj);
9432 dumpExtension(fout, (ExtensionInfo *) dobj);
9435 dumpType(fout, (TypeInfo *) dobj);
9438 dumpShellType(fout, (ShellTypeInfo *) dobj);
9441 dumpFunc(fout, (FuncInfo *) dobj);
9444 dumpAgg(fout, (AggInfo *) dobj);
9447 dumpOpr(fout, (OprInfo *) dobj);
9449 case DO_ACCESS_METHOD:
9450 dumpAccessMethod(fout, (AccessMethodInfo *) dobj);
9453 dumpOpclass(fout, (OpclassInfo *) dobj);
9456 dumpOpfamily(fout, (OpfamilyInfo *) dobj);
9459 dumpCollation(fout, (CollInfo *) dobj);
9462 dumpConversion(fout, (ConvInfo *) dobj);
9465 dumpTable(fout, (TableInfo *) dobj);
9468 dumpAttrDef(fout, (AttrDefInfo *) dobj);
9471 dumpIndex(fout, (IndxInfo *) dobj);
9474 dumpStatisticsExt(fout, (StatsExtInfo *) dobj);
9476 case DO_REFRESH_MATVIEW:
9477 refreshMatViewData(fout, (TableDataInfo *) dobj);
9480 dumpRule(fout, (RuleInfo *) dobj);
9483 dumpTrigger(fout, (TriggerInfo *) dobj);
9485 case DO_EVENT_TRIGGER:
9486 dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
9489 dumpConstraint(fout, (ConstraintInfo *) dobj);
9491 case DO_FK_CONSTRAINT:
9492 dumpConstraint(fout, (ConstraintInfo *) dobj);
9495 dumpProcLang(fout, (ProcLangInfo *) dobj);
9498 dumpCast(fout, (CastInfo *) dobj);
9501 dumpTransform(fout, (TransformInfo *) dobj);
9503 case DO_SEQUENCE_SET:
9504 dumpSequenceData(fout, (TableDataInfo *) dobj);
9507 dumpTableData(fout, (TableDataInfo *) dobj);
9510 /* table rowtypes and array types are never dumped separately */
9513 dumpTSParser(fout, (TSParserInfo *) dobj);
9516 dumpTSDictionary(fout, (TSDictInfo *) dobj);
9519 dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
9522 dumpTSConfig(fout, (TSConfigInfo *) dobj);
9525 dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
9527 case DO_FOREIGN_SERVER:
9528 dumpForeignServer(fout, (ForeignServerInfo *) dobj);
9530 case DO_DEFAULT_ACL:
9531 dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
9534 dumpBlob(fout, (BlobInfo *) dobj);
9537 if (dobj->dump & DUMP_COMPONENT_DATA)
9538 ArchiveEntry(fout, dobj->catId, dobj->dumpId,
9539 dobj->name, NULL, NULL, "",
9540 false, "BLOBS", SECTION_DATA,
9546 dumpPolicy(fout, (PolicyInfo *) dobj);
9548 case DO_PUBLICATION:
9549 dumpPublication(fout, (PublicationInfo *) dobj);
9551 case DO_PUBLICATION_REL:
9552 dumpPublicationTable(fout, (PublicationRelInfo *) dobj);
9554 case DO_SUBSCRIPTION:
9555 dumpSubscription(fout, (SubscriptionInfo *) dobj);
9557 case DO_PRE_DATA_BOUNDARY:
9558 case DO_POST_DATA_BOUNDARY:
9559 /* never dumped, nothing to do */
9566 * writes out to fout the queries to recreate a user-defined namespace
9569 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
9571 DumpOptions *dopt = fout->dopt;
9577 /* Skip if not to be dumped */
9578 if (!nspinfo->dobj.dump || dopt->dataOnly)
9581 q = createPQExpBuffer();
9582 delq = createPQExpBuffer();
9583 labelq = createPQExpBuffer();
9585 qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
9587 appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
9589 appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
9591 appendPQExpBuffer(labelq, "SCHEMA %s", qnspname);
9593 if (dopt->binary_upgrade)
9594 binary_upgrade_extension_member(q, &nspinfo->dobj, labelq->data);
9596 if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
9597 ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
9601 false, "SCHEMA", SECTION_PRE_DATA,
9602 q->data, delq->data, NULL,
9606 /* Dump Schema Comments and Security Labels */
9607 if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
9608 dumpComment(fout, labelq->data,
9609 NULL, nspinfo->rolname,
9610 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
9612 if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
9613 dumpSecLabel(fout, labelq->data,
9614 NULL, nspinfo->rolname,
9615 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
9617 if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
9618 dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
9619 qnspname, NULL, nspinfo->dobj.name, NULL,
9620 nspinfo->rolname, nspinfo->nspacl, nspinfo->rnspacl,
9621 nspinfo->initnspacl, nspinfo->initrnspacl);
9625 destroyPQExpBuffer(q);
9626 destroyPQExpBuffer(delq);
9627 destroyPQExpBuffer(labelq);
9632 * writes out to fout the queries to recreate an extension
9635 dumpExtension(Archive *fout, ExtensionInfo *extinfo)
9637 DumpOptions *dopt = fout->dopt;
9643 /* Skip if not to be dumped */
9644 if (!extinfo->dobj.dump || dopt->dataOnly)
9647 q = createPQExpBuffer();
9648 delq = createPQExpBuffer();
9649 labelq = createPQExpBuffer();
9651 qextname = pg_strdup(fmtId(extinfo->dobj.name));
9653 appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
9655 if (!dopt->binary_upgrade)
9658 * In a regular dump, we use IF NOT EXISTS so that there isn't a
9659 * problem if the extension already exists in the target database;
9660 * this is essential for installed-by-default extensions such as
9663 * In binary-upgrade mode, that doesn't work well, so instead we skip
9664 * built-in extensions based on their OIDs; see
9665 * selectDumpableExtension.
9667 appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
9668 qextname, fmtId(extinfo->namespace));
9675 appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
9678 * We unconditionally create the extension, so we must drop it if it
9679 * exists. This could happen if the user deleted 'plpgsql' and then
9680 * readded it, causing its oid to be greater than g_last_builtin_oid.
9681 * The g_last_builtin_oid test was kept to avoid repeatedly dropping
9682 * and recreating extensions like 'plpgsql'.
9684 appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
9686 appendPQExpBufferStr(q,
9687 "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
9688 appendStringLiteralAH(q, extinfo->dobj.name, fout);
9689 appendPQExpBufferStr(q, ", ");
9690 appendStringLiteralAH(q, extinfo->namespace, fout);
9691 appendPQExpBufferStr(q, ", ");
9692 appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
9693 appendStringLiteralAH(q, extinfo->extversion, fout);
9694 appendPQExpBufferStr(q, ", ");
9697 * Note that we're pushing extconfig (an OID array) back into
9698 * pg_extension exactly as-is. This is OK because pg_class OIDs are
9699 * preserved in binary upgrade.
9701 if (strlen(extinfo->extconfig) > 2)
9702 appendStringLiteralAH(q, extinfo->extconfig, fout);
9704 appendPQExpBufferStr(q, "NULL");
9705 appendPQExpBufferStr(q, ", ");
9706 if (strlen(extinfo->extcondition) > 2)
9707 appendStringLiteralAH(q, extinfo->extcondition, fout);
9709 appendPQExpBufferStr(q, "NULL");
9710 appendPQExpBufferStr(q, ", ");
9711 appendPQExpBufferStr(q, "ARRAY[");
9713 for (i = 0; i < extinfo->dobj.nDeps; i++)
9715 DumpableObject *extobj;
9717 extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
9718 if (extobj && extobj->objType == DO_EXTENSION)
9721 appendPQExpBufferChar(q, ',');
9722 appendStringLiteralAH(q, extobj->name, fout);
9725 appendPQExpBufferStr(q, "]::pg_catalog.text[]");
9726 appendPQExpBufferStr(q, ");\n");
9729 appendPQExpBuffer(labelq, "EXTENSION %s", qextname);
9731 if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
9732 ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
9736 false, "EXTENSION", SECTION_PRE_DATA,
9737 q->data, delq->data, NULL,
9741 /* Dump Extension Comments and Security Labels */
9742 if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
9743 dumpComment(fout, labelq->data,
9745 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
9747 if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
9748 dumpSecLabel(fout, labelq->data,
9750 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
9754 destroyPQExpBuffer(q);
9755 destroyPQExpBuffer(delq);
9756 destroyPQExpBuffer(labelq);
9761 * writes out to fout the queries to recreate a user-defined type
9764 dumpType(Archive *fout, TypeInfo *tyinfo)
9766 DumpOptions *dopt = fout->dopt;
9768 /* Skip if not to be dumped */
9769 if (!tyinfo->dobj.dump || dopt->dataOnly)
9772 /* Dump out in proper style */
9773 if (tyinfo->typtype == TYPTYPE_BASE)
9774 dumpBaseType(fout, tyinfo);
9775 else if (tyinfo->typtype == TYPTYPE_DOMAIN)
9776 dumpDomain(fout, tyinfo);
9777 else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
9778 dumpCompositeType(fout, tyinfo);
9779 else if (tyinfo->typtype == TYPTYPE_ENUM)
9780 dumpEnumType(fout, tyinfo);
9781 else if (tyinfo->typtype == TYPTYPE_RANGE)
9782 dumpRangeType(fout, tyinfo);
9783 else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
9784 dumpUndefinedType(fout, tyinfo);
9786 write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
9792 * writes out to fout the queries to recreate a user-defined enum type
9795 dumpEnumType(Archive *fout, TypeInfo *tyinfo)
9797 DumpOptions *dopt = fout->dopt;
9798 PQExpBuffer q = createPQExpBuffer();
9799 PQExpBuffer delq = createPQExpBuffer();
9800 PQExpBuffer labelq = createPQExpBuffer();
9801 PQExpBuffer query = createPQExpBuffer();
9809 /* Set proper schema search path */
9810 selectSourceSchema(fout, "pg_catalog");
9812 if (fout->remoteVersion >= 90100)
9813 appendPQExpBuffer(query, "SELECT oid, enumlabel "
9814 "FROM pg_catalog.pg_enum "
9815 "WHERE enumtypid = '%u'"
9816 "ORDER BY enumsortorder",
9817 tyinfo->dobj.catId.oid);
9819 appendPQExpBuffer(query, "SELECT oid, enumlabel "
9820 "FROM pg_catalog.pg_enum "
9821 "WHERE enumtypid = '%u'"
9823 tyinfo->dobj.catId.oid);
9825 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9827 num = PQntuples(res);
9829 qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
9832 * DROP must be fully qualified in case same name appears in pg_catalog.
9833 * CASCADE shouldn't be required here as for normal types since the I/O
9834 * functions are generic and do not get dropped.
9836 appendPQExpBuffer(delq, "DROP TYPE %s.",
9837 fmtId(tyinfo->dobj.namespace->dobj.name));
9838 appendPQExpBuffer(delq, "%s;\n",
9841 if (dopt->binary_upgrade)
9842 binary_upgrade_set_type_oids_by_type_oid(fout, q,
9843 tyinfo->dobj.catId.oid);
9845 appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
9848 if (!dopt->binary_upgrade)
9850 /* Labels with server-assigned oids */
9851 for (i = 0; i < num; i++)
9853 label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
9855 appendPQExpBufferChar(q, ',');
9856 appendPQExpBufferStr(q, "\n ");
9857 appendStringLiteralAH(q, label, fout);
9861 appendPQExpBufferStr(q, "\n);\n");
9863 if (dopt->binary_upgrade)
9865 /* Labels with dump-assigned (preserved) oids */
9866 for (i = 0; i < num; i++)
9868 enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
9869 label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
9872 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
9873 appendPQExpBuffer(q,
9874 "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
9876 appendPQExpBuffer(q, "ALTER TYPE %s.",
9877 fmtId(tyinfo->dobj.namespace->dobj.name));
9878 appendPQExpBuffer(q, "%s ADD VALUE ",
9880 appendStringLiteralAH(q, label, fout);
9881 appendPQExpBufferStr(q, ";\n\n");
9885 appendPQExpBuffer(labelq, "TYPE %s", qtypname);
9887 if (dopt->binary_upgrade)
9888 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
9890 if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
9891 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
9893 tyinfo->dobj.namespace->dobj.name,
9895 tyinfo->rolname, false,
9896 "TYPE", SECTION_PRE_DATA,
9897 q->data, delq->data, NULL,
9901 /* Dump Type Comments and Security Labels */
9902 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
9903 dumpComment(fout, labelq->data,
9904 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
9905 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
9907 if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
9908 dumpSecLabel(fout, labelq->data,
9909 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
9910 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
9912 if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
9913 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
9914 qtypname, NULL, tyinfo->dobj.name,
9915 tyinfo->dobj.namespace->dobj.name,
9916 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
9917 tyinfo->inittypacl, tyinfo->initrtypacl);
9920 destroyPQExpBuffer(q);
9921 destroyPQExpBuffer(delq);
9922 destroyPQExpBuffer(labelq);
9923 destroyPQExpBuffer(query);
9928 * writes out to fout the queries to recreate a user-defined range type
9931 dumpRangeType(Archive *fout, TypeInfo *tyinfo)
9933 DumpOptions *dopt = fout->dopt;
9934 PQExpBuffer q = createPQExpBuffer();
9935 PQExpBuffer delq = createPQExpBuffer();
9936 PQExpBuffer labelq = createPQExpBuffer();
9937 PQExpBuffer query = createPQExpBuffer();
9944 * select appropriate schema to ensure names in CREATE are properly
9947 selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
9949 appendPQExpBuffer(query,
9950 "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
9951 "opc.opcname AS opcname, "
9952 "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
9953 " WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
9955 "CASE WHEN rngcollation = st.typcollation THEN 0 "
9956 " ELSE rngcollation END AS collation, "
9957 "rngcanonical, rngsubdiff "
9958 "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
9959 " pg_catalog.pg_opclass opc "
9960 "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
9962 tyinfo->dobj.catId.oid);
9964 res = ExecuteSqlQueryForSingleRow(fout, query->data);
9966 qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
9969 * DROP must be fully qualified in case same name appears in pg_catalog.
9970 * CASCADE shouldn't be required here as for normal types since the I/O
9971 * functions are generic and do not get dropped.
9973 appendPQExpBuffer(delq, "DROP TYPE %s.",
9974 fmtId(tyinfo->dobj.namespace->dobj.name));
9975 appendPQExpBuffer(delq, "%s;\n",
9978 if (dopt->binary_upgrade)
9979 binary_upgrade_set_type_oids_by_type_oid(fout,
9980 q, tyinfo->dobj.catId.oid);
9982 appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
9985 appendPQExpBuffer(q, "\n subtype = %s",
9986 PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
9988 /* print subtype_opclass only if not default for subtype */
9989 if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
9991 char *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
9992 char *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
9994 /* always schema-qualify, don't try to be smart */
9995 appendPQExpBuffer(q, ",\n subtype_opclass = %s.",
9997 appendPQExpBufferStr(q, fmtId(opcname));
10000 collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
10001 if (OidIsValid(collationOid))
10003 CollInfo *coll = findCollationByOid(collationOid);
10007 /* always schema-qualify, don't try to be smart */
10008 appendPQExpBuffer(q, ",\n collation = %s.",
10009 fmtId(coll->dobj.namespace->dobj.name));
10010 appendPQExpBufferStr(q, fmtId(coll->dobj.name));
10014 procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
10015 if (strcmp(procname, "-") != 0)
10016 appendPQExpBuffer(q, ",\n canonical = %s", procname);
10018 procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
10019 if (strcmp(procname, "-") != 0)
10020 appendPQExpBuffer(q, ",\n subtype_diff = %s", procname);
10022 appendPQExpBufferStr(q, "\n);\n");
10024 appendPQExpBuffer(labelq, "TYPE %s", qtypname);
10026 if (dopt->binary_upgrade)
10027 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
10029 if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10030 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10032 tyinfo->dobj.namespace->dobj.name,
10034 tyinfo->rolname, false,
10035 "TYPE", SECTION_PRE_DATA,
10036 q->data, delq->data, NULL,
10040 /* Dump Type Comments and Security Labels */
10041 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10042 dumpComment(fout, labelq->data,
10043 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10044 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10046 if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10047 dumpSecLabel(fout, labelq->data,
10048 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10049 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10051 if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10052 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10053 qtypname, NULL, tyinfo->dobj.name,
10054 tyinfo->dobj.namespace->dobj.name,
10055 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10056 tyinfo->inittypacl, tyinfo->initrtypacl);
10059 destroyPQExpBuffer(q);
10060 destroyPQExpBuffer(delq);
10061 destroyPQExpBuffer(labelq);
10062 destroyPQExpBuffer(query);
10066 * dumpUndefinedType
10067 * writes out to fout the queries to recreate a !typisdefined type
10069 * This is a shell type, but we use different terminology to distinguish
10070 * this case from where we have to emit a shell type definition to break
10071 * circular dependencies. An undefined type shouldn't ever have anything
10075 dumpUndefinedType(Archive *fout, TypeInfo *tyinfo)
10077 DumpOptions *dopt = fout->dopt;
10078 PQExpBuffer q = createPQExpBuffer();
10079 PQExpBuffer delq = createPQExpBuffer();
10080 PQExpBuffer labelq = createPQExpBuffer();
10083 qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10086 * DROP must be fully qualified in case same name appears in pg_catalog.
10088 appendPQExpBuffer(delq, "DROP TYPE %s.",
10089 fmtId(tyinfo->dobj.namespace->dobj.name));
10090 appendPQExpBuffer(delq, "%s;\n",
10093 if (dopt->binary_upgrade)
10094 binary_upgrade_set_type_oids_by_type_oid(fout,
10095 q, tyinfo->dobj.catId.oid);
10097 appendPQExpBuffer(q, "CREATE TYPE %s;\n",
10100 appendPQExpBuffer(labelq, "TYPE %s", qtypname);
10102 if (dopt->binary_upgrade)
10103 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
10105 if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10106 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10108 tyinfo->dobj.namespace->dobj.name,
10110 tyinfo->rolname, false,
10111 "TYPE", SECTION_PRE_DATA,
10112 q->data, delq->data, NULL,
10116 /* Dump Type Comments and Security Labels */
10117 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10118 dumpComment(fout, labelq->data,
10119 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10120 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10122 if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10123 dumpSecLabel(fout, labelq->data,
10124 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10125 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10127 if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10128 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10129 qtypname, NULL, tyinfo->dobj.name,
10130 tyinfo->dobj.namespace->dobj.name,
10131 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10132 tyinfo->inittypacl, tyinfo->initrtypacl);
10134 destroyPQExpBuffer(q);
10135 destroyPQExpBuffer(delq);
10136 destroyPQExpBuffer(labelq);
10141 * writes out to fout the queries to recreate a user-defined base type
10144 dumpBaseType(Archive *fout, TypeInfo *tyinfo)
10146 DumpOptions *dopt = fout->dopt;
10147 PQExpBuffer q = createPQExpBuffer();
10148 PQExpBuffer delq = createPQExpBuffer();
10149 PQExpBuffer labelq = createPQExpBuffer();
10150 PQExpBuffer query = createPQExpBuffer();
10167 char *typispreferred;
10172 char *typcollatable;
10174 bool typdefault_is_literal = false;
10176 /* Set proper schema search path so regproc references list correctly */
10177 selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
10179 /* Fetch type-specific details */
10180 if (fout->remoteVersion >= 90100)
10182 appendPQExpBuffer(query, "SELECT typlen, "
10183 "typinput, typoutput, typreceive, typsend, "
10184 "typmodin, typmodout, typanalyze, "
10185 "typreceive::pg_catalog.oid AS typreceiveoid, "
10186 "typsend::pg_catalog.oid AS typsendoid, "
10187 "typmodin::pg_catalog.oid AS typmodinoid, "
10188 "typmodout::pg_catalog.oid AS typmodoutoid, "
10189 "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10190 "typcategory, typispreferred, "
10191 "typdelim, typbyval, typalign, typstorage, "
10192 "(typcollation <> 0) AS typcollatable, "
10193 "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
10194 "FROM pg_catalog.pg_type "
10195 "WHERE oid = '%u'::pg_catalog.oid",
10196 tyinfo->dobj.catId.oid);
10198 else if (fout->remoteVersion >= 80400)
10200 appendPQExpBuffer(query, "SELECT typlen, "
10201 "typinput, typoutput, typreceive, typsend, "
10202 "typmodin, typmodout, typanalyze, "
10203 "typreceive::pg_catalog.oid AS typreceiveoid, "
10204 "typsend::pg_catalog.oid AS typsendoid, "
10205 "typmodin::pg_catalog.oid AS typmodinoid, "
10206 "typmodout::pg_catalog.oid AS typmodoutoid, "
10207 "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10208 "typcategory, typispreferred, "
10209 "typdelim, typbyval, typalign, typstorage, "
10210 "false AS typcollatable, "
10211 "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
10212 "FROM pg_catalog.pg_type "
10213 "WHERE oid = '%u'::pg_catalog.oid",
10214 tyinfo->dobj.catId.oid);
10216 else if (fout->remoteVersion >= 80300)
10218 /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
10219 appendPQExpBuffer(query, "SELECT typlen, "
10220 "typinput, typoutput, typreceive, typsend, "
10221 "typmodin, typmodout, typanalyze, "
10222 "typreceive::pg_catalog.oid AS typreceiveoid, "
10223 "typsend::pg_catalog.oid AS typsendoid, "
10224 "typmodin::pg_catalog.oid AS typmodinoid, "
10225 "typmodout::pg_catalog.oid AS typmodoutoid, "
10226 "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10227 "'U' AS typcategory, false AS typispreferred, "
10228 "typdelim, typbyval, typalign, typstorage, "
10229 "false AS typcollatable, "
10230 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10231 "FROM pg_catalog.pg_type "
10232 "WHERE oid = '%u'::pg_catalog.oid",
10233 tyinfo->dobj.catId.oid);
10237 appendPQExpBuffer(query, "SELECT typlen, "
10238 "typinput, typoutput, typreceive, typsend, "
10239 "'-' AS typmodin, '-' AS typmodout, "
10241 "typreceive::pg_catalog.oid AS typreceiveoid, "
10242 "typsend::pg_catalog.oid AS typsendoid, "
10243 "0 AS typmodinoid, 0 AS typmodoutoid, "
10244 "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10245 "'U' AS typcategory, false AS typispreferred, "
10246 "typdelim, typbyval, typalign, typstorage, "
10247 "false AS typcollatable, "
10248 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10249 "FROM pg_catalog.pg_type "
10250 "WHERE oid = '%u'::pg_catalog.oid",
10251 tyinfo->dobj.catId.oid);
10254 res = ExecuteSqlQueryForSingleRow(fout, query->data);
10256 typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
10257 typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
10258 typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
10259 typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
10260 typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
10261 typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
10262 typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
10263 typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
10264 typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
10265 typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
10266 typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
10267 typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
10268 typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
10269 typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
10270 typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
10271 typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
10272 typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
10273 typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
10274 typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
10275 typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
10276 if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
10277 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
10278 else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
10280 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
10281 typdefault_is_literal = true; /* it needs quotes */
10286 qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10289 * DROP must be fully qualified in case same name appears in pg_catalog.
10290 * The reason we include CASCADE is that the circular dependency between
10291 * the type and its I/O functions makes it impossible to drop the type any
10294 appendPQExpBuffer(delq, "DROP TYPE %s.",
10295 fmtId(tyinfo->dobj.namespace->dobj.name));
10296 appendPQExpBuffer(delq, "%s CASCADE;\n",
10299 /* We might already have a shell type, but setting pg_type_oid is harmless */
10300 if (dopt->binary_upgrade)
10301 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10302 tyinfo->dobj.catId.oid);
10304 appendPQExpBuffer(q,
10305 "CREATE TYPE %s (\n"
10306 " INTERNALLENGTH = %s",
10308 (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
10310 /* regproc result is sufficiently quoted already */
10311 appendPQExpBuffer(q, ",\n INPUT = %s", typinput);
10312 appendPQExpBuffer(q, ",\n OUTPUT = %s", typoutput);
10313 if (OidIsValid(typreceiveoid))
10314 appendPQExpBuffer(q, ",\n RECEIVE = %s", typreceive);
10315 if (OidIsValid(typsendoid))
10316 appendPQExpBuffer(q, ",\n SEND = %s", typsend);
10317 if (OidIsValid(typmodinoid))
10318 appendPQExpBuffer(q, ",\n TYPMOD_IN = %s", typmodin);
10319 if (OidIsValid(typmodoutoid))
10320 appendPQExpBuffer(q, ",\n TYPMOD_OUT = %s", typmodout);
10321 if (OidIsValid(typanalyzeoid))
10322 appendPQExpBuffer(q, ",\n ANALYZE = %s", typanalyze);
10324 if (strcmp(typcollatable, "t") == 0)
10325 appendPQExpBufferStr(q, ",\n COLLATABLE = true");
10327 if (typdefault != NULL)
10329 appendPQExpBufferStr(q, ",\n DEFAULT = ");
10330 if (typdefault_is_literal)
10331 appendStringLiteralAH(q, typdefault, fout);
10333 appendPQExpBufferStr(q, typdefault);
10336 if (OidIsValid(tyinfo->typelem))
10340 /* reselect schema in case changed by function dump */
10341 selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
10342 elemType = getFormattedTypeName(fout, tyinfo->typelem, zeroAsOpaque);
10343 appendPQExpBuffer(q, ",\n ELEMENT = %s", elemType);
10347 if (strcmp(typcategory, "U") != 0)
10349 appendPQExpBufferStr(q, ",\n CATEGORY = ");
10350 appendStringLiteralAH(q, typcategory, fout);
10353 if (strcmp(typispreferred, "t") == 0)
10354 appendPQExpBufferStr(q, ",\n PREFERRED = true");
10356 if (typdelim && strcmp(typdelim, ",") != 0)
10358 appendPQExpBufferStr(q, ",\n DELIMITER = ");
10359 appendStringLiteralAH(q, typdelim, fout);
10362 if (strcmp(typalign, "c") == 0)
10363 appendPQExpBufferStr(q, ",\n ALIGNMENT = char");
10364 else if (strcmp(typalign, "s") == 0)
10365 appendPQExpBufferStr(q, ",\n ALIGNMENT = int2");
10366 else if (strcmp(typalign, "i") == 0)
10367 appendPQExpBufferStr(q, ",\n ALIGNMENT = int4");
10368 else if (strcmp(typalign, "d") == 0)
10369 appendPQExpBufferStr(q, ",\n ALIGNMENT = double");
10371 if (strcmp(typstorage, "p") == 0)
10372 appendPQExpBufferStr(q, ",\n STORAGE = plain");
10373 else if (strcmp(typstorage, "e") == 0)
10374 appendPQExpBufferStr(q, ",\n STORAGE = external");
10375 else if (strcmp(typstorage, "x") == 0)
10376 appendPQExpBufferStr(q, ",\n STORAGE = extended");
10377 else if (strcmp(typstorage, "m") == 0)
10378 appendPQExpBufferStr(q, ",\n STORAGE = main");
10380 if (strcmp(typbyval, "t") == 0)
10381 appendPQExpBufferStr(q, ",\n PASSEDBYVALUE");
10383 appendPQExpBufferStr(q, "\n);\n");
10385 appendPQExpBuffer(labelq, "TYPE %s", qtypname);
10387 if (dopt->binary_upgrade)
10388 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
10390 if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10391 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10393 tyinfo->dobj.namespace->dobj.name,
10395 tyinfo->rolname, false,
10396 "TYPE", SECTION_PRE_DATA,
10397 q->data, delq->data, NULL,
10401 /* Dump Type Comments and Security Labels */
10402 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10403 dumpComment(fout, labelq->data,
10404 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10405 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10407 if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10408 dumpSecLabel(fout, labelq->data,
10409 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10410 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10412 if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10413 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10414 qtypname, NULL, tyinfo->dobj.name,
10415 tyinfo->dobj.namespace->dobj.name,
10416 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10417 tyinfo->inittypacl, tyinfo->initrtypacl);
10420 destroyPQExpBuffer(q);
10421 destroyPQExpBuffer(delq);
10422 destroyPQExpBuffer(labelq);
10423 destroyPQExpBuffer(query);
10428 * writes out to fout the queries to recreate a user-defined domain
10431 dumpDomain(Archive *fout, TypeInfo *tyinfo)
10433 DumpOptions *dopt = fout->dopt;
10434 PQExpBuffer q = createPQExpBuffer();
10435 PQExpBuffer delq = createPQExpBuffer();
10436 PQExpBuffer labelq = createPQExpBuffer();
10437 PQExpBuffer query = createPQExpBuffer();
10445 bool typdefault_is_literal = false;
10447 /* Set proper schema search path so type references list correctly */
10448 selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
10450 /* Fetch domain specific details */
10451 if (fout->remoteVersion >= 90100)
10453 /* typcollation is new in 9.1 */
10454 appendPQExpBuffer(query, "SELECT t.typnotnull, "
10455 "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
10456 "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
10458 "CASE WHEN t.typcollation <> u.typcollation "
10459 "THEN t.typcollation ELSE 0 END AS typcollation "
10460 "FROM pg_catalog.pg_type t "
10461 "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
10462 "WHERE t.oid = '%u'::pg_catalog.oid",
10463 tyinfo->dobj.catId.oid);
10467 appendPQExpBuffer(query, "SELECT typnotnull, "
10468 "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
10469 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
10470 "typdefault, 0 AS typcollation "
10471 "FROM pg_catalog.pg_type "
10472 "WHERE oid = '%u'::pg_catalog.oid",
10473 tyinfo->dobj.catId.oid);
10476 res = ExecuteSqlQueryForSingleRow(fout, query->data);
10478 typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
10479 typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
10480 if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
10481 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
10482 else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
10484 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
10485 typdefault_is_literal = true; /* it needs quotes */
10489 typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
10491 if (dopt->binary_upgrade)
10492 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10493 tyinfo->dobj.catId.oid);
10495 qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10497 appendPQExpBuffer(q,
10498 "CREATE DOMAIN %s AS %s",
10502 /* Print collation only if different from base type's collation */
10503 if (OidIsValid(typcollation))
10507 coll = findCollationByOid(typcollation);
10510 /* always schema-qualify, don't try to be smart */
10511 appendPQExpBuffer(q, " COLLATE %s.",
10512 fmtId(coll->dobj.namespace->dobj.name));
10513 appendPQExpBufferStr(q, fmtId(coll->dobj.name));
10517 if (typnotnull[0] == 't')
10518 appendPQExpBufferStr(q, " NOT NULL");
10520 if (typdefault != NULL)
10522 appendPQExpBufferStr(q, " DEFAULT ");
10523 if (typdefault_is_literal)
10524 appendStringLiteralAH(q, typdefault, fout);
10526 appendPQExpBufferStr(q, typdefault);
10532 * Add any CHECK constraints for the domain
10534 for (i = 0; i < tyinfo->nDomChecks; i++)
10536 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
10538 if (!domcheck->separate)
10539 appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
10540 fmtId(domcheck->dobj.name), domcheck->condef);
10543 appendPQExpBufferStr(q, ";\n");
10546 * DROP must be fully qualified in case same name appears in pg_catalog
10548 appendPQExpBuffer(delq, "DROP DOMAIN %s.",
10549 fmtId(tyinfo->dobj.namespace->dobj.name));
10550 appendPQExpBuffer(delq, "%s;\n",
10553 appendPQExpBuffer(labelq, "DOMAIN %s", qtypname);
10555 if (dopt->binary_upgrade)
10556 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
10558 if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10559 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10561 tyinfo->dobj.namespace->dobj.name,
10563 tyinfo->rolname, false,
10564 "DOMAIN", SECTION_PRE_DATA,
10565 q->data, delq->data, NULL,
10569 /* Dump Domain Comments and Security Labels */
10570 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10571 dumpComment(fout, labelq->data,
10572 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10573 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10575 if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10576 dumpSecLabel(fout, labelq->data,
10577 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10578 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10580 if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10581 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10582 qtypname, NULL, tyinfo->dobj.name,
10583 tyinfo->dobj.namespace->dobj.name,
10584 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10585 tyinfo->inittypacl, tyinfo->initrtypacl);
10587 /* Dump any per-constraint comments */
10588 for (i = 0; i < tyinfo->nDomChecks; i++)
10590 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
10591 PQExpBuffer labelq = createPQExpBuffer();
10593 appendPQExpBuffer(labelq, "CONSTRAINT %s ",
10594 fmtId(domcheck->dobj.name));
10595 appendPQExpBuffer(labelq, "ON DOMAIN %s",
10598 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10599 dumpComment(fout, labelq->data,
10600 tyinfo->dobj.namespace->dobj.name,
10602 domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
10604 destroyPQExpBuffer(labelq);
10607 destroyPQExpBuffer(q);
10608 destroyPQExpBuffer(delq);
10609 destroyPQExpBuffer(labelq);
10610 destroyPQExpBuffer(query);
10614 * dumpCompositeType
10615 * writes out to fout the queries to recreate a user-defined stand-alone
10619 dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
10621 DumpOptions *dopt = fout->dopt;
10622 PQExpBuffer q = createPQExpBuffer();
10623 PQExpBuffer dropped = createPQExpBuffer();
10624 PQExpBuffer delq = createPQExpBuffer();
10625 PQExpBuffer labelq = createPQExpBuffer();
10626 PQExpBuffer query = createPQExpBuffer();
10634 int i_attisdropped;
10635 int i_attcollation;
10639 /* Set proper schema search path so type references list correctly */
10640 selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
10642 /* Fetch type specific details */
10643 if (fout->remoteVersion >= 90100)
10646 * attcollation is new in 9.1. Since we only want to dump COLLATE
10647 * clauses for attributes whose collation is different from their
10648 * type's default, we use a CASE here to suppress uninteresting
10649 * attcollations cheaply. atttypid will be 0 for dropped columns;
10650 * collation does not matter for those.
10652 appendPQExpBuffer(query, "SELECT a.attname, "
10653 "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
10654 "a.attlen, a.attalign, a.attisdropped, "
10655 "CASE WHEN a.attcollation <> at.typcollation "
10656 "THEN a.attcollation ELSE 0 END AS attcollation "
10657 "FROM pg_catalog.pg_type ct "
10658 "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
10659 "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
10660 "WHERE ct.oid = '%u'::pg_catalog.oid "
10661 "ORDER BY a.attnum ",
10662 tyinfo->dobj.catId.oid);
10667 * Since ALTER TYPE could not drop columns until 9.1, attisdropped
10668 * should always be false.
10670 appendPQExpBuffer(query, "SELECT a.attname, "
10671 "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
10672 "a.attlen, a.attalign, a.attisdropped, "
10673 "0 AS attcollation "
10674 "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
10675 "WHERE ct.oid = '%u'::pg_catalog.oid "
10676 "AND a.attrelid = ct.typrelid "
10677 "ORDER BY a.attnum ",
10678 tyinfo->dobj.catId.oid);
10681 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10683 ntups = PQntuples(res);
10685 i_attname = PQfnumber(res, "attname");
10686 i_atttypdefn = PQfnumber(res, "atttypdefn");
10687 i_attlen = PQfnumber(res, "attlen");
10688 i_attalign = PQfnumber(res, "attalign");
10689 i_attisdropped = PQfnumber(res, "attisdropped");
10690 i_attcollation = PQfnumber(res, "attcollation");
10692 if (dopt->binary_upgrade)
10694 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10695 tyinfo->dobj.catId.oid);
10696 binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid, false);
10699 qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10701 appendPQExpBuffer(q, "CREATE TYPE %s AS (",
10705 for (i = 0; i < ntups; i++)
10714 attname = PQgetvalue(res, i, i_attname);
10715 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
10716 attlen = PQgetvalue(res, i, i_attlen);
10717 attalign = PQgetvalue(res, i, i_attalign);
10718 attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
10719 attcollation = atooid(PQgetvalue(res, i, i_attcollation));
10721 if (attisdropped && !dopt->binary_upgrade)
10724 /* Format properly if not first attr */
10725 if (actual_atts++ > 0)
10726 appendPQExpBufferChar(q, ',');
10727 appendPQExpBufferStr(q, "\n\t");
10731 appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
10733 /* Add collation if not default for the column type */
10734 if (OidIsValid(attcollation))
10738 coll = findCollationByOid(attcollation);
10741 /* always schema-qualify, don't try to be smart */
10742 appendPQExpBuffer(q, " COLLATE %s.",
10743 fmtId(coll->dobj.namespace->dobj.name));
10744 appendPQExpBufferStr(q, fmtId(coll->dobj.name));
10751 * This is a dropped attribute and we're in binary_upgrade mode.
10752 * Insert a placeholder for it in the CREATE TYPE command, and set
10753 * length and alignment with direct UPDATE to the catalogs
10754 * afterwards. See similar code in dumpTableSchema().
10756 appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
10758 /* stash separately for insertion after the CREATE TYPE */
10759 appendPQExpBufferStr(dropped,
10760 "\n-- For binary upgrade, recreate dropped column.\n");
10761 appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
10762 "SET attlen = %s, "
10763 "attalign = '%s', attbyval = false\n"
10764 "WHERE attname = ", attlen, attalign);
10765 appendStringLiteralAH(dropped, attname, fout);
10766 appendPQExpBufferStr(dropped, "\n AND attrelid = ");
10767 appendStringLiteralAH(dropped, qtypname, fout);
10768 appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
10770 appendPQExpBuffer(dropped, "ALTER TYPE %s ",
10772 appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
10776 appendPQExpBufferStr(q, "\n);\n");
10777 appendPQExpBufferStr(q, dropped->data);
10780 * DROP must be fully qualified in case same name appears in pg_catalog
10782 appendPQExpBuffer(delq, "DROP TYPE %s.",
10783 fmtId(tyinfo->dobj.namespace->dobj.name));
10784 appendPQExpBuffer(delq, "%s;\n",
10787 appendPQExpBuffer(labelq, "TYPE %s", qtypname);
10789 if (dopt->binary_upgrade)
10790 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
10792 if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10793 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10795 tyinfo->dobj.namespace->dobj.name,
10797 tyinfo->rolname, false,
10798 "TYPE", SECTION_PRE_DATA,
10799 q->data, delq->data, NULL,
10804 /* Dump Type Comments and Security Labels */
10805 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10806 dumpComment(fout, labelq->data,
10807 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10808 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10810 if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10811 dumpSecLabel(fout, labelq->data,
10812 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10813 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10815 if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10816 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10817 qtypname, NULL, tyinfo->dobj.name,
10818 tyinfo->dobj.namespace->dobj.name,
10819 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10820 tyinfo->inittypacl, tyinfo->initrtypacl);
10823 destroyPQExpBuffer(q);
10824 destroyPQExpBuffer(dropped);
10825 destroyPQExpBuffer(delq);
10826 destroyPQExpBuffer(labelq);
10827 destroyPQExpBuffer(query);
10829 /* Dump any per-column comments */
10830 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10831 dumpCompositeTypeColComments(fout, tyinfo);
10835 * dumpCompositeTypeColComments
10836 * writes out to fout the queries to recreate comments on the columns of
10837 * a user-defined stand-alone composite type
10840 dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
10842 CommentItem *comments;
10846 PQExpBuffer target;
10853 query = createPQExpBuffer();
10855 appendPQExpBuffer(query,
10856 "SELECT c.tableoid, a.attname, a.attnum "
10857 "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
10858 "WHERE c.oid = '%u' AND c.oid = a.attrelid "
10859 " AND NOT a.attisdropped "
10860 "ORDER BY a.attnum ",
10863 /* Fetch column attnames */
10864 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10866 ntups = PQntuples(res);
10870 destroyPQExpBuffer(query);
10874 pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
10876 /* Search for comments associated with type's pg_class OID */
10877 ncomments = findComments(fout,
10882 /* If no comments exist, we're done */
10883 if (ncomments <= 0)
10886 destroyPQExpBuffer(query);
10890 /* Build COMMENT ON statements */
10891 target = createPQExpBuffer();
10893 i_attnum = PQfnumber(res, "attnum");
10894 i_attname = PQfnumber(res, "attname");
10895 while (ncomments > 0)
10897 const char *attname;
10900 for (i = 0; i < ntups; i++)
10902 if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
10904 attname = PQgetvalue(res, i, i_attname);
10908 if (attname) /* just in case we don't find it */
10910 const char *descr = comments->descr;
10912 resetPQExpBuffer(target);
10913 appendPQExpBuffer(target, "COLUMN %s.",
10914 fmtId(tyinfo->dobj.name));
10915 appendPQExpBufferStr(target, fmtId(attname));
10917 resetPQExpBuffer(query);
10918 appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
10919 appendStringLiteralAH(query, descr, fout);
10920 appendPQExpBufferStr(query, ";\n");
10922 ArchiveEntry(fout, nilCatalogId, createDumpId(),
10924 tyinfo->dobj.namespace->dobj.name,
10925 NULL, tyinfo->rolname,
10926 false, "COMMENT", SECTION_NONE,
10927 query->data, "", NULL,
10928 &(tyinfo->dobj.dumpId), 1,
10937 destroyPQExpBuffer(query);
10938 destroyPQExpBuffer(target);
10943 * writes out to fout the queries to create a shell type
10945 * We dump a shell definition in advance of the I/O functions for the type.
10948 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
10950 DumpOptions *dopt = fout->dopt;
10953 /* Skip if not to be dumped */
10954 if (!stinfo->dobj.dump || dopt->dataOnly)
10957 q = createPQExpBuffer();
10960 * Note the lack of a DROP command for the shell type; any required DROP
10961 * is driven off the base type entry, instead. This interacts with
10962 * _printTocEntry()'s use of the presence of a DROP command to decide
10963 * whether an entry needs an ALTER OWNER command. We don't want to alter
10964 * the shell type's owner immediately on creation; that should happen only
10965 * after it's filled in, otherwise the backend complains.
10968 if (dopt->binary_upgrade)
10969 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10970 stinfo->baseType->dobj.catId.oid);
10972 appendPQExpBuffer(q, "CREATE TYPE %s;\n",
10973 fmtId(stinfo->dobj.name));
10975 if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10976 ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
10978 stinfo->dobj.namespace->dobj.name,
10980 stinfo->baseType->rolname, false,
10981 "SHELL TYPE", SECTION_PRE_DATA,
10986 destroyPQExpBuffer(q);
10991 * writes out to fout the queries to recreate a user-defined
10992 * procedural language
10995 dumpProcLang(Archive *fout, ProcLangInfo *plang)
10997 DumpOptions *dopt = fout->dopt;
10998 PQExpBuffer defqry;
10999 PQExpBuffer delqry;
11000 PQExpBuffer labelq;
11004 FuncInfo *funcInfo;
11005 FuncInfo *inlineInfo = NULL;
11006 FuncInfo *validatorInfo = NULL;
11008 /* Skip if not to be dumped */
11009 if (!plang->dobj.dump || dopt->dataOnly)
11013 * Try to find the support function(s). It is not an error if we don't
11014 * find them --- if the functions are in the pg_catalog schema, as is
11015 * standard in 8.1 and up, then we won't have loaded them. (In this case
11016 * we will emit a parameterless CREATE LANGUAGE command, which will
11017 * require PL template knowledge in the backend to reload.)
11020 funcInfo = findFuncByOid(plang->lanplcallfoid);
11021 if (funcInfo != NULL && !funcInfo->dobj.dump)
11022 funcInfo = NULL; /* treat not-dumped same as not-found */
11024 if (OidIsValid(plang->laninline))
11026 inlineInfo = findFuncByOid(plang->laninline);
11027 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
11031 if (OidIsValid(plang->lanvalidator))
11033 validatorInfo = findFuncByOid(plang->lanvalidator);
11034 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
11035 validatorInfo = NULL;
11039 * If the functions are dumpable then emit a traditional CREATE LANGUAGE
11040 * with parameters. Otherwise, we'll write a parameterless command, which
11041 * will rely on data from pg_pltemplate.
11043 useParams = (funcInfo != NULL &&
11044 (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
11045 (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
11047 defqry = createPQExpBuffer();
11048 delqry = createPQExpBuffer();
11049 labelq = createPQExpBuffer();
11051 qlanname = pg_strdup(fmtId(plang->dobj.name));
11054 * If dumping a HANDLER clause, treat the language as being in the handler
11055 * function's schema; this avoids cluttering the HANDLER clause. Otherwise
11056 * it doesn't really have a schema.
11059 lanschema = funcInfo->dobj.namespace->dobj.name;
11063 appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
11068 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
11069 plang->lanpltrusted ? "TRUSTED " : "",
11071 appendPQExpBuffer(defqry, " HANDLER %s",
11072 fmtId(funcInfo->dobj.name));
11073 if (OidIsValid(plang->laninline))
11075 appendPQExpBufferStr(defqry, " INLINE ");
11076 /* Cope with possibility that inline is in different schema */
11077 if (inlineInfo->dobj.namespace != funcInfo->dobj.namespace)
11078 appendPQExpBuffer(defqry, "%s.",
11079 fmtId(inlineInfo->dobj.namespace->dobj.name));
11080 appendPQExpBufferStr(defqry, fmtId(inlineInfo->dobj.name));
11082 if (OidIsValid(plang->lanvalidator))
11084 appendPQExpBufferStr(defqry, " VALIDATOR ");
11085 /* Cope with possibility that validator is in different schema */
11086 if (validatorInfo->dobj.namespace != funcInfo->dobj.namespace)
11087 appendPQExpBuffer(defqry, "%s.",
11088 fmtId(validatorInfo->dobj.namespace->dobj.name));
11089 appendPQExpBufferStr(defqry, fmtId(validatorInfo->dobj.name));
11095 * If not dumping parameters, then use CREATE OR REPLACE so that the
11096 * command will not fail if the language is preinstalled in the target
11097 * database. We restrict the use of REPLACE to this case so as to
11098 * eliminate the risk of replacing a language with incompatible
11099 * parameter settings: this command will only succeed at all if there
11100 * is a pg_pltemplate entry, and if there is one, the existing entry
11101 * must match it too.
11103 appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
11106 appendPQExpBufferStr(defqry, ";\n");
11108 appendPQExpBuffer(labelq, "LANGUAGE %s", qlanname);
11110 if (dopt->binary_upgrade)
11111 binary_upgrade_extension_member(defqry, &plang->dobj, labelq->data);
11113 if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
11114 ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
11116 lanschema, NULL, plang->lanowner,
11117 false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
11118 defqry->data, delqry->data, NULL,
11122 /* Dump Proc Lang Comments and Security Labels */
11123 if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
11124 dumpComment(fout, labelq->data,
11125 lanschema, plang->lanowner,
11126 plang->dobj.catId, 0, plang->dobj.dumpId);
11128 if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
11129 dumpSecLabel(fout, labelq->data,
11130 lanschema, plang->lanowner,
11131 plang->dobj.catId, 0, plang->dobj.dumpId);
11133 if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
11134 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
11135 qlanname, NULL, plang->dobj.name,
11137 plang->lanowner, plang->lanacl, plang->rlanacl,
11138 plang->initlanacl, plang->initrlanacl);
11142 destroyPQExpBuffer(defqry);
11143 destroyPQExpBuffer(delqry);
11144 destroyPQExpBuffer(labelq);
11148 * format_function_arguments: generate function name and argument list
11150 * This is used when we can rely on pg_get_function_arguments to format
11151 * the argument list. Note, however, that pg_get_function_arguments
11152 * does not special-case zero-argument aggregates.
11155 format_function_arguments(FuncInfo *finfo, char *funcargs, bool is_agg)
11157 PQExpBufferData fn;
11159 initPQExpBuffer(&fn);
11160 appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
11161 if (is_agg && finfo->nargs == 0)
11162 appendPQExpBufferStr(&fn, "(*)");
11164 appendPQExpBuffer(&fn, "(%s)", funcargs);
11169 * format_function_arguments_old: generate function name and argument list
11171 * The argument type names are qualified if needed. The function name
11172 * is never qualified.
11174 * This is used only with pre-8.4 servers, so we aren't expecting to see
11175 * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
11177 * Any or all of allargtypes, argmodes, argnames may be NULL.
11180 format_function_arguments_old(Archive *fout,
11181 FuncInfo *finfo, int nallargs,
11182 char **allargtypes,
11186 PQExpBufferData fn;
11189 initPQExpBuffer(&fn);
11190 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11191 for (j = 0; j < nallargs; j++)
11195 const char *argmode;
11196 const char *argname;
11198 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
11199 typname = getFormattedTypeName(fout, typid, zeroAsOpaque);
11203 switch (argmodes[j][0])
11205 case PROARGMODE_IN:
11208 case PROARGMODE_OUT:
11211 case PROARGMODE_INOUT:
11212 argmode = "INOUT ";
11215 write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
11223 argname = argnames ? argnames[j] : (char *) NULL;
11224 if (argname && argname[0] == '\0')
11227 appendPQExpBuffer(&fn, "%s%s%s%s%s",
11228 (j > 0) ? ", " : "",
11230 argname ? fmtId(argname) : "",
11231 argname ? " " : "",
11235 appendPQExpBufferChar(&fn, ')');
11240 * format_function_signature: generate function name and argument list
11242 * This is like format_function_arguments_old except that only a minimal
11243 * list of input argument types is generated; this is sufficient to
11244 * reference the function, but not to define it.
11246 * If honor_quotes is false then the function name is never quoted.
11247 * This is appropriate for use in TOC tags, but not in SQL commands.
11250 format_function_signature(Archive *fout, FuncInfo *finfo, bool honor_quotes)
11252 PQExpBufferData fn;
11255 initPQExpBuffer(&fn);
11257 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11259 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
11260 for (j = 0; j < finfo->nargs; j++)
11265 appendPQExpBufferStr(&fn, ", ");
11267 typname = getFormattedTypeName(fout, finfo->argtypes[j],
11269 appendPQExpBufferStr(&fn, typname);
11272 appendPQExpBufferChar(&fn, ')');
11279 * dump out one function
11282 dumpFunc(Archive *fout, FuncInfo *finfo)
11284 DumpOptions *dopt = fout->dopt;
11287 PQExpBuffer delqry;
11288 PQExpBuffer labelq;
11289 PQExpBuffer asPart;
11291 char *funcsig; /* identity signature */
11292 char *funcfullsig = NULL; /* full signature */
11300 char *proallargtypes;
11308 char *proleakproof;
11316 char **allargtypes = NULL;
11317 char **argmodes = NULL;
11318 char **argnames = NULL;
11319 char **configitems = NULL;
11320 int nconfigitems = 0;
11323 /* Skip if not to be dumped */
11324 if (!finfo->dobj.dump || dopt->dataOnly)
11327 query = createPQExpBuffer();
11328 q = createPQExpBuffer();
11329 delqry = createPQExpBuffer();
11330 labelq = createPQExpBuffer();
11331 asPart = createPQExpBuffer();
11333 /* Set proper schema search path so type references list correctly */
11334 selectSourceSchema(fout, finfo->dobj.namespace->dobj.name);
11336 /* Fetch function-specific details */
11337 if (fout->remoteVersion >= 90600)
11340 * proparallel was added in 9.6
11342 appendPQExpBuffer(query,
11343 "SELECT proretset, prosrc, probin, "
11344 "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11345 "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11346 "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11347 "array_to_string(protrftypes, ' ') AS protrftypes, "
11348 "proiswindow, provolatile, proisstrict, prosecdef, "
11349 "proleakproof, proconfig, procost, prorows, "
11351 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11352 "FROM pg_catalog.pg_proc "
11353 "WHERE oid = '%u'::pg_catalog.oid",
11354 finfo->dobj.catId.oid);
11356 else if (fout->remoteVersion >= 90500)
11359 * protrftypes was added in 9.5
11361 appendPQExpBuffer(query,
11362 "SELECT proretset, prosrc, probin, "
11363 "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11364 "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11365 "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11366 "array_to_string(protrftypes, ' ') AS protrftypes, "
11367 "proiswindow, provolatile, proisstrict, prosecdef, "
11368 "proleakproof, proconfig, procost, prorows, "
11369 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11370 "FROM pg_catalog.pg_proc "
11371 "WHERE oid = '%u'::pg_catalog.oid",
11372 finfo->dobj.catId.oid);
11374 else if (fout->remoteVersion >= 90200)
11377 * proleakproof was added in 9.2
11379 appendPQExpBuffer(query,
11380 "SELECT proretset, prosrc, probin, "
11381 "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11382 "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11383 "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11384 "proiswindow, provolatile, proisstrict, prosecdef, "
11385 "proleakproof, proconfig, procost, prorows, "
11386 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11387 "FROM pg_catalog.pg_proc "
11388 "WHERE oid = '%u'::pg_catalog.oid",
11389 finfo->dobj.catId.oid);
11391 else if (fout->remoteVersion >= 80400)
11394 * In 8.4 and up we rely on pg_get_function_arguments and
11395 * pg_get_function_result instead of examining proallargtypes etc.
11397 appendPQExpBuffer(query,
11398 "SELECT proretset, prosrc, probin, "
11399 "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11400 "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11401 "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11402 "proiswindow, provolatile, proisstrict, prosecdef, "
11403 "false AS proleakproof, "
11404 " proconfig, procost, prorows, "
11405 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11406 "FROM pg_catalog.pg_proc "
11407 "WHERE oid = '%u'::pg_catalog.oid",
11408 finfo->dobj.catId.oid);
11410 else if (fout->remoteVersion >= 80300)
11412 appendPQExpBuffer(query,
11413 "SELECT proretset, prosrc, probin, "
11414 "proallargtypes, proargmodes, proargnames, "
11415 "false AS proiswindow, "
11416 "provolatile, proisstrict, prosecdef, "
11417 "false AS proleakproof, "
11418 "proconfig, procost, prorows, "
11419 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11420 "FROM pg_catalog.pg_proc "
11421 "WHERE oid = '%u'::pg_catalog.oid",
11422 finfo->dobj.catId.oid);
11424 else if (fout->remoteVersion >= 80100)
11426 appendPQExpBuffer(query,
11427 "SELECT proretset, prosrc, probin, "
11428 "proallargtypes, proargmodes, proargnames, "
11429 "false AS proiswindow, "
11430 "provolatile, proisstrict, prosecdef, "
11431 "false AS proleakproof, "
11432 "null AS proconfig, 0 AS procost, 0 AS prorows, "
11433 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11434 "FROM pg_catalog.pg_proc "
11435 "WHERE oid = '%u'::pg_catalog.oid",
11436 finfo->dobj.catId.oid);
11440 appendPQExpBuffer(query,
11441 "SELECT proretset, prosrc, probin, "
11442 "null AS proallargtypes, "
11443 "null AS proargmodes, "
11445 "false AS proiswindow, "
11446 "provolatile, proisstrict, prosecdef, "
11447 "false AS proleakproof, "
11448 "null AS proconfig, 0 AS procost, 0 AS prorows, "
11449 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11450 "FROM pg_catalog.pg_proc "
11451 "WHERE oid = '%u'::pg_catalog.oid",
11452 finfo->dobj.catId.oid);
11455 res = ExecuteSqlQueryForSingleRow(fout, query->data);
11457 proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
11458 prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
11459 probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
11460 if (fout->remoteVersion >= 80400)
11462 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
11463 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
11464 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
11465 proallargtypes = proargmodes = proargnames = NULL;
11469 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
11470 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
11471 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
11472 funcargs = funciargs = funcresult = NULL;
11474 if (PQfnumber(res, "protrftypes") != -1)
11475 protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
11477 protrftypes = NULL;
11478 proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow"));
11479 provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
11480 proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
11481 prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
11482 proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
11483 proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
11484 procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
11485 prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
11487 if (PQfnumber(res, "proparallel") != -1)
11488 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
11490 proparallel = NULL;
11492 lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
11495 * See backend/commands/functioncmds.c for details of how the 'AS' clause
11496 * is used. In 8.4 and up, an unused probin is NULL (here ""); previous
11497 * versions would set it to "-". There are no known cases in which prosrc
11498 * is unused, so the tests below for "-" are probably useless.
11500 if (probin[0] != '\0' && strcmp(probin, "-") != 0)
11502 appendPQExpBufferStr(asPart, "AS ");
11503 appendStringLiteralAH(asPart, probin, fout);
11504 if (strcmp(prosrc, "-") != 0)
11506 appendPQExpBufferStr(asPart, ", ");
11509 * where we have bin, use dollar quoting if allowed and src
11510 * contains quote or backslash; else use regular quoting.
11512 if (dopt->disable_dollar_quoting ||
11513 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
11514 appendStringLiteralAH(asPart, prosrc, fout);
11516 appendStringLiteralDQ(asPart, prosrc, NULL);
11521 if (strcmp(prosrc, "-") != 0)
11523 appendPQExpBufferStr(asPart, "AS ");
11524 /* with no bin, dollar quote src unconditionally if allowed */
11525 if (dopt->disable_dollar_quoting)
11526 appendStringLiteralAH(asPart, prosrc, fout);
11528 appendStringLiteralDQ(asPart, prosrc, NULL);
11532 nallargs = finfo->nargs; /* unless we learn different from allargs */
11534 if (proallargtypes && *proallargtypes)
11538 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
11539 nitems < finfo->nargs)
11541 write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
11544 allargtypes = NULL;
11550 if (proargmodes && *proargmodes)
11554 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
11555 nitems != nallargs)
11557 write_msg(NULL, "WARNING: could not parse proargmodes array\n");
11564 if (proargnames && *proargnames)
11568 if (!parsePGArray(proargnames, &argnames, &nitems) ||
11569 nitems != nallargs)
11571 write_msg(NULL, "WARNING: could not parse proargnames array\n");
11578 if (proconfig && *proconfig)
11580 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
11582 write_msg(NULL, "WARNING: could not parse proconfig array\n");
11585 configitems = NULL;
11592 /* 8.4 or later; we rely on server-side code for most of the work */
11593 funcfullsig = format_function_arguments(finfo, funcargs, false);
11594 funcsig = format_function_arguments(finfo, funciargs, false);
11597 /* pre-8.4, do it ourselves */
11598 funcsig = format_function_arguments_old(fout,
11599 finfo, nallargs, allargtypes,
11600 argmodes, argnames);
11602 funcsig_tag = format_function_signature(fout, finfo, false);
11605 * DROP must be fully qualified in case same name appears in pg_catalog
11607 appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
11608 fmtId(finfo->dobj.namespace->dobj.name),
11611 appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig ? funcfullsig :
11614 appendPQExpBuffer(q, "RETURNS %s", funcresult);
11617 rettypename = getFormattedTypeName(fout, finfo->prorettype,
11619 appendPQExpBuffer(q, "RETURNS %s%s",
11620 (proretset[0] == 't') ? "SETOF " : "",
11625 appendPQExpBuffer(q, "\n LANGUAGE %s", fmtId(lanname));
11627 if (protrftypes != NULL && strcmp(protrftypes, "") != 0)
11629 Oid *typeids = palloc(FUNC_MAX_ARGS * sizeof(Oid));
11632 appendPQExpBufferStr(q, " TRANSFORM ");
11633 parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
11634 for (i = 0; typeids[i]; i++)
11637 appendPQExpBufferStr(q, ", ");
11638 appendPQExpBuffer(q, "FOR TYPE %s",
11639 getFormattedTypeName(fout, typeids[i], zeroAsNone));
11643 if (proiswindow[0] == 't')
11644 appendPQExpBufferStr(q, " WINDOW");
11646 if (provolatile[0] != PROVOLATILE_VOLATILE)
11648 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
11649 appendPQExpBufferStr(q, " IMMUTABLE");
11650 else if (provolatile[0] == PROVOLATILE_STABLE)
11651 appendPQExpBufferStr(q, " STABLE");
11652 else if (provolatile[0] != PROVOLATILE_VOLATILE)
11653 exit_horribly(NULL, "unrecognized provolatile value for function \"%s\"\n",
11657 if (proisstrict[0] == 't')
11658 appendPQExpBufferStr(q, " STRICT");
11660 if (prosecdef[0] == 't')
11661 appendPQExpBufferStr(q, " SECURITY DEFINER");
11663 if (proleakproof[0] == 't')
11664 appendPQExpBufferStr(q, " LEAKPROOF");
11667 * COST and ROWS are emitted only if present and not default, so as not to
11668 * break backwards-compatibility of the dump without need. Keep this code
11669 * in sync with the defaults in functioncmds.c.
11671 if (strcmp(procost, "0") != 0)
11673 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
11675 /* default cost is 1 */
11676 if (strcmp(procost, "1") != 0)
11677 appendPQExpBuffer(q, " COST %s", procost);
11681 /* default cost is 100 */
11682 if (strcmp(procost, "100") != 0)
11683 appendPQExpBuffer(q, " COST %s", procost);
11686 if (proretset[0] == 't' &&
11687 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
11688 appendPQExpBuffer(q, " ROWS %s", prorows);
11690 if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
11692 if (proparallel[0] == PROPARALLEL_SAFE)
11693 appendPQExpBufferStr(q, " PARALLEL SAFE");
11694 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
11695 appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
11696 else if (proparallel[0] != PROPARALLEL_UNSAFE)
11697 exit_horribly(NULL, "unrecognized proparallel value for function \"%s\"\n",
11701 for (i = 0; i < nconfigitems; i++)
11703 /* we feel free to scribble on configitems[] here */
11704 char *configitem = configitems[i];
11707 pos = strchr(configitem, '=');
11711 appendPQExpBuffer(q, "\n SET %s TO ", fmtId(configitem));
11714 * Some GUC variable names are 'LIST' type and hence must not be
11717 if (pg_strcasecmp(configitem, "DateStyle") == 0
11718 || pg_strcasecmp(configitem, "search_path") == 0)
11719 appendPQExpBufferStr(q, pos);
11721 appendStringLiteralAH(q, pos, fout);
11724 appendPQExpBuffer(q, "\n %s;\n", asPart->data);
11726 appendPQExpBuffer(labelq, "FUNCTION %s", funcsig);
11728 if (dopt->binary_upgrade)
11729 binary_upgrade_extension_member(q, &finfo->dobj, labelq->data);
11731 if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11732 ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
11734 finfo->dobj.namespace->dobj.name,
11736 finfo->rolname, false,
11737 "FUNCTION", SECTION_PRE_DATA,
11738 q->data, delqry->data, NULL,
11742 /* Dump Function Comments and Security Labels */
11743 if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11744 dumpComment(fout, labelq->data,
11745 finfo->dobj.namespace->dobj.name, finfo->rolname,
11746 finfo->dobj.catId, 0, finfo->dobj.dumpId);
11748 if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11749 dumpSecLabel(fout, labelq->data,
11750 finfo->dobj.namespace->dobj.name, finfo->rolname,
11751 finfo->dobj.catId, 0, finfo->dobj.dumpId);
11753 if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
11754 dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
11755 funcsig, NULL, funcsig_tag,
11756 finfo->dobj.namespace->dobj.name,
11757 finfo->rolname, finfo->proacl, finfo->rproacl,
11758 finfo->initproacl, finfo->initrproacl);
11762 destroyPQExpBuffer(query);
11763 destroyPQExpBuffer(q);
11764 destroyPQExpBuffer(delqry);
11765 destroyPQExpBuffer(labelq);
11766 destroyPQExpBuffer(asPart);
11783 * Dump a user-defined cast
11786 dumpCast(Archive *fout, CastInfo *cast)
11788 DumpOptions *dopt = fout->dopt;
11789 PQExpBuffer defqry;
11790 PQExpBuffer delqry;
11791 PQExpBuffer labelq;
11792 FuncInfo *funcInfo = NULL;
11796 /* Skip if not to be dumped */
11797 if (!cast->dobj.dump || dopt->dataOnly)
11800 /* Cannot dump if we don't have the cast function's info */
11801 if (OidIsValid(cast->castfunc))
11803 funcInfo = findFuncByOid(cast->castfunc);
11804 if (funcInfo == NULL)
11805 exit_horribly(NULL, "could not find function definition for function with OID %u\n",
11810 * Make sure we are in proper schema (needed for getFormattedTypeName).
11811 * Casts don't have a schema of their own, so use pg_catalog.
11813 selectSourceSchema(fout, "pg_catalog");
11815 defqry = createPQExpBuffer();
11816 delqry = createPQExpBuffer();
11817 labelq = createPQExpBuffer();
11819 sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
11820 targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
11821 appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
11822 sourceType, targetType);
11824 appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
11825 sourceType, targetType);
11827 switch (cast->castmethod)
11829 case COERCION_METHOD_BINARY:
11830 appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
11832 case COERCION_METHOD_INOUT:
11833 appendPQExpBufferStr(defqry, "WITH INOUT");
11835 case COERCION_METHOD_FUNCTION:
11838 char *fsig = format_function_signature(fout, funcInfo, true);
11841 * Always qualify the function name, in case it is not in
11842 * pg_catalog schema (format_function_signature won't qualify
11845 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
11846 fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
11850 write_msg(NULL, "WARNING: bogus value in pg_cast.castfunc or pg_cast.castmethod field\n");
11853 write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
11856 if (cast->castcontext == 'a')
11857 appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
11858 else if (cast->castcontext == 'i')
11859 appendPQExpBufferStr(defqry, " AS IMPLICIT");
11860 appendPQExpBufferStr(defqry, ";\n");
11862 appendPQExpBuffer(labelq, "CAST (%s AS %s)",
11863 sourceType, targetType);
11865 if (dopt->binary_upgrade)
11866 binary_upgrade_extension_member(defqry, &cast->dobj, labelq->data);
11868 if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
11869 ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
11871 "pg_catalog", NULL, "",
11872 false, "CAST", SECTION_PRE_DATA,
11873 defqry->data, delqry->data, NULL,
11877 /* Dump Cast Comments */
11878 if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
11879 dumpComment(fout, labelq->data,
11881 cast->dobj.catId, 0, cast->dobj.dumpId);
11886 destroyPQExpBuffer(defqry);
11887 destroyPQExpBuffer(delqry);
11888 destroyPQExpBuffer(labelq);
11895 dumpTransform(Archive *fout, TransformInfo *transform)
11897 DumpOptions *dopt = fout->dopt;
11898 PQExpBuffer defqry;
11899 PQExpBuffer delqry;
11900 PQExpBuffer labelq;
11901 FuncInfo *fromsqlFuncInfo = NULL;
11902 FuncInfo *tosqlFuncInfo = NULL;
11904 char *transformType;
11906 /* Skip if not to be dumped */
11907 if (!transform->dobj.dump || dopt->dataOnly)
11910 /* Cannot dump if we don't have the transform functions' info */
11911 if (OidIsValid(transform->trffromsql))
11913 fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
11914 if (fromsqlFuncInfo == NULL)
11915 exit_horribly(NULL, "could not find function definition for function with OID %u\n",
11916 transform->trffromsql);
11918 if (OidIsValid(transform->trftosql))
11920 tosqlFuncInfo = findFuncByOid(transform->trftosql);
11921 if (tosqlFuncInfo == NULL)
11922 exit_horribly(NULL, "could not find function definition for function with OID %u\n",
11923 transform->trftosql);
11926 /* Make sure we are in proper schema (needed for getFormattedTypeName) */
11927 selectSourceSchema(fout, "pg_catalog");
11929 defqry = createPQExpBuffer();
11930 delqry = createPQExpBuffer();
11931 labelq = createPQExpBuffer();
11933 lanname = get_language_name(fout, transform->trflang);
11934 transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
11936 appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
11937 transformType, lanname);
11939 appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
11940 transformType, lanname);
11942 if (!transform->trffromsql && !transform->trftosql)
11943 write_msg(NULL, "WARNING: bogus transform definition, at least one of trffromsql and trftosql should be nonzero\n");
11945 if (transform->trffromsql)
11947 if (fromsqlFuncInfo)
11949 char *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
11952 * Always qualify the function name, in case it is not in
11953 * pg_catalog schema (format_function_signature won't qualify it).
11955 appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
11956 fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
11960 write_msg(NULL, "WARNING: bogus value in pg_transform.trffromsql field\n");
11963 if (transform->trftosql)
11965 if (transform->trffromsql)
11966 appendPQExpBuffer(defqry, ", ");
11970 char *fsig = format_function_signature(fout, tosqlFuncInfo, true);
11973 * Always qualify the function name, in case it is not in
11974 * pg_catalog schema (format_function_signature won't qualify it).
11976 appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
11977 fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
11981 write_msg(NULL, "WARNING: bogus value in pg_transform.trftosql field\n");
11984 appendPQExpBuffer(defqry, ");\n");
11986 appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
11987 transformType, lanname);
11989 if (dopt->binary_upgrade)
11990 binary_upgrade_extension_member(defqry, &transform->dobj, labelq->data);
11992 if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
11993 ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
11995 "pg_catalog", NULL, "",
11996 false, "TRANSFORM", SECTION_PRE_DATA,
11997 defqry->data, delqry->data, NULL,
11998 transform->dobj.dependencies, transform->dobj.nDeps,
12001 /* Dump Transform Comments */
12002 if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
12003 dumpComment(fout, labelq->data,
12005 transform->dobj.catId, 0, transform->dobj.dumpId);
12008 free(transformType);
12009 destroyPQExpBuffer(defqry);
12010 destroyPQExpBuffer(delqry);
12011 destroyPQExpBuffer(labelq);
12017 * write out a single operator definition
12020 dumpOpr(Archive *fout, OprInfo *oprinfo)
12022 DumpOptions *dopt = fout->dopt;
12026 PQExpBuffer labelq;
12028 PQExpBuffer details;
12053 /* Skip if not to be dumped */
12054 if (!oprinfo->dobj.dump || dopt->dataOnly)
12058 * some operators are invalid because they were the result of user
12059 * defining operators before commutators exist
12061 if (!OidIsValid(oprinfo->oprcode))
12064 query = createPQExpBuffer();
12065 q = createPQExpBuffer();
12066 delq = createPQExpBuffer();
12067 labelq = createPQExpBuffer();
12068 oprid = createPQExpBuffer();
12069 details = createPQExpBuffer();
12071 /* Make sure we are in proper schema so regoperator works correctly */
12072 selectSourceSchema(fout, oprinfo->dobj.namespace->dobj.name);
12074 if (fout->remoteVersion >= 80300)
12076 appendPQExpBuffer(query, "SELECT oprkind, "
12077 "oprcode::pg_catalog.regprocedure, "
12078 "oprleft::pg_catalog.regtype, "
12079 "oprright::pg_catalog.regtype, "
12080 "oprcom::pg_catalog.regoperator, "
12081 "oprnegate::pg_catalog.regoperator, "
12082 "oprrest::pg_catalog.regprocedure, "
12083 "oprjoin::pg_catalog.regprocedure, "
12084 "oprcanmerge, oprcanhash "
12085 "FROM pg_catalog.pg_operator "
12086 "WHERE oid = '%u'::pg_catalog.oid",
12087 oprinfo->dobj.catId.oid);
12091 appendPQExpBuffer(query, "SELECT oprkind, "
12092 "oprcode::pg_catalog.regprocedure, "
12093 "oprleft::pg_catalog.regtype, "
12094 "oprright::pg_catalog.regtype, "
12095 "oprcom::pg_catalog.regoperator, "
12096 "oprnegate::pg_catalog.regoperator, "
12097 "oprrest::pg_catalog.regprocedure, "
12098 "oprjoin::pg_catalog.regprocedure, "
12099 "(oprlsortop != 0) AS oprcanmerge, "
12101 "FROM pg_catalog.pg_operator "
12102 "WHERE oid = '%u'::pg_catalog.oid",
12103 oprinfo->dobj.catId.oid);
12106 res = ExecuteSqlQueryForSingleRow(fout, query->data);
12108 i_oprkind = PQfnumber(res, "oprkind");
12109 i_oprcode = PQfnumber(res, "oprcode");
12110 i_oprleft = PQfnumber(res, "oprleft");
12111 i_oprright = PQfnumber(res, "oprright");
12112 i_oprcom = PQfnumber(res, "oprcom");
12113 i_oprnegate = PQfnumber(res, "oprnegate");
12114 i_oprrest = PQfnumber(res, "oprrest");
12115 i_oprjoin = PQfnumber(res, "oprjoin");
12116 i_oprcanmerge = PQfnumber(res, "oprcanmerge");
12117 i_oprcanhash = PQfnumber(res, "oprcanhash");
12119 oprkind = PQgetvalue(res, 0, i_oprkind);
12120 oprcode = PQgetvalue(res, 0, i_oprcode);
12121 oprleft = PQgetvalue(res, 0, i_oprleft);
12122 oprright = PQgetvalue(res, 0, i_oprright);
12123 oprcom = PQgetvalue(res, 0, i_oprcom);
12124 oprnegate = PQgetvalue(res, 0, i_oprnegate);
12125 oprrest = PQgetvalue(res, 0, i_oprrest);
12126 oprjoin = PQgetvalue(res, 0, i_oprjoin);
12127 oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
12128 oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
12130 oprregproc = convertRegProcReference(fout, oprcode);
12133 appendPQExpBuffer(details, " PROCEDURE = %s", oprregproc);
12137 appendPQExpBuffer(oprid, "%s (",
12138 oprinfo->dobj.name);
12141 * right unary means there's a left arg and left unary means there's a
12144 if (strcmp(oprkind, "r") == 0 ||
12145 strcmp(oprkind, "b") == 0)
12147 appendPQExpBuffer(details, ",\n LEFTARG = %s", oprleft);
12148 appendPQExpBufferStr(oprid, oprleft);
12151 appendPQExpBufferStr(oprid, "NONE");
12153 if (strcmp(oprkind, "l") == 0 ||
12154 strcmp(oprkind, "b") == 0)
12156 appendPQExpBuffer(details, ",\n RIGHTARG = %s", oprright);
12157 appendPQExpBuffer(oprid, ", %s)", oprright);
12160 appendPQExpBufferStr(oprid, ", NONE)");
12162 oprref = convertOperatorReference(fout, oprcom);
12165 appendPQExpBuffer(details, ",\n COMMUTATOR = %s", oprref);
12169 oprref = convertOperatorReference(fout, oprnegate);
12172 appendPQExpBuffer(details, ",\n NEGATOR = %s", oprref);
12176 if (strcmp(oprcanmerge, "t") == 0)
12177 appendPQExpBufferStr(details, ",\n MERGES");
12179 if (strcmp(oprcanhash, "t") == 0)
12180 appendPQExpBufferStr(details, ",\n HASHES");
12182 oprregproc = convertRegProcReference(fout, oprrest);
12185 appendPQExpBuffer(details, ",\n RESTRICT = %s", oprregproc);
12189 oprregproc = convertRegProcReference(fout, oprjoin);
12192 appendPQExpBuffer(details, ",\n JOIN = %s", oprregproc);
12197 * DROP must be fully qualified in case same name appears in pg_catalog
12199 appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
12200 fmtId(oprinfo->dobj.namespace->dobj.name),
12203 appendPQExpBuffer(q, "CREATE OPERATOR %s (\n%s\n);\n",
12204 oprinfo->dobj.name, details->data);
12206 appendPQExpBuffer(labelq, "OPERATOR %s", oprid->data);
12208 if (dopt->binary_upgrade)
12209 binary_upgrade_extension_member(q, &oprinfo->dobj, labelq->data);
12211 if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12212 ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
12213 oprinfo->dobj.name,
12214 oprinfo->dobj.namespace->dobj.name,
12217 false, "OPERATOR", SECTION_PRE_DATA,
12218 q->data, delq->data, NULL,
12222 /* Dump Operator Comments */
12223 if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12224 dumpComment(fout, labelq->data,
12225 oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
12226 oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
12230 destroyPQExpBuffer(query);
12231 destroyPQExpBuffer(q);
12232 destroyPQExpBuffer(delq);
12233 destroyPQExpBuffer(labelq);
12234 destroyPQExpBuffer(oprid);
12235 destroyPQExpBuffer(details);
12239 * Convert a function reference obtained from pg_operator
12241 * Returns allocated string of what to print, or NULL if function references
12242 * is InvalidOid. Returned string is expected to be free'd by the caller.
12244 * The input is a REGPROCEDURE display; we have to strip the argument-types
12248 convertRegProcReference(Archive *fout, const char *proc)
12254 /* In all cases "-" means a null reference */
12255 if (strcmp(proc, "-") == 0)
12258 name = pg_strdup(proc);
12259 /* find non-double-quoted left paren */
12261 for (paren = name; *paren; paren++)
12263 if (*paren == '(' && !inquote)
12269 inquote = !inquote;
12275 * Convert an operator cross-reference obtained from pg_operator
12277 * Returns an allocated string of what to print, or NULL to print nothing.
12278 * Caller is responsible for free'ing result string.
12280 * The input is a REGOPERATOR display; we have to strip the argument-types
12281 * part, and add OPERATOR() decoration if the name is schema-qualified.
12284 convertOperatorReference(Archive *fout, const char *opr)
12292 /* In all cases "0" means a null reference */
12293 if (strcmp(opr, "0") == 0)
12296 name = pg_strdup(opr);
12297 /* find non-double-quoted left paren, and check for non-quoted dot */
12300 for (ptr = name; *ptr; ptr++)
12303 inquote = !inquote;
12304 else if (*ptr == '.' && !inquote)
12306 else if (*ptr == '(' && !inquote)
12312 /* If not schema-qualified, don't need to add OPERATOR() */
12315 oname = psprintf("OPERATOR(%s)", name);
12321 * Convert a function OID obtained from pg_ts_parser or pg_ts_template
12323 * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
12324 * argument lists of these functions are predetermined. Note that the
12325 * caller should ensure we are in the proper schema, because the results
12326 * are search path dependent!
12329 convertTSFunction(Archive *fout, Oid funcOid)
12335 snprintf(query, sizeof(query),
12336 "SELECT '%u'::pg_catalog.regproc", funcOid);
12337 res = ExecuteSqlQueryForSingleRow(fout, query);
12339 result = pg_strdup(PQgetvalue(res, 0, 0));
12348 * write out a single access method definition
12351 dumpAccessMethod(Archive *fout, AccessMethodInfo *aminfo)
12353 DumpOptions *dopt = fout->dopt;
12356 PQExpBuffer labelq;
12359 /* Skip if not to be dumped */
12360 if (!aminfo->dobj.dump || dopt->dataOnly)
12363 q = createPQExpBuffer();
12364 delq = createPQExpBuffer();
12365 labelq = createPQExpBuffer();
12367 qamname = pg_strdup(fmtId(aminfo->dobj.name));
12369 appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
12371 switch (aminfo->amtype)
12374 appendPQExpBuffer(q, "TYPE INDEX ");
12377 write_msg(NULL, "WARNING: invalid type \"%c\" of access method \"%s\"\n",
12378 aminfo->amtype, qamname);
12380 destroyPQExpBuffer(q);
12381 destroyPQExpBuffer(delq);
12382 destroyPQExpBuffer(labelq);
12386 appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
12388 appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
12391 appendPQExpBuffer(labelq, "ACCESS METHOD %s",
12394 if (dopt->binary_upgrade)
12395 binary_upgrade_extension_member(q, &aminfo->dobj, labelq->data);
12397 if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12398 ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
12403 false, "ACCESS METHOD", SECTION_PRE_DATA,
12404 q->data, delq->data, NULL,
12408 /* Dump Access Method Comments */
12409 if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12410 dumpComment(fout, labelq->data,
12412 aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
12416 destroyPQExpBuffer(q);
12417 destroyPQExpBuffer(delq);
12418 destroyPQExpBuffer(labelq);
12423 * write out a single operator class definition
12426 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
12428 DumpOptions *dopt = fout->dopt;
12432 PQExpBuffer labelq;
12439 int i_opcfamilyname;
12440 int i_opcfamilynsp;
12442 int i_amopstrategy;
12443 int i_amopreqcheck;
12446 int i_sortfamilynsp;
12449 int i_amproclefttype;
12450 int i_amprocrighttype;
12455 char *opcfamilyname;
12456 char *opcfamilynsp;
12458 char *amopstrategy;
12459 char *amopreqcheck;
12462 char *sortfamilynsp;
12465 char *amproclefttype;
12466 char *amprocrighttype;
12470 /* Skip if not to be dumped */
12471 if (!opcinfo->dobj.dump || dopt->dataOnly)
12474 query = createPQExpBuffer();
12475 q = createPQExpBuffer();
12476 delq = createPQExpBuffer();
12477 labelq = createPQExpBuffer();
12479 /* Make sure we are in proper schema so regoperator works correctly */
12480 selectSourceSchema(fout, opcinfo->dobj.namespace->dobj.name);
12482 /* Get additional fields from the pg_opclass row */
12483 if (fout->remoteVersion >= 80300)
12485 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
12486 "opckeytype::pg_catalog.regtype, "
12487 "opcdefault, opcfamily, "
12488 "opfname AS opcfamilyname, "
12489 "nspname AS opcfamilynsp, "
12490 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
12491 "FROM pg_catalog.pg_opclass c "
12492 "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
12493 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12494 "WHERE c.oid = '%u'::pg_catalog.oid",
12495 opcinfo->dobj.catId.oid);
12499 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
12500 "opckeytype::pg_catalog.regtype, "
12501 "opcdefault, NULL AS opcfamily, "
12502 "NULL AS opcfamilyname, "
12503 "NULL AS opcfamilynsp, "
12504 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
12505 "FROM pg_catalog.pg_opclass "
12506 "WHERE oid = '%u'::pg_catalog.oid",
12507 opcinfo->dobj.catId.oid);
12510 res = ExecuteSqlQueryForSingleRow(fout, query->data);
12512 i_opcintype = PQfnumber(res, "opcintype");
12513 i_opckeytype = PQfnumber(res, "opckeytype");
12514 i_opcdefault = PQfnumber(res, "opcdefault");
12515 i_opcfamily = PQfnumber(res, "opcfamily");
12516 i_opcfamilyname = PQfnumber(res, "opcfamilyname");
12517 i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
12518 i_amname = PQfnumber(res, "amname");
12520 /* opcintype may still be needed after we PQclear res */
12521 opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
12522 opckeytype = PQgetvalue(res, 0, i_opckeytype);
12523 opcdefault = PQgetvalue(res, 0, i_opcdefault);
12524 /* opcfamily will still be needed after we PQclear res */
12525 opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
12526 opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
12527 opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
12528 /* amname will still be needed after we PQclear res */
12529 amname = pg_strdup(PQgetvalue(res, 0, i_amname));
12532 * DROP must be fully qualified in case same name appears in pg_catalog
12534 appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
12535 fmtId(opcinfo->dobj.namespace->dobj.name));
12536 appendPQExpBuffer(delq, ".%s",
12537 fmtId(opcinfo->dobj.name));
12538 appendPQExpBuffer(delq, " USING %s;\n",
12541 /* Build the fixed portion of the CREATE command */
12542 appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n ",
12543 fmtId(opcinfo->dobj.name));
12544 if (strcmp(opcdefault, "t") == 0)
12545 appendPQExpBufferStr(q, "DEFAULT ");
12546 appendPQExpBuffer(q, "FOR TYPE %s USING %s",
12549 if (strlen(opcfamilyname) > 0)
12551 appendPQExpBufferStr(q, " FAMILY ");
12552 if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
12553 appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
12554 appendPQExpBufferStr(q, fmtId(opcfamilyname));
12556 appendPQExpBufferStr(q, " AS\n ");
12560 if (strcmp(opckeytype, "-") != 0)
12562 appendPQExpBuffer(q, "STORAGE %s",
12570 * Now fetch and print the OPERATOR entries (pg_amop rows).
12572 * Print only those opfamily members that are tied to the opclass by
12573 * pg_depend entries.
12575 * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
12576 * older server's opclass in which it is used. This is to avoid
12577 * hard-to-detect breakage if a newer pg_dump is used to dump from an
12578 * older server and then reload into that old version. This can go away
12579 * once 8.3 is so old as to not be of interest to anyone.
12581 resetPQExpBuffer(query);
12583 if (fout->remoteVersion >= 90100)
12585 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12586 "amopopr::pg_catalog.regoperator, "
12587 "opfname AS sortfamily, "
12588 "nspname AS sortfamilynsp "
12589 "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
12590 "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
12591 "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
12592 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12593 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12594 "AND refobjid = '%u'::pg_catalog.oid "
12595 "AND amopfamily = '%s'::pg_catalog.oid "
12596 "ORDER BY amopstrategy",
12597 opcinfo->dobj.catId.oid,
12600 else if (fout->remoteVersion >= 80400)
12602 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12603 "amopopr::pg_catalog.regoperator, "
12604 "NULL AS sortfamily, "
12605 "NULL AS sortfamilynsp "
12606 "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12607 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12608 "AND refobjid = '%u'::pg_catalog.oid "
12609 "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12610 "AND objid = ao.oid "
12611 "ORDER BY amopstrategy",
12612 opcinfo->dobj.catId.oid);
12614 else if (fout->remoteVersion >= 80300)
12616 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
12617 "amopopr::pg_catalog.regoperator, "
12618 "NULL AS sortfamily, "
12619 "NULL AS sortfamilynsp "
12620 "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12621 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12622 "AND refobjid = '%u'::pg_catalog.oid "
12623 "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12624 "AND objid = ao.oid "
12625 "ORDER BY amopstrategy",
12626 opcinfo->dobj.catId.oid);
12631 * Here, we print all entries since there are no opfamilies and hence
12632 * no loose operators to worry about.
12634 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
12635 "amopopr::pg_catalog.regoperator, "
12636 "NULL AS sortfamily, "
12637 "NULL AS sortfamilynsp "
12638 "FROM pg_catalog.pg_amop "
12639 "WHERE amopclaid = '%u'::pg_catalog.oid "
12640 "ORDER BY amopstrategy",
12641 opcinfo->dobj.catId.oid);
12644 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12646 ntups = PQntuples(res);
12648 i_amopstrategy = PQfnumber(res, "amopstrategy");
12649 i_amopreqcheck = PQfnumber(res, "amopreqcheck");
12650 i_amopopr = PQfnumber(res, "amopopr");
12651 i_sortfamily = PQfnumber(res, "sortfamily");
12652 i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
12654 for (i = 0; i < ntups; i++)
12656 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
12657 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
12658 amopopr = PQgetvalue(res, i, i_amopopr);
12659 sortfamily = PQgetvalue(res, i, i_sortfamily);
12660 sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
12663 appendPQExpBufferStr(q, " ,\n ");
12665 appendPQExpBuffer(q, "OPERATOR %s %s",
12666 amopstrategy, amopopr);
12668 if (strlen(sortfamily) > 0)
12670 appendPQExpBufferStr(q, " FOR ORDER BY ");
12671 if (strcmp(sortfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
12672 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
12673 appendPQExpBufferStr(q, fmtId(sortfamily));
12676 if (strcmp(amopreqcheck, "t") == 0)
12677 appendPQExpBufferStr(q, " RECHECK");
12685 * Now fetch and print the FUNCTION entries (pg_amproc rows).
12687 * Print only those opfamily members that are tied to the opclass by
12688 * pg_depend entries.
12690 * We print the amproclefttype/amprocrighttype even though in most cases
12691 * the backend could deduce the right values, because of the corner case
12692 * of a btree sort support function for a cross-type comparison. That's
12693 * only allowed in 9.2 and later, but for simplicity print them in all
12694 * versions that have the columns.
12696 resetPQExpBuffer(query);
12698 if (fout->remoteVersion >= 80300)
12700 appendPQExpBuffer(query, "SELECT amprocnum, "
12701 "amproc::pg_catalog.regprocedure, "
12702 "amproclefttype::pg_catalog.regtype, "
12703 "amprocrighttype::pg_catalog.regtype "
12704 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
12705 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12706 "AND refobjid = '%u'::pg_catalog.oid "
12707 "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
12708 "AND objid = ap.oid "
12709 "ORDER BY amprocnum",
12710 opcinfo->dobj.catId.oid);
12714 appendPQExpBuffer(query, "SELECT amprocnum, "
12715 "amproc::pg_catalog.regprocedure, "
12716 "'' AS amproclefttype, "
12717 "'' AS amprocrighttype "
12718 "FROM pg_catalog.pg_amproc "
12719 "WHERE amopclaid = '%u'::pg_catalog.oid "
12720 "ORDER BY amprocnum",
12721 opcinfo->dobj.catId.oid);
12724 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12726 ntups = PQntuples(res);
12728 i_amprocnum = PQfnumber(res, "amprocnum");
12729 i_amproc = PQfnumber(res, "amproc");
12730 i_amproclefttype = PQfnumber(res, "amproclefttype");
12731 i_amprocrighttype = PQfnumber(res, "amprocrighttype");
12733 for (i = 0; i < ntups; i++)
12735 amprocnum = PQgetvalue(res, i, i_amprocnum);
12736 amproc = PQgetvalue(res, i, i_amproc);
12737 amproclefttype = PQgetvalue(res, i, i_amproclefttype);
12738 amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
12741 appendPQExpBufferStr(q, " ,\n ");
12743 appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
12745 if (*amproclefttype && *amprocrighttype)
12746 appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
12748 appendPQExpBuffer(q, " %s", amproc);
12756 * If needComma is still false it means we haven't added anything after
12757 * the AS keyword. To avoid printing broken SQL, append a dummy STORAGE
12758 * clause with the same datatype. This isn't sanctioned by the
12759 * documentation, but actually DefineOpClass will treat it as a no-op.
12762 appendPQExpBuffer(q, "STORAGE %s", opcintype);
12764 appendPQExpBufferStr(q, ";\n");
12766 appendPQExpBuffer(labelq, "OPERATOR CLASS %s",
12767 fmtId(opcinfo->dobj.name));
12768 appendPQExpBuffer(labelq, " USING %s",
12771 if (dopt->binary_upgrade)
12772 binary_upgrade_extension_member(q, &opcinfo->dobj, labelq->data);
12774 if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12775 ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
12776 opcinfo->dobj.name,
12777 opcinfo->dobj.namespace->dobj.name,
12780 false, "OPERATOR CLASS", SECTION_PRE_DATA,
12781 q->data, delq->data, NULL,
12785 /* Dump Operator Class Comments */
12786 if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12787 dumpComment(fout, labelq->data,
12788 opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
12789 opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
12794 destroyPQExpBuffer(query);
12795 destroyPQExpBuffer(q);
12796 destroyPQExpBuffer(delq);
12797 destroyPQExpBuffer(labelq);
12802 * write out a single operator family definition
12804 * Note: this also dumps any "loose" operator members that aren't bound to a
12805 * specific opclass within the opfamily.
12808 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
12810 DumpOptions *dopt = fout->dopt;
12814 PQExpBuffer labelq;
12817 PGresult *res_procs;
12820 int i_amopstrategy;
12821 int i_amopreqcheck;
12824 int i_sortfamilynsp;
12827 int i_amproclefttype;
12828 int i_amprocrighttype;
12830 char *amopstrategy;
12831 char *amopreqcheck;
12834 char *sortfamilynsp;
12837 char *amproclefttype;
12838 char *amprocrighttype;
12842 /* Skip if not to be dumped */
12843 if (!opfinfo->dobj.dump || dopt->dataOnly)
12846 query = createPQExpBuffer();
12847 q = createPQExpBuffer();
12848 delq = createPQExpBuffer();
12849 labelq = createPQExpBuffer();
12851 /* Make sure we are in proper schema so regoperator works correctly */
12852 selectSourceSchema(fout, opfinfo->dobj.namespace->dobj.name);
12855 * Fetch only those opfamily members that are tied directly to the
12856 * opfamily by pg_depend entries.
12858 * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
12859 * older server's opclass in which it is used. This is to avoid
12860 * hard-to-detect breakage if a newer pg_dump is used to dump from an
12861 * older server and then reload into that old version. This can go away
12862 * once 8.3 is so old as to not be of interest to anyone.
12864 if (fout->remoteVersion >= 90100)
12866 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12867 "amopopr::pg_catalog.regoperator, "
12868 "opfname AS sortfamily, "
12869 "nspname AS sortfamilynsp "
12870 "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
12871 "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
12872 "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
12873 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12874 "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
12875 "AND refobjid = '%u'::pg_catalog.oid "
12876 "AND amopfamily = '%u'::pg_catalog.oid "
12877 "ORDER BY amopstrategy",
12878 opfinfo->dobj.catId.oid,
12879 opfinfo->dobj.catId.oid);
12881 else if (fout->remoteVersion >= 80400)
12883 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12884 "amopopr::pg_catalog.regoperator, "
12885 "NULL AS sortfamily, "
12886 "NULL AS sortfamilynsp "
12887 "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12888 "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
12889 "AND refobjid = '%u'::pg_catalog.oid "
12890 "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12891 "AND objid = ao.oid "
12892 "ORDER BY amopstrategy",
12893 opfinfo->dobj.catId.oid);
12897 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
12898 "amopopr::pg_catalog.regoperator, "
12899 "NULL AS sortfamily, "
12900 "NULL AS sortfamilynsp "
12901 "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12902 "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
12903 "AND refobjid = '%u'::pg_catalog.oid "
12904 "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12905 "AND objid = ao.oid "
12906 "ORDER BY amopstrategy",
12907 opfinfo->dobj.catId.oid);
12910 res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12912 resetPQExpBuffer(query);
12914 appendPQExpBuffer(query, "SELECT amprocnum, "
12915 "amproc::pg_catalog.regprocedure, "
12916 "amproclefttype::pg_catalog.regtype, "
12917 "amprocrighttype::pg_catalog.regtype "
12918 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
12919 "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
12920 "AND refobjid = '%u'::pg_catalog.oid "
12921 "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
12922 "AND objid = ap.oid "
12923 "ORDER BY amprocnum",
12924 opfinfo->dobj.catId.oid);
12926 res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12928 /* Get additional fields from the pg_opfamily row */
12929 resetPQExpBuffer(query);
12931 appendPQExpBuffer(query, "SELECT "
12932 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
12933 "FROM pg_catalog.pg_opfamily "
12934 "WHERE oid = '%u'::pg_catalog.oid",
12935 opfinfo->dobj.catId.oid);
12937 res = ExecuteSqlQueryForSingleRow(fout, query->data);
12939 i_amname = PQfnumber(res, "amname");
12941 /* amname will still be needed after we PQclear res */
12942 amname = pg_strdup(PQgetvalue(res, 0, i_amname));
12945 * DROP must be fully qualified in case same name appears in pg_catalog
12947 appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
12948 fmtId(opfinfo->dobj.namespace->dobj.name));
12949 appendPQExpBuffer(delq, ".%s",
12950 fmtId(opfinfo->dobj.name));
12951 appendPQExpBuffer(delq, " USING %s;\n",
12954 /* Build the fixed portion of the CREATE command */
12955 appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
12956 fmtId(opfinfo->dobj.name));
12957 appendPQExpBuffer(q, " USING %s;\n",
12962 /* Do we need an ALTER to add loose members? */
12963 if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
12965 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
12966 fmtId(opfinfo->dobj.name));
12967 appendPQExpBuffer(q, " USING %s ADD\n ",
12973 * Now fetch and print the OPERATOR entries (pg_amop rows).
12975 ntups = PQntuples(res_ops);
12977 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
12978 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
12979 i_amopopr = PQfnumber(res_ops, "amopopr");
12980 i_sortfamily = PQfnumber(res_ops, "sortfamily");
12981 i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
12983 for (i = 0; i < ntups; i++)
12985 amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
12986 amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
12987 amopopr = PQgetvalue(res_ops, i, i_amopopr);
12988 sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
12989 sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
12992 appendPQExpBufferStr(q, " ,\n ");
12994 appendPQExpBuffer(q, "OPERATOR %s %s",
12995 amopstrategy, amopopr);
12997 if (strlen(sortfamily) > 0)
12999 appendPQExpBufferStr(q, " FOR ORDER BY ");
13000 if (strcmp(sortfamilynsp, opfinfo->dobj.namespace->dobj.name) != 0)
13001 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
13002 appendPQExpBufferStr(q, fmtId(sortfamily));
13005 if (strcmp(amopreqcheck, "t") == 0)
13006 appendPQExpBufferStr(q, " RECHECK");
13012 * Now fetch and print the FUNCTION entries (pg_amproc rows).
13014 ntups = PQntuples(res_procs);
13016 i_amprocnum = PQfnumber(res_procs, "amprocnum");
13017 i_amproc = PQfnumber(res_procs, "amproc");
13018 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
13019 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
13021 for (i = 0; i < ntups; i++)
13023 amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
13024 amproc = PQgetvalue(res_procs, i, i_amproc);
13025 amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
13026 amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
13029 appendPQExpBufferStr(q, " ,\n ");
13031 appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
13032 amprocnum, amproclefttype, amprocrighttype,
13038 appendPQExpBufferStr(q, ";\n");
13041 appendPQExpBuffer(labelq, "OPERATOR FAMILY %s",
13042 fmtId(opfinfo->dobj.name));
13043 appendPQExpBuffer(labelq, " USING %s",
13046 if (dopt->binary_upgrade)
13047 binary_upgrade_extension_member(q, &opfinfo->dobj, labelq->data);
13049 if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13050 ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
13051 opfinfo->dobj.name,
13052 opfinfo->dobj.namespace->dobj.name,
13055 false, "OPERATOR FAMILY", SECTION_PRE_DATA,
13056 q->data, delq->data, NULL,
13060 /* Dump Operator Family Comments */
13061 if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13062 dumpComment(fout, labelq->data,
13063 opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
13064 opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
13068 PQclear(res_procs);
13069 destroyPQExpBuffer(query);
13070 destroyPQExpBuffer(q);
13071 destroyPQExpBuffer(delq);
13072 destroyPQExpBuffer(labelq);
13077 * write out a single collation definition
13080 dumpCollation(Archive *fout, CollInfo *collinfo)
13082 DumpOptions *dopt = fout->dopt;
13086 PQExpBuffer labelq;
13088 int i_collprovider;
13091 const char *collprovider;
13092 const char *collcollate;
13093 const char *collctype;
13095 /* Skip if not to be dumped */
13096 if (!collinfo->dobj.dump || dopt->dataOnly)
13099 query = createPQExpBuffer();
13100 q = createPQExpBuffer();
13101 delq = createPQExpBuffer();
13102 labelq = createPQExpBuffer();
13104 /* Make sure we are in proper schema */
13105 selectSourceSchema(fout, collinfo->dobj.namespace->dobj.name);
13107 /* Get collation-specific details */
13108 if (fout->remoteVersion >= 100000)
13109 appendPQExpBuffer(query, "SELECT "
13114 "FROM pg_catalog.pg_collation c "
13115 "WHERE c.oid = '%u'::pg_catalog.oid",
13116 collinfo->dobj.catId.oid);
13118 appendPQExpBuffer(query, "SELECT "
13119 "'c'::char AS collprovider, "
13122 "NULL AS collversion "
13123 "FROM pg_catalog.pg_collation c "
13124 "WHERE c.oid = '%u'::pg_catalog.oid",
13125 collinfo->dobj.catId.oid);
13127 res = ExecuteSqlQueryForSingleRow(fout, query->data);
13129 i_collprovider = PQfnumber(res, "collprovider");
13130 i_collcollate = PQfnumber(res, "collcollate");
13131 i_collctype = PQfnumber(res, "collctype");
13133 collprovider = PQgetvalue(res, 0, i_collprovider);
13134 collcollate = PQgetvalue(res, 0, i_collcollate);
13135 collctype = PQgetvalue(res, 0, i_collctype);
13138 * DROP must be fully qualified in case same name appears in pg_catalog
13140 appendPQExpBuffer(delq, "DROP COLLATION %s",
13141 fmtId(collinfo->dobj.namespace->dobj.name));
13142 appendPQExpBuffer(delq, ".%s;\n",
13143 fmtId(collinfo->dobj.name));
13145 appendPQExpBuffer(q, "CREATE COLLATION %s (",
13146 fmtId(collinfo->dobj.name));
13148 appendPQExpBufferStr(q, "provider = ");
13149 if (collprovider[0] == 'c')
13150 appendPQExpBufferStr(q, "libc");
13151 else if (collprovider[0] == 'i')
13152 appendPQExpBufferStr(q, "icu");
13153 else if (collprovider[0] == 'd')
13154 /* to allow dumping pg_catalog; not accepted on input */
13155 appendPQExpBufferStr(q, "default");
13157 exit_horribly(NULL,
13158 "unrecognized collation provider: %s\n",
13161 if (strcmp(collcollate, collctype) == 0)
13163 appendPQExpBufferStr(q, ", locale = ");
13164 appendStringLiteralAH(q, collcollate, fout);
13168 appendPQExpBufferStr(q, ", lc_collate = ");
13169 appendStringLiteralAH(q, collcollate, fout);
13170 appendPQExpBufferStr(q, ", lc_ctype = ");
13171 appendStringLiteralAH(q, collctype, fout);
13175 * For binary upgrade, carry over the collation version. For normal
13176 * dump/restore, omit the version, so that it is computed upon restore.
13178 if (dopt->binary_upgrade)
13182 i_collversion = PQfnumber(res, "collversion");
13183 if (!PQgetisnull(res, 0, i_collversion))
13185 appendPQExpBufferStr(q, ", version = ");
13186 appendStringLiteralAH(q,
13187 PQgetvalue(res, 0, i_collversion),
13192 appendPQExpBufferStr(q, ");\n");
13194 appendPQExpBuffer(labelq, "COLLATION %s", fmtId(collinfo->dobj.name));
13196 if (dopt->binary_upgrade)
13197 binary_upgrade_extension_member(q, &collinfo->dobj, labelq->data);
13199 if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13200 ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
13201 collinfo->dobj.name,
13202 collinfo->dobj.namespace->dobj.name,
13205 false, "COLLATION", SECTION_PRE_DATA,
13206 q->data, delq->data, NULL,
13210 /* Dump Collation Comments */
13211 if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13212 dumpComment(fout, labelq->data,
13213 collinfo->dobj.namespace->dobj.name, collinfo->rolname,
13214 collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
13218 destroyPQExpBuffer(query);
13219 destroyPQExpBuffer(q);
13220 destroyPQExpBuffer(delq);
13221 destroyPQExpBuffer(labelq);
13226 * write out a single conversion definition
13229 dumpConversion(Archive *fout, ConvInfo *convinfo)
13231 DumpOptions *dopt = fout->dopt;
13235 PQExpBuffer labelq;
13237 int i_conforencoding;
13238 int i_contoencoding;
13241 const char *conforencoding;
13242 const char *contoencoding;
13243 const char *conproc;
13246 /* Skip if not to be dumped */
13247 if (!convinfo->dobj.dump || dopt->dataOnly)
13250 query = createPQExpBuffer();
13251 q = createPQExpBuffer();
13252 delq = createPQExpBuffer();
13253 labelq = createPQExpBuffer();
13255 /* Make sure we are in proper schema */
13256 selectSourceSchema(fout, convinfo->dobj.namespace->dobj.name);
13258 /* Get conversion-specific details */
13259 appendPQExpBuffer(query, "SELECT "
13260 "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
13261 "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
13262 "conproc, condefault "
13263 "FROM pg_catalog.pg_conversion c "
13264 "WHERE c.oid = '%u'::pg_catalog.oid",
13265 convinfo->dobj.catId.oid);
13267 res = ExecuteSqlQueryForSingleRow(fout, query->data);
13269 i_conforencoding = PQfnumber(res, "conforencoding");
13270 i_contoencoding = PQfnumber(res, "contoencoding");
13271 i_conproc = PQfnumber(res, "conproc");
13272 i_condefault = PQfnumber(res, "condefault");
13274 conforencoding = PQgetvalue(res, 0, i_conforencoding);
13275 contoencoding = PQgetvalue(res, 0, i_contoencoding);
13276 conproc = PQgetvalue(res, 0, i_conproc);
13277 condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
13280 * DROP must be fully qualified in case same name appears in pg_catalog
13282 appendPQExpBuffer(delq, "DROP CONVERSION %s",
13283 fmtId(convinfo->dobj.namespace->dobj.name));
13284 appendPQExpBuffer(delq, ".%s;\n",
13285 fmtId(convinfo->dobj.name));
13287 appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
13288 (condefault) ? "DEFAULT " : "",
13289 fmtId(convinfo->dobj.name));
13290 appendStringLiteralAH(q, conforencoding, fout);
13291 appendPQExpBufferStr(q, " TO ");
13292 appendStringLiteralAH(q, contoencoding, fout);
13293 /* regproc output is already sufficiently quoted */
13294 appendPQExpBuffer(q, " FROM %s;\n", conproc);
13296 appendPQExpBuffer(labelq, "CONVERSION %s", fmtId(convinfo->dobj.name));
13298 if (dopt->binary_upgrade)
13299 binary_upgrade_extension_member(q, &convinfo->dobj, labelq->data);
13301 if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13302 ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
13303 convinfo->dobj.name,
13304 convinfo->dobj.namespace->dobj.name,
13307 false, "CONVERSION", SECTION_PRE_DATA,
13308 q->data, delq->data, NULL,
13312 /* Dump Conversion Comments */
13313 if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13314 dumpComment(fout, labelq->data,
13315 convinfo->dobj.namespace->dobj.name, convinfo->rolname,
13316 convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
13320 destroyPQExpBuffer(query);
13321 destroyPQExpBuffer(q);
13322 destroyPQExpBuffer(delq);
13323 destroyPQExpBuffer(labelq);
13327 * format_aggregate_signature: generate aggregate name and argument list
13329 * The argument type names are qualified if needed. The aggregate name
13330 * is never qualified.
13333 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
13335 PQExpBufferData buf;
13338 initPQExpBuffer(&buf);
13340 appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
13342 appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
13344 if (agginfo->aggfn.nargs == 0)
13345 appendPQExpBuffer(&buf, "(*)");
13348 appendPQExpBufferChar(&buf, '(');
13349 for (j = 0; j < agginfo->aggfn.nargs; j++)
13353 typname = getFormattedTypeName(fout, agginfo->aggfn.argtypes[j],
13356 appendPQExpBuffer(&buf, "%s%s",
13357 (j > 0) ? ", " : "",
13361 appendPQExpBufferChar(&buf, ')');
13368 * write out a single aggregate definition
13371 dumpAgg(Archive *fout, AggInfo *agginfo)
13373 DumpOptions *dopt = fout->dopt;
13377 PQExpBuffer labelq;
13378 PQExpBuffer details;
13379 char *aggsig; /* identity signature */
13380 char *aggfullsig = NULL; /* full signature */
13385 int i_aggcombinefn;
13387 int i_aggdeserialfn;
13389 int i_aggminvtransfn;
13391 int i_aggfinalextra;
13392 int i_aggmfinalextra;
13394 int i_hypothetical;
13395 int i_aggtranstype;
13396 int i_aggtransspace;
13397 int i_aggmtranstype;
13398 int i_aggmtransspace;
13403 const char *aggtransfn;
13404 const char *aggfinalfn;
13405 const char *aggcombinefn;
13406 const char *aggserialfn;
13407 const char *aggdeserialfn;
13408 const char *aggmtransfn;
13409 const char *aggminvtransfn;
13410 const char *aggmfinalfn;
13411 bool aggfinalextra;
13412 bool aggmfinalextra;
13413 const char *aggsortop;
13414 char *aggsortconvop;
13416 const char *aggtranstype;
13417 const char *aggtransspace;
13418 const char *aggmtranstype;
13419 const char *aggmtransspace;
13420 const char *agginitval;
13421 const char *aggminitval;
13423 const char *proparallel;
13425 /* Skip if not to be dumped */
13426 if (!agginfo->aggfn.dobj.dump || dopt->dataOnly)
13429 query = createPQExpBuffer();
13430 q = createPQExpBuffer();
13431 delq = createPQExpBuffer();
13432 labelq = createPQExpBuffer();
13433 details = createPQExpBuffer();
13435 /* Make sure we are in proper schema */
13436 selectSourceSchema(fout, agginfo->aggfn.dobj.namespace->dobj.name);
13438 /* Get aggregate-specific details */
13439 if (fout->remoteVersion >= 90600)
13441 appendPQExpBuffer(query, "SELECT aggtransfn, "
13442 "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13443 "aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
13444 "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13445 "aggfinalextra, aggmfinalextra, "
13446 "aggsortop::pg_catalog.regoperator, "
13447 "(aggkind = 'h') AS hypothetical, "
13448 "aggtransspace, agginitval, "
13449 "aggmtransspace, aggminitval, "
13450 "true AS convertok, "
13451 "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13452 "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs, "
13454 "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13455 "WHERE a.aggfnoid = p.oid "
13456 "AND p.oid = '%u'::pg_catalog.oid",
13457 agginfo->aggfn.dobj.catId.oid);
13459 else if (fout->remoteVersion >= 90400)
13461 appendPQExpBuffer(query, "SELECT aggtransfn, "
13462 "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13463 "'-' AS aggcombinefn, '-' AS aggserialfn, "
13464 "'-' AS aggdeserialfn, aggmtransfn, aggminvtransfn, "
13465 "aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13466 "aggfinalextra, aggmfinalextra, "
13467 "aggsortop::pg_catalog.regoperator, "
13468 "(aggkind = 'h') AS hypothetical, "
13469 "aggtransspace, agginitval, "
13470 "aggmtransspace, aggminitval, "
13471 "true AS convertok, "
13472 "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13473 "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
13474 "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13475 "WHERE a.aggfnoid = p.oid "
13476 "AND p.oid = '%u'::pg_catalog.oid",
13477 agginfo->aggfn.dobj.catId.oid);
13479 else if (fout->remoteVersion >= 80400)
13481 appendPQExpBuffer(query, "SELECT aggtransfn, "
13482 "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13483 "'-' AS aggcombinefn, '-' AS aggserialfn, "
13484 "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13485 "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13486 "0 AS aggmtranstype, false AS aggfinalextra, "
13487 "false AS aggmfinalextra, "
13488 "aggsortop::pg_catalog.regoperator, "
13489 "false AS hypothetical, "
13490 "0 AS aggtransspace, agginitval, "
13491 "0 AS aggmtransspace, NULL AS aggminitval, "
13492 "true AS convertok, "
13493 "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13494 "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
13495 "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13496 "WHERE a.aggfnoid = p.oid "
13497 "AND p.oid = '%u'::pg_catalog.oid",
13498 agginfo->aggfn.dobj.catId.oid);
13500 else if (fout->remoteVersion >= 80100)
13502 appendPQExpBuffer(query, "SELECT aggtransfn, "
13503 "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13504 "'-' AS aggcombinefn, '-' AS aggserialfn, "
13505 "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13506 "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13507 "0 AS aggmtranstype, false AS aggfinalextra, "
13508 "false AS aggmfinalextra, "
13509 "aggsortop::pg_catalog.regoperator, "
13510 "false AS hypothetical, "
13511 "0 AS aggtransspace, agginitval, "
13512 "0 AS aggmtransspace, NULL AS aggminitval, "
13513 "true AS convertok "
13514 "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13515 "WHERE a.aggfnoid = p.oid "
13516 "AND p.oid = '%u'::pg_catalog.oid",
13517 agginfo->aggfn.dobj.catId.oid);
13521 appendPQExpBuffer(query, "SELECT aggtransfn, "
13522 "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13523 "'-' AS aggcombinefn, '-' AS aggserialfn, "
13524 "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13525 "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13526 "0 AS aggmtranstype, false AS aggfinalextra, "
13527 "false AS aggmfinalextra, 0 AS aggsortop, "
13528 "false AS hypothetical, "
13529 "0 AS aggtransspace, agginitval, "
13530 "0 AS aggmtransspace, NULL AS aggminitval, "
13531 "true AS convertok "
13532 "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13533 "WHERE a.aggfnoid = p.oid "
13534 "AND p.oid = '%u'::pg_catalog.oid",
13535 agginfo->aggfn.dobj.catId.oid);
13538 res = ExecuteSqlQueryForSingleRow(fout, query->data);
13540 i_aggtransfn = PQfnumber(res, "aggtransfn");
13541 i_aggfinalfn = PQfnumber(res, "aggfinalfn");
13542 i_aggcombinefn = PQfnumber(res, "aggcombinefn");
13543 i_aggserialfn = PQfnumber(res, "aggserialfn");
13544 i_aggdeserialfn = PQfnumber(res, "aggdeserialfn");
13545 i_aggmtransfn = PQfnumber(res, "aggmtransfn");
13546 i_aggminvtransfn = PQfnumber(res, "aggminvtransfn");
13547 i_aggmfinalfn = PQfnumber(res, "aggmfinalfn");
13548 i_aggfinalextra = PQfnumber(res, "aggfinalextra");
13549 i_aggmfinalextra = PQfnumber(res, "aggmfinalextra");
13550 i_aggsortop = PQfnumber(res, "aggsortop");
13551 i_hypothetical = PQfnumber(res, "hypothetical");
13552 i_aggtranstype = PQfnumber(res, "aggtranstype");
13553 i_aggtransspace = PQfnumber(res, "aggtransspace");
13554 i_aggmtranstype = PQfnumber(res, "aggmtranstype");
13555 i_aggmtransspace = PQfnumber(res, "aggmtransspace");
13556 i_agginitval = PQfnumber(res, "agginitval");
13557 i_aggminitval = PQfnumber(res, "aggminitval");
13558 i_convertok = PQfnumber(res, "convertok");
13559 i_proparallel = PQfnumber(res, "proparallel");
13561 aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
13562 aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
13563 aggcombinefn = PQgetvalue(res, 0, i_aggcombinefn);
13564 aggserialfn = PQgetvalue(res, 0, i_aggserialfn);
13565 aggdeserialfn = PQgetvalue(res, 0, i_aggdeserialfn);
13566 aggmtransfn = PQgetvalue(res, 0, i_aggmtransfn);
13567 aggminvtransfn = PQgetvalue(res, 0, i_aggminvtransfn);
13568 aggmfinalfn = PQgetvalue(res, 0, i_aggmfinalfn);
13569 aggfinalextra = (PQgetvalue(res, 0, i_aggfinalextra)[0] == 't');
13570 aggmfinalextra = (PQgetvalue(res, 0, i_aggmfinalextra)[0] == 't');
13571 aggsortop = PQgetvalue(res, 0, i_aggsortop);
13572 hypothetical = (PQgetvalue(res, 0, i_hypothetical)[0] == 't');
13573 aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
13574 aggtransspace = PQgetvalue(res, 0, i_aggtransspace);
13575 aggmtranstype = PQgetvalue(res, 0, i_aggmtranstype);
13576 aggmtransspace = PQgetvalue(res, 0, i_aggmtransspace);
13577 agginitval = PQgetvalue(res, 0, i_agginitval);
13578 aggminitval = PQgetvalue(res, 0, i_aggminitval);
13579 convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
13581 if (fout->remoteVersion >= 80400)
13583 /* 8.4 or later; we rely on server-side code for most of the work */
13587 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
13588 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
13589 aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
13590 aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
13593 /* pre-8.4, do it ourselves */
13594 aggsig = format_aggregate_signature(agginfo, fout, true);
13596 aggsig_tag = format_aggregate_signature(agginfo, fout, false);
13598 if (i_proparallel != -1)
13599 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
13601 proparallel = NULL;
13605 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
13616 /* regproc and regtype output is already sufficiently quoted */
13617 appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
13618 aggtransfn, aggtranstype);
13620 if (strcmp(aggtransspace, "0") != 0)
13622 appendPQExpBuffer(details, ",\n SSPACE = %s",
13626 if (!PQgetisnull(res, 0, i_agginitval))
13628 appendPQExpBufferStr(details, ",\n INITCOND = ");
13629 appendStringLiteralAH(details, agginitval, fout);
13632 if (strcmp(aggfinalfn, "-") != 0)
13634 appendPQExpBuffer(details, ",\n FINALFUNC = %s",
13637 appendPQExpBufferStr(details, ",\n FINALFUNC_EXTRA");
13640 if (strcmp(aggcombinefn, "-") != 0)
13641 appendPQExpBuffer(details, ",\n COMBINEFUNC = %s", aggcombinefn);
13643 if (strcmp(aggserialfn, "-") != 0)
13644 appendPQExpBuffer(details, ",\n SERIALFUNC = %s", aggserialfn);
13646 if (strcmp(aggdeserialfn, "-") != 0)
13647 appendPQExpBuffer(details, ",\n DESERIALFUNC = %s", aggdeserialfn);
13649 if (strcmp(aggmtransfn, "-") != 0)
13651 appendPQExpBuffer(details, ",\n MSFUNC = %s,\n MINVFUNC = %s,\n MSTYPE = %s",
13657 if (strcmp(aggmtransspace, "0") != 0)
13659 appendPQExpBuffer(details, ",\n MSSPACE = %s",
13663 if (!PQgetisnull(res, 0, i_aggminitval))
13665 appendPQExpBufferStr(details, ",\n MINITCOND = ");
13666 appendStringLiteralAH(details, aggminitval, fout);
13669 if (strcmp(aggmfinalfn, "-") != 0)
13671 appendPQExpBuffer(details, ",\n MFINALFUNC = %s",
13673 if (aggmfinalextra)
13674 appendPQExpBufferStr(details, ",\n MFINALFUNC_EXTRA");
13677 aggsortconvop = convertOperatorReference(fout, aggsortop);
13680 appendPQExpBuffer(details, ",\n SORTOP = %s",
13682 free(aggsortconvop);
13686 appendPQExpBufferStr(details, ",\n HYPOTHETICAL");
13688 if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
13690 if (proparallel[0] == PROPARALLEL_SAFE)
13691 appendPQExpBufferStr(details, ",\n PARALLEL = safe");
13692 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
13693 appendPQExpBufferStr(details, ",\n PARALLEL = restricted");
13694 else if (proparallel[0] != PROPARALLEL_UNSAFE)
13695 exit_horribly(NULL, "unrecognized proparallel value for function \"%s\"\n",
13696 agginfo->aggfn.dobj.name);
13700 * DROP must be fully qualified in case same name appears in pg_catalog
13702 appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
13703 fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
13706 appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
13707 aggfullsig ? aggfullsig : aggsig, details->data);
13709 appendPQExpBuffer(labelq, "AGGREGATE %s", aggsig);
13711 if (dopt->binary_upgrade)
13712 binary_upgrade_extension_member(q, &agginfo->aggfn.dobj, labelq->data);
13714 if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
13715 ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
13716 agginfo->aggfn.dobj.dumpId,
13718 agginfo->aggfn.dobj.namespace->dobj.name,
13720 agginfo->aggfn.rolname,
13721 false, "AGGREGATE", SECTION_PRE_DATA,
13722 q->data, delq->data, NULL,
13726 /* Dump Aggregate Comments */
13727 if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
13728 dumpComment(fout, labelq->data,
13729 agginfo->aggfn.dobj.namespace->dobj.name,
13730 agginfo->aggfn.rolname,
13731 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
13733 if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
13734 dumpSecLabel(fout, labelq->data,
13735 agginfo->aggfn.dobj.namespace->dobj.name,
13736 agginfo->aggfn.rolname,
13737 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
13740 * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
13741 * command look like a function's GRANT; in particular this affects the
13742 * syntax for zero-argument aggregates and ordered-set aggregates.
13747 aggsig = format_function_signature(fout, &agginfo->aggfn, true);
13748 aggsig_tag = format_function_signature(fout, &agginfo->aggfn, false);
13750 if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
13751 dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
13753 aggsig, NULL, aggsig_tag,
13754 agginfo->aggfn.dobj.namespace->dobj.name,
13755 agginfo->aggfn.rolname, agginfo->aggfn.proacl,
13756 agginfo->aggfn.rproacl,
13757 agginfo->aggfn.initproacl, agginfo->aggfn.initrproacl);
13766 destroyPQExpBuffer(query);
13767 destroyPQExpBuffer(q);
13768 destroyPQExpBuffer(delq);
13769 destroyPQExpBuffer(labelq);
13770 destroyPQExpBuffer(details);
13775 * write out a single text search parser
13778 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
13780 DumpOptions *dopt = fout->dopt;
13783 PQExpBuffer labelq;
13785 /* Skip if not to be dumped */
13786 if (!prsinfo->dobj.dump || dopt->dataOnly)
13789 q = createPQExpBuffer();
13790 delq = createPQExpBuffer();
13791 labelq = createPQExpBuffer();
13793 /* Make sure we are in proper schema */
13794 selectSourceSchema(fout, prsinfo->dobj.namespace->dobj.name);
13796 appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
13797 fmtId(prsinfo->dobj.name));
13799 appendPQExpBuffer(q, " START = %s,\n",
13800 convertTSFunction(fout, prsinfo->prsstart));
13801 appendPQExpBuffer(q, " GETTOKEN = %s,\n",
13802 convertTSFunction(fout, prsinfo->prstoken));
13803 appendPQExpBuffer(q, " END = %s,\n",
13804 convertTSFunction(fout, prsinfo->prsend));
13805 if (prsinfo->prsheadline != InvalidOid)
13806 appendPQExpBuffer(q, " HEADLINE = %s,\n",
13807 convertTSFunction(fout, prsinfo->prsheadline));
13808 appendPQExpBuffer(q, " LEXTYPES = %s );\n",
13809 convertTSFunction(fout, prsinfo->prslextype));
13812 * DROP must be fully qualified in case same name appears in pg_catalog
13814 appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s",
13815 fmtId(prsinfo->dobj.namespace->dobj.name));
13816 appendPQExpBuffer(delq, ".%s;\n",
13817 fmtId(prsinfo->dobj.name));
13819 appendPQExpBuffer(labelq, "TEXT SEARCH PARSER %s",
13820 fmtId(prsinfo->dobj.name));
13822 if (dopt->binary_upgrade)
13823 binary_upgrade_extension_member(q, &prsinfo->dobj, labelq->data);
13825 if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13826 ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
13827 prsinfo->dobj.name,
13828 prsinfo->dobj.namespace->dobj.name,
13831 false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
13832 q->data, delq->data, NULL,
13836 /* Dump Parser Comments */
13837 if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13838 dumpComment(fout, labelq->data,
13839 prsinfo->dobj.namespace->dobj.name, "",
13840 prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
13842 destroyPQExpBuffer(q);
13843 destroyPQExpBuffer(delq);
13844 destroyPQExpBuffer(labelq);
13849 * write out a single text search dictionary
13852 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
13854 DumpOptions *dopt = fout->dopt;
13857 PQExpBuffer labelq;
13863 /* Skip if not to be dumped */
13864 if (!dictinfo->dobj.dump || dopt->dataOnly)
13867 q = createPQExpBuffer();
13868 delq = createPQExpBuffer();
13869 labelq = createPQExpBuffer();
13870 query = createPQExpBuffer();
13872 /* Fetch name and namespace of the dictionary's template */
13873 selectSourceSchema(fout, "pg_catalog");
13874 appendPQExpBuffer(query, "SELECT nspname, tmplname "
13875 "FROM pg_ts_template p, pg_namespace n "
13876 "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
13877 dictinfo->dicttemplate);
13878 res = ExecuteSqlQueryForSingleRow(fout, query->data);
13879 nspname = PQgetvalue(res, 0, 0);
13880 tmplname = PQgetvalue(res, 0, 1);
13882 /* Make sure we are in proper schema */
13883 selectSourceSchema(fout, dictinfo->dobj.namespace->dobj.name);
13885 appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
13886 fmtId(dictinfo->dobj.name));
13888 appendPQExpBufferStr(q, " TEMPLATE = ");
13889 if (strcmp(nspname, dictinfo->dobj.namespace->dobj.name) != 0)
13890 appendPQExpBuffer(q, "%s.", fmtId(nspname));
13891 appendPQExpBufferStr(q, fmtId(tmplname));
13895 /* the dictinitoption can be dumped straight into the command */
13896 if (dictinfo->dictinitoption)
13897 appendPQExpBuffer(q, ",\n %s", dictinfo->dictinitoption);
13899 appendPQExpBufferStr(q, " );\n");
13902 * DROP must be fully qualified in case same name appears in pg_catalog
13904 appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s",
13905 fmtId(dictinfo->dobj.namespace->dobj.name));
13906 appendPQExpBuffer(delq, ".%s;\n",
13907 fmtId(dictinfo->dobj.name));
13909 appendPQExpBuffer(labelq, "TEXT SEARCH DICTIONARY %s",
13910 fmtId(dictinfo->dobj.name));
13912 if (dopt->binary_upgrade)
13913 binary_upgrade_extension_member(q, &dictinfo->dobj, labelq->data);
13915 if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13916 ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
13917 dictinfo->dobj.name,
13918 dictinfo->dobj.namespace->dobj.name,
13921 false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
13922 q->data, delq->data, NULL,
13926 /* Dump Dictionary Comments */
13927 if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13928 dumpComment(fout, labelq->data,
13929 dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
13930 dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
13932 destroyPQExpBuffer(q);
13933 destroyPQExpBuffer(delq);
13934 destroyPQExpBuffer(labelq);
13935 destroyPQExpBuffer(query);
13940 * write out a single text search template
13943 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
13945 DumpOptions *dopt = fout->dopt;
13948 PQExpBuffer labelq;
13950 /* Skip if not to be dumped */
13951 if (!tmplinfo->dobj.dump || dopt->dataOnly)
13954 q = createPQExpBuffer();
13955 delq = createPQExpBuffer();
13956 labelq = createPQExpBuffer();
13958 /* Make sure we are in proper schema */
13959 selectSourceSchema(fout, tmplinfo->dobj.namespace->dobj.name);
13961 appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
13962 fmtId(tmplinfo->dobj.name));
13964 if (tmplinfo->tmplinit != InvalidOid)
13965 appendPQExpBuffer(q, " INIT = %s,\n",
13966 convertTSFunction(fout, tmplinfo->tmplinit));
13967 appendPQExpBuffer(q, " LEXIZE = %s );\n",
13968 convertTSFunction(fout, tmplinfo->tmpllexize));
13971 * DROP must be fully qualified in case same name appears in pg_catalog
13973 appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s",
13974 fmtId(tmplinfo->dobj.namespace->dobj.name));
13975 appendPQExpBuffer(delq, ".%s;\n",
13976 fmtId(tmplinfo->dobj.name));
13978 appendPQExpBuffer(labelq, "TEXT SEARCH TEMPLATE %s",
13979 fmtId(tmplinfo->dobj.name));
13981 if (dopt->binary_upgrade)
13982 binary_upgrade_extension_member(q, &tmplinfo->dobj, labelq->data);
13984 if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13985 ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
13986 tmplinfo->dobj.name,
13987 tmplinfo->dobj.namespace->dobj.name,
13990 false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
13991 q->data, delq->data, NULL,
13995 /* Dump Template Comments */
13996 if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13997 dumpComment(fout, labelq->data,
13998 tmplinfo->dobj.namespace->dobj.name, "",
13999 tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
14001 destroyPQExpBuffer(q);
14002 destroyPQExpBuffer(delq);
14003 destroyPQExpBuffer(labelq);
14008 * write out a single text search configuration
14011 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
14013 DumpOptions *dopt = fout->dopt;
14016 PQExpBuffer labelq;
14026 /* Skip if not to be dumped */
14027 if (!cfginfo->dobj.dump || dopt->dataOnly)
14030 q = createPQExpBuffer();
14031 delq = createPQExpBuffer();
14032 labelq = createPQExpBuffer();
14033 query = createPQExpBuffer();
14035 /* Fetch name and namespace of the config's parser */
14036 selectSourceSchema(fout, "pg_catalog");
14037 appendPQExpBuffer(query, "SELECT nspname, prsname "
14038 "FROM pg_ts_parser p, pg_namespace n "
14039 "WHERE p.oid = '%u' AND n.oid = prsnamespace",
14040 cfginfo->cfgparser);
14041 res = ExecuteSqlQueryForSingleRow(fout, query->data);
14042 nspname = PQgetvalue(res, 0, 0);
14043 prsname = PQgetvalue(res, 0, 1);
14045 /* Make sure we are in proper schema */
14046 selectSourceSchema(fout, cfginfo->dobj.namespace->dobj.name);
14048 appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
14049 fmtId(cfginfo->dobj.name));
14051 appendPQExpBufferStr(q, " PARSER = ");
14052 if (strcmp(nspname, cfginfo->dobj.namespace->dobj.name) != 0)
14053 appendPQExpBuffer(q, "%s.", fmtId(nspname));
14054 appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
14058 resetPQExpBuffer(query);
14059 appendPQExpBuffer(query,
14061 " ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
14062 " WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
14063 " m.mapdict::pg_catalog.regdictionary AS dictname\n"
14064 "FROM pg_catalog.pg_ts_config_map AS m\n"
14065 "WHERE m.mapcfg = '%u'\n"
14066 "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
14067 cfginfo->cfgparser, cfginfo->dobj.catId.oid);
14069 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14070 ntups = PQntuples(res);
14072 i_tokenname = PQfnumber(res, "tokenname");
14073 i_dictname = PQfnumber(res, "dictname");
14075 for (i = 0; i < ntups; i++)
14077 char *tokenname = PQgetvalue(res, i, i_tokenname);
14078 char *dictname = PQgetvalue(res, i, i_dictname);
14081 strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
14083 /* starting a new token type, so start a new command */
14085 appendPQExpBufferStr(q, ";\n");
14086 appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
14087 fmtId(cfginfo->dobj.name));
14088 /* tokenname needs quoting, dictname does NOT */
14089 appendPQExpBuffer(q, " ADD MAPPING FOR %s WITH %s",
14090 fmtId(tokenname), dictname);
14093 appendPQExpBuffer(q, ", %s", dictname);
14097 appendPQExpBufferStr(q, ";\n");
14102 * DROP must be fully qualified in case same name appears in pg_catalog
14104 appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s",
14105 fmtId(cfginfo->dobj.namespace->dobj.name));
14106 appendPQExpBuffer(delq, ".%s;\n",
14107 fmtId(cfginfo->dobj.name));
14109 appendPQExpBuffer(labelq, "TEXT SEARCH CONFIGURATION %s",
14110 fmtId(cfginfo->dobj.name));
14112 if (dopt->binary_upgrade)
14113 binary_upgrade_extension_member(q, &cfginfo->dobj, labelq->data);
14115 if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14116 ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
14117 cfginfo->dobj.name,
14118 cfginfo->dobj.namespace->dobj.name,
14121 false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
14122 q->data, delq->data, NULL,
14126 /* Dump Configuration Comments */
14127 if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14128 dumpComment(fout, labelq->data,
14129 cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
14130 cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
14132 destroyPQExpBuffer(q);
14133 destroyPQExpBuffer(delq);
14134 destroyPQExpBuffer(labelq);
14135 destroyPQExpBuffer(query);
14139 * dumpForeignDataWrapper
14140 * write out a single foreign-data wrapper definition
14143 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
14145 DumpOptions *dopt = fout->dopt;
14148 PQExpBuffer labelq;
14151 /* Skip if not to be dumped */
14152 if (!fdwinfo->dobj.dump || dopt->dataOnly)
14155 q = createPQExpBuffer();
14156 delq = createPQExpBuffer();
14157 labelq = createPQExpBuffer();
14159 qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
14161 appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
14164 if (strcmp(fdwinfo->fdwhandler, "-") != 0)
14165 appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
14167 if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
14168 appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
14170 if (strlen(fdwinfo->fdwoptions) > 0)
14171 appendPQExpBuffer(q, " OPTIONS (\n %s\n)", fdwinfo->fdwoptions);
14173 appendPQExpBufferStr(q, ";\n");
14175 appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
14178 appendPQExpBuffer(labelq, "FOREIGN DATA WRAPPER %s",
14181 if (dopt->binary_upgrade)
14182 binary_upgrade_extension_member(q, &fdwinfo->dobj, labelq->data);
14184 if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14185 ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14186 fdwinfo->dobj.name,
14190 false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
14191 q->data, delq->data, NULL,
14195 /* Handle the ACL */
14196 if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
14197 dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14198 "FOREIGN DATA WRAPPER",
14199 qfdwname, NULL, fdwinfo->dobj.name,
14200 NULL, fdwinfo->rolname,
14201 fdwinfo->fdwacl, fdwinfo->rfdwacl,
14202 fdwinfo->initfdwacl, fdwinfo->initrfdwacl);
14204 /* Dump Foreign Data Wrapper Comments */
14205 if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14206 dumpComment(fout, labelq->data,
14207 NULL, fdwinfo->rolname,
14208 fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
14212 destroyPQExpBuffer(q);
14213 destroyPQExpBuffer(delq);
14214 destroyPQExpBuffer(labelq);
14218 * dumpForeignServer
14219 * write out a foreign server definition
14222 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
14224 DumpOptions *dopt = fout->dopt;
14227 PQExpBuffer labelq;
14233 /* Skip if not to be dumped */
14234 if (!srvinfo->dobj.dump || dopt->dataOnly)
14237 q = createPQExpBuffer();
14238 delq = createPQExpBuffer();
14239 labelq = createPQExpBuffer();
14240 query = createPQExpBuffer();
14242 qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
14244 /* look up the foreign-data wrapper */
14245 selectSourceSchema(fout, "pg_catalog");
14246 appendPQExpBuffer(query, "SELECT fdwname "
14247 "FROM pg_foreign_data_wrapper w "
14248 "WHERE w.oid = '%u'",
14250 res = ExecuteSqlQueryForSingleRow(fout, query->data);
14251 fdwname = PQgetvalue(res, 0, 0);
14253 appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
14254 if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
14256 appendPQExpBufferStr(q, " TYPE ");
14257 appendStringLiteralAH(q, srvinfo->srvtype, fout);
14259 if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
14261 appendPQExpBufferStr(q, " VERSION ");
14262 appendStringLiteralAH(q, srvinfo->srvversion, fout);
14265 appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
14266 appendPQExpBufferStr(q, fmtId(fdwname));
14268 if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
14269 appendPQExpBuffer(q, " OPTIONS (\n %s\n)", srvinfo->srvoptions);
14271 appendPQExpBufferStr(q, ";\n");
14273 appendPQExpBuffer(delq, "DROP SERVER %s;\n",
14276 appendPQExpBuffer(labelq, "SERVER %s", qsrvname);
14278 if (dopt->binary_upgrade)
14279 binary_upgrade_extension_member(q, &srvinfo->dobj, labelq->data);
14281 if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14282 ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14283 srvinfo->dobj.name,
14287 false, "SERVER", SECTION_PRE_DATA,
14288 q->data, delq->data, NULL,
14292 /* Handle the ACL */
14293 if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
14294 dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14296 qsrvname, NULL, srvinfo->dobj.name,
14297 NULL, srvinfo->rolname,
14298 srvinfo->srvacl, srvinfo->rsrvacl,
14299 srvinfo->initsrvacl, srvinfo->initrsrvacl);
14301 /* Dump user mappings */
14302 if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
14303 dumpUserMappings(fout,
14304 srvinfo->dobj.name, NULL,
14306 srvinfo->dobj.catId, srvinfo->dobj.dumpId);
14308 /* Dump Foreign Server Comments */
14309 if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14310 dumpComment(fout, labelq->data,
14311 NULL, srvinfo->rolname,
14312 srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
14316 destroyPQExpBuffer(q);
14317 destroyPQExpBuffer(delq);
14318 destroyPQExpBuffer(labelq);
14319 destroyPQExpBuffer(query);
14325 * This routine is used to dump any user mappings associated with the
14326 * server handed to this routine. Should be called after ArchiveEntry()
14330 dumpUserMappings(Archive *fout,
14331 const char *servername, const char *namespace,
14333 CatalogId catalogId, DumpId dumpId)
14345 q = createPQExpBuffer();
14346 tag = createPQExpBuffer();
14347 delq = createPQExpBuffer();
14348 query = createPQExpBuffer();
14351 * We read from the publicly accessible view pg_user_mappings, so as not
14352 * to fail if run by a non-superuser. Note that the view will show
14353 * umoptions as null if the user hasn't got privileges for the associated
14354 * server; this means that pg_dump will dump such a mapping, but with no
14355 * OPTIONS clause. A possible alternative is to skip such mappings
14356 * altogether, but it's not clear that that's an improvement.
14358 selectSourceSchema(fout, "pg_catalog");
14360 appendPQExpBuffer(query,
14362 "array_to_string(ARRAY("
14363 "SELECT quote_ident(option_name) || ' ' || "
14364 "quote_literal(option_value) "
14365 "FROM pg_options_to_table(umoptions) "
14366 "ORDER BY option_name"
14367 "), E',\n ') AS umoptions "
14368 "FROM pg_user_mappings "
14369 "WHERE srvid = '%u' "
14370 "ORDER BY usename",
14373 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14375 ntups = PQntuples(res);
14376 i_usename = PQfnumber(res, "usename");
14377 i_umoptions = PQfnumber(res, "umoptions");
14379 for (i = 0; i < ntups; i++)
14384 usename = PQgetvalue(res, i, i_usename);
14385 umoptions = PQgetvalue(res, i, i_umoptions);
14387 resetPQExpBuffer(q);
14388 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
14389 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
14391 if (umoptions && strlen(umoptions) > 0)
14392 appendPQExpBuffer(q, " OPTIONS (\n %s\n)", umoptions);
14394 appendPQExpBufferStr(q, ";\n");
14396 resetPQExpBuffer(delq);
14397 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
14398 appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
14400 resetPQExpBuffer(tag);
14401 appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
14402 usename, servername);
14404 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14409 "USER MAPPING", SECTION_PRE_DATA,
14410 q->data, delq->data, NULL,
14417 destroyPQExpBuffer(query);
14418 destroyPQExpBuffer(delq);
14419 destroyPQExpBuffer(tag);
14420 destroyPQExpBuffer(q);
14424 * Write out default privileges information
14427 dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
14429 DumpOptions *dopt = fout->dopt;
14434 /* Skip if not to be dumped */
14435 if (!daclinfo->dobj.dump || dopt->dataOnly || dopt->aclsSkip)
14438 q = createPQExpBuffer();
14439 tag = createPQExpBuffer();
14441 switch (daclinfo->defaclobjtype)
14443 case DEFACLOBJ_RELATION:
14446 case DEFACLOBJ_SEQUENCE:
14447 type = "SEQUENCES";
14449 case DEFACLOBJ_FUNCTION:
14450 type = "FUNCTIONS";
14452 case DEFACLOBJ_TYPE:
14455 case DEFACLOBJ_NAMESPACE:
14459 /* shouldn't get here */
14460 exit_horribly(NULL,
14461 "unrecognized object type in default privileges: %d\n",
14462 (int) daclinfo->defaclobjtype);
14463 type = ""; /* keep compiler quiet */
14466 appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
14468 /* build the actual command(s) for this tuple */
14469 if (!buildDefaultACLCommands(type,
14470 daclinfo->dobj.namespace != NULL ?
14471 daclinfo->dobj.namespace->dobj.name : NULL,
14472 daclinfo->defaclacl,
14473 daclinfo->rdefaclacl,
14474 daclinfo->initdefaclacl,
14475 daclinfo->initrdefaclacl,
14476 daclinfo->defaclrole,
14477 fout->remoteVersion,
14479 exit_horribly(NULL, "could not parse default ACL list (%s)\n",
14480 daclinfo->defaclacl);
14482 if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
14483 ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
14485 daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
14487 daclinfo->defaclrole,
14488 false, "DEFAULT ACL", SECTION_POST_DATA,
14493 destroyPQExpBuffer(tag);
14494 destroyPQExpBuffer(q);
14498 * Write out grant/revoke information
14500 * 'objCatId' is the catalog ID of the underlying object.
14501 * 'objDumpId' is the dump ID of the underlying object.
14502 * 'type' must be one of
14503 * TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
14504 * FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
14505 * 'name' is the formatted name of the object. Must be quoted etc. already.
14506 * 'subname' is the formatted name of the sub-object, if any. Must be quoted.
14507 * 'tag' is the tag for the archive entry (typ. unquoted name of object).
14508 * 'nspname' is the namespace the object is in (NULL if none).
14509 * 'owner' is the owner, NULL if there is no owner (for languages).
14510 * 'acls' contains the ACL string of the object from the appropriate system
14511 * catalog field; it will be passed to buildACLCommands for building the
14512 * appropriate GRANT commands.
14513 * 'racls' contains the ACL string of any initial-but-now-revoked ACLs of the
14514 * object; it will be passed to buildACLCommands for building the
14515 * appropriate REVOKE commands.
14516 * 'initacls' In binary-upgrade mode, ACL string of the object's initial
14517 * privileges, to be recorded into pg_init_privs
14518 * 'initracls' In binary-upgrade mode, ACL string of the object's
14519 * revoked-from-default privileges, to be recorded into pg_init_privs
14521 * NB: initacls/initracls are needed because extensions can set privileges on
14522 * an object during the extension's script file and we record those into
14523 * pg_init_privs as that object's initial privileges.
14527 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
14528 const char *type, const char *name, const char *subname,
14529 const char *tag, const char *nspname, const char *owner,
14530 const char *acls, const char *racls,
14531 const char *initacls, const char *initracls)
14533 DumpOptions *dopt = fout->dopt;
14536 /* Do nothing if ACL dump is not enabled */
14537 if (dopt->aclsSkip)
14540 /* --data-only skips ACLs *except* BLOB ACLs */
14541 if (dopt->dataOnly && strcmp(type, "LARGE OBJECT") != 0)
14544 sql = createPQExpBuffer();
14547 * Check to see if this object has had any initial ACLs included for it.
14548 * If so, we are in binary upgrade mode and these are the ACLs to turn
14549 * into GRANT and REVOKE statements to set and record the initial
14550 * privileges for an extension object. Let the backend know that these
14551 * are to be recorded by calling binary_upgrade_set_record_init_privs()
14552 * before and after.
14554 if (strlen(initacls) != 0 || strlen(initracls) != 0)
14556 appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
14557 if (!buildACLCommands(name, subname, type, initacls, initracls, owner,
14558 "", fout->remoteVersion, sql))
14559 exit_horribly(NULL,
14560 "could not parse initial GRANT ACL list (%s) or initial REVOKE ACL list (%s) for object \"%s\" (%s)\n",
14561 initacls, initracls, name, type);
14562 appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
14565 if (!buildACLCommands(name, subname, type, acls, racls, owner,
14566 "", fout->remoteVersion, sql))
14567 exit_horribly(NULL,
14568 "could not parse GRANT ACL list (%s) or REVOKE ACL list (%s) for object \"%s\" (%s)\n",
14569 acls, racls, name, type);
14572 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14575 owner ? owner : "",
14576 false, "ACL", SECTION_NONE,
14577 sql->data, "", NULL,
14581 destroyPQExpBuffer(sql);
14587 * This routine is used to dump any security labels associated with the
14588 * object handed to this routine. The routine takes a constant character
14589 * string for the target part of the security-label command, plus
14590 * the namespace and owner of the object (for labeling the ArchiveEntry),
14591 * plus catalog ID and subid which are the lookup key for pg_seclabel,
14592 * plus the dump ID for the object (for setting a dependency).
14593 * If a matching pg_seclabel entry is found, it is dumped.
14595 * Note: although this routine takes a dumpId for dependency purposes,
14596 * that purpose is just to mark the dependency in the emitted dump file
14597 * for possible future use by pg_restore. We do NOT use it for determining
14598 * ordering of the label in the dump file, because this routine is called
14599 * after dependency sorting occurs. This routine should be called just after
14600 * calling ArchiveEntry() for the specified object.
14603 dumpSecLabel(Archive *fout, const char *target,
14604 const char *namespace, const char *owner,
14605 CatalogId catalogId, int subid, DumpId dumpId)
14607 DumpOptions *dopt = fout->dopt;
14608 SecLabelItem *labels;
14613 /* do nothing, if --no-security-labels is supplied */
14614 if (dopt->no_security_labels)
14617 /* Comments are schema not data ... except blob comments are data */
14618 if (strncmp(target, "LARGE OBJECT ", 13) != 0)
14620 if (dopt->dataOnly)
14625 /* We do dump blob security labels in binary-upgrade mode */
14626 if (dopt->schemaOnly && !dopt->binary_upgrade)
14630 /* Search for security labels associated with catalogId, using table */
14631 nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
14633 query = createPQExpBuffer();
14635 for (i = 0; i < nlabels; i++)
14638 * Ignore label entries for which the subid doesn't match.
14640 if (labels[i].objsubid != subid)
14643 appendPQExpBuffer(query,
14644 "SECURITY LABEL FOR %s ON %s IS ",
14645 fmtId(labels[i].provider), target);
14646 appendStringLiteralAH(query, labels[i].label, fout);
14647 appendPQExpBufferStr(query, ";\n");
14650 if (query->len > 0)
14652 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14653 target, namespace, NULL, owner,
14654 false, "SECURITY LABEL", SECTION_NONE,
14655 query->data, "", NULL,
14659 destroyPQExpBuffer(query);
14663 * dumpTableSecLabel
14665 * As above, but dump security label for both the specified table (or view)
14669 dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
14671 DumpOptions *dopt = fout->dopt;
14672 SecLabelItem *labels;
14676 PQExpBuffer target;
14678 /* do nothing, if --no-security-labels is supplied */
14679 if (dopt->no_security_labels)
14682 /* SecLabel are SCHEMA not data */
14683 if (dopt->dataOnly)
14686 /* Search for comments associated with relation, using table */
14687 nlabels = findSecLabels(fout,
14688 tbinfo->dobj.catId.tableoid,
14689 tbinfo->dobj.catId.oid,
14692 /* If security labels exist, build SECURITY LABEL statements */
14696 query = createPQExpBuffer();
14697 target = createPQExpBuffer();
14699 for (i = 0; i < nlabels; i++)
14701 const char *colname;
14702 const char *provider = labels[i].provider;
14703 const char *label = labels[i].label;
14704 int objsubid = labels[i].objsubid;
14706 resetPQExpBuffer(target);
14709 appendPQExpBuffer(target, "%s %s", reltypename,
14710 fmtId(tbinfo->dobj.name));
14714 colname = getAttrName(objsubid, tbinfo);
14715 /* first fmtId result must be consumed before calling it again */
14716 appendPQExpBuffer(target, "COLUMN %s", fmtId(tbinfo->dobj.name));
14717 appendPQExpBuffer(target, ".%s", fmtId(colname));
14719 appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
14720 fmtId(provider), target->data);
14721 appendStringLiteralAH(query, label, fout);
14722 appendPQExpBufferStr(query, ";\n");
14724 if (query->len > 0)
14726 resetPQExpBuffer(target);
14727 appendPQExpBuffer(target, "%s %s", reltypename,
14728 fmtId(tbinfo->dobj.name));
14729 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14731 tbinfo->dobj.namespace->dobj.name,
14732 NULL, tbinfo->rolname,
14733 false, "SECURITY LABEL", SECTION_NONE,
14734 query->data, "", NULL,
14735 &(tbinfo->dobj.dumpId), 1,
14738 destroyPQExpBuffer(query);
14739 destroyPQExpBuffer(target);
14745 * Find the security label(s), if any, associated with the given object.
14746 * All the objsubid values associated with the given classoid/objoid are
14747 * found with one search.
14750 findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
14752 /* static storage for table of security labels */
14753 static SecLabelItem *labels = NULL;
14754 static int nlabels = -1;
14756 SecLabelItem *middle = NULL;
14758 SecLabelItem *high;
14761 /* Get security labels if we didn't already */
14763 nlabels = collectSecLabels(fout, &labels);
14765 if (nlabels <= 0) /* no labels, so no match is possible */
14772 * Do binary search to find some item matching the object.
14775 high = &labels[nlabels - 1];
14776 while (low <= high)
14778 middle = low + (high - low) / 2;
14780 if (classoid < middle->classoid)
14782 else if (classoid > middle->classoid)
14784 else if (objoid < middle->objoid)
14786 else if (objoid > middle->objoid)
14789 break; /* found a match */
14792 if (low > high) /* no matches */
14799 * Now determine how many items match the object. The search loop
14800 * invariant still holds: only items between low and high inclusive could
14804 while (middle > low)
14806 if (classoid != middle[-1].classoid ||
14807 objoid != middle[-1].objoid)
14816 while (middle <= high)
14818 if (classoid != middle->classoid ||
14819 objoid != middle->objoid)
14831 * Construct a table of all security labels available for database objects.
14832 * It's much faster to pull them all at once.
14834 * The table is sorted by classoid/objid/objsubid for speed in lookup.
14837 collectSecLabels(Archive *fout, SecLabelItem **items)
14848 SecLabelItem *labels;
14850 query = createPQExpBuffer();
14852 appendPQExpBufferStr(query,
14853 "SELECT label, provider, classoid, objoid, objsubid "
14854 "FROM pg_catalog.pg_seclabel "
14855 "ORDER BY classoid, objoid, objsubid");
14857 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14859 /* Construct lookup table containing OIDs in numeric form */
14860 i_label = PQfnumber(res, "label");
14861 i_provider = PQfnumber(res, "provider");
14862 i_classoid = PQfnumber(res, "classoid");
14863 i_objoid = PQfnumber(res, "objoid");
14864 i_objsubid = PQfnumber(res, "objsubid");
14866 ntups = PQntuples(res);
14868 labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
14870 for (i = 0; i < ntups; i++)
14872 labels[i].label = PQgetvalue(res, i, i_label);
14873 labels[i].provider = PQgetvalue(res, i, i_provider);
14874 labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
14875 labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
14876 labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
14879 /* Do NOT free the PGresult since we are keeping pointers into it */
14880 destroyPQExpBuffer(query);
14888 * write out to fout the declarations (not data) of a user-defined table
14891 dumpTable(Archive *fout, TableInfo *tbinfo)
14893 DumpOptions *dopt = fout->dopt;
14897 * noop if we are not dumping anything about this table, or if we are
14898 * doing a data-only dump
14900 if (!tbinfo->dobj.dump || dopt->dataOnly)
14903 if (tbinfo->relkind == RELKIND_SEQUENCE)
14904 dumpSequence(fout, tbinfo);
14906 dumpTableSchema(fout, tbinfo);
14908 /* Handle the ACL here */
14909 namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
14910 if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
14911 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
14912 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" :
14914 namecopy, NULL, tbinfo->dobj.name,
14915 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
14916 tbinfo->relacl, tbinfo->rrelacl,
14917 tbinfo->initrelacl, tbinfo->initrrelacl);
14920 * Handle column ACLs, if any. Note: we pull these with a separate query
14921 * rather than trying to fetch them during getTableAttrs, so that we won't
14922 * miss ACLs on system columns.
14924 if (fout->remoteVersion >= 80400 && tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
14926 PQExpBuffer query = createPQExpBuffer();
14930 if (fout->remoteVersion >= 90600)
14932 PQExpBuffer acl_subquery = createPQExpBuffer();
14933 PQExpBuffer racl_subquery = createPQExpBuffer();
14934 PQExpBuffer initacl_subquery = createPQExpBuffer();
14935 PQExpBuffer initracl_subquery = createPQExpBuffer();
14937 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
14938 initracl_subquery, "at.attacl", "c.relowner", "'c'",
14939 dopt->binary_upgrade);
14941 appendPQExpBuffer(query,
14942 "SELECT at.attname, "
14945 "%s AS initattacl, "
14946 "%s AS initrattacl "
14947 "FROM pg_catalog.pg_attribute at "
14948 "JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
14949 "LEFT JOIN pg_catalog.pg_init_privs pip ON "
14950 "(at.attrelid = pip.objoid "
14951 "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
14952 "AND at.attnum = pip.objsubid) "
14953 "WHERE at.attrelid = '%u'::pg_catalog.oid AND "
14954 "NOT at.attisdropped "
14956 "%s IS NOT NULL OR "
14957 "%s IS NOT NULL OR "
14958 "%s IS NOT NULL OR "
14960 "ORDER BY at.attnum",
14961 acl_subquery->data,
14962 racl_subquery->data,
14963 initacl_subquery->data,
14964 initracl_subquery->data,
14965 tbinfo->dobj.catId.oid,
14966 acl_subquery->data,
14967 racl_subquery->data,
14968 initacl_subquery->data,
14969 initracl_subquery->data);
14971 destroyPQExpBuffer(acl_subquery);
14972 destroyPQExpBuffer(racl_subquery);
14973 destroyPQExpBuffer(initacl_subquery);
14974 destroyPQExpBuffer(initracl_subquery);
14978 appendPQExpBuffer(query,
14979 "SELECT attname, attacl, NULL as rattacl, "
14980 "NULL AS initattacl, NULL AS initrattacl "
14981 "FROM pg_catalog.pg_attribute "
14982 "WHERE attrelid = '%u'::pg_catalog.oid AND NOT attisdropped "
14983 "AND attacl IS NOT NULL "
14985 tbinfo->dobj.catId.oid);
14988 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14990 for (i = 0; i < PQntuples(res); i++)
14992 char *attname = PQgetvalue(res, i, 0);
14993 char *attacl = PQgetvalue(res, i, 1);
14994 char *rattacl = PQgetvalue(res, i, 2);
14995 char *initattacl = PQgetvalue(res, i, 3);
14996 char *initrattacl = PQgetvalue(res, i, 4);
15000 attnamecopy = pg_strdup(fmtId(attname));
15001 acltag = psprintf("%s.%s", tbinfo->dobj.name, attname);
15002 /* Column's GRANT type is always TABLE */
15003 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
15004 namecopy, attnamecopy, acltag,
15005 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15006 attacl, rattacl, initattacl, initrattacl);
15011 destroyPQExpBuffer(query);
15020 * Create the AS clause for a view or materialized view. The semicolon is
15021 * stripped because a materialized view must add a WITH NO DATA clause.
15023 * This returns a new buffer which must be freed by the caller.
15026 createViewAsClause(Archive *fout, TableInfo *tbinfo)
15028 PQExpBuffer query = createPQExpBuffer();
15029 PQExpBuffer result = createPQExpBuffer();
15033 /* Fetch the view definition */
15034 appendPQExpBuffer(query,
15035 "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
15036 tbinfo->dobj.catId.oid);
15038 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15040 if (PQntuples(res) != 1)
15042 if (PQntuples(res) < 1)
15043 exit_horribly(NULL, "query to obtain definition of view \"%s\" returned no data\n",
15044 tbinfo->dobj.name);
15046 exit_horribly(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
15047 tbinfo->dobj.name);
15050 len = PQgetlength(res, 0, 0);
15053 exit_horribly(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
15054 tbinfo->dobj.name);
15056 /* Strip off the trailing semicolon so that other things may follow. */
15057 Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
15058 appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
15061 destroyPQExpBuffer(query);
15067 * Create a dummy AS clause for a view. This is used when the real view
15068 * definition has to be postponed because of circular dependencies.
15069 * We must duplicate the view's external properties -- column names and types
15070 * (including collation) -- so that it works for subsequent references.
15072 * This returns a new buffer which must be freed by the caller.
15075 createDummyViewAsClause(Archive *fout, TableInfo *tbinfo)
15077 PQExpBuffer result = createPQExpBuffer();
15080 appendPQExpBufferStr(result, "SELECT");
15082 for (j = 0; j < tbinfo->numatts; j++)
15085 appendPQExpBufferChar(result, ',');
15086 appendPQExpBufferStr(result, "\n ");
15088 appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
15091 * Must add collation if not default for the type, because CREATE OR
15092 * REPLACE VIEW won't change it
15094 if (OidIsValid(tbinfo->attcollation[j]))
15098 coll = findCollationByOid(tbinfo->attcollation[j]);
15101 /* always schema-qualify, don't try to be smart */
15102 appendPQExpBuffer(result, " COLLATE %s.",
15103 fmtId(coll->dobj.namespace->dobj.name));
15104 appendPQExpBufferStr(result, fmtId(coll->dobj.name));
15108 appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
15116 * write the declaration (not data) of one user-defined table or view
15119 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
15121 DumpOptions *dopt = fout->dopt;
15122 PQExpBuffer q = createPQExpBuffer();
15123 PQExpBuffer delq = createPQExpBuffer();
15124 PQExpBuffer labelq = createPQExpBuffer();
15126 TableInfo **parents;
15127 int actual_atts; /* number of attrs in this CREATE statement */
15128 const char *reltypename;
15135 /* Make sure we are in proper schema */
15136 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
15138 if (dopt->binary_upgrade)
15139 binary_upgrade_set_type_oids_by_rel_oid(fout, q,
15140 tbinfo->dobj.catId.oid);
15142 /* Is it a table or a view? */
15143 if (tbinfo->relkind == RELKIND_VIEW)
15145 PQExpBuffer result;
15148 * Note: keep this code in sync with the is_view case in dumpRule()
15151 reltypename = "VIEW";
15154 * DROP must be fully qualified in case same name appears in
15157 appendPQExpBuffer(delq, "DROP VIEW %s.",
15158 fmtId(tbinfo->dobj.namespace->dobj.name));
15159 appendPQExpBuffer(delq, "%s;\n",
15160 fmtId(tbinfo->dobj.name));
15162 if (dopt->binary_upgrade)
15163 binary_upgrade_set_pg_class_oids(fout, q,
15164 tbinfo->dobj.catId.oid, false);
15166 appendPQExpBuffer(q, "CREATE VIEW %s", fmtId(tbinfo->dobj.name));
15167 if (tbinfo->dummy_view)
15168 result = createDummyViewAsClause(fout, tbinfo);
15171 if (nonemptyReloptions(tbinfo->reloptions))
15173 appendPQExpBufferStr(q, " WITH (");
15174 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15175 appendPQExpBufferChar(q, ')');
15177 result = createViewAsClause(fout, tbinfo);
15179 appendPQExpBuffer(q, " AS\n%s", result->data);
15180 destroyPQExpBuffer(result);
15182 if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
15183 appendPQExpBuffer(q, "\n WITH %s CHECK OPTION", tbinfo->checkoption);
15184 appendPQExpBufferStr(q, ";\n");
15186 appendPQExpBuffer(labelq, "VIEW %s",
15187 fmtId(tbinfo->dobj.name));
15191 switch (tbinfo->relkind)
15193 case RELKIND_FOREIGN_TABLE:
15195 PQExpBuffer query = createPQExpBuffer();
15200 reltypename = "FOREIGN TABLE";
15202 /* retrieve name of foreign server and generic options */
15203 appendPQExpBuffer(query,
15204 "SELECT fs.srvname, "
15205 "pg_catalog.array_to_string(ARRAY("
15206 "SELECT pg_catalog.quote_ident(option_name) || "
15207 "' ' || pg_catalog.quote_literal(option_value) "
15208 "FROM pg_catalog.pg_options_to_table(ftoptions) "
15209 "ORDER BY option_name"
15210 "), E',\n ') AS ftoptions "
15211 "FROM pg_catalog.pg_foreign_table ft "
15212 "JOIN pg_catalog.pg_foreign_server fs "
15213 "ON (fs.oid = ft.ftserver) "
15214 "WHERE ft.ftrelid = '%u'",
15215 tbinfo->dobj.catId.oid);
15216 res = ExecuteSqlQueryForSingleRow(fout, query->data);
15217 i_srvname = PQfnumber(res, "srvname");
15218 i_ftoptions = PQfnumber(res, "ftoptions");
15219 srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
15220 ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
15222 destroyPQExpBuffer(query);
15225 case RELKIND_MATVIEW:
15226 reltypename = "MATERIALIZED VIEW";
15231 reltypename = "TABLE";
15236 numParents = tbinfo->numParents;
15237 parents = tbinfo->parents;
15240 * DROP must be fully qualified in case same name appears in
15243 appendPQExpBuffer(delq, "DROP %s %s.", reltypename,
15244 fmtId(tbinfo->dobj.namespace->dobj.name));
15245 appendPQExpBuffer(delq, "%s;\n",
15246 fmtId(tbinfo->dobj.name));
15248 appendPQExpBuffer(labelq, "%s %s", reltypename,
15249 fmtId(tbinfo->dobj.name));
15251 if (dopt->binary_upgrade)
15252 binary_upgrade_set_pg_class_oids(fout, q,
15253 tbinfo->dobj.catId.oid, false);
15255 appendPQExpBuffer(q, "CREATE %s%s %s",
15256 tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
15259 fmtId(tbinfo->dobj.name));
15262 * Attach to type, if reloftype; except in case of a binary upgrade,
15263 * we dump the table normally and attach it to the type afterward.
15265 if (tbinfo->reloftype && !dopt->binary_upgrade)
15266 appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
15269 * If the table is a partition, dump it as such; except in the case of
15270 * a binary upgrade, we dump the table normally and attach it to the
15271 * parent afterward.
15273 if (tbinfo->ispartition && !dopt->binary_upgrade)
15275 TableInfo *parentRel = tbinfo->parents[0];
15278 * With partitions, unlike inheritance, there can only be one
15281 if (tbinfo->numParents != 1)
15282 exit_horribly(NULL, "invalid number of parents %d for table \"%s\"\n",
15283 tbinfo->numParents, tbinfo->dobj.name);
15285 appendPQExpBuffer(q, " PARTITION OF ");
15286 if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
15287 appendPQExpBuffer(q, "%s.",
15288 fmtId(parentRel->dobj.namespace->dobj.name));
15289 appendPQExpBufferStr(q, fmtId(parentRel->dobj.name));
15292 if (tbinfo->relkind != RELKIND_MATVIEW)
15294 /* Dump the attributes */
15296 for (j = 0; j < tbinfo->numatts; j++)
15299 * Normally, dump if it's locally defined in this table, and
15300 * not dropped. But for binary upgrade, we'll dump all the
15301 * columns, and then fix up the dropped and nonlocal cases
15304 if (shouldPrintColumn(dopt, tbinfo, j))
15307 * Default value --- suppress if to be printed separately.
15309 bool has_default = (tbinfo->attrdefs[j] != NULL &&
15310 !tbinfo->attrdefs[j]->separate);
15313 * Not Null constraint --- suppress if inherited, except
15314 * in binary-upgrade case where that won't work.
15316 bool has_notnull = (tbinfo->notnull[j] &&
15317 (!tbinfo->inhNotNull[j] ||
15318 dopt->binary_upgrade));
15321 * Skip column if fully defined by reloftype or the
15322 * partition parent.
15324 if ((tbinfo->reloftype || tbinfo->ispartition) &&
15325 !has_default && !has_notnull && !dopt->binary_upgrade)
15328 /* Format properly if not first attr */
15329 if (actual_atts == 0)
15330 appendPQExpBufferStr(q, " (");
15332 appendPQExpBufferChar(q, ',');
15333 appendPQExpBufferStr(q, "\n ");
15336 /* Attribute name */
15337 appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
15339 if (tbinfo->attisdropped[j])
15342 * ALTER TABLE DROP COLUMN clears
15343 * pg_attribute.atttypid, so we will not have gotten a
15344 * valid type name; insert INTEGER as a stopgap. We'll
15345 * clean things up later.
15347 appendPQExpBufferStr(q, " INTEGER /* dummy */");
15348 /* Skip all the rest, too */
15355 * In binary-upgrade mode, we always include the type. If
15356 * we aren't in binary-upgrade mode, then we skip the type
15357 * when creating a typed table ('OF type_name') or a
15358 * partition ('PARTITION OF'), since the type comes from
15359 * the parent/partitioned table.
15361 if (dopt->binary_upgrade || (!tbinfo->reloftype && !tbinfo->ispartition))
15363 appendPQExpBuffer(q, " %s",
15364 tbinfo->atttypnames[j]);
15367 /* Add collation if not default for the type */
15368 if (OidIsValid(tbinfo->attcollation[j]))
15372 coll = findCollationByOid(tbinfo->attcollation[j]);
15375 /* always schema-qualify, don't try to be smart */
15376 appendPQExpBuffer(q, " COLLATE %s.",
15377 fmtId(coll->dobj.namespace->dobj.name));
15378 appendPQExpBufferStr(q, fmtId(coll->dobj.name));
15383 appendPQExpBuffer(q, " DEFAULT %s",
15384 tbinfo->attrdefs[j]->adef_expr);
15387 appendPQExpBufferStr(q, " NOT NULL");
15392 * Add non-inherited CHECK constraints, if any.
15394 for (j = 0; j < tbinfo->ncheck; j++)
15396 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
15398 if (constr->separate || !constr->conislocal)
15401 if (actual_atts == 0)
15402 appendPQExpBufferStr(q, " (\n ");
15404 appendPQExpBufferStr(q, ",\n ");
15406 appendPQExpBuffer(q, "CONSTRAINT %s ",
15407 fmtId(constr->dobj.name));
15408 appendPQExpBufferStr(q, constr->condef);
15414 appendPQExpBufferStr(q, "\n)");
15415 else if (!((tbinfo->reloftype || tbinfo->ispartition) &&
15416 !dopt->binary_upgrade))
15419 * We must have a parenthesized attribute list, even though
15420 * empty, when not using the OF TYPE or PARTITION OF syntax.
15422 appendPQExpBufferStr(q, " (\n)");
15425 if (tbinfo->ispartition && !dopt->binary_upgrade)
15427 appendPQExpBufferStr(q, "\n");
15428 appendPQExpBufferStr(q, tbinfo->partbound);
15431 /* Emit the INHERITS clause, except if this is a partition. */
15432 if (numParents > 0 &&
15433 !tbinfo->ispartition &&
15434 !dopt->binary_upgrade)
15436 appendPQExpBufferStr(q, "\nINHERITS (");
15437 for (k = 0; k < numParents; k++)
15439 TableInfo *parentRel = parents[k];
15442 appendPQExpBufferStr(q, ", ");
15443 if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
15444 appendPQExpBuffer(q, "%s.",
15445 fmtId(parentRel->dobj.namespace->dobj.name));
15446 appendPQExpBufferStr(q, fmtId(parentRel->dobj.name));
15448 appendPQExpBufferChar(q, ')');
15451 if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15452 appendPQExpBuffer(q, "\nPARTITION BY %s", tbinfo->partkeydef);
15454 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
15455 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
15458 if (nonemptyReloptions(tbinfo->reloptions) ||
15459 nonemptyReloptions(tbinfo->toast_reloptions))
15461 bool addcomma = false;
15463 appendPQExpBufferStr(q, "\nWITH (");
15464 if (nonemptyReloptions(tbinfo->reloptions))
15467 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15469 if (nonemptyReloptions(tbinfo->toast_reloptions))
15472 appendPQExpBufferStr(q, ", ");
15473 appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
15476 appendPQExpBufferChar(q, ')');
15479 /* Dump generic options if any */
15480 if (ftoptions && ftoptions[0])
15481 appendPQExpBuffer(q, "\nOPTIONS (\n %s\n)", ftoptions);
15484 * For materialized views, create the AS clause just like a view. At
15485 * this point, we always mark the view as not populated.
15487 if (tbinfo->relkind == RELKIND_MATVIEW)
15489 PQExpBuffer result;
15491 result = createViewAsClause(fout, tbinfo);
15492 appendPQExpBuffer(q, " AS\n%s\n WITH NO DATA;\n",
15494 destroyPQExpBuffer(result);
15497 appendPQExpBufferStr(q, ";\n");
15500 * To create binary-compatible heap files, we have to ensure the same
15501 * physical column order, including dropped columns, as in the
15502 * original. Therefore, we create dropped columns above and drop them
15503 * here, also updating their attlen/attalign values so that the
15504 * dropped column can be skipped properly. (We do not bother with
15505 * restoring the original attbyval setting.) Also, inheritance
15506 * relationships are set up by doing ALTER TABLE INHERIT rather than
15507 * using an INHERITS clause --- the latter would possibly mess up the
15508 * column order. That also means we have to take care about setting
15509 * attislocal correctly, plus fix up any inherited CHECK constraints.
15510 * Analogously, we set up typed tables using ALTER TABLE / OF here.
15512 if (dopt->binary_upgrade &&
15513 (tbinfo->relkind == RELKIND_RELATION ||
15514 tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
15515 tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
15517 for (j = 0; j < tbinfo->numatts; j++)
15519 if (tbinfo->attisdropped[j])
15521 appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
15522 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
15523 "SET attlen = %d, "
15524 "attalign = '%c', attbyval = false\n"
15525 "WHERE attname = ",
15527 tbinfo->attalign[j]);
15528 appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15529 appendPQExpBufferStr(q, "\n AND attrelid = ");
15530 appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
15531 appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15533 if (tbinfo->relkind == RELKIND_RELATION ||
15534 tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15535 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15536 fmtId(tbinfo->dobj.name));
15538 appendPQExpBuffer(q, "ALTER FOREIGN TABLE ONLY %s ",
15539 fmtId(tbinfo->dobj.name));
15540 appendPQExpBuffer(q, "DROP COLUMN %s;\n",
15541 fmtId(tbinfo->attnames[j]));
15543 else if (!tbinfo->attislocal[j])
15545 appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
15546 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
15547 "SET attislocal = false\n"
15548 "WHERE attname = ");
15549 appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15550 appendPQExpBufferStr(q, "\n AND attrelid = ");
15551 appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
15552 appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15556 for (k = 0; k < tbinfo->ncheck; k++)
15558 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
15560 if (constr->separate || constr->conislocal)
15563 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
15564 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15565 fmtId(tbinfo->dobj.name));
15566 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
15567 fmtId(constr->dobj.name));
15568 appendPQExpBuffer(q, "%s;\n", constr->condef);
15569 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
15570 "SET conislocal = false\n"
15571 "WHERE contype = 'c' AND conname = ");
15572 appendStringLiteralAH(q, constr->dobj.name, fout);
15573 appendPQExpBufferStr(q, "\n AND conrelid = ");
15574 appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
15575 appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15578 if (numParents > 0)
15580 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance and partitioning this way.\n");
15581 for (k = 0; k < numParents; k++)
15583 TableInfo *parentRel = parents[k];
15584 PQExpBuffer parentname = createPQExpBuffer();
15586 /* Schema-qualify the parent table, if necessary */
15587 if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
15588 appendPQExpBuffer(parentname, "%s.",
15589 fmtId(parentRel->dobj.namespace->dobj.name));
15591 appendPQExpBuffer(parentname, "%s",
15592 fmtId(parentRel->dobj.name));
15594 /* In the partitioning case, we alter the parent */
15595 if (tbinfo->ispartition)
15596 appendPQExpBuffer(q,
15597 "ALTER TABLE ONLY %s ATTACH PARTITION ",
15600 appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
15601 fmtId(tbinfo->dobj.name));
15603 /* Partition needs specifying the bounds */
15604 if (tbinfo->ispartition)
15605 appendPQExpBuffer(q, "%s %s;\n",
15606 fmtId(tbinfo->dobj.name),
15607 tbinfo->partbound);
15609 appendPQExpBuffer(q, "%s;\n", parentname->data);
15611 destroyPQExpBuffer(parentname);
15615 if (tbinfo->reloftype)
15617 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
15618 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
15619 fmtId(tbinfo->dobj.name),
15620 tbinfo->reloftype);
15623 appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
15624 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
15625 "SET relfrozenxid = '%u', relminmxid = '%u'\n"
15627 tbinfo->frozenxid, tbinfo->minmxid);
15628 appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
15629 appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15631 if (tbinfo->toast_oid)
15633 /* We preserve the toast oids, so we can use it during restore */
15634 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
15635 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
15636 "SET relfrozenxid = '%u', relminmxid = '%u'\n"
15637 "WHERE oid = '%u';\n",
15638 tbinfo->toast_frozenxid,
15639 tbinfo->toast_minmxid, tbinfo->toast_oid);
15644 * In binary_upgrade mode, restore matviews' populated status by
15645 * poking pg_class directly. This is pretty ugly, but we can't use
15646 * REFRESH MATERIALIZED VIEW since it's possible that some underlying
15647 * matview is not populated even though this matview is.
15649 if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
15650 tbinfo->relispopulated)
15652 appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
15653 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
15654 "SET relispopulated = 't'\n"
15656 appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
15657 appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15661 * Dump additional per-column properties that we can't handle in the
15662 * main CREATE TABLE command.
15664 for (j = 0; j < tbinfo->numatts; j++)
15666 /* None of this applies to dropped columns */
15667 if (tbinfo->attisdropped[j])
15671 * If we didn't dump the column definition explicitly above, and
15672 * it is NOT NULL and did not inherit that property from a parent,
15673 * we have to mark it separately.
15675 if (!shouldPrintColumn(dopt, tbinfo, j) &&
15676 tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
15678 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15679 fmtId(tbinfo->dobj.name));
15680 appendPQExpBuffer(q, "ALTER COLUMN %s SET NOT NULL;\n",
15681 fmtId(tbinfo->attnames[j]));
15685 * Dump per-column statistics information. We only issue an ALTER
15686 * TABLE statement if the attstattarget entry for this column is
15687 * non-negative (i.e. it's not the default value)
15689 if (tbinfo->attstattarget[j] >= 0)
15691 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15692 fmtId(tbinfo->dobj.name));
15693 appendPQExpBuffer(q, "ALTER COLUMN %s ",
15694 fmtId(tbinfo->attnames[j]));
15695 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
15696 tbinfo->attstattarget[j]);
15700 * Dump per-column storage information. The statement is only
15701 * dumped if the storage has been changed from the type's default.
15703 if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
15705 switch (tbinfo->attstorage[j])
15711 storage = "EXTERNAL";
15717 storage = "EXTENDED";
15724 * Only dump the statement if it's a storage type we recognize
15726 if (storage != NULL)
15728 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15729 fmtId(tbinfo->dobj.name));
15730 appendPQExpBuffer(q, "ALTER COLUMN %s ",
15731 fmtId(tbinfo->attnames[j]));
15732 appendPQExpBuffer(q, "SET STORAGE %s;\n",
15738 * Dump per-column attributes.
15740 if (tbinfo->attoptions[j] && tbinfo->attoptions[j][0] != '\0')
15742 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15743 fmtId(tbinfo->dobj.name));
15744 appendPQExpBuffer(q, "ALTER COLUMN %s ",
15745 fmtId(tbinfo->attnames[j]));
15746 appendPQExpBuffer(q, "SET (%s);\n",
15747 tbinfo->attoptions[j]);
15751 * Dump per-column fdw options.
15753 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
15754 tbinfo->attfdwoptions[j] &&
15755 tbinfo->attfdwoptions[j][0] != '\0')
15757 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
15758 fmtId(tbinfo->dobj.name));
15759 appendPQExpBuffer(q, "ALTER COLUMN %s ",
15760 fmtId(tbinfo->attnames[j]));
15761 appendPQExpBuffer(q, "OPTIONS (\n %s\n);\n",
15762 tbinfo->attfdwoptions[j]);
15768 * dump properties we only have ALTER TABLE syntax for
15770 if ((tbinfo->relkind == RELKIND_RELATION ||
15771 tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
15772 tbinfo->relkind == RELKIND_MATVIEW) &&
15773 tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
15775 if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
15777 /* nothing to do, will be set when the index is dumped */
15779 else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
15781 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
15782 fmtId(tbinfo->dobj.name));
15784 else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
15786 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
15787 fmtId(tbinfo->dobj.name));
15791 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE && tbinfo->hasoids)
15792 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s SET WITH OIDS;\n",
15793 fmtId(tbinfo->dobj.name));
15795 if (tbinfo->forcerowsec)
15796 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
15797 fmtId(tbinfo->dobj.name));
15799 if (dopt->binary_upgrade)
15800 binary_upgrade_extension_member(q, &tbinfo->dobj, labelq->data);
15802 if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15803 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
15805 tbinfo->dobj.namespace->dobj.name,
15806 (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
15808 (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
15810 tbinfo->postponed_def ?
15811 SECTION_POST_DATA : SECTION_PRE_DATA,
15812 q->data, delq->data, NULL,
15817 /* Dump Table Comments */
15818 if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
15819 dumpTableComment(fout, tbinfo, reltypename);
15821 /* Dump Table Security Labels */
15822 if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
15823 dumpTableSecLabel(fout, tbinfo, reltypename);
15825 /* Dump comments on inlined table constraints */
15826 for (j = 0; j < tbinfo->ncheck; j++)
15828 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
15830 if (constr->separate || !constr->conislocal)
15833 if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
15834 dumpTableConstraintComment(fout, constr);
15837 destroyPQExpBuffer(q);
15838 destroyPQExpBuffer(delq);
15839 destroyPQExpBuffer(labelq);
15843 * dumpAttrDef --- dump an attribute's default-value declaration
15846 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
15848 DumpOptions *dopt = fout->dopt;
15849 TableInfo *tbinfo = adinfo->adtable;
15850 int adnum = adinfo->adnum;
15855 /* Skip if table definition not to be dumped */
15856 if (!tbinfo->dobj.dump || dopt->dataOnly)
15859 /* Skip if not "separate"; it was dumped in the table's definition */
15860 if (!adinfo->separate)
15863 q = createPQExpBuffer();
15864 delq = createPQExpBuffer();
15866 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15867 fmtId(tbinfo->dobj.name));
15868 appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
15869 fmtId(tbinfo->attnames[adnum - 1]),
15870 adinfo->adef_expr);
15873 * DROP must be fully qualified in case same name appears in pg_catalog
15875 appendPQExpBuffer(delq, "ALTER TABLE %s.",
15876 fmtId(tbinfo->dobj.namespace->dobj.name));
15877 appendPQExpBuffer(delq, "%s ",
15878 fmtId(tbinfo->dobj.name));
15879 appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
15880 fmtId(tbinfo->attnames[adnum - 1]));
15882 tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
15884 if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15885 ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
15887 tbinfo->dobj.namespace->dobj.name,
15890 false, "DEFAULT", SECTION_PRE_DATA,
15891 q->data, delq->data, NULL,
15896 destroyPQExpBuffer(q);
15897 destroyPQExpBuffer(delq);
15901 * getAttrName: extract the correct name for an attribute
15903 * The array tblInfo->attnames[] only provides names of user attributes;
15904 * if a system attribute number is supplied, we have to fake it.
15905 * We also do a little bit of bounds checking for safety's sake.
15907 static const char *
15908 getAttrName(int attrnum, TableInfo *tblInfo)
15910 if (attrnum > 0 && attrnum <= tblInfo->numatts)
15911 return tblInfo->attnames[attrnum - 1];
15914 case SelfItemPointerAttributeNumber:
15916 case ObjectIdAttributeNumber:
15918 case MinTransactionIdAttributeNumber:
15920 case MinCommandIdAttributeNumber:
15922 case MaxTransactionIdAttributeNumber:
15924 case MaxCommandIdAttributeNumber:
15926 case TableOidAttributeNumber:
15929 exit_horribly(NULL, "invalid column number %d for table \"%s\"\n",
15930 attrnum, tblInfo->dobj.name);
15931 return NULL; /* keep compiler quiet */
15936 * write out to fout a user-defined index
15939 dumpIndex(Archive *fout, IndxInfo *indxinfo)
15941 DumpOptions *dopt = fout->dopt;
15942 TableInfo *tbinfo = indxinfo->indextable;
15943 bool is_constraint = (indxinfo->indexconstraint != 0);
15946 PQExpBuffer labelq;
15948 if (dopt->dataOnly)
15951 q = createPQExpBuffer();
15952 delq = createPQExpBuffer();
15953 labelq = createPQExpBuffer();
15955 appendPQExpBuffer(labelq, "INDEX %s",
15956 fmtId(indxinfo->dobj.name));
15959 * If there's an associated constraint, don't dump the index per se, but
15960 * do dump any comment for it. (This is safe because dependency ordering
15961 * will have ensured the constraint is emitted first.) Note that the
15962 * emitted comment has to be shown as depending on the constraint, not the
15963 * index, in such cases.
15965 if (!is_constraint)
15967 if (dopt->binary_upgrade)
15968 binary_upgrade_set_pg_class_oids(fout, q,
15969 indxinfo->dobj.catId.oid, true);
15971 /* Plain secondary index */
15972 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
15974 /* If the index is clustered, we need to record that. */
15975 if (indxinfo->indisclustered)
15977 appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
15978 fmtId(tbinfo->dobj.name));
15979 appendPQExpBuffer(q, " ON %s;\n",
15980 fmtId(indxinfo->dobj.name));
15983 /* If the index defines identity, we need to record that. */
15984 if (indxinfo->indisreplident)
15986 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
15987 fmtId(tbinfo->dobj.name));
15988 appendPQExpBuffer(q, " INDEX %s;\n",
15989 fmtId(indxinfo->dobj.name));
15993 * DROP must be fully qualified in case same name appears in
15996 appendPQExpBuffer(delq, "DROP INDEX %s.",
15997 fmtId(tbinfo->dobj.namespace->dobj.name));
15998 appendPQExpBuffer(delq, "%s;\n",
15999 fmtId(indxinfo->dobj.name));
16001 if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16002 ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
16003 indxinfo->dobj.name,
16004 tbinfo->dobj.namespace->dobj.name,
16005 indxinfo->tablespace,
16006 tbinfo->rolname, false,
16007 "INDEX", SECTION_POST_DATA,
16008 q->data, delq->data, NULL,
16013 /* Dump Index Comments */
16014 if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16015 dumpComment(fout, labelq->data,
16016 tbinfo->dobj.namespace->dobj.name,
16018 indxinfo->dobj.catId, 0,
16019 is_constraint ? indxinfo->indexconstraint :
16020 indxinfo->dobj.dumpId);
16022 destroyPQExpBuffer(q);
16023 destroyPQExpBuffer(delq);
16024 destroyPQExpBuffer(labelq);
16028 * dumpStatisticsExt
16029 * write out to fout an extended statistics object
16032 dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo)
16034 DumpOptions *dopt = fout->dopt;
16035 TableInfo *tbinfo = statsextinfo->statsexttable;
16038 PQExpBuffer labelq;
16040 if (dopt->dataOnly)
16043 q = createPQExpBuffer();
16044 delq = createPQExpBuffer();
16045 labelq = createPQExpBuffer();
16047 appendPQExpBuffer(labelq, "STATISTICS %s",
16048 fmtId(statsextinfo->dobj.name));
16050 appendPQExpBuffer(q, "%s;\n", statsextinfo->statsextdef);
16052 appendPQExpBuffer(delq, "DROP STATISTICS %s.",
16053 fmtId(tbinfo->dobj.namespace->dobj.name));
16054 appendPQExpBuffer(delq, "%s;\n",
16055 fmtId(statsextinfo->dobj.name));
16057 if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16058 ArchiveEntry(fout, statsextinfo->dobj.catId,
16059 statsextinfo->dobj.dumpId,
16060 statsextinfo->dobj.name,
16061 tbinfo->dobj.namespace->dobj.name,
16063 tbinfo->rolname, false,
16064 "STATISTICS", SECTION_POST_DATA,
16065 q->data, delq->data, NULL,
16069 /* Dump Statistics Comments */
16070 if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16071 dumpComment(fout, labelq->data,
16072 tbinfo->dobj.namespace->dobj.name,
16074 statsextinfo->dobj.catId, 0,
16075 statsextinfo->dobj.dumpId);
16077 destroyPQExpBuffer(q);
16078 destroyPQExpBuffer(delq);
16079 destroyPQExpBuffer(labelq);
16084 * write out to fout a user-defined constraint
16087 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
16089 DumpOptions *dopt = fout->dopt;
16090 TableInfo *tbinfo = coninfo->contable;
16095 /* Skip if not to be dumped */
16096 if (!coninfo->dobj.dump || dopt->dataOnly)
16099 q = createPQExpBuffer();
16100 delq = createPQExpBuffer();
16102 if (coninfo->contype == 'p' ||
16103 coninfo->contype == 'u' ||
16104 coninfo->contype == 'x')
16106 /* Index-related constraint */
16107 IndxInfo *indxinfo;
16110 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
16112 if (indxinfo == NULL)
16113 exit_horribly(NULL, "missing index for constraint \"%s\"\n",
16114 coninfo->dobj.name);
16116 if (dopt->binary_upgrade)
16117 binary_upgrade_set_pg_class_oids(fout, q,
16118 indxinfo->dobj.catId.oid, true);
16120 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
16121 fmtId(tbinfo->dobj.name));
16122 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
16123 fmtId(coninfo->dobj.name));
16125 if (coninfo->condef)
16127 /* pg_get_constraintdef should have provided everything */
16128 appendPQExpBuffer(q, "%s;\n", coninfo->condef);
16132 appendPQExpBuffer(q, "%s (",
16133 coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
16134 for (k = 0; k < indxinfo->indnkeys; k++)
16136 int indkey = (int) indxinfo->indkeys[k];
16137 const char *attname;
16139 if (indkey == InvalidAttrNumber)
16141 attname = getAttrName(indkey, tbinfo);
16143 appendPQExpBuffer(q, "%s%s",
16144 (k == 0) ? "" : ", ",
16148 appendPQExpBufferChar(q, ')');
16150 if (nonemptyReloptions(indxinfo->indreloptions))
16152 appendPQExpBufferStr(q, " WITH (");
16153 appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
16154 appendPQExpBufferChar(q, ')');
16157 if (coninfo->condeferrable)
16159 appendPQExpBufferStr(q, " DEFERRABLE");
16160 if (coninfo->condeferred)
16161 appendPQExpBufferStr(q, " INITIALLY DEFERRED");
16164 appendPQExpBufferStr(q, ";\n");
16167 /* If the index is clustered, we need to record that. */
16168 if (indxinfo->indisclustered)
16170 appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16171 fmtId(tbinfo->dobj.name));
16172 appendPQExpBuffer(q, " ON %s;\n",
16173 fmtId(indxinfo->dobj.name));
16177 * DROP must be fully qualified in case same name appears in
16180 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
16181 fmtId(tbinfo->dobj.namespace->dobj.name));
16182 appendPQExpBuffer(delq, "%s ",
16183 fmtId(tbinfo->dobj.name));
16184 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16185 fmtId(coninfo->dobj.name));
16187 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16189 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16190 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16192 tbinfo->dobj.namespace->dobj.name,
16193 indxinfo->tablespace,
16194 tbinfo->rolname, false,
16195 "CONSTRAINT", SECTION_POST_DATA,
16196 q->data, delq->data, NULL,
16200 else if (coninfo->contype == 'f')
16203 * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
16204 * current table data is not processed
16206 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
16207 fmtId(tbinfo->dobj.name));
16208 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
16209 fmtId(coninfo->dobj.name),
16213 * DROP must be fully qualified in case same name appears in
16216 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
16217 fmtId(tbinfo->dobj.namespace->dobj.name));
16218 appendPQExpBuffer(delq, "%s ",
16219 fmtId(tbinfo->dobj.name));
16220 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16221 fmtId(coninfo->dobj.name));
16223 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16225 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16226 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16228 tbinfo->dobj.namespace->dobj.name,
16230 tbinfo->rolname, false,
16231 "FK CONSTRAINT", SECTION_POST_DATA,
16232 q->data, delq->data, NULL,
16236 else if (coninfo->contype == 'c' && tbinfo)
16238 /* CHECK constraint on a table */
16240 /* Ignore if not to be dumped separately, or if it was inherited */
16241 if (coninfo->separate && coninfo->conislocal)
16243 /* not ONLY since we want it to propagate to children */
16244 appendPQExpBuffer(q, "ALTER TABLE %s\n",
16245 fmtId(tbinfo->dobj.name));
16246 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
16247 fmtId(coninfo->dobj.name),
16251 * DROP must be fully qualified in case same name appears in
16254 appendPQExpBuffer(delq, "ALTER TABLE %s.",
16255 fmtId(tbinfo->dobj.namespace->dobj.name));
16256 appendPQExpBuffer(delq, "%s ",
16257 fmtId(tbinfo->dobj.name));
16258 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16259 fmtId(coninfo->dobj.name));
16261 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16263 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16264 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16266 tbinfo->dobj.namespace->dobj.name,
16268 tbinfo->rolname, false,
16269 "CHECK CONSTRAINT", SECTION_POST_DATA,
16270 q->data, delq->data, NULL,
16275 else if (coninfo->contype == 'c' && tbinfo == NULL)
16277 /* CHECK constraint on a domain */
16278 TypeInfo *tyinfo = coninfo->condomain;
16280 /* Ignore if not to be dumped separately */
16281 if (coninfo->separate)
16283 appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
16284 fmtId(tyinfo->dobj.name));
16285 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
16286 fmtId(coninfo->dobj.name),
16290 * DROP must be fully qualified in case same name appears in
16293 appendPQExpBuffer(delq, "ALTER DOMAIN %s.",
16294 fmtId(tyinfo->dobj.namespace->dobj.name));
16295 appendPQExpBuffer(delq, "%s ",
16296 fmtId(tyinfo->dobj.name));
16297 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16298 fmtId(coninfo->dobj.name));
16300 tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
16302 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16303 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16305 tyinfo->dobj.namespace->dobj.name,
16307 tyinfo->rolname, false,
16308 "CHECK CONSTRAINT", SECTION_POST_DATA,
16309 q->data, delq->data, NULL,
16316 exit_horribly(NULL, "unrecognized constraint type: %c\n",
16320 /* Dump Constraint Comments --- only works for table constraints */
16321 if (tbinfo && coninfo->separate &&
16322 coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16323 dumpTableConstraintComment(fout, coninfo);
16326 destroyPQExpBuffer(q);
16327 destroyPQExpBuffer(delq);
16331 * dumpTableConstraintComment --- dump a constraint's comment if any
16333 * This is split out because we need the function in two different places
16334 * depending on whether the constraint is dumped as part of CREATE TABLE
16335 * or as a separate ALTER command.
16338 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
16340 TableInfo *tbinfo = coninfo->contable;
16341 PQExpBuffer labelq = createPQExpBuffer();
16343 appendPQExpBuffer(labelq, "CONSTRAINT %s ",
16344 fmtId(coninfo->dobj.name));
16345 appendPQExpBuffer(labelq, "ON %s",
16346 fmtId(tbinfo->dobj.name));
16348 if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16349 dumpComment(fout, labelq->data,
16350 tbinfo->dobj.namespace->dobj.name,
16352 coninfo->dobj.catId, 0,
16353 coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
16355 destroyPQExpBuffer(labelq);
16359 * findLastBuiltinOid_V71 -
16361 * find the last built in oid
16363 * For 7.1 through 8.0, we do this by retrieving datlastsysoid from the
16364 * pg_database entry for the current database.
16367 findLastBuiltinOid_V71(Archive *fout, const char *dbname)
16371 PQExpBuffer query = createPQExpBuffer();
16373 resetPQExpBuffer(query);
16374 appendPQExpBufferStr(query, "SELECT datlastsysoid from pg_database where datname = ");
16375 appendStringLiteralAH(query, dbname, fout);
16377 res = ExecuteSqlQueryForSingleRow(fout, query->data);
16378 last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
16380 destroyPQExpBuffer(query);
16387 * write the declaration (not data) of one user-defined sequence
16390 dumpSequence(Archive *fout, TableInfo *tbinfo)
16392 DumpOptions *dopt = fout->dopt;
16402 PQExpBuffer query = createPQExpBuffer();
16403 PQExpBuffer delqry = createPQExpBuffer();
16404 PQExpBuffer labelq = createPQExpBuffer();
16406 if (fout->remoteVersion >= 100000)
16408 /* Make sure we are in proper schema */
16409 selectSourceSchema(fout, "pg_catalog");
16411 appendPQExpBuffer(query,
16412 "SELECT format_type(seqtypid, NULL), "
16413 "seqstart, seqincrement, "
16415 "seqcache, seqcycle "
16417 "JOIN pg_sequence s ON (s.seqrelid = c.oid) "
16418 "WHERE c.oid = '%u'::oid",
16419 tbinfo->dobj.catId.oid);
16421 else if (fout->remoteVersion >= 80400)
16424 * Before PostgreSQL 10, sequence metadata is in the sequence itself,
16425 * so switch to the sequence's schema instead of pg_catalog.
16428 /* Make sure we are in proper schema */
16429 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
16431 appendPQExpBuffer(query,
16432 "SELECT 'bigint'::name AS sequence_type, "
16433 "start_value, increment_by, max_value, min_value, "
16434 "cache_value, is_cycled FROM %s",
16435 fmtId(tbinfo->dobj.name));
16439 /* Make sure we are in proper schema */
16440 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
16442 appendPQExpBuffer(query,
16443 "SELECT 'bigint'::name AS sequence_type, "
16444 "0 AS start_value, increment_by, max_value, min_value, "
16445 "cache_value, is_cycled FROM %s",
16446 fmtId(tbinfo->dobj.name));
16449 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16451 if (PQntuples(res) != 1)
16453 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
16454 "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
16456 tbinfo->dobj.name, PQntuples(res));
16460 seqtype = PQgetvalue(res, 0, 0);
16461 startv = PQgetvalue(res, 0, 1);
16462 incby = PQgetvalue(res, 0, 2);
16463 maxv = PQgetvalue(res, 0, 3);
16464 minv = PQgetvalue(res, 0, 4);
16465 cache = PQgetvalue(res, 0, 5);
16466 cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
16468 is_ascending = incby[0] != '-';
16470 if (is_ascending && atoi(minv) == 1)
16472 if (!is_ascending && atoi(maxv) == -1)
16475 if (strcmp(seqtype, "smallint") == 0)
16477 if (!is_ascending && atoi(minv) == PG_INT16_MIN)
16479 if (is_ascending && atoi(maxv) == PG_INT16_MAX)
16482 else if (strcmp(seqtype, "integer") == 0)
16484 if (!is_ascending && atoi(minv) == PG_INT32_MIN)
16486 if (is_ascending && atoi(maxv) == PG_INT32_MAX)
16489 else if (strcmp(seqtype, "bigint") == 0)
16494 snprintf(bufm, sizeof(bufm), INT64_FORMAT, PG_INT64_MIN);
16495 snprintf(bufx, sizeof(bufx), INT64_FORMAT, PG_INT64_MAX);
16497 if (!is_ascending && strcmp(minv, bufm) == 0)
16499 if (is_ascending && strcmp(maxv, bufx) == 0)
16504 * DROP must be fully qualified in case same name appears in pg_catalog
16506 if (!tbinfo->is_identity_sequence)
16508 appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
16509 fmtId(tbinfo->dobj.namespace->dobj.name));
16510 appendPQExpBuffer(delqry, "%s;\n",
16511 fmtId(tbinfo->dobj.name));
16514 resetPQExpBuffer(query);
16516 if (dopt->binary_upgrade)
16518 binary_upgrade_set_pg_class_oids(fout, query,
16519 tbinfo->dobj.catId.oid, false);
16520 binary_upgrade_set_type_oids_by_rel_oid(fout, query,
16521 tbinfo->dobj.catId.oid);
16524 if (tbinfo->is_identity_sequence)
16526 TableInfo *owning_tab = findTableByOid(tbinfo->owning_tab);
16528 appendPQExpBuffer(query,
16530 fmtId(owning_tab->dobj.name));
16531 appendPQExpBuffer(query,
16532 "ALTER COLUMN %s ADD GENERATED ",
16533 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
16534 if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
16535 appendPQExpBuffer(query, "ALWAYS");
16536 else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
16537 appendPQExpBuffer(query, "BY DEFAULT");
16538 appendPQExpBuffer(query, " AS IDENTITY (\n SEQUENCE NAME %s\n",
16539 fmtId(tbinfo->dobj.name));
16543 appendPQExpBuffer(query,
16544 "CREATE SEQUENCE %s\n",
16545 fmtId(tbinfo->dobj.name));
16547 if (strcmp(seqtype, "bigint") != 0)
16548 appendPQExpBuffer(query, " AS %s\n", seqtype);
16551 if (fout->remoteVersion >= 80400)
16552 appendPQExpBuffer(query, " START WITH %s\n", startv);
16554 appendPQExpBuffer(query, " INCREMENT BY %s\n", incby);
16557 appendPQExpBuffer(query, " MINVALUE %s\n", minv);
16559 appendPQExpBufferStr(query, " NO MINVALUE\n");
16562 appendPQExpBuffer(query, " MAXVALUE %s\n", maxv);
16564 appendPQExpBufferStr(query, " NO MAXVALUE\n");
16566 appendPQExpBuffer(query,
16568 cache, (cycled ? "\n CYCLE" : ""));
16570 if (tbinfo->is_identity_sequence)
16571 appendPQExpBufferStr(query, "\n);\n");
16573 appendPQExpBufferStr(query, ";\n");
16575 appendPQExpBuffer(labelq, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
16577 /* binary_upgrade: no need to clear TOAST table oid */
16579 if (dopt->binary_upgrade)
16580 binary_upgrade_extension_member(query, &tbinfo->dobj,
16583 if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16584 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
16586 tbinfo->dobj.namespace->dobj.name,
16589 false, "SEQUENCE", SECTION_PRE_DATA,
16590 query->data, delqry->data, NULL,
16595 * If the sequence is owned by a table column, emit the ALTER for it as a
16596 * separate TOC entry immediately following the sequence's own entry. It's
16597 * OK to do this rather than using full sorting logic, because the
16598 * dependency that tells us it's owned will have forced the table to be
16599 * created first. We can't just include the ALTER in the TOC entry
16600 * because it will fail if we haven't reassigned the sequence owner to
16601 * match the table's owner.
16603 * We need not schema-qualify the table reference because both sequence
16604 * and table must be in the same schema.
16606 if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
16608 TableInfo *owning_tab = findTableByOid(tbinfo->owning_tab);
16610 if (owning_tab == NULL)
16611 exit_horribly(NULL, "failed sanity check, parent table with OID %u of sequence with OID %u not found\n",
16612 tbinfo->owning_tab, tbinfo->dobj.catId.oid);
16614 if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
16616 resetPQExpBuffer(query);
16617 appendPQExpBuffer(query, "ALTER SEQUENCE %s",
16618 fmtId(tbinfo->dobj.name));
16619 appendPQExpBuffer(query, " OWNED BY %s",
16620 fmtId(owning_tab->dobj.name));
16621 appendPQExpBuffer(query, ".%s;\n",
16622 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
16624 if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16625 ArchiveEntry(fout, nilCatalogId, createDumpId(),
16627 tbinfo->dobj.namespace->dobj.name,
16630 false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
16631 query->data, "", NULL,
16632 &(tbinfo->dobj.dumpId), 1,
16637 /* Dump Sequence Comments and Security Labels */
16638 if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16639 dumpComment(fout, labelq->data,
16640 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
16641 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
16643 if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
16644 dumpSecLabel(fout, labelq->data,
16645 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
16646 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
16650 destroyPQExpBuffer(query);
16651 destroyPQExpBuffer(delqry);
16652 destroyPQExpBuffer(labelq);
16657 * write the data of one user-defined sequence
16660 dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
16662 TableInfo *tbinfo = tdinfo->tdtable;
16666 PQExpBuffer query = createPQExpBuffer();
16668 /* Make sure we are in proper schema */
16669 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
16671 appendPQExpBuffer(query,
16672 "SELECT last_value, is_called FROM %s",
16673 fmtId(tbinfo->dobj.name));
16675 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16677 if (PQntuples(res) != 1)
16679 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
16680 "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
16682 tbinfo->dobj.name, PQntuples(res));
16686 last = PQgetvalue(res, 0, 0);
16687 called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
16689 resetPQExpBuffer(query);
16690 appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
16691 appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
16692 appendPQExpBuffer(query, ", %s, %s);\n",
16693 last, (called ? "true" : "false"));
16695 if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
16696 ArchiveEntry(fout, nilCatalogId, createDumpId(),
16698 tbinfo->dobj.namespace->dobj.name,
16701 false, "SEQUENCE SET", SECTION_DATA,
16702 query->data, "", NULL,
16703 &(tbinfo->dobj.dumpId), 1,
16708 destroyPQExpBuffer(query);
16713 * write the declaration of one user-defined table trigger
16716 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
16718 DumpOptions *dopt = fout->dopt;
16719 TableInfo *tbinfo = tginfo->tgtable;
16721 PQExpBuffer delqry;
16722 PQExpBuffer labelq;
16730 * we needn't check dobj.dump because TriggerInfo wouldn't have been
16731 * created in the first place for non-dumpable triggers
16733 if (dopt->dataOnly)
16736 query = createPQExpBuffer();
16737 delqry = createPQExpBuffer();
16738 labelq = createPQExpBuffer();
16741 * DROP must be fully qualified in case same name appears in pg_catalog
16743 appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
16744 fmtId(tginfo->dobj.name));
16745 appendPQExpBuffer(delqry, "ON %s.",
16746 fmtId(tbinfo->dobj.namespace->dobj.name));
16747 appendPQExpBuffer(delqry, "%s;\n",
16748 fmtId(tbinfo->dobj.name));
16752 appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
16756 if (tginfo->tgisconstraint)
16758 appendPQExpBufferStr(query, "CREATE CONSTRAINT TRIGGER ");
16759 appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
16763 appendPQExpBufferStr(query, "CREATE TRIGGER ");
16764 appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
16766 appendPQExpBufferStr(query, "\n ");
16769 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
16770 appendPQExpBufferStr(query, "BEFORE");
16771 else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
16772 appendPQExpBufferStr(query, "AFTER");
16773 else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
16774 appendPQExpBufferStr(query, "INSTEAD OF");
16777 write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
16782 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
16784 appendPQExpBufferStr(query, " INSERT");
16787 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
16790 appendPQExpBufferStr(query, " OR DELETE");
16792 appendPQExpBufferStr(query, " DELETE");
16795 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
16798 appendPQExpBufferStr(query, " OR UPDATE");
16800 appendPQExpBufferStr(query, " UPDATE");
16803 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
16806 appendPQExpBufferStr(query, " OR TRUNCATE");
16808 appendPQExpBufferStr(query, " TRUNCATE");
16811 appendPQExpBuffer(query, " ON %s\n",
16812 fmtId(tbinfo->dobj.name));
16814 if (tginfo->tgisconstraint)
16816 if (OidIsValid(tginfo->tgconstrrelid))
16818 /* regclass output is already quoted */
16819 appendPQExpBuffer(query, " FROM %s\n ",
16820 tginfo->tgconstrrelname);
16822 if (!tginfo->tgdeferrable)
16823 appendPQExpBufferStr(query, "NOT ");
16824 appendPQExpBufferStr(query, "DEFERRABLE INITIALLY ");
16825 if (tginfo->tginitdeferred)
16826 appendPQExpBufferStr(query, "DEFERRED\n");
16828 appendPQExpBufferStr(query, "IMMEDIATE\n");
16831 if (TRIGGER_FOR_ROW(tginfo->tgtype))
16832 appendPQExpBufferStr(query, " FOR EACH ROW\n ");
16834 appendPQExpBufferStr(query, " FOR EACH STATEMENT\n ");
16836 /* regproc output is already sufficiently quoted */
16837 appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
16840 tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
16843 for (findx = 0; findx < tginfo->tgnargs; findx++)
16845 /* find the embedded null that terminates this trigger argument */
16846 size_t tlen = strlen(p);
16848 if (p + tlen >= tgargs + lentgargs)
16850 /* hm, not found before end of bytea value... */
16851 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
16854 tbinfo->dobj.name);
16859 appendPQExpBufferStr(query, ", ");
16860 appendStringLiteralAH(query, p, fout);
16864 appendPQExpBufferStr(query, ");\n");
16867 if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
16869 appendPQExpBuffer(query, "\nALTER TABLE %s ",
16870 fmtId(tbinfo->dobj.name));
16871 switch (tginfo->tgenabled)
16875 appendPQExpBufferStr(query, "DISABLE");
16878 appendPQExpBufferStr(query, "ENABLE ALWAYS");
16881 appendPQExpBufferStr(query, "ENABLE REPLICA");
16884 appendPQExpBufferStr(query, "ENABLE");
16887 appendPQExpBuffer(query, " TRIGGER %s;\n",
16888 fmtId(tginfo->dobj.name));
16891 appendPQExpBuffer(labelq, "TRIGGER %s ",
16892 fmtId(tginfo->dobj.name));
16893 appendPQExpBuffer(labelq, "ON %s",
16894 fmtId(tbinfo->dobj.name));
16896 tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
16898 if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16899 ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
16901 tbinfo->dobj.namespace->dobj.name,
16903 tbinfo->rolname, false,
16904 "TRIGGER", SECTION_POST_DATA,
16905 query->data, delqry->data, NULL,
16909 if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16910 dumpComment(fout, labelq->data,
16911 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
16912 tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
16915 destroyPQExpBuffer(query);
16916 destroyPQExpBuffer(delqry);
16917 destroyPQExpBuffer(labelq);
16922 * write the declaration of one user-defined event trigger
16925 dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
16927 DumpOptions *dopt = fout->dopt;
16929 PQExpBuffer delqry;
16930 PQExpBuffer labelq;
16932 /* Skip if not to be dumped */
16933 if (!evtinfo->dobj.dump || dopt->dataOnly)
16936 query = createPQExpBuffer();
16937 delqry = createPQExpBuffer();
16938 labelq = createPQExpBuffer();
16940 appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
16941 appendPQExpBufferStr(query, fmtId(evtinfo->dobj.name));
16942 appendPQExpBufferStr(query, " ON ");
16943 appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
16945 if (strcmp("", evtinfo->evttags) != 0)
16947 appendPQExpBufferStr(query, "\n WHEN TAG IN (");
16948 appendPQExpBufferStr(query, evtinfo->evttags);
16949 appendPQExpBufferChar(query, ')');
16952 appendPQExpBufferStr(query, "\n EXECUTE PROCEDURE ");
16953 appendPQExpBufferStr(query, evtinfo->evtfname);
16954 appendPQExpBufferStr(query, "();\n");
16956 if (evtinfo->evtenabled != 'O')
16958 appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
16959 fmtId(evtinfo->dobj.name));
16960 switch (evtinfo->evtenabled)
16963 appendPQExpBufferStr(query, "DISABLE");
16966 appendPQExpBufferStr(query, "ENABLE ALWAYS");
16969 appendPQExpBufferStr(query, "ENABLE REPLICA");
16972 appendPQExpBufferStr(query, "ENABLE");
16975 appendPQExpBufferStr(query, ";\n");
16978 appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
16979 fmtId(evtinfo->dobj.name));
16981 appendPQExpBuffer(labelq, "EVENT TRIGGER %s",
16982 fmtId(evtinfo->dobj.name));
16984 if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16985 ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
16986 evtinfo->dobj.name, NULL, NULL,
16987 evtinfo->evtowner, false,
16988 "EVENT TRIGGER", SECTION_POST_DATA,
16989 query->data, delqry->data, NULL,
16993 if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16994 dumpComment(fout, labelq->data,
16995 NULL, evtinfo->evtowner,
16996 evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
16998 destroyPQExpBuffer(query);
16999 destroyPQExpBuffer(delqry);
17000 destroyPQExpBuffer(labelq);
17008 dumpRule(Archive *fout, RuleInfo *rinfo)
17010 DumpOptions *dopt = fout->dopt;
17011 TableInfo *tbinfo = rinfo->ruletable;
17015 PQExpBuffer delcmd;
17016 PQExpBuffer labelq;
17020 /* Skip if not to be dumped */
17021 if (!rinfo->dobj.dump || dopt->dataOnly)
17025 * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
17026 * we do not want to dump it as a separate object.
17028 if (!rinfo->separate)
17032 * If it's an ON SELECT rule, we want to print it as a view definition,
17033 * instead of a rule.
17035 is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
17038 * Make sure we are in proper schema.
17040 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
17042 query = createPQExpBuffer();
17043 cmd = createPQExpBuffer();
17044 delcmd = createPQExpBuffer();
17045 labelq = createPQExpBuffer();
17049 PQExpBuffer result;
17052 * We need OR REPLACE here because we'll be replacing a dummy view.
17053 * Otherwise this should look largely like the regular view dump code.
17055 appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
17056 fmtId(tbinfo->dobj.name));
17057 if (nonemptyReloptions(tbinfo->reloptions))
17059 appendPQExpBufferStr(cmd, " WITH (");
17060 appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
17061 appendPQExpBufferChar(cmd, ')');
17063 result = createViewAsClause(fout, tbinfo);
17064 appendPQExpBuffer(cmd, " AS\n%s", result->data);
17065 destroyPQExpBuffer(result);
17066 if (tbinfo->checkoption != NULL)
17067 appendPQExpBuffer(cmd, "\n WITH %s CHECK OPTION",
17068 tbinfo->checkoption);
17069 appendPQExpBufferStr(cmd, ";\n");
17073 /* In the rule case, just print pg_get_ruledef's result verbatim */
17074 appendPQExpBuffer(query,
17075 "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
17076 rinfo->dobj.catId.oid);
17078 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17080 if (PQntuples(res) != 1)
17082 write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
17083 rinfo->dobj.name, tbinfo->dobj.name);
17087 printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
17093 * Add the command to alter the rules replication firing semantics if it
17094 * differs from the default.
17096 if (rinfo->ev_enabled != 'O')
17098 appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtId(tbinfo->dobj.name));
17099 switch (rinfo->ev_enabled)
17102 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
17103 fmtId(rinfo->dobj.name));
17106 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
17107 fmtId(rinfo->dobj.name));
17110 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
17111 fmtId(rinfo->dobj.name));
17117 * DROP must be fully qualified in case same name appears in pg_catalog
17122 * We can't DROP a view's ON SELECT rule. Instead, use CREATE OR
17123 * REPLACE VIEW to replace the rule with something with minimal
17126 PQExpBuffer result;
17128 appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s.",
17129 fmtId(tbinfo->dobj.namespace->dobj.name));
17130 appendPQExpBuffer(delcmd, "%s",
17131 fmtId(tbinfo->dobj.name));
17132 result = createDummyViewAsClause(fout, tbinfo);
17133 appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
17134 destroyPQExpBuffer(result);
17138 appendPQExpBuffer(delcmd, "DROP RULE %s ",
17139 fmtId(rinfo->dobj.name));
17140 appendPQExpBuffer(delcmd, "ON %s.",
17141 fmtId(tbinfo->dobj.namespace->dobj.name));
17142 appendPQExpBuffer(delcmd, "%s;\n",
17143 fmtId(tbinfo->dobj.name));
17146 appendPQExpBuffer(labelq, "RULE %s",
17147 fmtId(rinfo->dobj.name));
17148 appendPQExpBuffer(labelq, " ON %s",
17149 fmtId(tbinfo->dobj.name));
17151 tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
17153 if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17154 ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
17156 tbinfo->dobj.namespace->dobj.name,
17158 tbinfo->rolname, false,
17159 "RULE", SECTION_POST_DATA,
17160 cmd->data, delcmd->data, NULL,
17164 /* Dump rule comments */
17165 if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17166 dumpComment(fout, labelq->data,
17167 tbinfo->dobj.namespace->dobj.name,
17169 rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
17172 destroyPQExpBuffer(query);
17173 destroyPQExpBuffer(cmd);
17174 destroyPQExpBuffer(delcmd);
17175 destroyPQExpBuffer(labelq);
17179 * getExtensionMembership --- obtain extension membership data
17181 * We need to identify objects that are extension members as soon as they're
17182 * loaded, so that we can correctly determine whether they need to be dumped.
17183 * Generally speaking, extension member objects will get marked as *not* to
17184 * be dumped, as they will be recreated by the single CREATE EXTENSION
17185 * command. However, in binary upgrade mode we still need to dump the members
17189 getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
17200 ExtensionMemberId *extmembers;
17201 ExtensionInfo *ext;
17203 /* Nothing to do if no extensions */
17204 if (numExtensions == 0)
17207 /* Make sure we are in proper schema */
17208 selectSourceSchema(fout, "pg_catalog");
17210 query = createPQExpBuffer();
17212 /* refclassid constraint is redundant but may speed the search */
17213 appendPQExpBufferStr(query, "SELECT "
17214 "classid, objid, refobjid "
17216 "WHERE refclassid = 'pg_extension'::regclass "
17217 "AND deptype = 'e' "
17220 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17222 ntups = PQntuples(res);
17224 i_classid = PQfnumber(res, "classid");
17225 i_objid = PQfnumber(res, "objid");
17226 i_refobjid = PQfnumber(res, "refobjid");
17228 extmembers = (ExtensionMemberId *) pg_malloc(ntups * sizeof(ExtensionMemberId));
17232 * Accumulate data into extmembers[].
17234 * Since we ordered the SELECT by referenced ID, we can expect that
17235 * multiple entries for the same extension will appear together; this
17236 * saves on searches.
17240 for (i = 0; i < ntups; i++)
17245 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17246 objId.oid = atooid(PQgetvalue(res, i, i_objid));
17247 extId = atooid(PQgetvalue(res, i, i_refobjid));
17250 ext->dobj.catId.oid != extId)
17251 ext = findExtensionByOid(extId);
17255 /* shouldn't happen */
17256 fprintf(stderr, "could not find referenced extension %u\n", extId);
17260 extmembers[nextmembers].catId = objId;
17261 extmembers[nextmembers].ext = ext;
17267 /* Remember the data for use later */
17268 setExtensionMembership(extmembers, nextmembers);
17270 destroyPQExpBuffer(query);
17274 * processExtensionTables --- deal with extension configuration tables
17276 * There are two parts to this process:
17278 * 1. Identify and create dump records for extension configuration tables.
17280 * Extensions can mark tables as "configuration", which means that the user
17281 * is able and expected to modify those tables after the extension has been
17282 * loaded. For these tables, we dump out only the data- the structure is
17283 * expected to be handled at CREATE EXTENSION time, including any indexes or
17284 * foreign keys, which brings us to-
17286 * 2. Record FK dependencies between configuration tables.
17288 * Due to the FKs being created at CREATE EXTENSION time and therefore before
17289 * the data is loaded, we have to work out what the best order for reloading
17290 * the data is, to avoid FK violations when the tables are restored. This is
17291 * not perfect- we can't handle circular dependencies and if any exist they
17292 * will cause an invalid dump to be produced (though at least all of the data
17293 * is included for a user to manually restore). This is currently documented
17294 * but perhaps we can provide a better solution in the future.
17297 processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
17300 DumpOptions *dopt = fout->dopt;
17308 /* Nothing to do if no extensions */
17309 if (numExtensions == 0)
17313 * Identify extension configuration tables and create TableDataInfo
17314 * objects for them, ensuring their data will be dumped even though the
17315 * tables themselves won't be.
17317 * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
17318 * user data in a configuration table is treated like schema data. This
17319 * seems appropriate since system data in a config table would get
17320 * reloaded by CREATE EXTENSION.
17322 for (i = 0; i < numExtensions; i++)
17324 ExtensionInfo *curext = &(extinfo[i]);
17325 char *extconfig = curext->extconfig;
17326 char *extcondition = curext->extcondition;
17327 char **extconfigarray = NULL;
17328 char **extconditionarray = NULL;
17330 int nconditionitems;
17332 if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
17333 parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
17334 nconfigitems == nconditionitems)
17338 for (j = 0; j < nconfigitems; j++)
17340 TableInfo *configtbl;
17341 Oid configtbloid = atooid(extconfigarray[j]);
17343 curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
17345 configtbl = findTableByOid(configtbloid);
17346 if (configtbl == NULL)
17350 * Tables of not-to-be-dumped extensions shouldn't be dumped
17351 * unless the table or its schema is explicitly included
17353 if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
17355 /* check table explicitly requested */
17356 if (table_include_oids.head != NULL &&
17357 simple_oid_list_member(&table_include_oids,
17361 /* check table's schema explicitly requested */
17362 if (configtbl->dobj.namespace->dobj.dump &
17363 DUMP_COMPONENT_DATA)
17367 /* check table excluded by an exclusion switch */
17368 if (table_exclude_oids.head != NULL &&
17369 simple_oid_list_member(&table_exclude_oids,
17373 /* check schema excluded by an exclusion switch */
17374 if (simple_oid_list_member(&schema_exclude_oids,
17375 configtbl->dobj.namespace->dobj.catId.oid))
17381 * Note: config tables are dumped without OIDs regardless
17382 * of the --oids setting. This is because row filtering
17383 * conditions aren't compatible with dumping OIDs.
17385 makeTableDataInfo(dopt, configtbl, false);
17386 if (configtbl->dataObj != NULL)
17388 if (strlen(extconditionarray[j]) > 0)
17389 configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
17394 if (extconfigarray)
17395 free(extconfigarray);
17396 if (extconditionarray)
17397 free(extconditionarray);
17401 * Now that all the TableInfoData objects have been created for all the
17402 * extensions, check their FK dependencies and register them to try and
17403 * dump the data out in an order that they can be restored in.
17405 * Note that this is not a problem for user tables as their FKs are
17406 * recreated after the data has been loaded.
17409 /* Make sure we are in proper schema */
17410 selectSourceSchema(fout, "pg_catalog");
17412 query = createPQExpBuffer();
17414 printfPQExpBuffer(query,
17415 "SELECT conrelid, confrelid "
17416 "FROM pg_constraint "
17417 "JOIN pg_depend ON (objid = confrelid) "
17418 "WHERE contype = 'f' "
17419 "AND refclassid = 'pg_extension'::regclass "
17420 "AND classid = 'pg_class'::regclass;");
17422 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17423 ntups = PQntuples(res);
17425 i_conrelid = PQfnumber(res, "conrelid");
17426 i_confrelid = PQfnumber(res, "confrelid");
17428 /* Now get the dependencies and register them */
17429 for (i = 0; i < ntups; i++)
17433 TableInfo *reftable,
17436 conrelid = atooid(PQgetvalue(res, i, i_conrelid));
17437 confrelid = atooid(PQgetvalue(res, i, i_confrelid));
17438 contable = findTableByOid(conrelid);
17439 reftable = findTableByOid(confrelid);
17441 if (reftable == NULL ||
17442 reftable->dataObj == NULL ||
17443 contable == NULL ||
17444 contable->dataObj == NULL)
17448 * Make referencing TABLE_DATA object depend on the referenced table's
17449 * TABLE_DATA object.
17451 addObjectDependency(&contable->dataObj->dobj,
17452 reftable->dataObj->dobj.dumpId);
17455 destroyPQExpBuffer(query);
17459 * getDependencies --- obtain available dependency data
17462 getDependencies(Archive *fout)
17473 DumpableObject *dobj,
17477 write_msg(NULL, "reading dependency data\n");
17479 /* Make sure we are in proper schema */
17480 selectSourceSchema(fout, "pg_catalog");
17482 query = createPQExpBuffer();
17485 * PIN dependencies aren't interesting, and EXTENSION dependencies were
17486 * already processed by getExtensionMembership.
17488 appendPQExpBufferStr(query, "SELECT "
17489 "classid, objid, refclassid, refobjid, deptype "
17491 "WHERE deptype != 'p' AND deptype != 'e' "
17494 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17496 ntups = PQntuples(res);
17498 i_classid = PQfnumber(res, "classid");
17499 i_objid = PQfnumber(res, "objid");
17500 i_refclassid = PQfnumber(res, "refclassid");
17501 i_refobjid = PQfnumber(res, "refobjid");
17502 i_deptype = PQfnumber(res, "deptype");
17505 * Since we ordered the SELECT by referencing ID, we can expect that
17506 * multiple entries for the same object will appear together; this saves
17511 for (i = 0; i < ntups; i++)
17514 CatalogId refobjId;
17517 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17518 objId.oid = atooid(PQgetvalue(res, i, i_objid));
17519 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
17520 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
17521 deptype = *(PQgetvalue(res, i, i_deptype));
17523 if (dobj == NULL ||
17524 dobj->catId.tableoid != objId.tableoid ||
17525 dobj->catId.oid != objId.oid)
17526 dobj = findObjectByCatalogId(objId);
17529 * Failure to find objects mentioned in pg_depend is not unexpected,
17530 * since for example we don't collect info about TOAST tables.
17535 fprintf(stderr, "no referencing object %u %u\n",
17536 objId.tableoid, objId.oid);
17541 refdobj = findObjectByCatalogId(refobjId);
17543 if (refdobj == NULL)
17546 fprintf(stderr, "no referenced object %u %u\n",
17547 refobjId.tableoid, refobjId.oid);
17553 * Ordinarily, table rowtypes have implicit dependencies on their
17554 * tables. However, for a composite type the implicit dependency goes
17555 * the other way in pg_depend; which is the right thing for DROP but
17556 * it doesn't produce the dependency ordering we need. So in that one
17557 * case, we reverse the direction of the dependency.
17559 if (deptype == 'i' &&
17560 dobj->objType == DO_TABLE &&
17561 refdobj->objType == DO_TYPE)
17562 addObjectDependency(refdobj, dobj->dumpId);
17565 addObjectDependency(dobj, refdobj->dumpId);
17570 destroyPQExpBuffer(query);
17575 * createBoundaryObjects - create dummy DumpableObjects to represent
17576 * dump section boundaries.
17578 static DumpableObject *
17579 createBoundaryObjects(void)
17581 DumpableObject *dobjs;
17583 dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
17585 dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
17586 dobjs[0].catId = nilCatalogId;
17587 AssignDumpId(dobjs + 0);
17588 dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
17590 dobjs[1].objType = DO_POST_DATA_BOUNDARY;
17591 dobjs[1].catId = nilCatalogId;
17592 AssignDumpId(dobjs + 1);
17593 dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
17599 * addBoundaryDependencies - add dependencies as needed to enforce the dump
17600 * section boundaries.
17603 addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
17604 DumpableObject *boundaryObjs)
17606 DumpableObject *preDataBound = boundaryObjs + 0;
17607 DumpableObject *postDataBound = boundaryObjs + 1;
17610 for (i = 0; i < numObjs; i++)
17612 DumpableObject *dobj = dobjs[i];
17615 * The classification of object types here must match the SECTION_xxx
17616 * values assigned during subsequent ArchiveEntry calls!
17618 switch (dobj->objType)
17623 case DO_SHELL_TYPE:
17627 case DO_ACCESS_METHOD:
17631 case DO_CONVERSION:
17636 case DO_DUMMY_TYPE:
17639 case DO_TSTEMPLATE:
17642 case DO_FOREIGN_SERVER:
17645 /* Pre-data objects: must come before the pre-data boundary */
17646 addObjectDependency(preDataBound, dobj->dumpId);
17648 case DO_TABLE_DATA:
17649 case DO_SEQUENCE_SET:
17651 /* Data objects: must come between the boundaries */
17652 addObjectDependency(dobj, preDataBound->dumpId);
17653 addObjectDependency(postDataBound, dobj->dumpId);
17657 case DO_REFRESH_MATVIEW:
17659 case DO_EVENT_TRIGGER:
17660 case DO_DEFAULT_ACL:
17662 case DO_PUBLICATION:
17663 case DO_PUBLICATION_REL:
17664 case DO_SUBSCRIPTION:
17665 /* Post-data objects: must come after the post-data boundary */
17666 addObjectDependency(dobj, postDataBound->dumpId);
17669 /* Rules are post-data, but only if dumped separately */
17670 if (((RuleInfo *) dobj)->separate)
17671 addObjectDependency(dobj, postDataBound->dumpId);
17673 case DO_CONSTRAINT:
17674 case DO_FK_CONSTRAINT:
17675 /* Constraints are post-data, but only if dumped separately */
17676 if (((ConstraintInfo *) dobj)->separate)
17677 addObjectDependency(dobj, postDataBound->dumpId);
17679 case DO_PRE_DATA_BOUNDARY:
17680 /* nothing to do */
17682 case DO_POST_DATA_BOUNDARY:
17683 /* must come after the pre-data boundary */
17684 addObjectDependency(dobj, preDataBound->dumpId);
17692 * BuildArchiveDependencies - create dependency data for archive TOC entries
17694 * The raw dependency data obtained by getDependencies() is not terribly
17695 * useful in an archive dump, because in many cases there are dependency
17696 * chains linking through objects that don't appear explicitly in the dump.
17697 * For example, a view will depend on its _RETURN rule while the _RETURN rule
17698 * will depend on other objects --- but the rule will not appear as a separate
17699 * object in the dump. We need to adjust the view's dependencies to include
17700 * whatever the rule depends on that is included in the dump.
17702 * Just to make things more complicated, there are also "special" dependencies
17703 * such as the dependency of a TABLE DATA item on its TABLE, which we must
17704 * not rearrange because pg_restore knows that TABLE DATA only depends on
17705 * its table. In these cases we must leave the dependencies strictly as-is
17706 * even if they refer to not-to-be-dumped objects.
17708 * To handle this, the convention is that "special" dependencies are created
17709 * during ArchiveEntry calls, and an archive TOC item that has any such
17710 * entries will not be touched here. Otherwise, we recursively search the
17711 * DumpableObject data structures to build the correct dependencies for each
17712 * archive TOC item.
17715 BuildArchiveDependencies(Archive *fout)
17717 ArchiveHandle *AH = (ArchiveHandle *) fout;
17720 /* Scan all TOC entries in the archive */
17721 for (te = AH->toc->next; te != AH->toc; te = te->next)
17723 DumpableObject *dobj;
17724 DumpId *dependencies;
17728 /* No need to process entries that will not be dumped */
17731 /* Ignore entries that already have "special" dependencies */
17734 /* Otherwise, look up the item's original DumpableObject, if any */
17735 dobj = findObjectByDumpId(te->dumpId);
17738 /* No work if it has no dependencies */
17739 if (dobj->nDeps <= 0)
17741 /* Set up work array */
17743 dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
17745 /* Recursively find all dumpable dependencies */
17746 findDumpableDependencies(AH, dobj,
17747 &dependencies, &nDeps, &allocDeps);
17748 /* And save 'em ... */
17751 dependencies = (DumpId *) pg_realloc(dependencies,
17752 nDeps * sizeof(DumpId));
17753 te->dependencies = dependencies;
17757 free(dependencies);
17761 /* Recursive search subroutine for BuildArchiveDependencies */
17763 findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
17764 DumpId **dependencies, int *nDeps, int *allocDeps)
17769 * Ignore section boundary objects: if we search through them, we'll
17770 * report lots of bogus dependencies.
17772 if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
17773 dobj->objType == DO_POST_DATA_BOUNDARY)
17776 for (i = 0; i < dobj->nDeps; i++)
17778 DumpId depid = dobj->dependencies[i];
17780 if (TocIDRequired(AH, depid) != 0)
17782 /* Object will be dumped, so just reference it as a dependency */
17783 if (*nDeps >= *allocDeps)
17786 *dependencies = (DumpId *) pg_realloc(*dependencies,
17787 *allocDeps * sizeof(DumpId));
17789 (*dependencies)[*nDeps] = depid;
17795 * Object will not be dumped, so recursively consider its deps. We
17796 * rely on the assumption that sortDumpableObjects already broke
17797 * any dependency loops, else we might recurse infinitely.
17799 DumpableObject *otherdobj = findObjectByDumpId(depid);
17802 findDumpableDependencies(AH, otherdobj,
17803 dependencies, nDeps, allocDeps);
17810 * selectSourceSchema - make the specified schema the active search path
17811 * in the source database.
17813 * NB: pg_catalog is explicitly searched after the specified schema;
17814 * so user names are only qualified if they are cross-schema references,
17815 * and system names are only qualified if they conflict with a user name
17816 * in the current schema.
17818 * Whenever the selected schema is not pg_catalog, be careful to qualify
17819 * references to system catalogs and types in our emitted commands!
17821 * This function is called only from selectSourceSchemaOnAH and
17822 * selectSourceSchema.
17825 selectSourceSchema(Archive *fout, const char *schemaName)
17829 /* This is checked by the callers already */
17830 Assert(schemaName != NULL && *schemaName != '\0');
17832 query = createPQExpBuffer();
17833 appendPQExpBuffer(query, "SET search_path = %s",
17834 fmtId(schemaName));
17835 if (strcmp(schemaName, "pg_catalog") != 0)
17836 appendPQExpBufferStr(query, ", pg_catalog");
17838 ExecuteSqlStatement(fout, query->data);
17840 destroyPQExpBuffer(query);
17844 * getFormattedTypeName - retrieve a nicely-formatted type name for the
17847 * NB: the result may depend on the currently-selected search_path; this is
17848 * why we don't try to cache the names.
17851 getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
17859 if ((opts & zeroAsOpaque) != 0)
17860 return pg_strdup(g_opaque_type);
17861 else if ((opts & zeroAsAny) != 0)
17862 return pg_strdup("'any'");
17863 else if ((opts & zeroAsStar) != 0)
17864 return pg_strdup("*");
17865 else if ((opts & zeroAsNone) != 0)
17866 return pg_strdup("NONE");
17869 query = createPQExpBuffer();
17870 appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
17873 res = ExecuteSqlQueryForSingleRow(fout, query->data);
17875 /* result of format_type is already quoted */
17876 result = pg_strdup(PQgetvalue(res, 0, 0));
17879 destroyPQExpBuffer(query);
17885 * Return a column list clause for the given relation.
17887 * Special case: if there are no undropped columns in the relation, return
17888 * "", not an invalid "()" column list.
17890 static const char *
17891 fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
17893 int numatts = ti->numatts;
17894 char **attnames = ti->attnames;
17895 bool *attisdropped = ti->attisdropped;
17899 appendPQExpBufferChar(buffer, '(');
17901 for (i = 0; i < numatts; i++)
17903 if (attisdropped[i])
17906 appendPQExpBufferStr(buffer, ", ");
17907 appendPQExpBufferStr(buffer, fmtId(attnames[i]));
17912 return ""; /* no undropped columns */
17914 appendPQExpBufferChar(buffer, ')');
17915 return buffer->data;
17919 * Check if a reloptions array is nonempty.
17922 nonemptyReloptions(const char *reloptions)
17924 /* Don't want to print it if it's just "{}" */
17925 return (reloptions != NULL && strlen(reloptions) > 2);
17929 * Format a reloptions array and append it to the given buffer.
17931 * "prefix" is prepended to the option names; typically it's "" or "toast.".
17934 appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
17935 const char *prefix, Archive *fout)
17939 res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
17940 fout->std_strings);
17942 write_msg(NULL, "WARNING: could not parse reloptions array\n");