PostgreSQL Source Code  git master
pg_dump.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * pg_dump.c
4  * pg_dump is a utility for dumping out a postgres database
5  * into a script file.
6  *
7  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  * pg_dump will read the system catalogs in a database and dump out a
11  * script that reproduces the schema in terms of SQL that is understood
12  * by PostgreSQL
13  *
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,
23  * but it can happen.
24  *
25  * http://archives.postgresql.org/pgsql-bugs/2010-02/msg00187.php
26  *
27  * IDENTIFICATION
28  * src/bin/pg_dump/pg_dump.c
29  *
30  *-------------------------------------------------------------------------
31  */
32 #include "postgres_fe.h"
33 
34 #include <unistd.h>
35 #include <ctype.h>
36 #include <limits.h>
37 #ifdef HAVE_TERMIOS_H
38 #include <termios.h>
39 #endif
40 
41 #include "access/attnum.h"
42 #include "access/sysattr.h"
43 #include "access/transam.h"
44 #include "catalog/pg_aggregate_d.h"
45 #include "catalog/pg_am_d.h"
46 #include "catalog/pg_attribute_d.h"
47 #include "catalog/pg_authid_d.h"
48 #include "catalog/pg_cast_d.h"
49 #include "catalog/pg_class_d.h"
50 #include "catalog/pg_default_acl_d.h"
51 #include "catalog/pg_largeobject_d.h"
52 #include "catalog/pg_largeobject_metadata_d.h"
53 #include "catalog/pg_proc_d.h"
55 #include "catalog/pg_trigger_d.h"
56 #include "catalog/pg_type_d.h"
57 #include "common/connect.h"
58 #include "common/relpath.h"
59 #include "compress_io.h"
60 #include "dumputils.h"
61 #include "fe_utils/option_utils.h"
62 #include "fe_utils/string_utils.h"
63 #include "filter.h"
64 #include "getopt_long.h"
65 #include "libpq/libpq-fs.h"
66 #include "parallel.h"
67 #include "pg_backup_db.h"
68 #include "pg_backup_utils.h"
69 #include "pg_dump.h"
70 #include "storage/block.h"
71 
72 typedef struct
73 {
74  Oid roleoid; /* role's OID */
75  const char *rolename; /* role's name */
76 } RoleNameItem;
77 
78 typedef struct
79 {
80  const char *descr; /* comment for an object */
81  Oid classoid; /* object class (catalog OID) */
82  Oid objoid; /* object OID */
83  int objsubid; /* subobject (table column #) */
84 } CommentItem;
85 
86 typedef struct
87 {
88  const char *provider; /* label provider of this security label */
89  const char *label; /* security label for an object */
90  Oid classoid; /* object class (catalog OID) */
91  Oid objoid; /* object OID */
92  int objsubid; /* subobject (table column #) */
93 } SecLabelItem;
94 
95 typedef enum OidOptions
96 {
101 
102 /* global decls */
103 static bool dosync = true; /* Issue fsync() to make dump durable on disk. */
104 
105 static Oid g_last_builtin_oid; /* value of the last builtin oid */
106 
107 /* The specified names/patterns should to match at least one entity */
108 static int strict_names = 0;
109 
111 
112 /*
113  * Object inclusion/exclusion lists
114  *
115  * The string lists record the patterns given by command-line switches,
116  * which we then convert to lists of OIDs of matching objects.
117  */
119 static SimpleOidList schema_include_oids = {NULL, NULL};
121 static SimpleOidList schema_exclude_oids = {NULL, NULL};
122 
125 static SimpleOidList table_include_oids = {NULL, NULL};
128 static SimpleOidList table_exclude_oids = {NULL, NULL};
131 static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
132 
135 
137 static SimpleOidList extension_include_oids = {NULL, NULL};
138 
140 static SimpleOidList extension_exclude_oids = {NULL, NULL};
141 
142 static const CatalogId nilCatalogId = {0, 0};
143 
144 /* override for standard extra_float_digits setting */
145 static bool have_extra_float_digits = false;
147 
148 /* sorted table of role names */
149 static RoleNameItem *rolenames = NULL;
150 static int nrolenames = 0;
151 
152 /* sorted table of comments */
153 static CommentItem *comments = NULL;
154 static int ncomments = 0;
155 
156 /* sorted table of security labels */
157 static SecLabelItem *seclabels = NULL;
158 static int nseclabels = 0;
159 
160 /*
161  * The default number of rows per INSERT when
162  * --inserts is specified without --rows-per-insert
163  */
164 #define DUMP_DEFAULT_ROWS_PER_INSERT 1
165 
166 /*
167  * Maximum number of large objects to group into a single ArchiveEntry.
168  * At some point we might want to make this user-controllable, but for now
169  * a hard-wired setting will suffice.
170  */
171 #define MAX_BLOBS_PER_ARCHIVE_ENTRY 1000
172 
173 /*
174  * Macro for producing quoted, schema-qualified name of a dumpable object.
175  */
176 #define fmtQualifiedDumpable(obj) \
177  fmtQualifiedId((obj)->dobj.namespace->dobj.name, \
178  (obj)->dobj.name)
179 
180 static void help(const char *progname);
181 static void setup_connection(Archive *AH,
182  const char *dumpencoding, const char *dumpsnapshot,
183  char *use_role);
185 static void expand_schema_name_patterns(Archive *fout,
186  SimpleStringList *patterns,
187  SimpleOidList *oids,
188  bool strict_names);
189 static void expand_extension_name_patterns(Archive *fout,
190  SimpleStringList *patterns,
191  SimpleOidList *oids,
192  bool strict_names);
194  SimpleStringList *patterns,
195  SimpleOidList *oids);
196 static void expand_table_name_patterns(Archive *fout,
197  SimpleStringList *patterns,
198  SimpleOidList *oids,
199  bool strict_names,
200  bool with_child_tables);
201 static void prohibit_crossdb_refs(PGconn *conn, const char *dbname,
202  const char *pattern);
203 
204 static NamespaceInfo *findNamespace(Oid nsoid);
205 static void dumpTableData(Archive *fout, const TableDataInfo *tdinfo);
206 static void refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo);
207 static const char *getRoleName(const char *roleoid_str);
208 static void collectRoleNames(Archive *fout);
209 static void getAdditionalACLs(Archive *fout);
210 static void dumpCommentExtended(Archive *fout, const char *type,
211  const char *name, const char *namespace,
212  const char *owner, CatalogId catalogId,
213  int subid, DumpId dumpId,
214  const char *initdb_comment);
215 static inline void dumpComment(Archive *fout, const char *type,
216  const char *name, const char *namespace,
217  const char *owner, CatalogId catalogId,
218  int subid, DumpId dumpId);
219 static int findComments(Oid classoid, Oid objoid, CommentItem **items);
220 static void collectComments(Archive *fout);
221 static void dumpSecLabel(Archive *fout, const char *type, const char *name,
222  const char *namespace, const char *owner,
223  CatalogId catalogId, int subid, DumpId dumpId);
224 static int findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items);
225 static void collectSecLabels(Archive *fout);
226 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
227 static void dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo);
228 static void dumpExtension(Archive *fout, const ExtensionInfo *extinfo);
229 static void dumpType(Archive *fout, const TypeInfo *tyinfo);
230 static void dumpBaseType(Archive *fout, const TypeInfo *tyinfo);
231 static void dumpEnumType(Archive *fout, const TypeInfo *tyinfo);
232 static void dumpRangeType(Archive *fout, const TypeInfo *tyinfo);
233 static void dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo);
234 static void dumpDomain(Archive *fout, const TypeInfo *tyinfo);
235 static void dumpCompositeType(Archive *fout, const TypeInfo *tyinfo);
236 static void dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
237  PGresult *res);
238 static void dumpShellType(Archive *fout, const ShellTypeInfo *stinfo);
239 static void dumpProcLang(Archive *fout, const ProcLangInfo *plang);
240 static void dumpFunc(Archive *fout, const FuncInfo *finfo);
241 static void dumpCast(Archive *fout, const CastInfo *cast);
242 static void dumpTransform(Archive *fout, const TransformInfo *transform);
243 static void dumpOpr(Archive *fout, const OprInfo *oprinfo);
244 static void dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo);
245 static void dumpOpclass(Archive *fout, const OpclassInfo *opcinfo);
246 static void dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo);
247 static void dumpCollation(Archive *fout, const CollInfo *collinfo);
248 static void dumpConversion(Archive *fout, const ConvInfo *convinfo);
249 static void dumpRule(Archive *fout, const RuleInfo *rinfo);
250 static void dumpAgg(Archive *fout, const AggInfo *agginfo);
251 static void dumpTrigger(Archive *fout, const TriggerInfo *tginfo);
252 static void dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo);
253 static void dumpTable(Archive *fout, const TableInfo *tbinfo);
254 static void dumpTableSchema(Archive *fout, const TableInfo *tbinfo);
255 static void dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo);
256 static void dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo);
257 static void dumpSequence(Archive *fout, const TableInfo *tbinfo);
258 static void dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo);
259 static void dumpIndex(Archive *fout, const IndxInfo *indxinfo);
260 static void dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo);
261 static void dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo);
262 static void dumpConstraint(Archive *fout, const ConstraintInfo *coninfo);
263 static void dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo);
264 static void dumpTSParser(Archive *fout, const TSParserInfo *prsinfo);
265 static void dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo);
266 static void dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo);
267 static void dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo);
268 static void dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo);
269 static void dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo);
270 static void dumpUserMappings(Archive *fout,
271  const char *servername, const char *namespace,
272  const char *owner, CatalogId catalogId, DumpId dumpId);
273 static void dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo);
274 
275 static DumpId dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
276  const char *type, const char *name, const char *subname,
277  const char *nspname, const char *tag, const char *owner,
278  const DumpableAcl *dacl);
279 
280 static void getDependencies(Archive *fout);
281 static void BuildArchiveDependencies(Archive *fout);
282 static void findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
283  DumpId **dependencies, int *nDeps, int *allocDeps);
284 
286 static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
287  DumpableObject *boundaryObjs);
288 
289 static void addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx);
290 static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
291 static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind);
292 static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo);
293 static void buildMatViewRefreshDependencies(Archive *fout);
294 static void getTableDataFKConstraints(void);
295 static char *format_function_arguments(const FuncInfo *finfo, const char *funcargs,
296  bool is_agg);
297 static char *format_function_signature(Archive *fout,
298  const FuncInfo *finfo, bool honor_quotes);
299 static char *convertRegProcReference(const char *proc);
300 static char *getFormattedOperatorName(const char *oproid);
301 static char *convertTSFunction(Archive *fout, Oid funcOid);
302 static const char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
303 static void getLOs(Archive *fout);
304 static void dumpLO(Archive *fout, const LoInfo *loinfo);
305 static int dumpLOs(Archive *fout, const void *arg);
306 static void dumpPolicy(Archive *fout, const PolicyInfo *polinfo);
307 static void dumpPublication(Archive *fout, const PublicationInfo *pubinfo);
308 static void dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo);
309 static void dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo);
310 static void dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo);
311 static void dumpDatabase(Archive *fout);
312 static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
313  const char *dbname, Oid dboid);
314 static void dumpEncoding(Archive *AH);
315 static void dumpStdStrings(Archive *AH);
316 static void dumpSearchPath(Archive *AH);
318  PQExpBuffer upgrade_buffer,
319  Oid pg_type_oid,
320  bool force_array_type,
321  bool include_multirange_type);
323  PQExpBuffer upgrade_buffer,
324  const TableInfo *tbinfo);
325 static void binary_upgrade_set_pg_class_oids(Archive *fout,
326  PQExpBuffer upgrade_buffer,
327  Oid pg_class_oid, bool is_index);
328 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
329  const DumpableObject *dobj,
330  const char *objtype,
331  const char *objname,
332  const char *objnamespace);
333 static const char *getAttrName(int attrnum, const TableInfo *tblInfo);
334 static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
335 static bool nonemptyReloptions(const char *reloptions);
336 static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
337  const char *prefix, Archive *fout);
338 static char *get_synchronized_snapshot(Archive *fout);
339 static void setupDumpWorker(Archive *AH);
340 static TableInfo *getRootTableInfo(const TableInfo *tbinfo);
341 static bool forcePartitionRootLoad(const TableInfo *tbinfo);
342 static void read_dump_filters(const char *filename, DumpOptions *dopt);
343 
344 
345 int
346 main(int argc, char **argv)
347 {
348  int c;
349  const char *filename = NULL;
350  const char *format = "p";
351  TableInfo *tblinfo;
352  int numTables;
353  DumpableObject **dobjs;
354  int numObjs;
355  DumpableObject *boundaryObjs;
356  int i;
357  int optindex;
358  RestoreOptions *ropt;
359  Archive *fout; /* the script file */
360  bool g_verbose = false;
361  const char *dumpencoding = NULL;
362  const char *dumpsnapshot = NULL;
363  char *use_role = NULL;
364  int numWorkers = 1;
365  int plainText = 0;
366  ArchiveFormat archiveFormat = archUnknown;
367  ArchiveMode archiveMode;
368  pg_compress_specification compression_spec = {0};
369  char *compression_detail = NULL;
370  char *compression_algorithm_str = "none";
371  char *error_detail = NULL;
372  bool user_compression_defined = false;
374 
375  static DumpOptions dopt;
376 
377  static struct option long_options[] = {
378  {"data-only", no_argument, NULL, 'a'},
379  {"blobs", no_argument, NULL, 'b'},
380  {"large-objects", no_argument, NULL, 'b'},
381  {"no-blobs", no_argument, NULL, 'B'},
382  {"no-large-objects", no_argument, NULL, 'B'},
383  {"clean", no_argument, NULL, 'c'},
384  {"create", no_argument, NULL, 'C'},
385  {"dbname", required_argument, NULL, 'd'},
386  {"extension", required_argument, NULL, 'e'},
387  {"file", required_argument, NULL, 'f'},
388  {"format", required_argument, NULL, 'F'},
389  {"host", required_argument, NULL, 'h'},
390  {"jobs", 1, NULL, 'j'},
391  {"no-reconnect", no_argument, NULL, 'R'},
392  {"no-owner", no_argument, NULL, 'O'},
393  {"port", required_argument, NULL, 'p'},
394  {"schema", required_argument, NULL, 'n'},
395  {"exclude-schema", required_argument, NULL, 'N'},
396  {"schema-only", no_argument, NULL, 's'},
397  {"superuser", required_argument, NULL, 'S'},
398  {"table", required_argument, NULL, 't'},
399  {"exclude-table", required_argument, NULL, 'T'},
400  {"no-password", no_argument, NULL, 'w'},
401  {"password", no_argument, NULL, 'W'},
402  {"username", required_argument, NULL, 'U'},
403  {"verbose", no_argument, NULL, 'v'},
404  {"no-privileges", no_argument, NULL, 'x'},
405  {"no-acl", no_argument, NULL, 'x'},
406  {"compress", required_argument, NULL, 'Z'},
407  {"encoding", required_argument, NULL, 'E'},
408  {"help", no_argument, NULL, '?'},
409  {"version", no_argument, NULL, 'V'},
410 
411  /*
412  * the following options don't have an equivalent short option letter
413  */
414  {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
415  {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
416  {"column-inserts", no_argument, &dopt.column_inserts, 1},
417  {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
418  {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
419  {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
420  {"exclude-table-data", required_argument, NULL, 4},
421  {"extra-float-digits", required_argument, NULL, 8},
422  {"if-exists", no_argument, &dopt.if_exists, 1},
423  {"inserts", no_argument, NULL, 9},
424  {"lock-wait-timeout", required_argument, NULL, 2},
425  {"no-table-access-method", no_argument, &dopt.outputNoTableAm, 1},
426  {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
427  {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
428  {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
429  {"role", required_argument, NULL, 3},
430  {"section", required_argument, NULL, 5},
431  {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
432  {"snapshot", required_argument, NULL, 6},
433  {"strict-names", no_argument, &strict_names, 1},
434  {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
435  {"no-comments", no_argument, &dopt.no_comments, 1},
436  {"no-publications", no_argument, &dopt.no_publications, 1},
437  {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
438  {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
439  {"no-toast-compression", no_argument, &dopt.no_toast_compression, 1},
440  {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
441  {"no-sync", no_argument, NULL, 7},
442  {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
443  {"rows-per-insert", required_argument, NULL, 10},
444  {"include-foreign-data", required_argument, NULL, 11},
445  {"table-and-children", required_argument, NULL, 12},
446  {"exclude-table-and-children", required_argument, NULL, 13},
447  {"exclude-table-data-and-children", required_argument, NULL, 14},
448  {"sync-method", required_argument, NULL, 15},
449  {"filter", required_argument, NULL, 16},
450  {"exclude-extension", required_argument, NULL, 17},
451 
452  {NULL, 0, NULL, 0}
453  };
454 
455  pg_logging_init(argv[0]);
457  set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
458 
459  /*
460  * Initialize what we need for parallel execution, especially for thread
461  * support on Windows.
462  */
464 
465  progname = get_progname(argv[0]);
466 
467  if (argc > 1)
468  {
469  if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
470  {
471  help(progname);
472  exit_nicely(0);
473  }
474  if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
475  {
476  puts("pg_dump (PostgreSQL) " PG_VERSION);
477  exit_nicely(0);
478  }
479  }
480 
481  InitDumpOptions(&dopt);
482 
483  while ((c = getopt_long(argc, argv, "abBcCd:e:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxZ:",
484  long_options, &optindex)) != -1)
485  {
486  switch (c)
487  {
488  case 'a': /* Dump data only */
489  dopt.dataOnly = true;
490  break;
491 
492  case 'b': /* Dump LOs */
493  dopt.outputLOs = true;
494  break;
495 
496  case 'B': /* Don't dump LOs */
497  dopt.dontOutputLOs = true;
498  break;
499 
500  case 'c': /* clean (i.e., drop) schema prior to create */
501  dopt.outputClean = 1;
502  break;
503 
504  case 'C': /* Create DB */
505  dopt.outputCreateDB = 1;
506  break;
507 
508  case 'd': /* database name */
509  dopt.cparams.dbname = pg_strdup(optarg);
510  break;
511 
512  case 'e': /* include extension(s) */
514  dopt.include_everything = false;
515  break;
516 
517  case 'E': /* Dump encoding */
518  dumpencoding = pg_strdup(optarg);
519  break;
520 
521  case 'f':
523  break;
524 
525  case 'F':
527  break;
528 
529  case 'h': /* server host */
530  dopt.cparams.pghost = pg_strdup(optarg);
531  break;
532 
533  case 'j': /* number of dump jobs */
534  if (!option_parse_int(optarg, "-j/--jobs", 1,
535  PG_MAX_JOBS,
536  &numWorkers))
537  exit_nicely(1);
538  break;
539 
540  case 'n': /* include schema(s) */
542  dopt.include_everything = false;
543  break;
544 
545  case 'N': /* exclude schema(s) */
547  break;
548 
549  case 'O': /* Don't reconnect to match owner */
550  dopt.outputNoOwner = 1;
551  break;
552 
553  case 'p': /* server port */
554  dopt.cparams.pgport = pg_strdup(optarg);
555  break;
556 
557  case 'R':
558  /* no-op, still accepted for backwards compatibility */
559  break;
560 
561  case 's': /* dump schema only */
562  dopt.schemaOnly = true;
563  break;
564 
565  case 'S': /* Username for superuser in plain text output */
567  break;
568 
569  case 't': /* include table(s) */
571  dopt.include_everything = false;
572  break;
573 
574  case 'T': /* exclude table(s) */
576  break;
577 
578  case 'U':
580  break;
581 
582  case 'v': /* verbose */
583  g_verbose = true;
585  break;
586 
587  case 'w':
589  break;
590 
591  case 'W':
593  break;
594 
595  case 'x': /* skip ACL dump */
596  dopt.aclsSkip = true;
597  break;
598 
599  case 'Z': /* Compression */
600  parse_compress_options(optarg, &compression_algorithm_str,
601  &compression_detail);
602  user_compression_defined = true;
603  break;
604 
605  case 0:
606  /* This covers the long options. */
607  break;
608 
609  case 2: /* lock-wait-timeout */
611  break;
612 
613  case 3: /* SET ROLE */
614  use_role = pg_strdup(optarg);
615  break;
616 
617  case 4: /* exclude table(s) data */
619  break;
620 
621  case 5: /* section */
623  break;
624 
625  case 6: /* snapshot */
626  dumpsnapshot = pg_strdup(optarg);
627  break;
628 
629  case 7: /* no-sync */
630  dosync = false;
631  break;
632 
633  case 8:
635  if (!option_parse_int(optarg, "--extra-float-digits", -15, 3,
637  exit_nicely(1);
638  break;
639 
640  case 9: /* inserts */
641 
642  /*
643  * dump_inserts also stores --rows-per-insert, careful not to
644  * overwrite that.
645  */
646  if (dopt.dump_inserts == 0)
648  break;
649 
650  case 10: /* rows per insert */
651  if (!option_parse_int(optarg, "--rows-per-insert", 1, INT_MAX,
652  &dopt.dump_inserts))
653  exit_nicely(1);
654  break;
655 
656  case 11: /* include foreign data */
658  optarg);
659  break;
660 
661  case 12: /* include table(s) and their children */
663  optarg);
664  dopt.include_everything = false;
665  break;
666 
667  case 13: /* exclude table(s) and their children */
669  optarg);
670  break;
671 
672  case 14: /* exclude data of table(s) and children */
674  optarg);
675  break;
676 
677  case 15:
679  exit_nicely(1);
680  break;
681 
682  case 16: /* read object filters from file */
683  read_dump_filters(optarg, &dopt);
684  break;
685 
686  case 17: /* exclude extension(s) */
688  optarg);
689  break;
690 
691  default:
692  /* getopt_long already emitted a complaint */
693  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
694  exit_nicely(1);
695  }
696  }
697 
698  /*
699  * Non-option argument specifies database name as long as it wasn't
700  * already specified with -d / --dbname
701  */
702  if (optind < argc && dopt.cparams.dbname == NULL)
703  dopt.cparams.dbname = argv[optind++];
704 
705  /* Complain if any arguments remain */
706  if (optind < argc)
707  {
708  pg_log_error("too many command-line arguments (first is \"%s\")",
709  argv[optind]);
710  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
711  exit_nicely(1);
712  }
713 
714  /* --column-inserts implies --inserts */
715  if (dopt.column_inserts && dopt.dump_inserts == 0)
717 
718  /*
719  * Binary upgrade mode implies dumping sequence data even in schema-only
720  * mode. This is not exposed as a separate option, but kept separate
721  * internally for clarity.
722  */
723  if (dopt.binary_upgrade)
724  dopt.sequence_data = 1;
725 
726  if (dopt.dataOnly && dopt.schemaOnly)
727  pg_fatal("options -s/--schema-only and -a/--data-only cannot be used together");
728 
730  pg_fatal("options -s/--schema-only and --include-foreign-data cannot be used together");
731 
732  if (numWorkers > 1 && foreign_servers_include_patterns.head != NULL)
733  pg_fatal("option --include-foreign-data is not supported with parallel backup");
734 
735  if (dopt.dataOnly && dopt.outputClean)
736  pg_fatal("options -c/--clean and -a/--data-only cannot be used together");
737 
738  if (dopt.if_exists && !dopt.outputClean)
739  pg_fatal("option --if-exists requires option -c/--clean");
740 
741  /*
742  * --inserts are already implied above if --column-inserts or
743  * --rows-per-insert were specified.
744  */
745  if (dopt.do_nothing && dopt.dump_inserts == 0)
746  pg_fatal("option --on-conflict-do-nothing requires option --inserts, --rows-per-insert, or --column-inserts");
747 
748  /* Identify archive format to emit */
749  archiveFormat = parseArchiveFormat(format, &archiveMode);
750 
751  /* archiveFormat specific setup */
752  if (archiveFormat == archNull)
753  plainText = 1;
754 
755  /*
756  * Custom and directory formats are compressed by default with gzip when
757  * available, not the others. If gzip is not available, no compression is
758  * done by default.
759  */
760  if ((archiveFormat == archCustom || archiveFormat == archDirectory) &&
761  !user_compression_defined)
762  {
763 #ifdef HAVE_LIBZ
764  compression_algorithm_str = "gzip";
765 #else
766  compression_algorithm_str = "none";
767 #endif
768  }
769 
770  /*
771  * Compression options
772  */
773  if (!parse_compress_algorithm(compression_algorithm_str,
775  pg_fatal("unrecognized compression algorithm: \"%s\"",
776  compression_algorithm_str);
777 
779  &compression_spec);
780  error_detail = validate_compress_specification(&compression_spec);
781  if (error_detail != NULL)
782  pg_fatal("invalid compression specification: %s",
783  error_detail);
784 
785  error_detail = supports_compression(compression_spec);
786  if (error_detail != NULL)
787  pg_fatal("%s", error_detail);
788 
789  /*
790  * Disable support for zstd workers for now - these are based on
791  * threading, and it's unclear how it interacts with parallel dumps on
792  * platforms where that relies on threads too (e.g. Windows).
793  */
794  if (compression_spec.options & PG_COMPRESSION_OPTION_WORKERS)
795  pg_log_warning("compression option \"%s\" is not currently supported by pg_dump",
796  "workers");
797 
798  /*
799  * If emitting an archive format, we always want to emit a DATABASE item,
800  * in case --create is specified at pg_restore time.
801  */
802  if (!plainText)
803  dopt.outputCreateDB = 1;
804 
805  /* Parallel backup only in the directory archive format so far */
806  if (archiveFormat != archDirectory && numWorkers > 1)
807  pg_fatal("parallel backup only supported by the directory format");
808 
809  /* Open the output file */
810  fout = CreateArchive(filename, archiveFormat, compression_spec,
811  dosync, archiveMode, setupDumpWorker, sync_method);
812 
813  /* Make dump options accessible right away */
814  SetArchiveOptions(fout, &dopt, NULL);
815 
816  /* Register the cleanup hook */
817  on_exit_close_archive(fout);
818 
819  /* Let the archiver know how noisy to be */
820  fout->verbose = g_verbose;
821 
822 
823  /*
824  * We allow the server to be back to 9.2, and up to any minor release of
825  * our own major version. (See also version check in pg_dumpall.c.)
826  */
827  fout->minRemoteVersion = 90200;
828  fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
829 
830  fout->numWorkers = numWorkers;
831 
832  /*
833  * Open the database using the Archiver, so it knows about it. Errors mean
834  * death.
835  */
836  ConnectDatabase(fout, &dopt.cparams, false);
837  setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
838 
839  /*
840  * On hot standbys, never try to dump unlogged table data, since it will
841  * just throw an error.
842  */
843  if (fout->isStandby)
844  dopt.no_unlogged_table_data = true;
845 
846  /*
847  * Find the last built-in OID, if needed (prior to 8.1)
848  *
849  * With 8.1 and above, we can just use FirstNormalObjectId - 1.
850  */
852 
853  pg_log_info("last built-in OID is %u", g_last_builtin_oid);
854 
855  /* Expand schema selection patterns into OID lists */
856  if (schema_include_patterns.head != NULL)
857  {
860  strict_names);
861  if (schema_include_oids.head == NULL)
862  pg_fatal("no matching schemas were found");
863  }
866  false);
867  /* non-matching exclusion patterns aren't an error */
868 
869  /* Expand table selection patterns into OID lists */
872  strict_names, false);
875  strict_names, true);
876  if ((table_include_patterns.head != NULL ||
878  table_include_oids.head == NULL)
879  pg_fatal("no matching tables were found");
880 
883  false, false);
886  false, true);
887 
890  false, false);
893  false, true);
894 
897 
898  /* non-matching exclusion patterns aren't an error */
899 
900  /* Expand extension selection patterns into OID lists */
901  if (extension_include_patterns.head != NULL)
902  {
905  strict_names);
906  if (extension_include_oids.head == NULL)
907  pg_fatal("no matching extensions were found");
908  }
911  false);
912  /* non-matching exclusion patterns aren't an error */
913 
914  /*
915  * Dumping LOs is the default for dumps where an inclusion switch is not
916  * used (an "include everything" dump). -B can be used to exclude LOs
917  * from those dumps. -b can be used to include LOs even when an inclusion
918  * switch is used.
919  *
920  * -s means "schema only" and LOs are data, not schema, so we never
921  * include LOs when -s is used.
922  */
923  if (dopt.include_everything && !dopt.schemaOnly && !dopt.dontOutputLOs)
924  dopt.outputLOs = true;
925 
926  /*
927  * Collect role names so we can map object owner OIDs to names.
928  */
929  collectRoleNames(fout);
930 
931  /*
932  * Now scan the database and create DumpableObject structs for all the
933  * objects we intend to dump.
934  */
935  tblinfo = getSchemaData(fout, &numTables);
936 
937  if (!dopt.schemaOnly)
938  {
939  getTableData(&dopt, tblinfo, numTables, 0);
941  if (dopt.dataOnly)
943  }
944 
945  if (dopt.schemaOnly && dopt.sequence_data)
946  getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
947 
948  /*
949  * In binary-upgrade mode, we do not have to worry about the actual LO
950  * data or the associated metadata that resides in the pg_largeobject and
951  * pg_largeobject_metadata tables, respectively.
952  *
953  * However, we do need to collect LO information as there may be comments
954  * or other information on LOs that we do need to dump out.
955  */
956  if (dopt.outputLOs || dopt.binary_upgrade)
957  getLOs(fout);
958 
959  /*
960  * Collect dependency data to assist in ordering the objects.
961  */
962  getDependencies(fout);
963 
964  /*
965  * Collect ACLs, comments, and security labels, if wanted.
966  */
967  if (!dopt.aclsSkip)
968  getAdditionalACLs(fout);
969  if (!dopt.no_comments)
970  collectComments(fout);
971  if (!dopt.no_security_labels)
972  collectSecLabels(fout);
973 
974  /* Lastly, create dummy objects to represent the section boundaries */
975  boundaryObjs = createBoundaryObjects();
976 
977  /* Get pointers to all the known DumpableObjects */
978  getDumpableObjects(&dobjs, &numObjs);
979 
980  /*
981  * Add dummy dependencies to enforce the dump section ordering.
982  */
983  addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
984 
985  /*
986  * Sort the objects into a safe dump order (no forward references).
987  *
988  * We rely on dependency information to help us determine a safe order, so
989  * the initial sort is mostly for cosmetic purposes: we sort by name to
990  * ensure that logically identical schemas will dump identically.
991  */
992  sortDumpableObjectsByTypeName(dobjs, numObjs);
993 
994  sortDumpableObjects(dobjs, numObjs,
995  boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
996 
997  /*
998  * Create archive TOC entries for all the objects to be dumped, in a safe
999  * order.
1000  */
1001 
1002  /*
1003  * First the special entries for ENCODING, STDSTRINGS, and SEARCHPATH.
1004  */
1005  dumpEncoding(fout);
1006  dumpStdStrings(fout);
1007  dumpSearchPath(fout);
1008 
1009  /* The database items are always next, unless we don't want them at all */
1010  if (dopt.outputCreateDB)
1011  dumpDatabase(fout);
1012 
1013  /* Now the rearrangeable objects. */
1014  for (i = 0; i < numObjs; i++)
1015  dumpDumpableObject(fout, dobjs[i]);
1016 
1017  /*
1018  * Set up options info to ensure we dump what we want.
1019  */
1020  ropt = NewRestoreOptions();
1021  ropt->filename = filename;
1022 
1023  /* if you change this list, see dumpOptionsFromRestoreOptions */
1024  ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
1025  ropt->cparams.pgport = dopt.cparams.pgport ? pg_strdup(dopt.cparams.pgport) : NULL;
1026  ropt->cparams.pghost = dopt.cparams.pghost ? pg_strdup(dopt.cparams.pghost) : NULL;
1027  ropt->cparams.username = dopt.cparams.username ? pg_strdup(dopt.cparams.username) : NULL;
1029  ropt->dropSchema = dopt.outputClean;
1030  ropt->dataOnly = dopt.dataOnly;
1031  ropt->schemaOnly = dopt.schemaOnly;
1032  ropt->if_exists = dopt.if_exists;
1033  ropt->column_inserts = dopt.column_inserts;
1034  ropt->dumpSections = dopt.dumpSections;
1035  ropt->aclsSkip = dopt.aclsSkip;
1036  ropt->superuser = dopt.outputSuperuser;
1037  ropt->createDB = dopt.outputCreateDB;
1038  ropt->noOwner = dopt.outputNoOwner;
1039  ropt->noTableAm = dopt.outputNoTableAm;
1040  ropt->noTablespace = dopt.outputNoTablespaces;
1041  ropt->disable_triggers = dopt.disable_triggers;
1042  ropt->use_setsessauth = dopt.use_setsessauth;
1044  ropt->dump_inserts = dopt.dump_inserts;
1045  ropt->no_comments = dopt.no_comments;
1046  ropt->no_publications = dopt.no_publications;
1048  ropt->no_subscriptions = dopt.no_subscriptions;
1049  ropt->lockWaitTimeout = dopt.lockWaitTimeout;
1052  ropt->sequence_data = dopt.sequence_data;
1053  ropt->binary_upgrade = dopt.binary_upgrade;
1054 
1055  ropt->compression_spec = compression_spec;
1056 
1057  ropt->suppressDumpWarnings = true; /* We've already shown them */
1058 
1059  SetArchiveOptions(fout, &dopt, ropt);
1060 
1061  /* Mark which entries should be output */
1063 
1064  /*
1065  * The archive's TOC entries are now marked as to which ones will actually
1066  * be output, so we can set up their dependency lists properly. This isn't
1067  * necessary for plain-text output, though.
1068  */
1069  if (!plainText)
1071 
1072  /*
1073  * And finally we can do the actual output.
1074  *
1075  * Note: for non-plain-text output formats, the output file is written
1076  * inside CloseArchive(). This is, um, bizarre; but not worth changing
1077  * right now.
1078  */
1079  if (plainText)
1080  RestoreArchive(fout);
1081 
1082  CloseArchive(fout);
1083 
1084  exit_nicely(0);
1085 }
1086 
1087 
1088 static void
1089 help(const char *progname)
1090 {
1091  printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
1092  printf(_("Usage:\n"));
1093  printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
1094 
1095  printf(_("\nGeneral options:\n"));
1096  printf(_(" -f, --file=FILENAME output file or directory name\n"));
1097  printf(_(" -F, --format=c|d|t|p output file format (custom, directory, tar,\n"
1098  " plain text (default))\n"));
1099  printf(_(" -j, --jobs=NUM use this many parallel jobs to dump\n"));
1100  printf(_(" -v, --verbose verbose mode\n"));
1101  printf(_(" -V, --version output version information, then exit\n"));
1102  printf(_(" -Z, --compress=METHOD[:DETAIL]\n"
1103  " compress as specified\n"));
1104  printf(_(" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
1105  printf(_(" --no-sync do not wait for changes to be written safely to disk\n"));
1106  printf(_(" --sync-method=METHOD set method for syncing files to disk\n"));
1107  printf(_(" -?, --help show this help, then exit\n"));
1108 
1109  printf(_("\nOptions controlling the output content:\n"));
1110  printf(_(" -a, --data-only dump only the data, not the schema\n"));
1111  printf(_(" -b, --large-objects include large objects in dump\n"));
1112  printf(_(" --blobs (same as --large-objects, deprecated)\n"));
1113  printf(_(" -B, --no-large-objects exclude large objects in dump\n"));
1114  printf(_(" --no-blobs (same as --no-large-objects, deprecated)\n"));
1115  printf(_(" -c, --clean clean (drop) database objects before recreating\n"));
1116  printf(_(" -C, --create include commands to create database in dump\n"));
1117  printf(_(" -e, --extension=PATTERN dump the specified extension(s) only\n"));
1118  printf(_(" -E, --encoding=ENCODING dump the data in encoding ENCODING\n"));
1119  printf(_(" -n, --schema=PATTERN dump the specified schema(s) only\n"));
1120  printf(_(" -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n"));
1121  printf(_(" -O, --no-owner skip restoration of object ownership in\n"
1122  " plain-text format\n"));
1123  printf(_(" -s, --schema-only dump only the schema, no data\n"));
1124  printf(_(" -S, --superuser=NAME superuser user name to use in plain-text format\n"));
1125  printf(_(" -t, --table=PATTERN dump only the specified table(s)\n"));
1126  printf(_(" -T, --exclude-table=PATTERN do NOT dump the specified table(s)\n"));
1127  printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
1128  printf(_(" --binary-upgrade for use by upgrade utilities only\n"));
1129  printf(_(" --column-inserts dump data as INSERT commands with column names\n"));
1130  printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n"));
1131  printf(_(" --disable-triggers disable triggers during data-only restore\n"));
1132  printf(_(" --enable-row-security enable row security (dump only content user has\n"
1133  " access to)\n"));
1134  printf(_(" --exclude-extension=PATTERN do NOT dump the specified extension(s)\n"));
1135  printf(_(" --exclude-table-and-children=PATTERN\n"
1136  " do NOT dump the specified table(s), including\n"
1137  " child and partition tables\n"));
1138  printf(_(" --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n"));
1139  printf(_(" --exclude-table-data-and-children=PATTERN\n"
1140  " do NOT dump data for the specified table(s),\n"
1141  " including child and partition tables\n"));
1142  printf(_(" --extra-float-digits=NUM override default setting for extra_float_digits\n"));
1143  printf(_(" --filter=FILENAME include or exclude objects and data from dump\n"
1144  " based on expressions in FILENAME\n"));
1145  printf(_(" --if-exists use IF EXISTS when dropping objects\n"));
1146  printf(_(" --include-foreign-data=PATTERN\n"
1147  " include data of foreign tables on foreign\n"
1148  " servers matching PATTERN\n"));
1149  printf(_(" --inserts dump data as INSERT commands, rather than COPY\n"));
1150  printf(_(" --load-via-partition-root load partitions via the root table\n"));
1151  printf(_(" --no-comments do not dump comments\n"));
1152  printf(_(" --no-publications do not dump publications\n"));
1153  printf(_(" --no-security-labels do not dump security label assignments\n"));
1154  printf(_(" --no-subscriptions do not dump subscriptions\n"));
1155  printf(_(" --no-table-access-method do not dump table access methods\n"));
1156  printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
1157  printf(_(" --no-toast-compression do not dump TOAST compression methods\n"));
1158  printf(_(" --no-unlogged-table-data do not dump unlogged table data\n"));
1159  printf(_(" --on-conflict-do-nothing add ON CONFLICT DO NOTHING to INSERT commands\n"));
1160  printf(_(" --quote-all-identifiers quote all identifiers, even if not key words\n"));
1161  printf(_(" --rows-per-insert=NROWS number of rows per INSERT; implies --inserts\n"));
1162  printf(_(" --section=SECTION dump named section (pre-data, data, or post-data)\n"));
1163  printf(_(" --serializable-deferrable wait until the dump can run without anomalies\n"));
1164  printf(_(" --snapshot=SNAPSHOT use given snapshot for the dump\n"));
1165  printf(_(" --strict-names require table and/or schema include patterns to\n"
1166  " match at least one entity each\n"));
1167  printf(_(" --table-and-children=PATTERN dump only the specified table(s), including\n"
1168  " child and partition tables\n"));
1169  printf(_(" --use-set-session-authorization\n"
1170  " use SET SESSION AUTHORIZATION commands instead of\n"
1171  " ALTER OWNER commands to set ownership\n"));
1172 
1173  printf(_("\nConnection options:\n"));
1174  printf(_(" -d, --dbname=DBNAME database to dump\n"));
1175  printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
1176  printf(_(" -p, --port=PORT database server port number\n"));
1177  printf(_(" -U, --username=NAME connect as specified database user\n"));
1178  printf(_(" -w, --no-password never prompt for password\n"));
1179  printf(_(" -W, --password force password prompt (should happen automatically)\n"));
1180  printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
1181 
1182  printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
1183  "variable value is used.\n\n"));
1184  printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
1185  printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
1186 }
1187 
1188 static void
1189 setup_connection(Archive *AH, const char *dumpencoding,
1190  const char *dumpsnapshot, char *use_role)
1191 {
1192  DumpOptions *dopt = AH->dopt;
1193  PGconn *conn = GetConnection(AH);
1194  const char *std_strings;
1195 
1197 
1198  /*
1199  * Set the client encoding if requested.
1200  */
1201  if (dumpencoding)
1202  {
1203  if (PQsetClientEncoding(conn, dumpencoding) < 0)
1204  pg_fatal("invalid client encoding \"%s\" specified",
1205  dumpencoding);
1206  }
1207 
1208  /*
1209  * Get the active encoding and the standard_conforming_strings setting, so
1210  * we know how to escape strings.
1211  */
1213 
1214  std_strings = PQparameterStatus(conn, "standard_conforming_strings");
1215  AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
1216 
1217  /*
1218  * Set the role if requested. In a parallel dump worker, we'll be passed
1219  * use_role == NULL, but AH->use_role is already set (if user specified it
1220  * originally) and we should use that.
1221  */
1222  if (!use_role && AH->use_role)
1223  use_role = AH->use_role;
1224 
1225  /* Set the role if requested */
1226  if (use_role)
1227  {
1228  PQExpBuffer query = createPQExpBuffer();
1229 
1230  appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
1231  ExecuteSqlStatement(AH, query->data);
1232  destroyPQExpBuffer(query);
1233 
1234  /* save it for possible later use by parallel workers */
1235  if (!AH->use_role)
1236  AH->use_role = pg_strdup(use_role);
1237  }
1238 
1239  /* Set the datestyle to ISO to ensure the dump's portability */
1240  ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
1241 
1242  /* Likewise, avoid using sql_standard intervalstyle */
1243  ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
1244 
1245  /*
1246  * Use an explicitly specified extra_float_digits if it has been provided.
1247  * Otherwise, set extra_float_digits so that we can dump float data
1248  * exactly (given correctly implemented float I/O code, anyway).
1249  */
1251  {
1253 
1254  appendPQExpBuffer(q, "SET extra_float_digits TO %d",
1256  ExecuteSqlStatement(AH, q->data);
1257  destroyPQExpBuffer(q);
1258  }
1259  else
1260  ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
1261 
1262  /*
1263  * Disable synchronized scanning, to prevent unpredictable changes in row
1264  * ordering across a dump and reload.
1265  */
1266  ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
1267 
1268  /*
1269  * Disable timeouts if supported.
1270  */
1271  ExecuteSqlStatement(AH, "SET statement_timeout = 0");
1272  if (AH->remoteVersion >= 90300)
1273  ExecuteSqlStatement(AH, "SET lock_timeout = 0");
1274  if (AH->remoteVersion >= 90600)
1275  ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
1276  if (AH->remoteVersion >= 170000)
1277  ExecuteSqlStatement(AH, "SET transaction_timeout = 0");
1278 
1279  /*
1280  * Quote all identifiers, if requested.
1281  */
1283  ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1284 
1285  /*
1286  * Adjust row-security mode, if supported.
1287  */
1288  if (AH->remoteVersion >= 90500)
1289  {
1290  if (dopt->enable_row_security)
1291  ExecuteSqlStatement(AH, "SET row_security = on");
1292  else
1293  ExecuteSqlStatement(AH, "SET row_security = off");
1294  }
1295 
1296  /*
1297  * Initialize prepared-query state to "nothing prepared". We do this here
1298  * so that a parallel dump worker will have its own state.
1299  */
1300  AH->is_prepared = (bool *) pg_malloc0(NUM_PREP_QUERIES * sizeof(bool));
1301 
1302  /*
1303  * Start transaction-snapshot mode transaction to dump consistent data.
1304  */
1305  ExecuteSqlStatement(AH, "BEGIN");
1306 
1307  /*
1308  * To support the combination of serializable_deferrable with the jobs
1309  * option we use REPEATABLE READ for the worker connections that are
1310  * passed a snapshot. As long as the snapshot is acquired in a
1311  * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
1312  * REPEATABLE READ transaction provides the appropriate integrity
1313  * guarantees. This is a kluge, but safe for back-patching.
1314  */
1315  if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
1317  "SET TRANSACTION ISOLATION LEVEL "
1318  "SERIALIZABLE, READ ONLY, DEFERRABLE");
1319  else
1321  "SET TRANSACTION ISOLATION LEVEL "
1322  "REPEATABLE READ, READ ONLY");
1323 
1324  /*
1325  * If user specified a snapshot to use, select that. In a parallel dump
1326  * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
1327  * is already set (if the server can handle it) and we should use that.
1328  */
1329  if (dumpsnapshot)
1330  AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
1331 
1332  if (AH->sync_snapshot_id)
1333  {
1334  PQExpBuffer query = createPQExpBuffer();
1335 
1336  appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT ");
1338  ExecuteSqlStatement(AH, query->data);
1339  destroyPQExpBuffer(query);
1340  }
1341  else if (AH->numWorkers > 1)
1342  {
1343  if (AH->isStandby && AH->remoteVersion < 100000)
1344  pg_fatal("parallel dumps from standby servers are not supported by this server version");
1346  }
1347 }
1348 
1349 /* Set up connection for a parallel worker process */
1350 static void
1352 {
1353  /*
1354  * We want to re-select all the same values the leader connection is
1355  * using. We'll have inherited directly-usable values in
1356  * AH->sync_snapshot_id and AH->use_role, but we need to translate the
1357  * inherited encoding value back to a string to pass to setup_connection.
1358  */
1359  setup_connection(AH,
1361  NULL,
1362  NULL);
1363 }
1364 
1365 static char *
1367 {
1368  char *query = "SELECT pg_catalog.pg_export_snapshot()";
1369  char *result;
1370  PGresult *res;
1371 
1372  res = ExecuteSqlQueryForSingleRow(fout, query);
1373  result = pg_strdup(PQgetvalue(res, 0, 0));
1374  PQclear(res);
1375 
1376  return result;
1377 }
1378 
1379 static ArchiveFormat
1381 {
1382  ArchiveFormat archiveFormat;
1383 
1384  *mode = archModeWrite;
1385 
1386  if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1387  {
1388  /* This is used by pg_dumpall, and is not documented */
1389  archiveFormat = archNull;
1390  *mode = archModeAppend;
1391  }
1392  else if (pg_strcasecmp(format, "c") == 0)
1393  archiveFormat = archCustom;
1394  else if (pg_strcasecmp(format, "custom") == 0)
1395  archiveFormat = archCustom;
1396  else if (pg_strcasecmp(format, "d") == 0)
1397  archiveFormat = archDirectory;
1398  else if (pg_strcasecmp(format, "directory") == 0)
1399  archiveFormat = archDirectory;
1400  else if (pg_strcasecmp(format, "p") == 0)
1401  archiveFormat = archNull;
1402  else if (pg_strcasecmp(format, "plain") == 0)
1403  archiveFormat = archNull;
1404  else if (pg_strcasecmp(format, "t") == 0)
1405  archiveFormat = archTar;
1406  else if (pg_strcasecmp(format, "tar") == 0)
1407  archiveFormat = archTar;
1408  else
1409  pg_fatal("invalid output format \"%s\" specified", format);
1410  return archiveFormat;
1411 }
1412 
1413 /*
1414  * Find the OIDs of all schemas matching the given list of patterns,
1415  * and append them to the given OID list.
1416  */
1417 static void
1419  SimpleStringList *patterns,
1420  SimpleOidList *oids,
1421  bool strict_names)
1422 {
1423  PQExpBuffer query;
1424  PGresult *res;
1425  SimpleStringListCell *cell;
1426  int i;
1427 
1428  if (patterns->head == NULL)
1429  return; /* nothing to do */
1430 
1431  query = createPQExpBuffer();
1432 
1433  /*
1434  * The loop below runs multiple SELECTs might sometimes result in
1435  * duplicate entries in the OID list, but we don't care.
1436  */
1437 
1438  for (cell = patterns->head; cell; cell = cell->next)
1439  {
1440  PQExpBufferData dbbuf;
1441  int dotcnt;
1442 
1443  appendPQExpBufferStr(query,
1444  "SELECT oid FROM pg_catalog.pg_namespace n\n");
1445  initPQExpBuffer(&dbbuf);
1446  processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1447  false, NULL, "n.nspname", NULL, NULL, &dbbuf,
1448  &dotcnt);
1449  if (dotcnt > 1)
1450  pg_fatal("improper qualified name (too many dotted names): %s",
1451  cell->val);
1452  else if (dotcnt == 1)
1453  prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
1454  termPQExpBuffer(&dbbuf);
1455 
1456  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1457  if (strict_names && PQntuples(res) == 0)
1458  pg_fatal("no matching schemas were found for pattern \"%s\"", cell->val);
1459 
1460  for (i = 0; i < PQntuples(res); i++)
1461  {
1463  }
1464 
1465  PQclear(res);
1466  resetPQExpBuffer(query);
1467  }
1468 
1469  destroyPQExpBuffer(query);
1470 }
1471 
1472 /*
1473  * Find the OIDs of all extensions matching the given list of patterns,
1474  * and append them to the given OID list.
1475  */
1476 static void
1478  SimpleStringList *patterns,
1479  SimpleOidList *oids,
1480  bool strict_names)
1481 {
1482  PQExpBuffer query;
1483  PGresult *res;
1484  SimpleStringListCell *cell;
1485  int i;
1486 
1487  if (patterns->head == NULL)
1488  return; /* nothing to do */
1489 
1490  query = createPQExpBuffer();
1491 
1492  /*
1493  * The loop below runs multiple SELECTs might sometimes result in
1494  * duplicate entries in the OID list, but we don't care.
1495  */
1496  for (cell = patterns->head; cell; cell = cell->next)
1497  {
1498  int dotcnt;
1499 
1500  appendPQExpBufferStr(query,
1501  "SELECT oid FROM pg_catalog.pg_extension e\n");
1502  processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1503  false, NULL, "e.extname", NULL, NULL, NULL,
1504  &dotcnt);
1505  if (dotcnt > 0)
1506  pg_fatal("improper qualified name (too many dotted names): %s",
1507  cell->val);
1508 
1509  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1510  if (strict_names && PQntuples(res) == 0)
1511  pg_fatal("no matching extensions were found for pattern \"%s\"", cell->val);
1512 
1513  for (i = 0; i < PQntuples(res); i++)
1514  {
1516  }
1517 
1518  PQclear(res);
1519  resetPQExpBuffer(query);
1520  }
1521 
1522  destroyPQExpBuffer(query);
1523 }
1524 
1525 /*
1526  * Find the OIDs of all foreign servers matching the given list of patterns,
1527  * and append them to the given OID list.
1528  */
1529 static void
1531  SimpleStringList *patterns,
1532  SimpleOidList *oids)
1533 {
1534  PQExpBuffer query;
1535  PGresult *res;
1536  SimpleStringListCell *cell;
1537  int i;
1538 
1539  if (patterns->head == NULL)
1540  return; /* nothing to do */
1541 
1542  query = createPQExpBuffer();
1543 
1544  /*
1545  * The loop below runs multiple SELECTs might sometimes result in
1546  * duplicate entries in the OID list, but we don't care.
1547  */
1548 
1549  for (cell = patterns->head; cell; cell = cell->next)
1550  {
1551  int dotcnt;
1552 
1553  appendPQExpBufferStr(query,
1554  "SELECT oid FROM pg_catalog.pg_foreign_server s\n");
1555  processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1556  false, NULL, "s.srvname", NULL, NULL, NULL,
1557  &dotcnt);
1558  if (dotcnt > 0)
1559  pg_fatal("improper qualified name (too many dotted names): %s",
1560  cell->val);
1561 
1562  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1563  if (PQntuples(res) == 0)
1564  pg_fatal("no matching foreign servers were found for pattern \"%s\"", cell->val);
1565 
1566  for (i = 0; i < PQntuples(res); i++)
1568 
1569  PQclear(res);
1570  resetPQExpBuffer(query);
1571  }
1572 
1573  destroyPQExpBuffer(query);
1574 }
1575 
1576 /*
1577  * Find the OIDs of all tables matching the given list of patterns,
1578  * and append them to the given OID list. See also expand_dbname_patterns()
1579  * in pg_dumpall.c
1580  */
1581 static void
1583  SimpleStringList *patterns, SimpleOidList *oids,
1584  bool strict_names, bool with_child_tables)
1585 {
1586  PQExpBuffer query;
1587  PGresult *res;
1588  SimpleStringListCell *cell;
1589  int i;
1590 
1591  if (patterns->head == NULL)
1592  return; /* nothing to do */
1593 
1594  query = createPQExpBuffer();
1595 
1596  /*
1597  * this might sometimes result in duplicate entries in the OID list, but
1598  * we don't care.
1599  */
1600 
1601  for (cell = patterns->head; cell; cell = cell->next)
1602  {
1603  PQExpBufferData dbbuf;
1604  int dotcnt;
1605 
1606  /*
1607  * Query must remain ABSOLUTELY devoid of unqualified names. This
1608  * would be unnecessary given a pg_table_is_visible() variant taking a
1609  * search_path argument.
1610  *
1611  * For with_child_tables, we start with the basic query's results and
1612  * recursively search the inheritance tree to add child tables.
1613  */
1614  if (with_child_tables)
1615  {
1616  appendPQExpBuffer(query, "WITH RECURSIVE partition_tree (relid) AS (\n");
1617  }
1618 
1619  appendPQExpBuffer(query,
1620  "SELECT c.oid"
1621  "\nFROM pg_catalog.pg_class c"
1622  "\n LEFT JOIN pg_catalog.pg_namespace n"
1623  "\n ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
1624  "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
1625  "\n (array['%c', '%c', '%c', '%c', '%c', '%c'])\n",
1626  RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1627  RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
1628  RELKIND_PARTITIONED_TABLE);
1629  initPQExpBuffer(&dbbuf);
1630  processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1631  false, "n.nspname", "c.relname", NULL,
1632  "pg_catalog.pg_table_is_visible(c.oid)", &dbbuf,
1633  &dotcnt);
1634  if (dotcnt > 2)
1635  pg_fatal("improper relation name (too many dotted names): %s",
1636  cell->val);
1637  else if (dotcnt == 2)
1638  prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
1639  termPQExpBuffer(&dbbuf);
1640 
1641  if (with_child_tables)
1642  {
1643  appendPQExpBuffer(query, "UNION"
1644  "\nSELECT i.inhrelid"
1645  "\nFROM partition_tree p"
1646  "\n JOIN pg_catalog.pg_inherits i"
1647  "\n ON p.relid OPERATOR(pg_catalog.=) i.inhparent"
1648  "\n)"
1649  "\nSELECT relid FROM partition_tree");
1650  }
1651 
1652  ExecuteSqlStatement(fout, "RESET search_path");
1653  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1656  if (strict_names && PQntuples(res) == 0)
1657  pg_fatal("no matching tables were found for pattern \"%s\"", cell->val);
1658 
1659  for (i = 0; i < PQntuples(res); i++)
1660  {
1662  }
1663 
1664  PQclear(res);
1665  resetPQExpBuffer(query);
1666  }
1667 
1668  destroyPQExpBuffer(query);
1669 }
1670 
1671 /*
1672  * Verifies that the connected database name matches the given database name,
1673  * and if not, dies with an error about the given pattern.
1674  *
1675  * The 'dbname' argument should be a literal name parsed from 'pattern'.
1676  */
1677 static void
1678 prohibit_crossdb_refs(PGconn *conn, const char *dbname, const char *pattern)
1679 {
1680  const char *db;
1681 
1682  db = PQdb(conn);
1683  if (db == NULL)
1684  pg_fatal("You are currently not connected to a database.");
1685 
1686  if (strcmp(db, dbname) != 0)
1687  pg_fatal("cross-database references are not implemented: %s",
1688  pattern);
1689 }
1690 
1691 /*
1692  * checkExtensionMembership
1693  * Determine whether object is an extension member, and if so,
1694  * record an appropriate dependency and set the object's dump flag.
1695  *
1696  * It's important to call this for each object that could be an extension
1697  * member. Generally, we integrate this with determining the object's
1698  * to-be-dumped-ness, since extension membership overrides other rules for that.
1699  *
1700  * Returns true if object is an extension member, else false.
1701  */
1702 static bool
1704 {
1705  ExtensionInfo *ext = findOwningExtension(dobj->catId);
1706 
1707  if (ext == NULL)
1708  return false;
1709 
1710  dobj->ext_member = true;
1711 
1712  /* Record dependency so that getDependencies needn't deal with that */
1713  addObjectDependency(dobj, ext->dobj.dumpId);
1714 
1715  /*
1716  * In 9.6 and above, mark the member object to have any non-initial ACLs
1717  * dumped. (Any initial ACLs will be removed later, using data from
1718  * pg_init_privs, so that we'll dump only the delta from the extension's
1719  * initial setup.)
1720  *
1721  * Prior to 9.6, we do not include any extension member components.
1722  *
1723  * In binary upgrades, we still dump all components of the members
1724  * individually, since the idea is to exactly reproduce the database
1725  * contents rather than replace the extension contents with something
1726  * different.
1727  *
1728  * Note: it might be interesting someday to implement storage and delta
1729  * dumping of extension members' RLS policies and/or security labels.
1730  * However there is a pitfall for RLS policies: trying to dump them
1731  * requires getting a lock on their tables, and the calling user might not
1732  * have privileges for that. We need no lock to examine a table's ACLs,
1733  * so the current feature doesn't have a problem of that sort.
1734  */
1735  if (fout->dopt->binary_upgrade)
1736  dobj->dump = ext->dobj.dump;
1737  else
1738  {
1739  if (fout->remoteVersion < 90600)
1740  dobj->dump = DUMP_COMPONENT_NONE;
1741  else
1742  dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL);
1743  }
1744 
1745  return true;
1746 }
1747 
1748 /*
1749  * selectDumpableNamespace: policy-setting subroutine
1750  * Mark a namespace as to be dumped or not
1751  */
1752 static void
1754 {
1755  /*
1756  * DUMP_COMPONENT_DEFINITION typically implies a CREATE SCHEMA statement
1757  * and (for --clean) a DROP SCHEMA statement. (In the absence of
1758  * DUMP_COMPONENT_DEFINITION, this value is irrelevant.)
1759  */
1760  nsinfo->create = true;
1761 
1762  /*
1763  * If specific tables are being dumped, do not dump any complete
1764  * namespaces. If specific namespaces are being dumped, dump just those
1765  * namespaces. Otherwise, dump all non-system namespaces.
1766  */
1767  if (table_include_oids.head != NULL)
1768  nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1769  else if (schema_include_oids.head != NULL)
1770  nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
1772  nsinfo->dobj.catId.oid) ?
1774  else if (fout->remoteVersion >= 90600 &&
1775  strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
1776  {
1777  /*
1778  * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
1779  * they are interesting (and not the original ACLs which were set at
1780  * initdb time, see pg_init_privs).
1781  */
1782  nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1783  }
1784  else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1785  strcmp(nsinfo->dobj.name, "information_schema") == 0)
1786  {
1787  /* Other system schemas don't get dumped */
1788  nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1789  }
1790  else if (strcmp(nsinfo->dobj.name, "public") == 0)
1791  {
1792  /*
1793  * The public schema is a strange beast that sits in a sort of
1794  * no-mans-land between being a system object and a user object.
1795  * CREATE SCHEMA would fail, so its DUMP_COMPONENT_DEFINITION is just
1796  * a comment and an indication of ownership. If the owner is the
1797  * default, omit that superfluous DUMP_COMPONENT_DEFINITION. Before
1798  * v15, the default owner was BOOTSTRAP_SUPERUSERID.
1799  */
1800  nsinfo->create = false;
1801  nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
1802  if (nsinfo->nspowner == ROLE_PG_DATABASE_OWNER)
1803  nsinfo->dobj.dump &= ~DUMP_COMPONENT_DEFINITION;
1805 
1806  /*
1807  * Also, make like it has a comment even if it doesn't; this is so
1808  * that we'll emit a command to drop the comment, if appropriate.
1809  * (Without this, we'd not call dumpCommentExtended for it.)
1810  */
1812  }
1813  else
1814  nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
1815 
1816  /*
1817  * In any case, a namespace can be excluded by an exclusion switch
1818  */
1819  if (nsinfo->dobj.dump_contains &&
1821  nsinfo->dobj.catId.oid))
1822  nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1823 
1824  /*
1825  * If the schema belongs to an extension, allow extension membership to
1826  * override the dump decision for the schema itself. However, this does
1827  * not change dump_contains, so this won't change what we do with objects
1828  * within the schema. (If they belong to the extension, they'll get
1829  * suppressed by it, otherwise not.)
1830  */
1831  (void) checkExtensionMembership(&nsinfo->dobj, fout);
1832 }
1833 
1834 /*
1835  * selectDumpableTable: policy-setting subroutine
1836  * Mark a table as to be dumped or not
1837  */
1838 static void
1840 {
1841  if (checkExtensionMembership(&tbinfo->dobj, fout))
1842  return; /* extension membership overrides all else */
1843 
1844  /*
1845  * If specific tables are being dumped, dump just those tables; else, dump
1846  * according to the parent namespace's dump flag.
1847  */
1848  if (table_include_oids.head != NULL)
1850  tbinfo->dobj.catId.oid) ?
1852  else
1853  tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
1854 
1855  /*
1856  * In any case, a table can be excluded by an exclusion switch
1857  */
1858  if (tbinfo->dobj.dump &&
1860  tbinfo->dobj.catId.oid))
1861  tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
1862 }
1863 
1864 /*
1865  * selectDumpableType: policy-setting subroutine
1866  * Mark a type as to be dumped or not
1867  *
1868  * If it's a table's rowtype or an autogenerated array type, we also apply a
1869  * special type code to facilitate sorting into the desired order. (We don't
1870  * want to consider those to be ordinary types because that would bring tables
1871  * up into the datatype part of the dump order.) We still set the object's
1872  * dump flag; that's not going to cause the dummy type to be dumped, but we
1873  * need it so that casts involving such types will be dumped correctly -- see
1874  * dumpCast. This means the flag should be set the same as for the underlying
1875  * object (the table or base type).
1876  */
1877 static void
1879 {
1880  /* skip complex types, except for standalone composite types */
1881  if (OidIsValid(tyinfo->typrelid) &&
1882  tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1883  {
1884  TableInfo *tytable = findTableByOid(tyinfo->typrelid);
1885 
1886  tyinfo->dobj.objType = DO_DUMMY_TYPE;
1887  if (tytable != NULL)
1888  tyinfo->dobj.dump = tytable->dobj.dump;
1889  else
1890  tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
1891  return;
1892  }
1893 
1894  /* skip auto-generated array and multirange types */
1895  if (tyinfo->isArray || tyinfo->isMultirange)
1896  {
1897  tyinfo->dobj.objType = DO_DUMMY_TYPE;
1898 
1899  /*
1900  * Fall through to set the dump flag; we assume that the subsequent
1901  * rules will do the same thing as they would for the array's base
1902  * type or multirange's range type. (We cannot reliably look up the
1903  * base type here, since getTypes may not have processed it yet.)
1904  */
1905  }
1906 
1907  if (checkExtensionMembership(&tyinfo->dobj, fout))
1908  return; /* extension membership overrides all else */
1909 
1910  /* Dump based on if the contents of the namespace are being dumped */
1911  tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
1912 }
1913 
1914 /*
1915  * selectDumpableDefaultACL: policy-setting subroutine
1916  * Mark a default ACL as to be dumped or not
1917  *
1918  * For per-schema default ACLs, dump if the schema is to be dumped.
1919  * Otherwise dump if we are dumping "everything". Note that dataOnly
1920  * and aclsSkip are checked separately.
1921  */
1922 static void
1924 {
1925  /* Default ACLs can't be extension members */
1926 
1927  if (dinfo->dobj.namespace)
1928  /* default ACLs are considered part of the namespace */
1929  dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
1930  else
1931  dinfo->dobj.dump = dopt->include_everything ?
1933 }
1934 
1935 /*
1936  * selectDumpableCast: policy-setting subroutine
1937  * Mark a cast as to be dumped or not
1938  *
1939  * Casts do not belong to any particular namespace (since they haven't got
1940  * names), nor do they have identifiable owners. To distinguish user-defined
1941  * casts from built-in ones, we must resort to checking whether the cast's
1942  * OID is in the range reserved for initdb.
1943  */
1944 static void
1946 {
1947  if (checkExtensionMembership(&cast->dobj, fout))
1948  return; /* extension membership overrides all else */
1949 
1950  /*
1951  * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
1952  * support ACLs currently.
1953  */
1954  if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1955  cast->dobj.dump = DUMP_COMPONENT_NONE;
1956  else
1957  cast->dobj.dump = fout->dopt->include_everything ?
1959 }
1960 
1961 /*
1962  * selectDumpableProcLang: policy-setting subroutine
1963  * Mark a procedural language as to be dumped or not
1964  *
1965  * Procedural languages do not belong to any particular namespace. To
1966  * identify built-in languages, we must resort to checking whether the
1967  * language's OID is in the range reserved for initdb.
1968  */
1969 static void
1971 {
1972  if (checkExtensionMembership(&plang->dobj, fout))
1973  return; /* extension membership overrides all else */
1974 
1975  /*
1976  * Only include procedural languages when we are dumping everything.
1977  *
1978  * For from-initdb procedural languages, only include ACLs, as we do for
1979  * the pg_catalog namespace. We need this because procedural languages do
1980  * not live in any namespace.
1981  */
1982  if (!fout->dopt->include_everything)
1983  plang->dobj.dump = DUMP_COMPONENT_NONE;
1984  else
1985  {
1986  if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1987  plang->dobj.dump = fout->remoteVersion < 90600 ?
1989  else
1990  plang->dobj.dump = DUMP_COMPONENT_ALL;
1991  }
1992 }
1993 
1994 /*
1995  * selectDumpableAccessMethod: policy-setting subroutine
1996  * Mark an access method as to be dumped or not
1997  *
1998  * Access methods do not belong to any particular namespace. To identify
1999  * built-in access methods, we must resort to checking whether the
2000  * method's OID is in the range reserved for initdb.
2001  */
2002 static void
2004 {
2005  if (checkExtensionMembership(&method->dobj, fout))
2006  return; /* extension membership overrides all else */
2007 
2008  /*
2009  * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
2010  * they do not support ACLs currently.
2011  */
2012  if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
2013  method->dobj.dump = DUMP_COMPONENT_NONE;
2014  else
2015  method->dobj.dump = fout->dopt->include_everything ?
2017 }
2018 
2019 /*
2020  * selectDumpableExtension: policy-setting subroutine
2021  * Mark an extension as to be dumped or not
2022  *
2023  * Built-in extensions should be skipped except for checking ACLs, since we
2024  * assume those will already be installed in the target database. We identify
2025  * such extensions by their having OIDs in the range reserved for initdb.
2026  * We dump all user-added extensions by default. No extensions are dumped
2027  * if include_everything is false (i.e., a --schema or --table switch was
2028  * given), except if --extension specifies a list of extensions to dump.
2029  */
2030 static void
2032 {
2033  /*
2034  * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
2035  * change permissions on their member objects, if they wish to, and have
2036  * those changes preserved.
2037  */
2038  if (extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
2039  extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
2040  else
2041  {
2042  /* check if there is a list of extensions to dump */
2043  if (extension_include_oids.head != NULL)
2044  extinfo->dobj.dump = extinfo->dobj.dump_contains =
2046  extinfo->dobj.catId.oid) ?
2048  else
2049  extinfo->dobj.dump = extinfo->dobj.dump_contains =
2050  dopt->include_everything ?
2052 
2053  /* check that the extension is not explicitly excluded */
2054  if (extinfo->dobj.dump &&
2056  extinfo->dobj.catId.oid))
2057  extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_NONE;
2058  }
2059 }
2060 
2061 /*
2062  * selectDumpablePublicationObject: policy-setting subroutine
2063  * Mark a publication object as to be dumped or not
2064  *
2065  * A publication can have schemas and tables which have schemas, but those are
2066  * ignored in decision making, because publications are only dumped when we are
2067  * dumping everything.
2068  */
2069 static void
2071 {
2072  if (checkExtensionMembership(dobj, fout))
2073  return; /* extension membership overrides all else */
2074 
2075  dobj->dump = fout->dopt->include_everything ?
2077 }
2078 
2079 /*
2080  * selectDumpableStatisticsObject: policy-setting subroutine
2081  * Mark an extended statistics object as to be dumped or not
2082  *
2083  * We dump an extended statistics object if the schema it's in and the table
2084  * it's for are being dumped. (This'll need more thought if statistics
2085  * objects ever support cross-table stats.)
2086  */
2087 static void
2089 {
2090  if (checkExtensionMembership(&sobj->dobj, fout))
2091  return; /* extension membership overrides all else */
2092 
2093  sobj->dobj.dump = sobj->dobj.namespace->dobj.dump_contains;
2094  if (sobj->stattable == NULL ||
2096  sobj->dobj.dump = DUMP_COMPONENT_NONE;
2097 }
2098 
2099 /*
2100  * selectDumpableObject: policy-setting subroutine
2101  * Mark a generic dumpable object as to be dumped or not
2102  *
2103  * Use this only for object types without a special-case routine above.
2104  */
2105 static void
2107 {
2108  if (checkExtensionMembership(dobj, fout))
2109  return; /* extension membership overrides all else */
2110 
2111  /*
2112  * Default policy is to dump if parent namespace is dumpable, or for
2113  * non-namespace-associated items, dump if we're dumping "everything".
2114  */
2115  if (dobj->namespace)
2116  dobj->dump = dobj->namespace->dobj.dump_contains;
2117  else
2118  dobj->dump = fout->dopt->include_everything ?
2120 }
2121 
2122 /*
2123  * Dump a table's contents for loading using the COPY command
2124  * - this routine is called by the Archiver when it wants the table
2125  * to be dumped.
2126  */
2127 static int
2128 dumpTableData_copy(Archive *fout, const void *dcontext)
2129 {
2130  TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
2131  TableInfo *tbinfo = tdinfo->tdtable;
2132  const char *classname = tbinfo->dobj.name;
2134 
2135  /*
2136  * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
2137  * which uses it already.
2138  */
2139  PQExpBuffer clistBuf = createPQExpBuffer();
2140  PGconn *conn = GetConnection(fout);
2141  PGresult *res;
2142  int ret;
2143  char *copybuf;
2144  const char *column_list;
2145 
2146  pg_log_info("dumping contents of table \"%s.%s\"",
2147  tbinfo->dobj.namespace->dobj.name, classname);
2148 
2149  /*
2150  * Specify the column list explicitly so that we have no possibility of
2151  * retrieving data in the wrong column order. (The default column
2152  * ordering of COPY will not be what we want in certain corner cases
2153  * involving ADD COLUMN and inheritance.)
2154  */
2155  column_list = fmtCopyColumnList(tbinfo, clistBuf);
2156 
2157  /*
2158  * Use COPY (SELECT ...) TO when dumping a foreign table's data, and when
2159  * a filter condition was specified. For other cases a simple COPY
2160  * suffices.
2161  */
2162  if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2163  {
2164  appendPQExpBufferStr(q, "COPY (SELECT ");
2165  /* klugery to get rid of parens in column list */
2166  if (strlen(column_list) > 2)
2167  {
2168  appendPQExpBufferStr(q, column_list + 1);
2169  q->data[q->len - 1] = ' ';
2170  }
2171  else
2172  appendPQExpBufferStr(q, "* ");
2173 
2174  appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
2175  fmtQualifiedDumpable(tbinfo),
2176  tdinfo->filtercond ? tdinfo->filtercond : "");
2177  }
2178  else
2179  {
2180  appendPQExpBuffer(q, "COPY %s %s TO stdout;",
2181  fmtQualifiedDumpable(tbinfo),
2182  column_list);
2183  }
2184  res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
2185  PQclear(res);
2186  destroyPQExpBuffer(clistBuf);
2187 
2188  for (;;)
2189  {
2190  ret = PQgetCopyData(conn, &copybuf, 0);
2191 
2192  if (ret < 0)
2193  break; /* done or error */
2194 
2195  if (copybuf)
2196  {
2197  WriteData(fout, copybuf, ret);
2198  PQfreemem(copybuf);
2199  }
2200 
2201  /* ----------
2202  * THROTTLE:
2203  *
2204  * There was considerable discussion in late July, 2000 regarding
2205  * slowing down pg_dump when backing up large tables. Users with both
2206  * slow & fast (multi-processor) machines experienced performance
2207  * degradation when doing a backup.
2208  *
2209  * Initial attempts based on sleeping for a number of ms for each ms
2210  * of work were deemed too complex, then a simple 'sleep in each loop'
2211  * implementation was suggested. The latter failed because the loop
2212  * was too tight. Finally, the following was implemented:
2213  *
2214  * If throttle is non-zero, then
2215  * See how long since the last sleep.
2216  * Work out how long to sleep (based on ratio).
2217  * If sleep is more than 100ms, then
2218  * sleep
2219  * reset timer
2220  * EndIf
2221  * EndIf
2222  *
2223  * where the throttle value was the number of ms to sleep per ms of
2224  * work. The calculation was done in each loop.
2225  *
2226  * Most of the hard work is done in the backend, and this solution
2227  * still did not work particularly well: on slow machines, the ratio
2228  * was 50:1, and on medium paced machines, 1:1, and on fast
2229  * multi-processor machines, it had little or no effect, for reasons
2230  * that were unclear.
2231  *
2232  * Further discussion ensued, and the proposal was dropped.
2233  *
2234  * For those people who want this feature, it can be implemented using
2235  * gettimeofday in each loop, calculating the time since last sleep,
2236  * multiplying that by the sleep ratio, then if the result is more
2237  * than a preset 'minimum sleep time' (say 100ms), call the 'select'
2238  * function to sleep for a subsecond period ie.
2239  *
2240  * select(0, NULL, NULL, NULL, &tvi);
2241  *
2242  * This will return after the interval specified in the structure tvi.
2243  * Finally, call gettimeofday again to save the 'last sleep time'.
2244  * ----------
2245  */
2246  }
2247  archprintf(fout, "\\.\n\n\n");
2248 
2249  if (ret == -2)
2250  {
2251  /* copy data transfer failed */
2252  pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
2253  pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
2254  pg_log_error_detail("Command was: %s", q->data);
2255  exit_nicely(1);
2256  }
2257 
2258  /* Check command status and return to normal libpq state */
2259  res = PQgetResult(conn);
2261  {
2262  pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
2263  pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
2264  pg_log_error_detail("Command was: %s", q->data);
2265  exit_nicely(1);
2266  }
2267  PQclear(res);
2268 
2269  /* Do this to ensure we've pumped libpq back to idle state */
2270  if (PQgetResult(conn) != NULL)
2271  pg_log_warning("unexpected extra results during COPY of table \"%s\"",
2272  classname);
2273 
2274  destroyPQExpBuffer(q);
2275  return 1;
2276 }
2277 
2278 /*
2279  * Dump table data using INSERT commands.
2280  *
2281  * Caution: when we restore from an archive file direct to database, the
2282  * INSERT commands emitted by this function have to be parsed by
2283  * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
2284  * E'' strings, or dollar-quoted strings. So don't emit anything like that.
2285  */
2286 static int
2287 dumpTableData_insert(Archive *fout, const void *dcontext)
2288 {
2289  TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
2290  TableInfo *tbinfo = tdinfo->tdtable;
2291  DumpOptions *dopt = fout->dopt;
2293  PQExpBuffer insertStmt = NULL;
2294  char *attgenerated;
2295  PGresult *res;
2296  int nfields,
2297  i;
2298  int rows_per_statement = dopt->dump_inserts;
2299  int rows_this_statement = 0;
2300 
2301  /*
2302  * If we're going to emit INSERTs with column names, the most efficient
2303  * way to deal with generated columns is to exclude them entirely. For
2304  * INSERTs without column names, we have to emit DEFAULT rather than the
2305  * actual column value --- but we can save a few cycles by fetching nulls
2306  * rather than the uninteresting-to-us value.
2307  */
2308  attgenerated = (char *) pg_malloc(tbinfo->numatts * sizeof(char));
2309  appendPQExpBufferStr(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT ");
2310  nfields = 0;
2311  for (i = 0; i < tbinfo->numatts; i++)
2312  {
2313  if (tbinfo->attisdropped[i])
2314  continue;
2315  if (tbinfo->attgenerated[i] && dopt->column_inserts)
2316  continue;
2317  if (nfields > 0)
2318  appendPQExpBufferStr(q, ", ");
2319  if (tbinfo->attgenerated[i])
2320  appendPQExpBufferStr(q, "NULL");
2321  else
2322  appendPQExpBufferStr(q, fmtId(tbinfo->attnames[i]));
2323  attgenerated[nfields] = tbinfo->attgenerated[i];
2324  nfields++;
2325  }
2326  /* Servers before 9.4 will complain about zero-column SELECT */
2327  if (nfields == 0)
2328  appendPQExpBufferStr(q, "NULL");
2329  appendPQExpBuffer(q, " FROM ONLY %s",
2330  fmtQualifiedDumpable(tbinfo));
2331  if (tdinfo->filtercond)
2332  appendPQExpBuffer(q, " %s", tdinfo->filtercond);
2333 
2334  ExecuteSqlStatement(fout, q->data);
2335 
2336  while (1)
2337  {
2338  res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
2339  PGRES_TUPLES_OK);
2340 
2341  /* cross-check field count, allowing for dummy NULL if any */
2342  if (nfields != PQnfields(res) &&
2343  !(nfields == 0 && PQnfields(res) == 1))
2344  pg_fatal("wrong number of fields retrieved from table \"%s\"",
2345  tbinfo->dobj.name);
2346 
2347  /*
2348  * First time through, we build as much of the INSERT statement as
2349  * possible in "insertStmt", which we can then just print for each
2350  * statement. If the table happens to have zero dumpable columns then
2351  * this will be a complete statement, otherwise it will end in
2352  * "VALUES" and be ready to have the row's column values printed.
2353  */
2354  if (insertStmt == NULL)
2355  {
2356  TableInfo *targettab;
2357 
2358  insertStmt = createPQExpBuffer();
2359 
2360  /*
2361  * When load-via-partition-root is set or forced, get the root
2362  * table name for the partition table, so that we can reload data
2363  * through the root table.
2364  */
2365  if (tbinfo->ispartition &&
2366  (dopt->load_via_partition_root ||
2367  forcePartitionRootLoad(tbinfo)))
2368  targettab = getRootTableInfo(tbinfo);
2369  else
2370  targettab = tbinfo;
2371 
2372  appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
2373  fmtQualifiedDumpable(targettab));
2374 
2375  /* corner case for zero-column table */
2376  if (nfields == 0)
2377  {
2378  appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
2379  }
2380  else
2381  {
2382  /* append the list of column names if required */
2383  if (dopt->column_inserts)
2384  {
2385  appendPQExpBufferChar(insertStmt, '(');
2386  for (int field = 0; field < nfields; field++)
2387  {
2388  if (field > 0)
2389  appendPQExpBufferStr(insertStmt, ", ");
2390  appendPQExpBufferStr(insertStmt,
2391  fmtId(PQfname(res, field)));
2392  }
2393  appendPQExpBufferStr(insertStmt, ") ");
2394  }
2395 
2396  if (tbinfo->needs_override)
2397  appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
2398 
2399  appendPQExpBufferStr(insertStmt, "VALUES");
2400  }
2401  }
2402 
2403  for (int tuple = 0; tuple < PQntuples(res); tuple++)
2404  {
2405  /* Write the INSERT if not in the middle of a multi-row INSERT. */
2406  if (rows_this_statement == 0)
2407  archputs(insertStmt->data, fout);
2408 
2409  /*
2410  * If it is zero-column table then we've already written the
2411  * complete statement, which will mean we've disobeyed
2412  * --rows-per-insert when it's set greater than 1. We do support
2413  * a way to make this multi-row with: SELECT UNION ALL SELECT
2414  * UNION ALL ... but that's non-standard so we should avoid it
2415  * given that using INSERTs is mostly only ever needed for
2416  * cross-database exports.
2417  */
2418  if (nfields == 0)
2419  continue;
2420 
2421  /* Emit a row heading */
2422  if (rows_per_statement == 1)
2423  archputs(" (", fout);
2424  else if (rows_this_statement > 0)
2425  archputs(",\n\t(", fout);
2426  else
2427  archputs("\n\t(", fout);
2428 
2429  for (int field = 0; field < nfields; field++)
2430  {
2431  if (field > 0)
2432  archputs(", ", fout);
2433  if (attgenerated[field])
2434  {
2435  archputs("DEFAULT", fout);
2436  continue;
2437  }
2438  if (PQgetisnull(res, tuple, field))
2439  {
2440  archputs("NULL", fout);
2441  continue;
2442  }
2443 
2444  /* XXX This code is partially duplicated in ruleutils.c */
2445  switch (PQftype(res, field))
2446  {
2447  case INT2OID:
2448  case INT4OID:
2449  case INT8OID:
2450  case OIDOID:
2451  case FLOAT4OID:
2452  case FLOAT8OID:
2453  case NUMERICOID:
2454  {
2455  /*
2456  * These types are printed without quotes unless
2457  * they contain values that aren't accepted by the
2458  * scanner unquoted (e.g., 'NaN'). Note that
2459  * strtod() and friends might accept NaN, so we
2460  * can't use that to test.
2461  *
2462  * In reality we only need to defend against
2463  * infinity and NaN, so we need not get too crazy
2464  * about pattern matching here.
2465  */
2466  const char *s = PQgetvalue(res, tuple, field);
2467 
2468  if (strspn(s, "0123456789 +-eE.") == strlen(s))
2469  archputs(s, fout);
2470  else
2471  archprintf(fout, "'%s'", s);
2472  }
2473  break;
2474 
2475  case BITOID:
2476  case VARBITOID:
2477  archprintf(fout, "B'%s'",
2478  PQgetvalue(res, tuple, field));
2479  break;
2480 
2481  case BOOLOID:
2482  if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
2483  archputs("true", fout);
2484  else
2485  archputs("false", fout);
2486  break;
2487 
2488  default:
2489  /* All other types are printed as string literals. */
2490  resetPQExpBuffer(q);
2492  PQgetvalue(res, tuple, field),
2493  fout);
2494  archputs(q->data, fout);
2495  break;
2496  }
2497  }
2498 
2499  /* Terminate the row ... */
2500  archputs(")", fout);
2501 
2502  /* ... and the statement, if the target no. of rows is reached */
2503  if (++rows_this_statement >= rows_per_statement)
2504  {
2505  if (dopt->do_nothing)
2506  archputs(" ON CONFLICT DO NOTHING;\n", fout);
2507  else
2508  archputs(";\n", fout);
2509  /* Reset the row counter */
2510  rows_this_statement = 0;
2511  }
2512  }
2513 
2514  if (PQntuples(res) <= 0)
2515  {
2516  PQclear(res);
2517  break;
2518  }
2519  PQclear(res);
2520  }
2521 
2522  /* Terminate any statements that didn't make the row count. */
2523  if (rows_this_statement > 0)
2524  {
2525  if (dopt->do_nothing)
2526  archputs(" ON CONFLICT DO NOTHING;\n", fout);
2527  else
2528  archputs(";\n", fout);
2529  }
2530 
2531  archputs("\n\n", fout);
2532 
2533  ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
2534 
2535  destroyPQExpBuffer(q);
2536  if (insertStmt != NULL)
2537  destroyPQExpBuffer(insertStmt);
2538  free(attgenerated);
2539 
2540  return 1;
2541 }
2542 
2543 /*
2544  * getRootTableInfo:
2545  * get the root TableInfo for the given partition table.
2546  */
2547 static TableInfo *
2549 {
2550  TableInfo *parentTbinfo;
2551 
2552  Assert(tbinfo->ispartition);
2553  Assert(tbinfo->numParents == 1);
2554 
2555  parentTbinfo = tbinfo->parents[0];
2556  while (parentTbinfo->ispartition)
2557  {
2558  Assert(parentTbinfo->numParents == 1);
2559  parentTbinfo = parentTbinfo->parents[0];
2560  }
2561 
2562  return parentTbinfo;
2563 }
2564 
2565 /*
2566  * forcePartitionRootLoad
2567  * Check if we must force load_via_partition_root for this partition.
2568  *
2569  * This is required if any level of ancestral partitioned table has an
2570  * unsafe partitioning scheme.
2571  */
2572 static bool
2574 {
2575  TableInfo *parentTbinfo;
2576 
2577  Assert(tbinfo->ispartition);
2578  Assert(tbinfo->numParents == 1);
2579 
2580  parentTbinfo = tbinfo->parents[0];
2581  if (parentTbinfo->unsafe_partitions)
2582  return true;
2583  while (parentTbinfo->ispartition)
2584  {
2585  Assert(parentTbinfo->numParents == 1);
2586  parentTbinfo = parentTbinfo->parents[0];
2587  if (parentTbinfo->unsafe_partitions)
2588  return true;
2589  }
2590 
2591  return false;
2592 }
2593 
2594 /*
2595  * dumpTableData -
2596  * dump the contents of a single table
2597  *
2598  * Actually, this just makes an ArchiveEntry for the table contents.
2599  */
2600 static void
2601 dumpTableData(Archive *fout, const TableDataInfo *tdinfo)
2602 {
2603  DumpOptions *dopt = fout->dopt;
2604  TableInfo *tbinfo = tdinfo->tdtable;
2605  PQExpBuffer copyBuf = createPQExpBuffer();
2606  PQExpBuffer clistBuf = createPQExpBuffer();
2607  DataDumperPtr dumpFn;
2608  char *tdDefn = NULL;
2609  char *copyStmt;
2610  const char *copyFrom;
2611 
2612  /* We had better have loaded per-column details about this table */
2613  Assert(tbinfo->interesting);
2614 
2615  /*
2616  * When load-via-partition-root is set or forced, get the root table name
2617  * for the partition table, so that we can reload data through the root
2618  * table. Then construct a comment to be inserted into the TOC entry's
2619  * defn field, so that such cases can be identified reliably.
2620  */
2621  if (tbinfo->ispartition &&
2622  (dopt->load_via_partition_root ||
2623  forcePartitionRootLoad(tbinfo)))
2624  {
2625  TableInfo *parentTbinfo;
2626 
2627  parentTbinfo = getRootTableInfo(tbinfo);
2628  copyFrom = fmtQualifiedDumpable(parentTbinfo);
2629  printfPQExpBuffer(copyBuf, "-- load via partition root %s",
2630  copyFrom);
2631  tdDefn = pg_strdup(copyBuf->data);
2632  }
2633  else
2634  copyFrom = fmtQualifiedDumpable(tbinfo);
2635 
2636  if (dopt->dump_inserts == 0)
2637  {
2638  /* Dump/restore using COPY */
2639  dumpFn = dumpTableData_copy;
2640  /* must use 2 steps here 'cause fmtId is nonreentrant */
2641  printfPQExpBuffer(copyBuf, "COPY %s ",
2642  copyFrom);
2643  appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
2644  fmtCopyColumnList(tbinfo, clistBuf));
2645  copyStmt = copyBuf->data;
2646  }
2647  else
2648  {
2649  /* Restore using INSERT */
2650  dumpFn = dumpTableData_insert;
2651  copyStmt = NULL;
2652  }
2653 
2654  /*
2655  * Note: although the TableDataInfo is a full DumpableObject, we treat its
2656  * dependency on its table as "special" and pass it to ArchiveEntry now.
2657  * See comments for BuildArchiveDependencies.
2658  */
2659  if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2660  {
2661  TocEntry *te;
2662 
2663  te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
2664  ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
2665  .namespace = tbinfo->dobj.namespace->dobj.name,
2666  .owner = tbinfo->rolname,
2667  .description = "TABLE DATA",
2668  .section = SECTION_DATA,
2669  .createStmt = tdDefn,
2670  .copyStmt = copyStmt,
2671  .deps = &(tbinfo->dobj.dumpId),
2672  .nDeps = 1,
2673  .dumpFn = dumpFn,
2674  .dumpArg = tdinfo));
2675 
2676  /*
2677  * Set the TocEntry's dataLength in case we are doing a parallel dump
2678  * and want to order dump jobs by table size. We choose to measure
2679  * dataLength in table pages (including TOAST pages) during dump, so
2680  * no scaling is needed.
2681  *
2682  * However, relpages is declared as "integer" in pg_class, and hence
2683  * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
2684  * Cast so that we get the right interpretation of table sizes
2685  * exceeding INT_MAX pages.
2686  */
2687  te->dataLength = (BlockNumber) tbinfo->relpages;
2688  te->dataLength += (BlockNumber) tbinfo->toastpages;
2689 
2690  /*
2691  * If pgoff_t is only 32 bits wide, the above refinement is useless,
2692  * and instead we'd better worry about integer overflow. Clamp to
2693  * INT_MAX if the correct result exceeds that.
2694  */
2695  if (sizeof(te->dataLength) == 4 &&
2696  (tbinfo->relpages < 0 || tbinfo->toastpages < 0 ||
2697  te->dataLength < 0))
2698  te->dataLength = INT_MAX;
2699  }
2700 
2701  destroyPQExpBuffer(copyBuf);
2702  destroyPQExpBuffer(clistBuf);
2703 }
2704 
2705 /*
2706  * refreshMatViewData -
2707  * load or refresh the contents of a single materialized view
2708  *
2709  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
2710  * statement.
2711  */
2712 static void
2714 {
2715  TableInfo *tbinfo = tdinfo->tdtable;
2716  PQExpBuffer q;
2717 
2718  /* If the materialized view is not flagged as populated, skip this. */
2719  if (!tbinfo->relispopulated)
2720  return;
2721 
2722  q = createPQExpBuffer();
2723 
2724  appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
2725  fmtQualifiedDumpable(tbinfo));
2726 
2727  if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2728  ArchiveEntry(fout,
2729  tdinfo->dobj.catId, /* catalog ID */
2730  tdinfo->dobj.dumpId, /* dump ID */
2731  ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
2732  .namespace = tbinfo->dobj.namespace->dobj.name,
2733  .owner = tbinfo->rolname,
2734  .description = "MATERIALIZED VIEW DATA",
2735  .section = SECTION_POST_DATA,
2736  .createStmt = q->data,
2737  .deps = tdinfo->dobj.dependencies,
2738  .nDeps = tdinfo->dobj.nDeps));
2739 
2740  destroyPQExpBuffer(q);
2741 }
2742 
2743 /*
2744  * getTableData -
2745  * set up dumpable objects representing the contents of tables
2746  */
2747 static void
2748 getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
2749 {
2750  int i;
2751 
2752  for (i = 0; i < numTables; i++)
2753  {
2754  if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
2755  (!relkind || tblinfo[i].relkind == relkind))
2756  makeTableDataInfo(dopt, &(tblinfo[i]));
2757  }
2758 }
2759 
2760 /*
2761  * Make a dumpable object for the data of this specific table
2762  *
2763  * Note: we make a TableDataInfo if and only if we are going to dump the
2764  * table data; the "dump" field in such objects isn't very interesting.
2765  */
2766 static void
2768 {
2769  TableDataInfo *tdinfo;
2770 
2771  /*
2772  * Nothing to do if we already decided to dump the table. This will
2773  * happen for "config" tables.
2774  */
2775  if (tbinfo->dataObj != NULL)
2776  return;
2777 
2778  /* Skip VIEWs (no data to dump) */
2779  if (tbinfo->relkind == RELKIND_VIEW)
2780  return;
2781  /* Skip FOREIGN TABLEs (no data to dump) unless requested explicitly */
2782  if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
2785  tbinfo->foreign_server)))
2786  return;
2787  /* Skip partitioned tables (data in partitions) */
2788  if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
2789  return;
2790 
2791  /* Don't dump data in unlogged tables, if so requested */
2792  if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
2793  dopt->no_unlogged_table_data)
2794  return;
2795 
2796  /* Check that the data is not explicitly excluded */
2798  tbinfo->dobj.catId.oid))
2799  return;
2800 
2801  /* OK, let's dump it */
2802  tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
2803 
2804  if (tbinfo->relkind == RELKIND_MATVIEW)
2805  tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
2806  else if (tbinfo->relkind == RELKIND_SEQUENCE)
2807  tdinfo->dobj.objType = DO_SEQUENCE_SET;
2808  else
2809  tdinfo->dobj.objType = DO_TABLE_DATA;
2810 
2811  /*
2812  * Note: use tableoid 0 so that this object won't be mistaken for
2813  * something that pg_depend entries apply to.
2814  */
2815  tdinfo->dobj.catId.tableoid = 0;
2816  tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
2817  AssignDumpId(&tdinfo->dobj);
2818  tdinfo->dobj.name = tbinfo->dobj.name;
2819  tdinfo->dobj.namespace = tbinfo->dobj.namespace;
2820  tdinfo->tdtable = tbinfo;
2821  tdinfo->filtercond = NULL; /* might get set later */
2822  addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
2823 
2824  /* A TableDataInfo contains data, of course */
2825  tdinfo->dobj.components |= DUMP_COMPONENT_DATA;
2826 
2827  tbinfo->dataObj = tdinfo;
2828 
2829  /* Make sure that we'll collect per-column info for this table. */
2830  tbinfo->interesting = true;
2831 }
2832 
2833 /*
2834  * The refresh for a materialized view must be dependent on the refresh for
2835  * any materialized view that this one is dependent on.
2836  *
2837  * This must be called after all the objects are created, but before they are
2838  * sorted.
2839  */
2840 static void
2842 {
2843  PQExpBuffer query;
2844  PGresult *res;
2845  int ntups,
2846  i;
2847  int i_classid,
2848  i_objid,
2849  i_refobjid;
2850 
2851  /* No Mat Views before 9.3. */
2852  if (fout->remoteVersion < 90300)
2853  return;
2854 
2855  query = createPQExpBuffer();
2856 
2857  appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
2858  "( "
2859  "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
2860  "FROM pg_depend d1 "
2861  "JOIN pg_class c1 ON c1.oid = d1.objid "
2862  "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
2863  " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
2864  "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
2865  "AND d2.objid = r1.oid "
2866  "AND d2.refobjid <> d1.objid "
2867  "JOIN pg_class c2 ON c2.oid = d2.refobjid "
2868  "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2869  CppAsString2(RELKIND_VIEW) ") "
2870  "WHERE d1.classid = 'pg_class'::regclass "
2871  "UNION "
2872  "SELECT w.objid, d3.refobjid, c3.relkind "
2873  "FROM w "
2874  "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
2875  "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
2876  "AND d3.objid = r3.oid "
2877  "AND d3.refobjid <> w.refobjid "
2878  "JOIN pg_class c3 ON c3.oid = d3.refobjid "
2879  "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2880  CppAsString2(RELKIND_VIEW) ") "
2881  ") "
2882  "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
2883  "FROM w "
2884  "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
2885 
2886  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2887 
2888  ntups = PQntuples(res);
2889 
2890  i_classid = PQfnumber(res, "classid");
2891  i_objid = PQfnumber(res, "objid");
2892  i_refobjid = PQfnumber(res, "refobjid");
2893 
2894  for (i = 0; i < ntups; i++)
2895  {
2896  CatalogId objId;
2897  CatalogId refobjId;
2898  DumpableObject *dobj;
2899  DumpableObject *refdobj;
2900  TableInfo *tbinfo;
2901  TableInfo *reftbinfo;
2902 
2903  objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
2904  objId.oid = atooid(PQgetvalue(res, i, i_objid));
2905  refobjId.tableoid = objId.tableoid;
2906  refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
2907 
2908  dobj = findObjectByCatalogId(objId);
2909  if (dobj == NULL)
2910  continue;
2911 
2912  Assert(dobj->objType == DO_TABLE);
2913  tbinfo = (TableInfo *) dobj;
2914  Assert(tbinfo->relkind == RELKIND_MATVIEW);
2915  dobj = (DumpableObject *) tbinfo->dataObj;
2916  if (dobj == NULL)
2917  continue;
2918  Assert(dobj->objType == DO_REFRESH_MATVIEW);
2919 
2920  refdobj = findObjectByCatalogId(refobjId);
2921  if (refdobj == NULL)
2922  continue;
2923 
2924  Assert(refdobj->objType == DO_TABLE);
2925  reftbinfo = (TableInfo *) refdobj;
2926  Assert(reftbinfo->relkind == RELKIND_MATVIEW);
2927  refdobj = (DumpableObject *) reftbinfo->dataObj;
2928  if (refdobj == NULL)
2929  continue;
2930  Assert(refdobj->objType == DO_REFRESH_MATVIEW);
2931 
2932  addObjectDependency(dobj, refdobj->dumpId);
2933 
2934  if (!reftbinfo->relispopulated)
2935  tbinfo->relispopulated = false;
2936  }
2937 
2938  PQclear(res);
2939 
2940  destroyPQExpBuffer(query);
2941 }
2942 
2943 /*
2944  * getTableDataFKConstraints -
2945  * add dump-order dependencies reflecting foreign key constraints
2946  *
2947  * This code is executed only in a data-only dump --- in schema+data dumps
2948  * we handle foreign key issues by not creating the FK constraints until
2949  * after the data is loaded. In a data-only dump, however, we want to
2950  * order the table data objects in such a way that a table's referenced
2951  * tables are restored first. (In the presence of circular references or
2952  * self-references this may be impossible; we'll detect and complain about
2953  * that during the dependency sorting step.)
2954  */
2955 static void
2957 {
2958  DumpableObject **dobjs;
2959  int numObjs;
2960  int i;
2961 
2962  /* Search through all the dumpable objects for FK constraints */
2963  getDumpableObjects(&dobjs, &numObjs);
2964  for (i = 0; i < numObjs; i++)
2965  {
2966  if (dobjs[i]->objType == DO_FK_CONSTRAINT)
2967  {
2968  ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
2969  TableInfo *ftable;
2970 
2971  /* Not interesting unless both tables are to be dumped */
2972  if (cinfo->contable == NULL ||
2973  cinfo->contable->dataObj == NULL)
2974  continue;
2975  ftable = findTableByOid(cinfo->confrelid);
2976  if (ftable == NULL ||
2977  ftable->dataObj == NULL)
2978  continue;
2979 
2980  /*
2981  * Okay, make referencing table's TABLE_DATA object depend on the
2982  * referenced table's TABLE_DATA object.
2983  */
2985  ftable->dataObj->dobj.dumpId);
2986  }
2987  }
2988  free(dobjs);
2989 }
2990 
2991 
2992 /*
2993  * dumpDatabase:
2994  * dump the database definition
2995  */
2996 static void
2998 {
2999  DumpOptions *dopt = fout->dopt;
3000  PQExpBuffer dbQry = createPQExpBuffer();
3001  PQExpBuffer delQry = createPQExpBuffer();
3002  PQExpBuffer creaQry = createPQExpBuffer();
3003  PQExpBuffer labelq = createPQExpBuffer();
3004  PGconn *conn = GetConnection(fout);
3005  PGresult *res;
3006  int i_tableoid,
3007  i_oid,
3008  i_datname,
3009  i_datdba,
3010  i_encoding,
3011  i_datlocprovider,
3012  i_collate,
3013  i_ctype,
3014  i_datlocale,
3015  i_daticurules,
3016  i_frozenxid,
3017  i_minmxid,
3018  i_datacl,
3019  i_acldefault,
3020  i_datistemplate,
3021  i_datconnlimit,
3022  i_datcollversion,
3023  i_tablespace;
3024  CatalogId dbCatId;
3025  DumpId dbDumpId;
3026  DumpableAcl dbdacl;
3027  const char *datname,
3028  *dba,
3029  *encoding,
3030  *datlocprovider,
3031  *collate,
3032  *ctype,
3033  *locale,
3034  *icurules,
3035  *datistemplate,
3036  *datconnlimit,
3037  *tablespace;
3038  uint32 frozenxid,
3039  minmxid;
3040  char *qdatname;
3041 
3042  pg_log_info("saving database definition");
3043 
3044  /*
3045  * Fetch the database-level properties for this database.
3046  */
3047  appendPQExpBufferStr(dbQry, "SELECT tableoid, oid, datname, "
3048  "datdba, "
3049  "pg_encoding_to_char(encoding) AS encoding, "
3050  "datcollate, datctype, datfrozenxid, "
3051  "datacl, acldefault('d', datdba) AS acldefault, "
3052  "datistemplate, datconnlimit, ");
3053  if (fout->remoteVersion >= 90300)
3054  appendPQExpBufferStr(dbQry, "datminmxid, ");
3055  else
3056  appendPQExpBufferStr(dbQry, "0 AS datminmxid, ");
3057  if (fout->remoteVersion >= 170000)
3058  appendPQExpBufferStr(dbQry, "datlocprovider, datlocale, datcollversion, ");
3059  else if (fout->remoteVersion >= 150000)
3060  appendPQExpBufferStr(dbQry, "datlocprovider, daticulocale AS datlocale, datcollversion, ");
3061  else
3062  appendPQExpBufferStr(dbQry, "'c' AS datlocprovider, NULL AS datlocale, NULL AS datcollversion, ");
3063  if (fout->remoteVersion >= 160000)
3064  appendPQExpBufferStr(dbQry, "daticurules, ");
3065  else
3066  appendPQExpBufferStr(dbQry, "NULL AS daticurules, ");
3067  appendPQExpBufferStr(dbQry,
3068  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
3069  "shobj_description(oid, 'pg_database') AS description "
3070  "FROM pg_database "
3071  "WHERE datname = current_database()");
3072 
3073  res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
3074 
3075  i_tableoid = PQfnumber(res, "tableoid");
3076  i_oid = PQfnumber(res, "oid");
3077  i_datname = PQfnumber(res, "datname");
3078  i_datdba = PQfnumber(res, "datdba");
3079  i_encoding = PQfnumber(res, "encoding");
3080  i_datlocprovider = PQfnumber(res, "datlocprovider");
3081  i_collate = PQfnumber(res, "datcollate");
3082  i_ctype = PQfnumber(res, "datctype");
3083  i_datlocale = PQfnumber(res, "datlocale");
3084  i_daticurules = PQfnumber(res, "daticurules");
3085  i_frozenxid = PQfnumber(res, "datfrozenxid");
3086  i_minmxid = PQfnumber(res, "datminmxid");
3087  i_datacl = PQfnumber(res, "datacl");
3088  i_acldefault = PQfnumber(res, "acldefault");
3089  i_datistemplate = PQfnumber(res, "datistemplate");
3090  i_datconnlimit = PQfnumber(res, "datconnlimit");
3091  i_datcollversion = PQfnumber(res, "datcollversion");
3092  i_tablespace = PQfnumber(res, "tablespace");
3093 
3094  dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
3095  dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
3096  datname = PQgetvalue(res, 0, i_datname);
3097  dba = getRoleName(PQgetvalue(res, 0, i_datdba));
3098  encoding = PQgetvalue(res, 0, i_encoding);
3099  datlocprovider = PQgetvalue(res, 0, i_datlocprovider);
3100  collate = PQgetvalue(res, 0, i_collate);
3101  ctype = PQgetvalue(res, 0, i_ctype);
3102  if (!PQgetisnull(res, 0, i_datlocale))
3103  locale = PQgetvalue(res, 0, i_datlocale);
3104  else
3105  locale = NULL;
3106  if (!PQgetisnull(res, 0, i_daticurules))
3107  icurules = PQgetvalue(res, 0, i_daticurules);
3108  else
3109  icurules = NULL;
3110  frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
3111  minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
3112  dbdacl.acl = PQgetvalue(res, 0, i_datacl);
3113  dbdacl.acldefault = PQgetvalue(res, 0, i_acldefault);
3114  datistemplate = PQgetvalue(res, 0, i_datistemplate);
3115  datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
3116  tablespace = PQgetvalue(res, 0, i_tablespace);
3117 
3118  qdatname = pg_strdup(fmtId(datname));
3119 
3120  /*
3121  * Prepare the CREATE DATABASE command. We must specify OID (if we want
3122  * to preserve that), as well as the encoding, locale, and tablespace
3123  * since those can't be altered later. Other DB properties are left to
3124  * the DATABASE PROPERTIES entry, so that they can be applied after
3125  * reconnecting to the target DB.
3126  */
3127  if (dopt->binary_upgrade)
3128  {
3129  appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0 OID = %u",
3130  qdatname, dbCatId.oid);
3131  }
3132  else
3133  {
3134  appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
3135  qdatname);
3136  }
3137  if (strlen(encoding) > 0)
3138  {
3139  appendPQExpBufferStr(creaQry, " ENCODING = ");
3140  appendStringLiteralAH(creaQry, encoding, fout);
3141  }
3142 
3143  appendPQExpBufferStr(creaQry, " LOCALE_PROVIDER = ");
3144  if (datlocprovider[0] == 'b')
3145  appendPQExpBufferStr(creaQry, "builtin");
3146  else if (datlocprovider[0] == 'c')
3147  appendPQExpBufferStr(creaQry, "libc");
3148  else if (datlocprovider[0] == 'i')
3149  appendPQExpBufferStr(creaQry, "icu");
3150  else
3151  pg_fatal("unrecognized locale provider: %s",
3152  datlocprovider);
3153 
3154  if (strlen(collate) > 0 && strcmp(collate, ctype) == 0)
3155  {
3156  appendPQExpBufferStr(creaQry, " LOCALE = ");
3157  appendStringLiteralAH(creaQry, collate, fout);
3158  }
3159  else
3160  {
3161  if (strlen(collate) > 0)
3162  {
3163  appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
3164  appendStringLiteralAH(creaQry, collate, fout);
3165  }
3166  if (strlen(ctype) > 0)
3167  {
3168  appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
3169  appendStringLiteralAH(creaQry, ctype, fout);
3170  }
3171  }
3172  if (locale)
3173  {
3174  if (datlocprovider[0] == 'b')
3175  appendPQExpBufferStr(creaQry, " BUILTIN_LOCALE = ");
3176  else
3177  appendPQExpBufferStr(creaQry, " ICU_LOCALE = ");
3178 
3179  appendStringLiteralAH(creaQry, locale, fout);
3180  }
3181 
3182  if (icurules)
3183  {
3184  appendPQExpBufferStr(creaQry, " ICU_RULES = ");
3185  appendStringLiteralAH(creaQry, icurules, fout);
3186  }
3187 
3188  /*
3189  * For binary upgrade, carry over the collation version. For normal
3190  * dump/restore, omit the version, so that it is computed upon restore.
3191  */
3192  if (dopt->binary_upgrade)
3193  {
3194  if (!PQgetisnull(res, 0, i_datcollversion))
3195  {
3196  appendPQExpBufferStr(creaQry, " COLLATION_VERSION = ");
3197  appendStringLiteralAH(creaQry,
3198  PQgetvalue(res, 0, i_datcollversion),
3199  fout);
3200  }
3201  }
3202 
3203  /*
3204  * Note: looking at dopt->outputNoTablespaces here is completely the wrong
3205  * thing; the decision whether to specify a tablespace should be left till
3206  * pg_restore, so that pg_restore --no-tablespaces applies. Ideally we'd
3207  * label the DATABASE entry with the tablespace and let the normal
3208  * tablespace selection logic work ... but CREATE DATABASE doesn't pay
3209  * attention to default_tablespace, so that won't work.
3210  */
3211  if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
3212  !dopt->outputNoTablespaces)
3213  appendPQExpBuffer(creaQry, " TABLESPACE = %s",
3214  fmtId(tablespace));
3215  appendPQExpBufferStr(creaQry, ";\n");
3216 
3217  appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
3218  qdatname);
3219 
3220  dbDumpId = createDumpId();
3221 
3222  ArchiveEntry(fout,
3223  dbCatId, /* catalog ID */
3224  dbDumpId, /* dump ID */
3225  ARCHIVE_OPTS(.tag = datname,
3226  .owner = dba,
3227  .description = "DATABASE",
3228  .section = SECTION_PRE_DATA,
3229  .createStmt = creaQry->data,
3230  .dropStmt = delQry->data));
3231 
3232  /* Compute correct tag for archive entry */
3233  appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
3234 
3235  /* Dump DB comment if any */
3236  {
3237  /*
3238  * 8.2 and up keep comments on shared objects in a shared table, so we
3239  * cannot use the dumpComment() code used for other database objects.
3240  * Be careful that the ArchiveEntry parameters match that function.
3241  */
3242  char *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
3243 
3244  if (comment && *comment && !dopt->no_comments)
3245  {
3246  resetPQExpBuffer(dbQry);
3247 
3248  /*
3249  * Generates warning when loaded into a differently-named
3250  * database.
3251  */
3252  appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
3253  appendStringLiteralAH(dbQry, comment, fout);
3254  appendPQExpBufferStr(dbQry, ";\n");
3255 
3257  ARCHIVE_OPTS(.tag = labelq->data,
3258  .owner = dba,
3259  .description = "COMMENT",
3260  .section = SECTION_NONE,
3261  .createStmt = dbQry->data,
3262  .deps = &dbDumpId,
3263  .nDeps = 1));
3264  }
3265  }
3266 
3267  /* Dump DB security label, if enabled */
3268  if (!dopt->no_security_labels)
3269  {
3270  PGresult *shres;
3271  PQExpBuffer seclabelQry;
3272 
3273  seclabelQry = createPQExpBuffer();
3274 
3275  buildShSecLabelQuery("pg_database", dbCatId.oid, seclabelQry);
3276  shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
3277  resetPQExpBuffer(seclabelQry);
3278  emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
3279  if (seclabelQry->len > 0)
3281  ARCHIVE_OPTS(.tag = labelq->data,
3282  .owner = dba,
3283  .description = "SECURITY LABEL",
3284  .section = SECTION_NONE,
3285  .createStmt = seclabelQry->data,
3286  .deps = &dbDumpId,
3287  .nDeps = 1));
3288  destroyPQExpBuffer(seclabelQry);
3289  PQclear(shres);
3290  }
3291 
3292  /*
3293  * Dump ACL if any. Note that we do not support initial privileges
3294  * (pg_init_privs) on databases.
3295  */
3296  dbdacl.privtype = 0;
3297  dbdacl.initprivs = NULL;
3298 
3299  dumpACL(fout, dbDumpId, InvalidDumpId, "DATABASE",
3300  qdatname, NULL, NULL,
3301  NULL, dba, &dbdacl);
3302 
3303  /*
3304  * Now construct a DATABASE PROPERTIES archive entry to restore any
3305  * non-default database-level properties. (The reason this must be
3306  * separate is that we cannot put any additional commands into the TOC
3307  * entry that has CREATE DATABASE. pg_restore would execute such a group
3308  * in an implicit transaction block, and the backend won't allow CREATE
3309  * DATABASE in that context.)
3310  */
3311  resetPQExpBuffer(creaQry);
3312  resetPQExpBuffer(delQry);
3313 
3314  if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
3315  appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
3316  qdatname, datconnlimit);
3317 
3318  if (strcmp(datistemplate, "t") == 0)
3319  {
3320  appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
3321  qdatname);
3322 
3323  /*
3324  * The backend won't accept DROP DATABASE on a template database. We
3325  * can deal with that by removing the template marking before the DROP
3326  * gets issued. We'd prefer to use ALTER DATABASE IF EXISTS here, but
3327  * since no such command is currently supported, fake it with a direct
3328  * UPDATE on pg_database.
3329  */
3330  appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
3331  "SET datistemplate = false WHERE datname = ");
3332  appendStringLiteralAH(delQry, datname, fout);
3333  appendPQExpBufferStr(delQry, ";\n");
3334  }
3335 
3336  /*
3337  * We do not restore pg_database.dathasloginevt because it is set
3338  * automatically on login event trigger creation.
3339  */
3340 
3341  /* Add database-specific SET options */
3342  dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
3343 
3344  /*
3345  * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
3346  * entry, too, for lack of a better place.
3347  */
3348  if (dopt->binary_upgrade)
3349  {
3350  appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
3351  appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
3352  "SET datfrozenxid = '%u', datminmxid = '%u'\n"
3353  "WHERE datname = ",
3354  frozenxid, minmxid);
3355  appendStringLiteralAH(creaQry, datname, fout);
3356  appendPQExpBufferStr(creaQry, ";\n");
3357  }
3358 
3359  if (creaQry->len > 0)
3361  ARCHIVE_OPTS(.tag = datname,
3362  .owner = dba,
3363  .description = "DATABASE PROPERTIES",
3364  .section = SECTION_PRE_DATA,
3365  .createStmt = creaQry->data,
3366  .dropStmt = delQry->data,
3367  .deps = &dbDumpId));
3368 
3369  /*
3370  * pg_largeobject comes from the old system intact, so set its
3371  * relfrozenxids, relminmxids and relfilenode.
3372  */
3373  if (dopt->binary_upgrade)
3374  {
3375  PGresult *lo_res;
3376  PQExpBuffer loFrozenQry = createPQExpBuffer();
3377  PQExpBuffer loOutQry = createPQExpBuffer();
3378  PQExpBuffer loHorizonQry = createPQExpBuffer();
3379  int ii_relfrozenxid,
3380  ii_relfilenode,
3381  ii_oid,
3382  ii_relminmxid;
3383 
3384  /*
3385  * pg_largeobject
3386  */
3387  if (fout->remoteVersion >= 90300)
3388  appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid, relfilenode, oid\n"
3389  "FROM pg_catalog.pg_class\n"
3390  "WHERE oid IN (%u, %u);\n",
3391  LargeObjectRelationId, LargeObjectLOidPNIndexId);
3392  else
3393  appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid, relfilenode, oid\n"
3394  "FROM pg_catalog.pg_class\n"
3395  "WHERE oid IN (%u, %u);\n",
3396  LargeObjectRelationId, LargeObjectLOidPNIndexId);
3397 
3398  lo_res = ExecuteSqlQuery(fout, loFrozenQry->data, PGRES_TUPLES_OK);
3399 
3400  ii_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
3401  ii_relminmxid = PQfnumber(lo_res, "relminmxid");
3402  ii_relfilenode = PQfnumber(lo_res, "relfilenode");
3403  ii_oid = PQfnumber(lo_res, "oid");
3404 
3405  appendPQExpBufferStr(loHorizonQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
3406  appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, preserve pg_largeobject and index relfilenodes\n");
3407  for (int i = 0; i < PQntuples(lo_res); ++i)
3408  {
3409  Oid oid;
3410  RelFileNumber relfilenumber;
3411 
3412  appendPQExpBuffer(loHorizonQry, "UPDATE pg_catalog.pg_class\n"
3413  "SET relfrozenxid = '%u', relminmxid = '%u'\n"
3414  "WHERE oid = %u;\n",
3415  atooid(PQgetvalue(lo_res, i, ii_relfrozenxid)),
3416  atooid(PQgetvalue(lo_res, i, ii_relminmxid)),
3417  atooid(PQgetvalue(lo_res, i, ii_oid)));
3418 
3419  oid = atooid(PQgetvalue(lo_res, i, ii_oid));
3420  relfilenumber = atooid(PQgetvalue(lo_res, i, ii_relfilenode));
3421 
3422  if (oid == LargeObjectRelationId)
3423  appendPQExpBuffer(loOutQry,
3424  "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
3425  relfilenumber);
3426  else if (oid == LargeObjectLOidPNIndexId)
3427  appendPQExpBuffer(loOutQry,
3428  "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
3429  relfilenumber);
3430  }
3431 
3432  appendPQExpBufferStr(loOutQry,
3433  "TRUNCATE pg_catalog.pg_largeobject;\n");
3434  appendPQExpBufferStr(loOutQry, loHorizonQry->data);
3435 
3437  ARCHIVE_OPTS(.tag = "pg_largeobject",
3438  .description = "pg_largeobject",
3439  .section = SECTION_PRE_DATA,
3440  .createStmt = loOutQry->data));
3441 
3442  PQclear(lo_res);
3443 
3444  destroyPQExpBuffer(loFrozenQry);
3445  destroyPQExpBuffer(loHorizonQry);
3446  destroyPQExpBuffer(loOutQry);
3447  }
3448 
3449  PQclear(res);
3450 
3451  free(qdatname);
3452  destroyPQExpBuffer(dbQry);
3453  destroyPQExpBuffer(delQry);
3454  destroyPQExpBuffer(creaQry);
3455  destroyPQExpBuffer(labelq);
3456 }
3457 
3458 /*
3459  * Collect any database-specific or role-and-database-specific SET options
3460  * for this database, and append them to outbuf.
3461  */
3462 static void
3464  const char *dbname, Oid dboid)
3465 {
3466  PGconn *conn = GetConnection(AH);
3468  PGresult *res;
3469 
3470  /* First collect database-specific options */
3471  printfPQExpBuffer(buf, "SELECT unnest(setconfig) FROM pg_db_role_setting "
3472  "WHERE setrole = 0 AND setdatabase = '%u'::oid",
3473  dboid);
3474 
3475  res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3476 
3477  for (int i = 0; i < PQntuples(res); i++)
3479  "DATABASE", dbname, NULL, NULL,
3480  outbuf);
3481 
3482  PQclear(res);
3483 
3484  /* Now look for role-and-database-specific options */
3485  printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
3486  "FROM pg_db_role_setting s, pg_roles r "
3487  "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
3488  dboid);
3489 
3490  res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3491 
3492  for (int i = 0; i < PQntuples(res); i++)
3494  "ROLE", PQgetvalue(res, i, 0),
3495  "DATABASE", dbname,
3496  outbuf);
3497 
3498  PQclear(res);
3499 
3501 }
3502 
3503 /*
3504  * dumpEncoding: put the correct encoding into the archive
3505  */
3506 static void
3508 {
3509  const char *encname = pg_encoding_to_char(AH->encoding);
3511 
3512  pg_log_info("saving encoding = %s", encname);
3513 
3514  appendPQExpBufferStr(qry, "SET client_encoding = ");
3515  appendStringLiteralAH(qry, encname, AH);
3516  appendPQExpBufferStr(qry, ";\n");
3517 
3519  ARCHIVE_OPTS(.tag = "ENCODING",
3520  .description = "ENCODING",
3521  .section = SECTION_PRE_DATA,
3522  .createStmt = qry->data));
3523 
3524  destroyPQExpBuffer(qry);
3525 }
3526 
3527 
3528 /*
3529  * dumpStdStrings: put the correct escape string behavior into the archive
3530  */
3531 static void
3533 {
3534  const char *stdstrings = AH->std_strings ? "on" : "off";
3536 
3537  pg_log_info("saving standard_conforming_strings = %s",
3538  stdstrings);
3539 
3540  appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
3541  stdstrings);
3542 
3544  ARCHIVE_OPTS(.tag = "STDSTRINGS",
3545  .description = "STDSTRINGS",
3546  .section = SECTION_PRE_DATA,
3547  .createStmt = qry->data));
3548 
3549  destroyPQExpBuffer(qry);
3550 }
3551 
3552 /*
3553  * dumpSearchPath: record the active search_path in the archive
3554  */
3555 static void
3557 {
3559  PQExpBuffer path = createPQExpBuffer();
3560  PGresult *res;
3561  char **schemanames = NULL;
3562  int nschemanames = 0;
3563  int i;
3564 
3565  /*
3566  * We use the result of current_schemas(), not the search_path GUC,
3567  * because that might contain wildcards such as "$user", which won't
3568  * necessarily have the same value during restore. Also, this way avoids
3569  * listing schemas that may appear in search_path but not actually exist,
3570  * which seems like a prudent exclusion.
3571  */
3573  "SELECT pg_catalog.current_schemas(false)");
3574 
3575  if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
3576  pg_fatal("could not parse result of current_schemas()");
3577 
3578  /*
3579  * We use set_config(), not a simple "SET search_path" command, because
3580  * the latter has less-clean behavior if the search path is empty. While
3581  * that's likely to get fixed at some point, it seems like a good idea to
3582  * be as backwards-compatible as possible in what we put into archives.
3583  */
3584  for (i = 0; i < nschemanames; i++)
3585  {
3586  if (i > 0)
3587  appendPQExpBufferStr(path, ", ");
3588  appendPQExpBufferStr(path, fmtId(schemanames[i]));
3589  }
3590 
3591  appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
3592  appendStringLiteralAH(qry, path->data, AH);
3593  appendPQExpBufferStr(qry, ", false);\n");
3594 
3595  pg_log_info("saving search_path = %s", path->data);
3596 
3598  ARCHIVE_OPTS(.tag = "SEARCHPATH",
3599  .description = "SEARCHPATH",
3600  .section = SECTION_PRE_DATA,
3601  .createStmt = qry->data));
3602 
3603  /* Also save it in AH->searchpath, in case we're doing plain text dump */
3604  AH->searchpath = pg_strdup(qry->data);
3605 
3606  free(schemanames);
3607  PQclear(res);
3608  destroyPQExpBuffer(qry);
3609  destroyPQExpBuffer(path);
3610 }
3611 
3612 
3613 /*
3614  * getLOs:
3615  * Collect schema-level data about large objects
3616  */
3617 static void
3619 {
3620  DumpOptions *dopt = fout->dopt;
3621  PQExpBuffer loQry = createPQExpBuffer();
3622  PGresult *res;
3623  int ntups;
3624  int i;
3625  int n;
3626  int i_oid;
3627  int i_lomowner;
3628  int i_lomacl;
3629  int i_acldefault;
3630 
3631  pg_log_info("reading large objects");
3632 
3633  /*
3634  * Fetch LO OIDs and owner/ACL data. Order the data so that all the blobs
3635  * with the same owner/ACL appear together.
3636  */
3637  appendPQExpBufferStr(loQry,
3638  "SELECT oid, lomowner, lomacl, "
3639  "acldefault('L', lomowner) AS acldefault "
3640  "FROM pg_largeobject_metadata "
3641  "ORDER BY lomowner, lomacl::pg_catalog.text, oid");
3642 
3643  res = ExecuteSqlQuery(fout, loQry->data, PGRES_TUPLES_OK);
3644 
3645  i_oid = PQfnumber(res, "oid");
3646  i_lomowner = PQfnumber(res, "lomowner");
3647  i_lomacl = PQfnumber(res, "lomacl");
3648  i_acldefault = PQfnumber(res, "acldefault");
3649 
3650  ntups = PQntuples(res);
3651 
3652  /*
3653  * Group the blobs into suitably-sized groups that have the same owner and
3654  * ACL setting, and build a metadata and a data DumpableObject for each
3655  * group. (If we supported initprivs for blobs, we'd have to insist that
3656  * groups also share initprivs settings, since the DumpableObject only has
3657  * room for one.) i is the index of the first tuple in the current group,
3658  * and n is the number of tuples we include in the group.
3659  */
3660  for (i = 0; i < ntups; i += n)
3661  {
3662  Oid thisoid = atooid(PQgetvalue(res, i, i_oid));
3663  char *thisowner = PQgetvalue(res, i, i_lomowner);
3664  char *thisacl = PQgetvalue(res, i, i_lomacl);
3665  LoInfo *loinfo;
3666  DumpableObject *lodata;
3667  char namebuf[64];
3668 
3669  /* Scan to find first tuple not to be included in group */
3670  n = 1;
3671  while (n < MAX_BLOBS_PER_ARCHIVE_ENTRY && i + n < ntups)
3672  {
3673  if (strcmp(thisowner, PQgetvalue(res, i + n, i_lomowner)) != 0 ||
3674  strcmp(thisacl, PQgetvalue(res, i + n, i_lomacl)) != 0)
3675  break;
3676  n++;
3677  }
3678 
3679  /* Build the metadata DumpableObject */
3680  loinfo = (LoInfo *) pg_malloc(offsetof(LoInfo, looids) + n * sizeof(Oid));
3681 
3682  loinfo->dobj.objType = DO_LARGE_OBJECT;
3683  loinfo->dobj.catId.tableoid = LargeObjectRelationId;
3684  loinfo->dobj.catId.oid = thisoid;
3685  AssignDumpId(&loinfo->dobj);
3686 
3687  if (n > 1)
3688  snprintf(namebuf, sizeof(namebuf), "%u..%u", thisoid,
3689  atooid(PQgetvalue(res, i + n - 1, i_oid)));
3690  else
3691  snprintf(namebuf, sizeof(namebuf), "%u", thisoid);
3692  loinfo->dobj.name = pg_strdup(namebuf);
3693  loinfo->dacl.acl = pg_strdup(thisacl);
3694  loinfo->dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
3695  loinfo->dacl.privtype = 0;
3696  loinfo->dacl.initprivs = NULL;
3697  loinfo->rolname = getRoleName(thisowner);
3698  loinfo->numlos = n;
3699  loinfo->looids[0] = thisoid;
3700  /* Collect OIDs of the remaining blobs in this group */
3701  for (int k = 1; k < n; k++)
3702  {
3703  CatalogId extraID;
3704 
3705  loinfo->looids[k] = atooid(PQgetvalue(res, i + k, i_oid));
3706 
3707  /* Make sure we can look up loinfo by any of the blobs' OIDs */
3708  extraID.tableoid = LargeObjectRelationId;
3709  extraID.oid = loinfo->looids[k];
3710  recordAdditionalCatalogID(extraID, &loinfo->dobj);
3711  }
3712 
3713  /* LOs have data */
3714  loinfo->dobj.components |= DUMP_COMPONENT_DATA;
3715 
3716  /* Mark whether LO group has a non-empty ACL */
3717  if (!PQgetisnull(res, i, i_lomacl))
3718  loinfo->dobj.components |= DUMP_COMPONENT_ACL;
3719 
3720  /*
3721  * In binary-upgrade mode for LOs, we do *not* dump out the LO data,
3722  * as it will be copied by pg_upgrade, which simply copies the
3723  * pg_largeobject table. We *do* however dump out anything but the
3724  * data, as pg_upgrade copies just pg_largeobject, but not
3725  * pg_largeobject_metadata, after the dump is restored.
3726  */
3727  if (dopt->binary_upgrade)
3728  loinfo->dobj.dump &= ~DUMP_COMPONENT_DATA;
3729 
3730  /*
3731  * Create a "BLOBS" data item for the group, too. This is just a
3732  * placeholder for sorting; it carries no data now.
3733  */
3734  lodata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
3735  lodata->objType = DO_LARGE_OBJECT_DATA;
3736  lodata->catId = nilCatalogId;
3737  AssignDumpId(lodata);
3738  lodata->name = pg_strdup(namebuf);
3739  lodata->components |= DUMP_COMPONENT_DATA;
3740  /* Set up explicit dependency from data to metadata */
3741  lodata->dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
3742  lodata->dependencies[0] = loinfo->dobj.dumpId;
3743  lodata->nDeps = lodata->allocDeps = 1;
3744  }
3745 
3746  PQclear(res);
3747  destroyPQExpBuffer(loQry);
3748 }
3749 
3750 /*
3751  * dumpLO
3752  *
3753  * dump the definition (metadata) of the given large object group
3754  */
3755 static void
3756 dumpLO(Archive *fout, const LoInfo *loinfo)
3757 {
3758  PQExpBuffer cquery = createPQExpBuffer();
3759 
3760  /*
3761  * The "definition" is just a newline-separated list of OIDs. We need to
3762  * put something into the dropStmt too, but it can just be a comment.
3763  */
3764  for (int i = 0; i < loinfo->numlos; i++)
3765  appendPQExpBuffer(cquery, "%u\n", loinfo->looids[i]);
3766 
3767  if (loinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
3768  ArchiveEntry(fout, loinfo->dobj.catId, loinfo->dobj.dumpId,
3769  ARCHIVE_OPTS(.tag = loinfo->dobj.name,
3770  .owner = loinfo->rolname,
3771  .description = "BLOB METADATA",
3772  .section = SECTION_DATA,
3773  .createStmt = cquery->data,
3774  .dropStmt = "-- dummy"));
3775 
3776  /*
3777  * Dump per-blob comments and seclabels if any. We assume these are rare
3778  * enough that it's okay to generate retail TOC entries for them.
3779  */
3780  if (loinfo->dobj.dump & (DUMP_COMPONENT_COMMENT |
3782  {
3783  for (int i = 0; i < loinfo->numlos; i++)
3784  {
3785  CatalogId catId;
3786  char namebuf[32];
3787 
3788  /* Build identifying info for this blob */
3789  catId.tableoid = loinfo->dobj.catId.tableoid;
3790  catId.oid = loinfo->looids[i];
3791  snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[i]);
3792 
3793  if (loinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3794  dumpComment(fout, "LARGE OBJECT", namebuf,
3795  NULL, loinfo->rolname,
3796  catId, 0, loinfo->dobj.dumpId);
3797 
3798  if (loinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3799  dumpSecLabel(fout, "LARGE OBJECT", namebuf,
3800  NULL, loinfo->rolname,
3801  catId, 0, loinfo->dobj.dumpId);
3802  }
3803  }
3804 
3805  /*
3806  * Dump the ACLs if any (remember that all blobs in the group will have
3807  * the same ACL). If there's just one blob, dump a simple ACL entry; if
3808  * there's more, make a "LARGE OBJECTS" entry that really contains only
3809  * the ACL for the first blob. _printTocEntry() will be cued by the tag
3810  * string to emit a mutated version for each blob.
3811  */
3812  if (loinfo->dobj.dump & DUMP_COMPONENT_ACL)
3813  {
3814  char namebuf[32];
3815 
3816  /* Build identifying info for the first blob */
3817  snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[0]);
3818 
3819  if (loinfo->numlos > 1)
3820  {
3821  char tagbuf[64];
3822 
3823  snprintf(tagbuf, sizeof(tagbuf), "LARGE OBJECTS %u..%u",
3824  loinfo->looids[0], loinfo->looids[loinfo->numlos - 1]);
3825 
3826  dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
3827  "LARGE OBJECT", namebuf, NULL, NULL,
3828  tagbuf, loinfo->rolname, &loinfo->dacl);
3829  }
3830  else
3831  {
3832  dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
3833  "LARGE OBJECT", namebuf, NULL, NULL,
3834  NULL, loinfo->rolname, &loinfo->dacl);
3835  }
3836  }
3837 
3838  destroyPQExpBuffer(cquery);
3839 }
3840 
3841 /*
3842  * dumpLOs:
3843  * dump the data contents of the large objects in the given group
3844  */
3845 static int
3846 dumpLOs(Archive *fout, const void *arg)
3847 {
3848  const LoInfo *loinfo = (const LoInfo *) arg;
3849  PGconn *conn = GetConnection(fout);
3850  char buf[LOBBUFSIZE];
3851 
3852  pg_log_info("saving large objects \"%s\"", loinfo->dobj.name);
3853 
3854  for (int i = 0; i < loinfo->numlos; i++)
3855  {
3856  Oid loOid = loinfo->looids[i];
3857  int loFd;
3858  int cnt;
3859 
3860  /* Open the LO */
3861  loFd = lo_open(conn, loOid, INV_READ);
3862  if (loFd == -1)
3863  pg_fatal("could not open large object %u: %s",
3864  loOid, PQerrorMessage(conn));
3865 
3866  StartLO(fout, loOid);
3867 
3868  /* Now read it in chunks, sending data to archive */
3869  do
3870  {
3871  cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
3872  if (cnt < 0)
3873  pg_fatal("error reading large object %u: %s",
3874  loOid, PQerrorMessage(conn));
3875 
3876  WriteData(fout, buf, cnt);
3877  } while (cnt > 0);
3878 
3879  lo_close(conn, loFd);
3880 
3881  EndLO(fout, loOid);
3882  }
3883 
3884  return 1;
3885 }
3886 
3887 /*
3888  * getPolicies
3889  * get information about all RLS policies on dumpable tables.
3890  */
3891 void
3892 getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
3893 {
3894  PQExpBuffer query;
3895  PQExpBuffer tbloids;
3896  PGresult *res;
3897  PolicyInfo *polinfo;
3898  int i_oid;
3899  int i_tableoid;
3900  int i_polrelid;
3901  int i_polname;
3902  int i_polcmd;
3903  int i_polpermissive;
3904  int i_polroles;
3905  int i_polqual;
3906  int i_polwithcheck;
3907  int i,
3908  j,
3909  ntups;
3910 
3911  /* No policies before 9.5 */
3912  if (fout->remoteVersion < 90500)
3913  return;
3914 
3915  query = createPQExpBuffer();
3916  tbloids = createPQExpBuffer();
3917 
3918  /*
3919  * Identify tables of interest, and check which ones have RLS enabled.
3920  */
3921  appendPQExpBufferChar(tbloids, '{');
3922  for (i = 0; i < numTables; i++)
3923  {
3924  TableInfo *tbinfo = &tblinfo[i];
3925 
3926  /* Ignore row security on tables not to be dumped */
3927  if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
3928  continue;
3929 
3930  /* It can't have RLS or policies if it's not a table */
3931  if (tbinfo->relkind != RELKIND_RELATION &&
3932  tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
3933  continue;
3934 
3935  /* Add it to the list of table OIDs to be probed below */
3936  if (tbloids->len > 1) /* do we have more than the '{'? */
3937  appendPQExpBufferChar(tbloids, ',');
3938  appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
3939 
3940  /* Is RLS enabled? (That's separate from whether it has policies) */
3941  if (tbinfo->rowsec)
3942  {
3944 
3945  /*
3946  * We represent RLS being enabled on a table by creating a
3947  * PolicyInfo object with null polname.
3948  *
3949  * Note: use tableoid 0 so that this object won't be mistaken for
3950  * something that pg_depend entries apply to.
3951  */
3952  polinfo = pg_malloc(sizeof(PolicyInfo));
3953  polinfo->dobj.objType = DO_POLICY;
3954  polinfo->dobj.catId.tableoid = 0;
3955  polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
3956  AssignDumpId(&polinfo->dobj);
3957  polinfo->dobj.namespace = tbinfo->dobj.namespace;
3958  polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
3959  polinfo->poltable = tbinfo;
3960  polinfo->polname = NULL;
3961  polinfo->polcmd = '\0';
3962  polinfo->polpermissive = 0;
3963  polinfo->polroles = NULL;
3964  polinfo->polqual = NULL;
3965  polinfo->polwithcheck = NULL;
3966  }
3967  }
3968  appendPQExpBufferChar(tbloids, '}');
3969 
3970  /*
3971  * Now, read all RLS policies belonging to the tables of interest, and
3972  * create PolicyInfo objects for them. (Note that we must filter the
3973  * results server-side not locally, because we dare not apply pg_get_expr
3974  * to tables we don't have lock on.)
3975  */
3976  pg_log_info("reading row-level security policies");
3977 
3978  printfPQExpBuffer(query,
3979  "SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
3980  if (fout->remoteVersion >= 100000)
3981  appendPQExpBufferStr(query, "pol.polpermissive, ");
3982  else
3983  appendPQExpBufferStr(query, "'t' as polpermissive, ");
3984  appendPQExpBuffer(query,
3985  "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3986  " 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, "
3987  "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3988  "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3989  "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
3990  "JOIN pg_catalog.pg_policy pol ON (src.tbloid = pol.polrelid)",
3991  tbloids->data);
3992 
3993  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3994 
3995  ntups = PQntuples(res);
3996  if (ntups > 0)
3997  {
3998  i_oid = PQfnumber(res, "oid");
3999  i_tableoid = PQfnumber(res, "tableoid");
4000  i_polrelid = PQfnumber(res, "polrelid");
4001  i_polname = PQfnumber(res, "polname");
4002  i_polcmd = PQfnumber(res, "polcmd");
4003  i_polpermissive = PQfnumber(res, "polpermissive");
4004  i_polroles = PQfnumber(res, "polroles");
4005  i_polqual = PQfnumber(res, "polqual");
4006  i_polwithcheck = PQfnumber(res, "polwithcheck");
4007 
4008  polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
4009 
4010  for (j = 0; j < ntups; j++)
4011  {
4012  Oid polrelid = atooid(PQgetvalue(res, j, i_polrelid));
4013  TableInfo *tbinfo = findTableByOid(polrelid);
4014 
4016 
4017  polinfo[j].dobj.objType = DO_POLICY;
4018  polinfo[j].dobj.catId.tableoid =
4019  atooid(PQgetvalue(res, j, i_tableoid));
4020  polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
4021  AssignDumpId(&polinfo[j].dobj);
4022  polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4023  polinfo[j].poltable = tbinfo;
4024  polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
4025  polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
4026 
4027  polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
4028  polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
4029 
4030  if (PQgetisnull(res, j, i_polroles))
4031  polinfo[j].polroles = NULL;
4032  else
4033  polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
4034 
4035  if (PQgetisnull(res, j, i_polqual))
4036  polinfo[j].polqual = NULL;
4037  else
4038  polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
4039 
4040  if (PQgetisnull(res, j, i_polwithcheck))
4041  polinfo[j].polwithcheck = NULL;
4042  else
4043  polinfo[j].polwithcheck
4044  = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
4045  }
4046  }
4047 
4048  PQclear(res);
4049 
4050  destroyPQExpBuffer(query);
4051  destroyPQExpBuffer(tbloids);
4052 }
4053 
4054 /*
4055  * dumpPolicy
4056  * dump the definition of the given policy
4057  */
4058 static void
4059 dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
4060 {
4061  DumpOptions *dopt = fout->dopt;
4062  TableInfo *tbinfo = polinfo->poltable;
4063  PQExpBuffer query;
4064  PQExpBuffer delqry;
4065  PQExpBuffer polprefix;
4066  char *qtabname;
4067  const char *cmd;
4068  char *tag;
4069 
4070  /* Do nothing in data-only dump */
4071  if (dopt->dataOnly)
4072  return;
4073 
4074  /*
4075  * If polname is NULL, then this record is just indicating that ROW LEVEL
4076  * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
4077  * ROW LEVEL SECURITY.
4078  */
4079  if (polinfo->polname == NULL)
4080  {
4081  query = createPQExpBuffer();
4082 
4083  appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
4084  fmtQualifiedDumpable(tbinfo));
4085 
4086  /*
4087  * We must emit the ROW SECURITY object's dependency on its table
4088  * explicitly, because it will not match anything in pg_depend (unlike
4089  * the case for other PolicyInfo objects).
4090  */
4091  if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4092  ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
4093  ARCHIVE_OPTS(.tag = polinfo->dobj.name,
4094  .namespace = polinfo->dobj.namespace->dobj.name,
4095  .owner = tbinfo->rolname,
4096  .description = "ROW SECURITY",
4097  .section = SECTION_POST_DATA,
4098  .createStmt = query->data,
4099  .deps = &(tbinfo->dobj.dumpId),
4100  .nDeps = 1));
4101 
4102  destroyPQExpBuffer(query);
4103  return;
4104  }
4105 
4106  if (polinfo->polcmd == '*')
4107  cmd = "";
4108  else if (polinfo->polcmd == 'r')
4109  cmd = " FOR SELECT";
4110  else if (polinfo->polcmd == 'a')
4111  cmd = " FOR INSERT";
4112  else if (polinfo->polcmd == 'w')
4113  cmd = " FOR UPDATE";
4114  else if (polinfo->polcmd == 'd')
4115  cmd = " FOR DELETE";
4116  else
4117  pg_fatal("unexpected policy command type: %c",
4118  polinfo->polcmd);
4119 
4120  query = createPQExpBuffer();
4121  delqry = createPQExpBuffer();
4122  polprefix = createPQExpBuffer();
4123 
4124  qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
4125 
4126  appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
4127 
4128  appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
4129  !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
4130 
4131  if (polinfo->polroles != NULL)
4132  appendPQExpBuffer(query, " TO %s", polinfo->polroles);
4133 
4134  if (polinfo->polqual != NULL)
4135  appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
4136 
4137  if (polinfo->polwithcheck != NULL)
4138  appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
4139 
4140  appendPQExpBufferStr(query, ";\n");
4141 
4142  appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
4143  appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
4144 
4145  appendPQExpBuffer(polprefix, "POLICY %s ON",
4146  fmtId(polinfo->polname));
4147 
4148  tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
4149 
4150  if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4151  ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
4152  ARCHIVE_OPTS(.tag = tag,
4153  .namespace = polinfo->dobj.namespace->dobj.name,
4154  .owner = tbinfo->rolname,
4155  .description = "POLICY",
4156  .section = SECTION_POST_DATA,
4157  .createStmt = query->data,
4158  .dropStmt = delqry->data));
4159 
4160  if (polinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4161  dumpComment(fout, polprefix->data, qtabname,
4162  tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
4163  polinfo->dobj.catId, 0, polinfo->dobj.dumpId);
4164 
4165  free(tag);
4166  destroyPQExpBuffer(query);
4167  destroyPQExpBuffer(delqry);
4168  destroyPQExpBuffer(polprefix);
4169  free(qtabname);
4170 }
4171 
4172 /*
4173  * getPublications
4174  * get information about publications
4175  */
4177 getPublications(Archive *fout, int *numPublications)
4178 {
4179  DumpOptions *dopt = fout->dopt;
4180  PQExpBuffer query;
4181  PGresult *res;
4182  PublicationInfo *pubinfo;
4183  int i_tableoid;
4184  int i_oid;
4185  int i_pubname;
4186  int i_pubowner;
4187  int i_puballtables;
4188  int i_pubinsert;
4189  int i_pubupdate;
4190  int i_pubdelete;
4191  int i_pubtruncate;
4192  int i_pubviaroot;
4193  int i,
4194  ntups;
4195 
4196  if (dopt->no_publications || fout->remoteVersion < 100000)
4197  {
4198  *numPublications = 0;
4199  return NULL;
4200  }
4201 
4202  query = createPQExpBuffer();
4203 
4204  resetPQExpBuffer(query);
4205 
4206  /* Get the publications. */
4207  if (fout->remoteVersion >= 130000)
4208  appendPQExpBufferStr(query,
4209  "SELECT p.tableoid, p.oid, p.pubname, "
4210  "p.pubowner, "
4211  "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, p.pubtruncate, p.pubviaroot "
4212  "FROM pg_publication p");
4213  else if (fout->remoteVersion >= 110000)
4214  appendPQExpBufferStr(query,
4215  "SELECT p.tableoid, p.oid, p.pubname, "
4216  "p.pubowner, "
4217  "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, p.pubtruncate, false AS pubviaroot "
4218  "FROM pg_publication p");
4219  else
4220  appendPQExpBufferStr(query,
4221  "SELECT p.tableoid, p.oid, p.pubname, "
4222  "p.pubowner, "
4223  "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, false AS pubtruncate, false AS pubviaroot "
4224  "FROM pg_publication p");
4225 
4226  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4227 
4228  ntups = PQntuples(res);
4229 
4230  i_tableoid = PQfnumber(res, "tableoid");
4231  i_oid = PQfnumber(res, "oid");
4232  i_pubname = PQfnumber(res, "pubname");
4233  i_pubowner = PQfnumber(res, "pubowner");
4234  i_puballtables = PQfnumber(res, "puballtables");
4235  i_pubinsert = PQfnumber(res, "pubinsert");
4236  i_pubupdate = PQfnumber(res, "pubupdate");
4237  i_pubdelete = PQfnumber(res, "pubdelete");
4238  i_pubtruncate = PQfnumber(res, "pubtruncate");
4239  i_pubviaroot = PQfnumber(res, "pubviaroot");
4240 
4241  pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
4242 
4243  for (i = 0; i < ntups; i++)
4244  {
4245  pubinfo[i].dobj.objType = DO_PUBLICATION;
4246  pubinfo[i].dobj.catId.tableoid =
4247  atooid(PQgetvalue(res, i, i_tableoid));
4248  pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4249  AssignDumpId(&pubinfo[i].dobj);
4250  pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
4251  pubinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_pubowner));
4252  pubinfo[i].puballtables =
4253  (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
4254  pubinfo[i].pubinsert =
4255  (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
4256  pubinfo[i].pubupdate =
4257  (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
4258  pubinfo[i].pubdelete =
4259  (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
4260  pubinfo[i].pubtruncate =
4261  (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
4262  pubinfo[i].pubviaroot =
4263  (strcmp(PQgetvalue(res, i, i_pubviaroot), "t") == 0);
4264 
4265  /* Decide whether we want to dump it */
4266  selectDumpableObject(&(pubinfo[i].dobj), fout);
4267  }
4268  PQclear(res);
4269 
4270  destroyPQExpBuffer(query);
4271 
4272  *numPublications = ntups;
4273  return pubinfo;
4274 }
4275 
4276 /*
4277  * dumpPublication
4278  * dump the definition of the given publication
4279  */
4280 static void
4282 {
4283  DumpOptions *dopt = fout->dopt;
4284  PQExpBuffer delq;
4285  PQExpBuffer query;
4286  char *qpubname;
4287  bool first = true;
4288 
4289  /* Do nothing in data-only dump */
4290  if (dopt->dataOnly)
4291  return;
4292 
4293  delq = createPQExpBuffer();
4294  query = createPQExpBuffer();
4295 
4296  qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
4297 
4298  appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
4299  qpubname);
4300 
4301  appendPQExpBuffer(query, "CREATE PUBLICATION %s",
4302  qpubname);
4303 
4304  if (pubinfo->puballtables)
4305  appendPQExpBufferStr(query, " FOR ALL TABLES");
4306 
4307  appendPQExpBufferStr(query, " WITH (publish = '");
4308  if (pubinfo->pubinsert)
4309  {
4310  appendPQExpBufferStr(query, "insert");
4311  first = false;
4312  }
4313 
4314  if (pubinfo->pubupdate)
4315  {
4316  if (!first)
4317  appendPQExpBufferStr(query, ", ");
4318 
4319  appendPQExpBufferStr(query, "update");
4320  first = false;
4321  }
4322 
4323  if (pubinfo->pubdelete)
4324  {
4325  if (!first)
4326  appendPQExpBufferStr(query, ", ");
4327 
4328  appendPQExpBufferStr(query, "delete");
4329  first = false;
4330  }
4331 
4332  if (pubinfo->pubtruncate)
4333  {
4334  if (!first)
4335  appendPQExpBufferStr(query, ", ");
4336 
4337  appendPQExpBufferStr(query, "truncate");
4338  first = false;
4339  }
4340 
4341  appendPQExpBufferChar(query, '\'');
4342 
4343  if (pubinfo->pubviaroot)
4344  appendPQExpBufferStr(query, ", publish_via_partition_root = true");
4345 
4346  appendPQExpBufferStr(query, ");\n");
4347 
4348  if (pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4349  ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
4350  ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
4351  .owner = pubinfo->rolname,
4352  .description = "PUBLICATION",
4353  .section = SECTION_POST_DATA,
4354  .createStmt = query->data,
4355  .dropStmt = delq->data));
4356 
4357  if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4358  dumpComment(fout, "PUBLICATION", qpubname,
4359  NULL, pubinfo->rolname,
4360  pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
4361 
4362  if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
4363  dumpSecLabel(fout, "PUBLICATION", qpubname,
4364  NULL, pubinfo->rolname,
4365  pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
4366 
4367  destroyPQExpBuffer(delq);
4368  destroyPQExpBuffer(query);
4369  free(qpubname);
4370 }
4371 
4372 /*
4373  * getPublicationNamespaces
4374  * get information about publication membership for dumpable schemas.
4375  */
4376 void
4378 {
4379  PQExpBuffer query;
4380  PGresult *res;
4381  PublicationSchemaInfo *pubsinfo;
4382  DumpOptions *dopt = fout->dopt;
4383  int i_tableoid;
4384  int i_oid;
4385  int i_pnpubid;
4386  int i_pnnspid;
4387  int i,
4388  j,
4389  ntups;
4390 
4391  if (dopt->no_publications || fout->remoteVersion < 150000)
4392  return;
4393 
4394  query = createPQExpBuffer();
4395 
4396  /* Collect all publication membership info. */
4397  appendPQExpBufferStr(query,
4398  "SELECT tableoid, oid, pnpubid, pnnspid "
4399  "FROM pg_catalog.pg_publication_namespace");
4400  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4401 
4402  ntups = PQntuples(res);
4403 
4404  i_tableoid = PQfnumber(res, "tableoid");
4405  i_oid = PQfnumber(res, "oid");
4406  i_pnpubid = PQfnumber(res, "pnpubid");
4407  i_pnnspid = PQfnumber(res, "pnnspid");
4408 
4409  /* this allocation may be more than we need */
4410  pubsinfo = pg_malloc(ntups * sizeof(PublicationSchemaInfo));
4411  j = 0;
4412 
4413  for (i = 0; i < ntups; i++)
4414  {
4415  Oid pnpubid = atooid(PQgetvalue(res, i, i_pnpubid));
4416  Oid pnnspid = atooid(PQgetvalue(res, i, i_pnnspid));
4417  PublicationInfo *pubinfo;
4418  NamespaceInfo *nspinfo;
4419 
4420  /*
4421  * Ignore any entries for which we aren't interested in either the
4422  * publication or the rel.
4423  */
4424  pubinfo = findPublicationByOid(pnpubid);
4425  if (pubinfo == NULL)
4426  continue;
4427  nspinfo = findNamespaceByOid(pnnspid);
4428  if (nspinfo == NULL)
4429  continue;
4430 
4431  /*
4432  * We always dump publication namespaces unless the corresponding
4433  * namespace is excluded from the dump.
4434  */
4435  if (nspinfo->dobj.dump == DUMP_COMPONENT_NONE)
4436  continue;
4437 
4438  /* OK, make a DumpableObject for this relationship */
4440  pubsinfo[j].dobj.catId.tableoid =
4441  atooid(PQgetvalue(res, i, i_tableoid));
4442  pubsinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4443  AssignDumpId(&pubsinfo[j].dobj);
4444  pubsinfo[j].dobj.namespace = nspinfo->dobj.namespace;
4445  pubsinfo[j].dobj.name = nspinfo->dobj.name;
4446  pubsinfo[j].publication = pubinfo;
4447  pubsinfo[j].pubschema = nspinfo;
4448 
4449  /* Decide whether we want to dump it */
4450  selectDumpablePublicationObject(&(pubsinfo[j].dobj), fout);
4451 
4452  j++;
4453  }
4454 
4455  PQclear(res);
4456  destroyPQExpBuffer(query);
4457 }
4458 
4459 /*
4460  * getPublicationTables
4461  * get information about publication membership for dumpable tables.
4462  */
4463 void
4464 getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
4465 {
4466  PQExpBuffer query;
4467  PGresult *res;
4468  PublicationRelInfo *pubrinfo;
4469  DumpOptions *dopt = fout->dopt;
4470  int i_tableoid;
4471  int i_oid;
4472  int i_prpubid;
4473  int i_prrelid;
4474  int i_prrelqual;
4475  int i_prattrs;
4476  int i,
4477  j,
4478  ntups;
4479 
4480  if (dopt->no_publications || fout->remoteVersion < 100000)
4481  return;
4482 
4483  query = createPQExpBuffer();
4484 
4485  /* Collect all publication membership info. */
4486  if (fout->remoteVersion >= 150000)
4487  appendPQExpBufferStr(query,
4488  "SELECT tableoid, oid, prpubid, prrelid, "
4489  "pg_catalog.pg_get_expr(prqual, prrelid) AS prrelqual, "
4490  "(CASE\n"
4491  " WHEN pr.prattrs IS NOT NULL THEN\n"
4492  " (SELECT array_agg(attname)\n"
4493  " FROM\n"
4494  " pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,\n"
4495  " pg_catalog.pg_attribute\n"
4496  " WHERE attrelid = pr.prrelid AND attnum = prattrs[s])\n"
4497  " ELSE NULL END) prattrs "
4498  "FROM pg_catalog.pg_publication_rel pr");
4499  else
4500  appendPQExpBufferStr(query,
4501  "SELECT tableoid, oid, prpubid, prrelid, "
4502  "NULL AS prrelqual, NULL AS prattrs "
4503  "FROM pg_catalog.pg_publication_rel");
4504  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4505 
4506  ntups = PQntuples(res);
4507 
4508  i_tableoid = PQfnumber(res, "tableoid");
4509  i_oid = PQfnumber(res, "oid");
4510  i_prpubid = PQfnumber(res, "prpubid");
4511  i_prrelid = PQfnumber(res, "prrelid");
4512  i_prrelqual = PQfnumber(res, "prrelqual");
4513  i_prattrs = PQfnumber(res, "prattrs");
4514 
4515  /* this allocation may be more than we need */
4516  pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
4517  j = 0;
4518 
4519  for (i = 0; i < ntups; i++)
4520  {
4521  Oid prpubid = atooid(PQgetvalue(res, i, i_prpubid));
4522  Oid prrelid = atooid(PQgetvalue(res, i, i_prrelid));
4523  PublicationInfo *pubinfo;
4524  TableInfo *tbinfo;
4525 
4526  /*
4527  * Ignore any entries for which we aren't interested in either the
4528  * publication or the rel.
4529  */
4530  pubinfo = findPublicationByOid(prpubid);
4531  if (pubinfo == NULL)
4532  continue;
4533  tbinfo = findTableByOid(prrelid);
4534  if (tbinfo == NULL)
4535  continue;
4536 
4537  /*
4538  * Ignore publication membership of tables whose definitions are not
4539  * to be dumped.
4540  */
4541  if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
4542  continue;
4543 
4544  /* OK, make a DumpableObject for this relationship */
4545  pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
4546  pubrinfo[j].dobj.catId.tableoid =
4547  atooid(PQgetvalue(res, i, i_tableoid));
4548  pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4549  AssignDumpId(&pubrinfo[j].dobj);
4550  pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4551  pubrinfo[j].dobj.name = tbinfo->dobj.name;
4552  pubrinfo[j].publication = pubinfo;
4553  pubrinfo[j].pubtable = tbinfo;
4554  if (PQgetisnull(res, i, i_prrelqual))
4555  pubrinfo[j].pubrelqual = NULL;
4556  else
4557  pubrinfo[j].pubrelqual = pg_strdup(PQgetvalue(res, i, i_prrelqual));
4558 
4559  if (!PQgetisnull(res, i, i_prattrs))
4560  {
4561  char **attnames;
4562  int nattnames;
4563  PQExpBuffer attribs;
4564 
4565  if (!parsePGArray(PQgetvalue(res, i, i_prattrs),
4566  &attnames, &nattnames))
4567  pg_fatal("could not parse %s array", "prattrs");
4568  attribs = createPQExpBuffer();
4569  for (int k = 0; k < nattnames; k++)
4570  {
4571  if (k > 0)
4572  appendPQExpBufferStr(attribs, ", ");
4573 
4574  appendPQExpBufferStr(attribs, fmtId(attnames[k]));
4575  }
4576  pubrinfo[j].pubrattrs = attribs->data;
4577  }
4578  else
4579  pubrinfo[j].pubrattrs = NULL;
4580 
4581  /* Decide whether we want to dump it */
4582  selectDumpablePublicationObject(&(pubrinfo[j].dobj), fout);
4583 
4584  j++;
4585  }
4586 
4587  PQclear(res);
4588  destroyPQExpBuffer(query);
4589 }
4590 
4591 /*
4592  * dumpPublicationNamespace
4593  * dump the definition of the given publication schema mapping.
4594  */
4595 static void
4597 {
4598  DumpOptions *dopt = fout->dopt;
4599  NamespaceInfo *schemainfo = pubsinfo->pubschema;
4600  PublicationInfo *pubinfo = pubsinfo->publication;
4601  PQExpBuffer query;
4602  char *tag;
4603 
4604  /* Do nothing in data-only dump */
4605  if (dopt->dataOnly)
4606  return;
4607 
4608  tag = psprintf("%s %s", pubinfo->dobj.name, schemainfo->dobj.name);
4609 
4610  query = createPQExpBuffer();
4611 
4612  appendPQExpBuffer(query, "ALTER PUBLICATION %s ", fmtId(pubinfo->dobj.name));
4613  appendPQExpBuffer(query, "ADD TABLES IN SCHEMA %s;\n", fmtId(schemainfo->dobj.name));
4614 
4615  /*
4616  * There is no point in creating drop query as the drop is done by schema
4617  * drop.
4618  */
4619  if (pubsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4620  ArchiveEntry(fout, pubsinfo->dobj.catId, pubsinfo->dobj.dumpId,
4621  ARCHIVE_OPTS(.tag = tag,
4622  .namespace = schemainfo->dobj.name,
4623  .owner = pubinfo->rolname,
4624  .description = "PUBLICATION TABLES IN SCHEMA",
4625  .section = SECTION_POST_DATA,
4626  .createStmt = query->data));
4627 
4628  /* These objects can't currently have comments or seclabels */
4629 
4630  free(tag);
4631  destroyPQExpBuffer(query);
4632 }
4633 
4634 /*
4635  * dumpPublicationTable
4636  * dump the definition of the given publication table mapping
4637  */
4638 static void
4640 {
4641  DumpOptions *dopt = fout->dopt;
4642  PublicationInfo *pubinfo = pubrinfo->publication;
4643  TableInfo *tbinfo = pubrinfo->pubtable;
4644  PQExpBuffer query;
4645  char *tag;
4646 
4647  /* Do nothing in data-only dump */
4648  if (dopt->dataOnly)
4649  return;
4650 
4651  tag = psprintf("%s %s", pubinfo->dobj.name, tbinfo->dobj.name);
4652 
4653  query = createPQExpBuffer();
4654 
4655  appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
4656  fmtId(pubinfo->dobj.name));
4657  appendPQExpBuffer(query, " %s",
4658  fmtQualifiedDumpable(tbinfo));
4659 
4660  if (pubrinfo->pubrattrs)
4661  appendPQExpBuffer(query, " (%s)", pubrinfo->pubrattrs);
4662 
4663  if (pubrinfo->pubrelqual)
4664  {
4665  /*
4666  * It's necessary to add parentheses around the expression because
4667  * pg_get_expr won't supply the parentheses for things like WHERE
4668  * TRUE.
4669  */
4670  appendPQExpBuffer(query, " WHERE (%s)", pubrinfo->pubrelqual);
4671  }
4672  appendPQExpBufferStr(query, ";\n");
4673 
4674  /*
4675  * There is no point in creating a drop query as the drop is done by table
4676  * drop. (If you think to change this, see also _printTocEntry().)
4677  * Although this object doesn't really have ownership as such, set the
4678  * owner field anyway to ensure that the command is run by the correct
4679  * role at restore time.
4680  */
4681  if (pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4682  ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
4683  ARCHIVE_OPTS(.tag = tag,
4684  .namespace = tbinfo->dobj.namespace->dobj.name,
4685  .owner = pubinfo->rolname,
4686  .description = "PUBLICATION TABLE",
4687  .section = SECTION_POST_DATA,
4688  .createStmt = query->data));
4689 
4690  /* These objects can't currently have comments or seclabels */
4691 
4692  free(tag);
4693  destroyPQExpBuffer(query);
4694 }
4695 
4696 /*
4697  * Is the currently connected user a superuser?
4698  */
4699 static bool
4701 {
4702  ArchiveHandle *AH = (ArchiveHandle *) fout;
4703  const char *val;
4704 
4705  val = PQparameterStatus(AH->connection, "is_superuser");
4706 
4707  if (val && strcmp(val, "on") == 0)
4708  return true;
4709 
4710  return false;
4711 }
4712 
4713 /*
4714  * getSubscriptions
4715  * get information about subscriptions
4716  */
4717 void
4719 {
4720  DumpOptions *dopt = fout->dopt;
4721  PQExpBuffer query;
4722  PGresult *res;
4723  SubscriptionInfo *subinfo;
4724  int i_tableoid;
4725  int i_oid;
4726  int i_subname;
4727  int i_subowner;
4728  int i_subbinary;
4729  int i_substream;
4730  int i_subtwophasestate;
4731  int i_subdisableonerr;
4732  int i_subpasswordrequired;
4733  int i_subrunasowner;
4734  int i_subconninfo;
4735  int i_subslotname;
4736  int i_subsynccommit;
4737  int i_subpublications;
4738  int i_suborigin;
4739  int i_suboriginremotelsn;
4740  int i_subenabled;
4741  int i_subfailover;
4742  int i,
4743  ntups;
4744 
4745  if (dopt->no_subscriptions || fout->remoteVersion < 100000)
4746  return;
4747 
4748  if (!is_superuser(fout))
4749  {
4750  int n;
4751 
4752  res = ExecuteSqlQuery(fout,
4753  "SELECT count(*) FROM pg_subscription "
4754  "WHERE subdbid = (SELECT oid FROM pg_database"
4755  " WHERE datname = current_database())",
4756  PGRES_TUPLES_OK);
4757  n = atoi(PQgetvalue(res, 0, 0));
4758  if (n > 0)
4759  pg_log_warning("subscriptions not dumped because current user is not a superuser");
4760  PQclear(res);
4761  return;
4762  }
4763 
4764  query = createPQExpBuffer();
4765 
4766  /* Get the subscriptions in current database. */
4767  appendPQExpBufferStr(query,
4768  "SELECT s.tableoid, s.oid, s.subname,\n"
4769  " s.subowner,\n"
4770  " s.subconninfo, s.subslotname, s.subsynccommit,\n"
4771  " s.subpublications,\n");
4772 
4773  if (fout->remoteVersion >= 140000)
4774  appendPQExpBufferStr(query, " s.subbinary,\n");
4775  else
4776  appendPQExpBufferStr(query, " false AS subbinary,\n");
4777 
4778  if (fout->remoteVersion >= 140000)
4779  appendPQExpBufferStr(query, " s.substream,\n");
4780  else
4781  appendPQExpBufferStr(query, " 'f' AS substream,\n");
4782 
4783  if (fout->remoteVersion >= 150000)
4784  appendPQExpBufferStr(query,
4785  " s.subtwophasestate,\n"
4786  " s.subdisableonerr,\n");
4787  else
4788  appendPQExpBuffer(query,
4789  " '%c' AS subtwophasestate,\n"
4790  " false AS subdisableonerr,\n",
4792 
4793  if (fout->remoteVersion >= 160000)
4794  appendPQExpBufferStr(query,
4795  " s.subpasswordrequired,\n"
4796  " s.subrunasowner,\n"
4797  " s.suborigin,\n");
4798  else
4799  appendPQExpBuffer(query,
4800  " 't' AS subpasswordrequired,\n"
4801  " 't' AS subrunasowner,\n"
4802  " '%s' AS suborigin,\n",
4804 
4805  if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
4806  appendPQExpBufferStr(query, " o.remote_lsn AS suboriginremotelsn,\n"
4807  " s.subenabled,\n");
4808  else
4809  appendPQExpBufferStr(query, " NULL AS suboriginremotelsn,\n"
4810  " false AS subenabled,\n");
4811 
4812  if (fout->remoteVersion >= 170000)
4813  appendPQExpBufferStr(query,
4814  " s.subfailover\n");
4815  else
4816  appendPQExpBuffer(query,
4817  " false AS subfailover\n");
4818 
4819  appendPQExpBufferStr(query,
4820  "FROM pg_subscription s\n");
4821 
4822  if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
4823  appendPQExpBufferStr(query,
4824  "LEFT JOIN pg_catalog.pg_replication_origin_status o \n"
4825  " ON o.external_id = 'pg_' || s.oid::text \n");
4826 
4827  appendPQExpBufferStr(query,
4828  "WHERE s.subdbid = (SELECT oid FROM pg_database\n"
4829  " WHERE datname = current_database())");
4830 
4831  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4832 
4833  ntups = PQntuples(res);
4834 
4835  /*
4836  * Get subscription fields. We don't include subskiplsn in the dump as
4837  * after restoring the dump this value may no longer be relevant.
4838  */
4839  i_tableoid = PQfnumber(res, "tableoid");
4840  i_oid = PQfnumber(res, "oid");
4841  i_subname = PQfnumber(res, "subname");
4842  i_subowner = PQfnumber(res, "subowner");
4843  i_subbinary = PQfnumber(res, "subbinary");
4844  i_substream = PQfnumber(res, "substream");
4845  i_subtwophasestate = PQfnumber(res, "subtwophasestate");
4846  i_subdisableonerr = PQfnumber(res, "subdisableonerr");
4847  i_subpasswordrequired = PQfnumber(res, "subpasswordrequired");
4848  i_subrunasowner = PQfnumber(res, "subrunasowner");
4849  i_subconninfo = PQfnumber(res, "subconninfo");
4850  i_subslotname = PQfnumber(res, "subslotname");
4851  i_subsynccommit = PQfnumber(res, "subsynccommit");
4852  i_subpublications = PQfnumber(res, "subpublications");
4853  i_suborigin = PQfnumber(res, "suborigin");
4854  i_suboriginremotelsn = PQfnumber(res, "suboriginremotelsn");
4855  i_subenabled = PQfnumber(res, "subenabled");
4856  i_subfailover = PQfnumber(res, "subfailover");
4857 
4858  subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
4859 
4860  for (i = 0; i < ntups; i++)
4861  {
4862  subinfo[i].dobj.objType = DO_SUBSCRIPTION;
4863  subinfo[i].dobj.catId.tableoid =
4864  atooid(PQgetvalue(res, i, i_tableoid));
4865  subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4866  AssignDumpId(&subinfo[i].dobj);
4867  subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
4868  subinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_subowner));
4869 
4870  subinfo[i].subbinary =
4871  pg_strdup(PQgetvalue(res, i, i_subbinary));
4872  subinfo[i].substream =
4873  pg_strdup(PQgetvalue(res, i, i_substream));
4874  subinfo[i].subtwophasestate =
4875  pg_strdup(PQgetvalue(res, i, i_subtwophasestate));
4876  subinfo[i].subdisableonerr =
4877  pg_strdup(PQgetvalue(res, i, i_subdisableonerr));
4878  subinfo[i].subpasswordrequired =
4879  pg_strdup(PQgetvalue(res, i, i_subpasswordrequired));
4880  subinfo[i].subrunasowner =
4881  pg_strdup(PQgetvalue(res, i, i_subrunasowner));
4882  subinfo[i].subconninfo =
4883  pg_strdup(PQgetvalue(res, i, i_subconninfo));
4884  if (PQgetisnull(res, i, i_subslotname))
4885  subinfo[i].subslotname = NULL;
4886  else
4887  subinfo[i].subslotname =
4888  pg_strdup(PQgetvalue(res, i, i_subslotname));
4889  subinfo[i].subsynccommit =
4890  pg_strdup(PQgetvalue(res, i, i_subsynccommit));
4891  subinfo[i].subpublications =
4892  pg_strdup(PQgetvalue(res, i, i_subpublications));
4893  subinfo[i].suborigin = pg_strdup(PQgetvalue(res, i, i_suborigin));
4894  if (PQgetisnull(res, i, i_suboriginremotelsn))
4895  subinfo[i].suboriginremotelsn = NULL;
4896  else
4897  subinfo[i].suboriginremotelsn =
4898  pg_strdup(PQgetvalue(res, i, i_suboriginremotelsn));
4899  subinfo[i].subenabled =
4900  pg_strdup(PQgetvalue(res, i, i_subenabled));
4901  subinfo[i].subfailover =
4902  pg_strdup(PQgetvalue(res, i, i_subfailover));
4903 
4904  /* Decide whether we want to dump it */
4905  selectDumpableObject(&(subinfo[i].dobj), fout);
4906  }
4907  PQclear(res);
4908 
4909  destroyPQExpBuffer(query);
4910 }
4911 
4912 /*
4913  * getSubscriptionTables
4914  * Get information about subscription membership for dumpable tables. This
4915  * will be used only in binary-upgrade mode for PG17 or later versions.
4916  */
4917 void
4919 {
4920  DumpOptions *dopt = fout->dopt;
4921  SubscriptionInfo *subinfo = NULL;
4922  SubRelInfo *subrinfo;
4923  PGresult *res;
4924  int i_srsubid;
4925  int i_srrelid;
4926  int i_srsubstate;
4927  int i_srsublsn;
4928  int ntups;
4929  Oid last_srsubid = InvalidOid;
4930 
4931  if (dopt->no_subscriptions || !dopt->binary_upgrade ||
4932  fout->remoteVersion < 170000)
4933  return;
4934 
4935  res = ExecuteSqlQuery(fout,
4936  "SELECT srsubid, srrelid, srsubstate, srsublsn "
4937  "FROM pg_catalog.pg_subscription_rel "
4938  "ORDER BY srsubid",
4939  PGRES_TUPLES_OK);
4940  ntups = PQntuples(res);
4941  if (ntups == 0)
4942  goto cleanup;
4943 
4944  /* Get pg_subscription_rel attributes */
4945  i_srsubid = PQfnumber(res, "srsubid");
4946  i_srrelid = PQfnumber(res, "srrelid");
4947  i_srsubstate = PQfnumber(res, "srsubstate");
4948  i_srsublsn = PQfnumber(res, "srsublsn");
4949 
4950  subrinfo = pg_malloc(ntups * sizeof(SubRelInfo));
4951  for (int i = 0; i < ntups; i++)
4952  {
4953  Oid cur_srsubid = atooid(PQgetvalue(res, i, i_srsubid));
4954  Oid relid = atooid(PQgetvalue(res, i, i_srrelid));
4955  TableInfo *tblinfo;
4956 
4957  /*
4958  * If we switched to a new subscription, check if the subscription
4959  * exists.
4960  */
4961  if (cur_srsubid != last_srsubid)
4962  {
4963  subinfo = findSubscriptionByOid(cur_srsubid);
4964  if (subinfo == NULL)
4965  pg_fatal("subscription with OID %u does not exist", cur_srsubid);
4966 
4967  last_srsubid = cur_srsubid;
4968  }
4969 
4970  tblinfo = findTableByOid(relid);
4971  if (tblinfo == NULL)
4972  pg_fatal("failed sanity check, table with OID %u not found",
4973  relid);
4974 
4975  /* OK, make a DumpableObject for this relationship */
4976  subrinfo[i].dobj.objType = DO_SUBSCRIPTION_REL;
4977  subrinfo[i].dobj.catId.tableoid = relid;
4978  subrinfo[i].dobj.catId.oid = cur_srsubid;
4979  AssignDumpId(&subrinfo[i].dobj);
4980  subrinfo[i].dobj.name = pg_strdup(subinfo->dobj.name);
4981  subrinfo[i].tblinfo = tblinfo;
4982  subrinfo[i].srsubstate = PQgetvalue(res, i, i_srsubstate)[0];
4983  if (PQgetisnull(res, i, i_srsublsn))
4984  subrinfo[i].srsublsn = NULL;
4985  else
4986  subrinfo[i].srsublsn = pg_strdup(PQgetvalue(res, i, i_srsublsn));
4987 
4988  subrinfo[i].subinfo = subinfo;
4989 
4990  /* Decide whether we want to dump it */
4991  selectDumpableObject(&(subrinfo[i].dobj), fout);
4992  }
4993 
4994 cleanup:
4995  PQclear(res);
4996 }
4997 
4998 /*
4999  * dumpSubscriptionTable
5000  * Dump the definition of the given subscription table mapping. This will be
5001  * used only in binary-upgrade mode for PG17 or later versions.
5002  */
5003 static void
5005 {
5006  DumpOptions *dopt = fout->dopt;
5007  SubscriptionInfo *subinfo = subrinfo->subinfo;
5008  PQExpBuffer query;
5009  char *tag;
5010 
5011  /* Do nothing in data-only dump */
5012  if (dopt->dataOnly)
5013  return;
5014 
5015  Assert(fout->dopt->binary_upgrade && fout->remoteVersion >= 170000);
5016 
5017  tag = psprintf("%s %s", subinfo->dobj.name, subrinfo->dobj.name);
5018 
5019  query = createPQExpBuffer();
5020 
5021  if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5022  {
5023  /*
5024  * binary_upgrade_add_sub_rel_state will add the subscription relation
5025  * to pg_subscription_rel table. This will be used only in
5026  * binary-upgrade mode.
5027  */
5028  appendPQExpBufferStr(query,
5029  "\n-- For binary upgrade, must preserve the subscriber table.\n");
5030  appendPQExpBufferStr(query,
5031  "SELECT pg_catalog.binary_upgrade_add_sub_rel_state(");
5032  appendStringLiteralAH(query, subrinfo->dobj.name, fout);
5033  appendPQExpBuffer(query,
5034  ", %u, '%c'",
5035  subrinfo->tblinfo->dobj.catId.oid,
5036  subrinfo->srsubstate);
5037 
5038  if (subrinfo->srsublsn && subrinfo->srsublsn[0] != '\0')
5039  appendPQExpBuffer(query, ", '%s'", subrinfo->srsublsn);
5040  else
5041  appendPQExpBuffer(query, ", NULL");
5042 
5043  appendPQExpBufferStr(query, ");\n");
5044  }
5045 
5046  /*
5047  * There is no point in creating a drop query as the drop is done by table
5048  * drop. (If you think to change this, see also _printTocEntry().)
5049  * Although this object doesn't really have ownership as such, set the
5050  * owner field anyway to ensure that the command is run by the correct
5051  * role at restore time.
5052  */
5053  if (subrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5054  ArchiveEntry(fout, subrinfo->dobj.catId, subrinfo->dobj.dumpId,
5055  ARCHIVE_OPTS(.tag = tag,
5056  .namespace = subrinfo->tblinfo->dobj.namespace->dobj.name,
5057  .owner = subinfo->rolname,
5058  .description = "SUBSCRIPTION TABLE",
5059  .section = SECTION_POST_DATA,
5060  .createStmt = query->data));
5061 
5062  /* These objects can't currently have comments or seclabels */
5063 
5064  free(tag);
5065  destroyPQExpBuffer(query);
5066 }
5067 
5068 /*
5069  * dumpSubscription
5070  * dump the definition of the given subscription
5071  */
5072 static void
5074 {
5075  DumpOptions *dopt = fout->dopt;
5076  PQExpBuffer delq;
5077  PQExpBuffer query;
5078  PQExpBuffer publications;
5079  char *qsubname;
5080  char **pubnames = NULL;
5081  int npubnames = 0;
5082  int i;
5083  char two_phase_disabled[] = {LOGICALREP_TWOPHASE_STATE_DISABLED, '\0'};
5084 
5085  /* Do nothing in data-only dump */
5086  if (dopt->dataOnly)
5087  return;
5088 
5089  delq = createPQExpBuffer();
5090  query = createPQExpBuffer();
5091 
5092  qsubname = pg_strdup(fmtId(subinfo->dobj.name));
5093 
5094  appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
5095  qsubname);
5096 
5097  appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
5098  qsubname);
5099  appendStringLiteralAH(query, subinfo->subconninfo, fout);
5100 
5101  /* Build list of quoted publications and append them to query. */
5102  if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
5103  pg_fatal("could not parse %s array", "subpublications");
5104 
5105  publications = createPQExpBuffer();
5106  for (i = 0; i < npubnames; i++)
5107  {
5108  if (i > 0)
5109  appendPQExpBufferStr(publications, ", ");
5110 
5111  appendPQExpBufferStr(publications, fmtId(pubnames[i]));
5112  }
5113 
5114  appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
5115  if (subinfo->subslotname)
5116  appendStringLiteralAH(query, subinfo->subslotname, fout);
5117  else
5118  appendPQExpBufferStr(query, "NONE");
5119 
5120  if (strcmp(subinfo->subbinary, "t") == 0)
5121  appendPQExpBufferStr(query, ", binary = true");
5122 
5123  if (strcmp(subinfo->substream, "t") == 0)
5124  appendPQExpBufferStr(query, ", streaming = on");
5125  else if (strcmp(subinfo->substream, "p") == 0)
5126  appendPQExpBufferStr(query, ", streaming = parallel");
5127 
5128  if (strcmp(subinfo->subtwophasestate, two_phase_disabled) != 0)
5129  appendPQExpBufferStr(query, ", two_phase = on");
5130 
5131  if (strcmp(subinfo->subdisableonerr, "t") == 0)
5132  appendPQExpBufferStr(query, ", disable_on_error = true");
5133 
5134  if (strcmp(subinfo->subpasswordrequired, "t") != 0)
5135  appendPQExpBuffer(query, ", password_required = false");
5136 
5137  if (strcmp(subinfo->subrunasowner, "t") == 0)
5138  appendPQExpBufferStr(query, ", run_as_owner = true");
5139 
5140  if (strcmp(subinfo->subfailover, "t") == 0)
5141  appendPQExpBufferStr(query, ", failover = true");
5142 
5143  if (strcmp(subinfo->subsynccommit, "off") != 0)
5144  appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
5145 
5146  if (pg_strcasecmp(subinfo->suborigin, LOGICALREP_ORIGIN_ANY) != 0)
5147  appendPQExpBuffer(query, ", origin = %s", subinfo->suborigin);
5148 
5149  appendPQExpBufferStr(query, ");\n");
5150 
5151  /*
5152  * In binary-upgrade mode, we allow the replication to continue after the
5153  * upgrade.
5154  */
5155  if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
5156  {
5157  if (subinfo->suboriginremotelsn)
5158  {
5159  /*
5160  * Preserve the remote_lsn for the subscriber's replication
5161  * origin. This value is required to start the replication from
5162  * the position before the upgrade. This value will be stale if
5163  * the publisher gets upgraded before the subscriber node.
5164  * However, this shouldn't be a problem as the upgrade of the
5165  * publisher ensures that all the transactions were replicated
5166  * before upgrading it.
5167  */
5168  appendPQExpBufferStr(query,
5169  "\n-- For binary upgrade, must preserve the remote_lsn for the subscriber's replication origin.\n");
5170  appendPQExpBufferStr(query,
5171  "SELECT pg_catalog.binary_upgrade_replorigin_advance(");
5172  appendStringLiteralAH(query, subinfo->dobj.name, fout);
5173  appendPQExpBuffer(query, ", '%s');\n", subinfo->suboriginremotelsn);
5174  }
5175 
5176  if (strcmp(subinfo->subenabled, "t") == 0)
5177  {
5178  /*
5179  * Enable the subscription to allow the replication to continue
5180  * after the upgrade.
5181  */
5182  appendPQExpBufferStr(query,
5183  "\n-- For binary upgrade, must preserve the subscriber's running state.\n");
5184  appendPQExpBuffer(query, "ALTER SUBSCRIPTION %s ENABLE;\n", qsubname);
5185  }
5186  }
5187 
5188  if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5189  ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
5190  ARCHIVE_OPTS(.tag = subinfo->dobj.name,
5191  .owner = subinfo->rolname,
5192  .description = "SUBSCRIPTION",
5193  .section = SECTION_POST_DATA,
5194  .createStmt = query->data,
5195  .dropStmt = delq->data));
5196 
5197  if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
5198  dumpComment(fout, "SUBSCRIPTION", qsubname,
5199  NULL, subinfo->rolname,
5200  subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
5201 
5202  if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
5203  dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
5204  NULL, subinfo->rolname,
5205  subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
5206 
5207  destroyPQExpBuffer(publications);
5208  free(pubnames);
5209 
5210  destroyPQExpBuffer(delq);
5211  destroyPQExpBuffer(query);
5212  free(qsubname);
5213 }
5214 
5215 /*
5216  * Given a "create query", append as many ALTER ... DEPENDS ON EXTENSION as
5217  * the object needs.
5218  */
5219 static void
5221  PQExpBuffer create,
5222  const DumpableObject *dobj,
5223  const char *catalog,
5224  const char *keyword,
5225  const char *objname)
5226 {
5227  if (dobj->depends_on_ext)
5228  {
5229  char *nm;
5230  PGresult *res;
5231  PQExpBuffer query;
5232  int ntups;
5233  int i_extname;
5234  int i;
5235 
5236  /* dodge fmtId() non-reentrancy */
5237  nm = pg_strdup(objname);
5238 
5239  query = createPQExpBuffer();
5240  appendPQExpBuffer(query,
5241  "SELECT e.extname "
5242  "FROM pg_catalog.pg_depend d, pg_catalog.pg_extension e "
5243  "WHERE d.refobjid = e.oid AND classid = '%s'::pg_catalog.regclass "
5244  "AND objid = '%u'::pg_catalog.oid AND deptype = 'x' "
5245  "AND refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass",
5246  catalog,
5247  dobj->catId.oid);
5248  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5249  ntups = PQntuples(res);
5250  i_extname = PQfnumber(res, "extname");
5251  for (i = 0; i < ntups; i++)
5252  {
5253  appendPQExpBuffer(create, "\nALTER %s %s DEPENDS ON EXTENSION %s;",
5254  keyword, nm,
5255  fmtId(PQgetvalue(res, i, i_extname)));
5256  }
5257 
5258  PQclear(res);
5259  destroyPQExpBuffer(query);
5260  pg_free(nm);
5261  }
5262 }
5263 
5264 static Oid
5266 {
5267  /*
5268  * If the old version didn't assign an array type, but the new version
5269  * does, we must select an unused type OID to assign. This currently only
5270  * happens for domains, when upgrading pre-v11 to v11 and up.
5271  *
5272  * Note: local state here is kind of ugly, but we must have some, since we
5273  * mustn't choose the same unused OID more than once.
5274  */
5275  static Oid next_possible_free_oid = FirstNormalObjectId;
5276  PGresult *res;
5277  bool is_dup;
5278 
5279  do
5280  {
5281  ++next_possible_free_oid;
5282  printfPQExpBuffer(upgrade_query,
5283  "SELECT EXISTS(SELECT 1 "
5284  "FROM pg_catalog.pg_type "
5285  "WHERE oid = '%u'::pg_catalog.oid);",
5286  next_possible_free_oid);
5287  res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
5288  is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
5289  PQclear(res);
5290  } while (is_dup);
5291 
5292  return next_possible_free_oid;
5293 }
5294 
5295 static void
5297  PQExpBuffer upgrade_buffer,
5298  Oid pg_type_oid,
5299  bool force_array_type,
5300  bool include_multirange_type)
5301 {
5302  PQExpBuffer upgrade_query = createPQExpBuffer();
5303  PGresult *res;
5304  Oid pg_type_array_oid;
5305  Oid pg_type_multirange_oid;
5306  Oid pg_type_multirange_array_oid;
5307 
5308  appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
5309  appendPQExpBuffer(upgrade_buffer,
5310  "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5311  pg_type_oid);
5312 
5313  appendPQExpBuffer(upgrade_query,
5314  "SELECT typarray "
5315  "FROM pg_catalog.pg_type "
5316  "WHERE oid = '%u'::pg_catalog.oid;",
5317  pg_type_oid);
5318 
5319  res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
5320 
5321  pg_type_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
5322 
5323  PQclear(res);
5324 
5325  if (!OidIsValid(pg_type_array_oid) && force_array_type)
5326  pg_type_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
5327 
5328  if (OidIsValid(pg_type_array_oid))
5329  {
5330  appendPQExpBufferStr(upgrade_buffer,
5331  "\n-- For binary upgrade, must preserve pg_type array oid\n");
5332  appendPQExpBuffer(upgrade_buffer,
5333  "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5334  pg_type_array_oid);
5335  }
5336 
5337  /*
5338  * Pre-set the multirange type oid and its own array type oid.
5339  */
5340  if (include_multirange_type)
5341  {
5342  if (fout->remoteVersion >= 140000)
5343  {
5344  printfPQExpBuffer(upgrade_query,
5345  "SELECT t.oid, t.typarray "
5346  "FROM pg_catalog.pg_type t "
5347  "JOIN pg_catalog.pg_range r "
5348  "ON t.oid = r.rngmultitypid "
5349  "WHERE r.rngtypid = '%u'::pg_catalog.oid;",
5350  pg_type_oid);
5351 
5352  res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
5353 
5354  pg_type_multirange_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
5355  pg_type_multirange_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
5356 
5357  PQclear(res);
5358  }
5359  else
5360  {
5361  pg_type_multirange_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
5362  pg_type_multirange_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
5363  }
5364 
5365  appendPQExpBufferStr(upgrade_buffer,
5366  "\n-- For binary upgrade, must preserve multirange pg_type oid\n");
5367  appendPQExpBuffer(upgrade_buffer,
5368  "SELECT pg_catalog.binary_upgrade_set_next_multirange_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5369  pg_type_multirange_oid);
5370  appendPQExpBufferStr(upgrade_buffer,
5371  "\n-- For binary upgrade, must preserve multirange pg_type array oid\n");
5372  appendPQExpBuffer(upgrade_buffer,
5373  "SELECT pg_catalog.binary_upgrade_set_next_multirange_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5374  pg_type_multirange_array_oid);
5375  }
5376 
5377  destroyPQExpBuffer(upgrade_query);
5378 }
5379 
5380 static void
5382  PQExpBuffer upgrade_buffer,
5383  const TableInfo *tbinfo)
5384 {
5385  Oid pg_type_oid = tbinfo->reltype;
5386 
5387  if (OidIsValid(pg_type_oid))
5388  binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
5389  pg_type_oid, false, false);
5390 }
5391 
5392 static void
5394  PQExpBuffer upgrade_buffer, Oid pg_class_oid,
5395  bool is_index)
5396 {
5397  PQExpBuffer upgrade_query = createPQExpBuffer();
5398  PGresult *upgrade_res;
5399  RelFileNumber relfilenumber;
5400  Oid toast_oid;
5401  RelFileNumber toast_relfilenumber;
5402  char relkind;
5403  Oid toast_index_oid;
5404  RelFileNumber toast_index_relfilenumber;
5405 
5406  /*
5407  * Preserve the OID and relfilenumber of the table, table's index, table's
5408  * toast table and toast table's index if any.
5409  *
5410  * One complexity is that the current table definition might not require
5411  * the creation of a TOAST table, but the old database might have a TOAST
5412  * table that was created earlier, before some wide columns were dropped.
5413  * By setting the TOAST oid we force creation of the TOAST heap and index
5414  * by the new backend, so we can copy the files during binary upgrade
5415  * without worrying about this case.
5416  */
5417  appendPQExpBuffer(upgrade_query,
5418  "SELECT c.relkind, c.relfilenode, c.reltoastrelid, ct.relfilenode AS toast_relfilenode, i.indexrelid, cti.relfilenode AS toast_index_relfilenode "
5419  "FROM pg_catalog.pg_class c LEFT JOIN "
5420  "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
5421  "LEFT JOIN pg_catalog.pg_class ct ON (c.reltoastrelid = ct.oid) "
5422  "LEFT JOIN pg_catalog.pg_class AS cti ON (i.indexrelid = cti.oid) "
5423  "WHERE c.oid = '%u'::pg_catalog.oid;",
5424  pg_class_oid);
5425 
5426  upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
5427 
5428  relkind = *PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "relkind"));
5429 
5430  relfilenumber = atooid(PQgetvalue(upgrade_res, 0,
5431  PQfnumber(upgrade_res, "relfilenode")));
5432  toast_oid = atooid(PQgetvalue(upgrade_res, 0,
5433  PQfnumber(upgrade_res, "reltoastrelid")));
5434  toast_relfilenumber = atooid(PQgetvalue(upgrade_res, 0,
5435  PQfnumber(upgrade_res, "toast_relfilenode")));
5436  toast_index_oid = atooid(PQgetvalue(upgrade_res, 0,
5437  PQfnumber(upgrade_res, "indexrelid")));
5438  toast_index_relfilenumber = atooid(PQgetvalue(upgrade_res, 0,
5439  PQfnumber(upgrade_res, "toast_index_relfilenode")));
5440 
5441  appendPQExpBufferStr(upgrade_buffer,
5442  "\n-- For binary upgrade, must preserve pg_class oids and relfilenodes\n");
5443 
5444  if (!is_index)
5445  {
5446  appendPQExpBuffer(upgrade_buffer,
5447  "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
5448  pg_class_oid);
5449 
5450  /*
5451  * Not every relation has storage. Also, in a pre-v12 database,
5452  * partitioned tables have a relfilenumber, which should not be
5453  * preserved when upgrading.
5454  */
5455  if (RelFileNumberIsValid(relfilenumber) && relkind != RELKIND_PARTITIONED_TABLE)
5456  appendPQExpBuffer(upgrade_buffer,
5457  "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
5458  relfilenumber);
5459 
5460  /*
5461  * In a pre-v12 database, partitioned tables might be marked as having
5462  * toast tables, but we should ignore them if so.
5463  */
5464  if (OidIsValid(toast_oid) &&
5465  relkind != RELKIND_PARTITIONED_TABLE)
5466  {
5467  appendPQExpBuffer(upgrade_buffer,
5468  "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
5469  toast_oid);
5470  appendPQExpBuffer(upgrade_buffer,
5471  "SELECT pg_catalog.binary_upgrade_set_next_toast_relfilenode('%u'::pg_catalog.oid);\n",
5472  toast_relfilenumber);
5473 
5474  /* every toast table has an index */
5475  appendPQExpBuffer(upgrade_buffer,
5476  "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
5477  toast_index_oid);
5478  appendPQExpBuffer(upgrade_buffer,
5479  "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
5480  toast_index_relfilenumber);
5481  }
5482 
5483  PQclear(upgrade_res);
5484  }
5485  else
5486  {
5487  /* Preserve the OID and relfilenumber of the index */
5488  appendPQExpBuffer(upgrade_buffer,
5489  "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
5490  pg_class_oid);
5491  appendPQExpBuffer(upgrade_buffer,
5492  "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
5493  relfilenumber);
5494  }
5495 
5496  appendPQExpBufferChar(upgrade_buffer, '\n');
5497 
5498  destroyPQExpBuffer(upgrade_query);
5499 }
5500 
5501 /*
5502  * If the DumpableObject is a member of an extension, add a suitable
5503  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
5504  *
5505  * For somewhat historical reasons, objname should already be quoted,
5506  * but not objnamespace (if any).
5507  */
5508 static void
5510  const DumpableObject *dobj,
5511  const char *objtype,
5512  const char *objname,
5513  const char *objnamespace)
5514 {
5515  DumpableObject *extobj = NULL;
5516  int i;
5517 
5518  if (!dobj->ext_member)
5519  return;
5520 
5521  /*
5522  * Find the parent extension. We could avoid this search if we wanted to
5523  * add a link field to DumpableObject, but the space costs of that would
5524  * be considerable. We assume that member objects could only have a
5525  * direct dependency on their own extension, not any others.
5526  */
5527  for (i = 0; i < dobj->nDeps; i++)
5528  {
5529  extobj = findObjectByDumpId(dobj->dependencies[i]);
5530  if (extobj && extobj->objType == DO_EXTENSION)
5531  break;
5532  extobj = NULL;
5533  }
5534  if (extobj == NULL)
5535  pg_fatal("could not find parent extension for %s %s",
5536  objtype, objname);
5537 
5538  appendPQExpBufferStr(upgrade_buffer,
5539  "\n-- For binary upgrade, handle extension membership the hard way\n");
5540  appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
5541  fmtId(extobj->name),
5542  objtype);
5543  if (objnamespace && *objnamespace)
5544  appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
5545  appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
5546 }
5547 
5548 /*
5549  * getNamespaces:
5550  * read all namespaces in the system catalogs and return them in the
5551  * NamespaceInfo* structure
5552  *
5553  * numNamespaces is set to the number of namespaces read in
5554  */
5555 NamespaceInfo *
5556 getNamespaces(Archive *fout, int *numNamespaces)
5557 {
5558  PGresult *res;
5559  int ntups;
5560  int i;
5561  PQExpBuffer query;
5562  NamespaceInfo *nsinfo;
5563  int i_tableoid;
5564  int i_oid;
5565  int i_nspname;
5566  int i_nspowner;
5567  int i_nspacl;
5568  int i_acldefault;
5569 
5570  query = createPQExpBuffer();
5571 
5572  /*
5573  * we fetch all namespaces including system ones, so that every object we
5574  * read in can be linked to a containing namespace.
5575  */
5576  appendPQExpBufferStr(query, "SELECT n.tableoid, n.oid, n.nspname, "
5577  "n.nspowner, "
5578  "n.nspacl, "
5579  "acldefault('n', n.nspowner) AS acldefault "
5580  "FROM pg_namespace n");
5581 
5582  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5583 
5584  ntups = PQntuples(res);
5585 
5586  nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
5587 
5588  i_tableoid = PQfnumber(res, "tableoid");
5589  i_oid = PQfnumber(res, "oid");
5590  i_nspname = PQfnumber(res, "nspname");
5591  i_nspowner = PQfnumber(res, "nspowner");
5592  i_nspacl = PQfnumber(res, "nspacl");
5593  i_acldefault = PQfnumber(res, "acldefault");
5594 
5595  for (i = 0; i < ntups; i++)
5596  {
5597  const char *nspowner;
5598 
5599  nsinfo[i].dobj.objType = DO_NAMESPACE;
5600  nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5601  nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5602  AssignDumpId(&nsinfo[i].dobj);
5603  nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
5604  nsinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_nspacl));
5605  nsinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
5606  nsinfo[i].dacl.privtype = 0;
5607  nsinfo[i].dacl.initprivs = NULL;
5608  nspowner = PQgetvalue(res, i, i_nspowner);
5609  nsinfo[i].nspowner = atooid(nspowner);
5610  nsinfo[i].rolname = getRoleName(nspowner);
5611 
5612  /* Decide whether to dump this namespace */
5613  selectDumpableNamespace(&nsinfo[i], fout);
5614 
5615  /* Mark whether namespace has an ACL */
5616  if (!PQgetisnull(res, i, i_nspacl))
5617  nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
5618 
5619  /*
5620  * We ignore any pg_init_privs.initprivs entry for the public schema
5621  * and assume a predetermined default, for several reasons. First,
5622  * dropping and recreating the schema removes its pg_init_privs entry,
5623  * but an empty destination database starts with this ACL nonetheless.
5624  * Second, we support dump/reload of public schema ownership changes.
5625  * ALTER SCHEMA OWNER filters nspacl through aclnewowner(), but
5626  * initprivs continues to reflect the initial owner. Hence,
5627  * synthesize the value that nspacl will have after the restore's
5628  * ALTER SCHEMA OWNER. Third, this makes the destination database
5629  * match the source's ACL, even if the latter was an initdb-default
5630  * ACL, which changed in v15. An upgrade pulls in changes to most
5631  * system object ACLs that the DBA had not customized. We've made the
5632  * public schema depart from that, because changing its ACL so easily
5633  * breaks applications.
5634  */
5635  if (strcmp(nsinfo[i].dobj.name, "public") == 0)
5636  {
5637  PQExpBuffer aclarray = createPQExpBuffer();
5638  PQExpBuffer aclitem = createPQExpBuffer();
5639 
5640  /* Standard ACL as of v15 is {owner=UC/owner,=U/owner} */
5641  appendPQExpBufferChar(aclarray, '{');
5642  quoteAclUserName(aclitem, nsinfo[i].rolname);
5643  appendPQExpBufferStr(aclitem, "=UC/");
5644  quoteAclUserName(aclitem, nsinfo[i].rolname);
5645  appendPGArray(aclarray, aclitem->data);
5646  resetPQExpBuffer(aclitem);
5647  appendPQExpBufferStr(aclitem, "=U/");
5648  quoteAclUserName(aclitem, nsinfo[i].rolname);
5649  appendPGArray(aclarray, aclitem->data);
5650  appendPQExpBufferChar(aclarray, '}');
5651 
5652  nsinfo[i].dacl.privtype = 'i';
5653  nsinfo[i].dacl.initprivs = pstrdup(aclarray->data);
5654  nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
5655 
5656  destroyPQExpBuffer(aclarray);
5657  destroyPQExpBuffer(aclitem);
5658  }
5659  }
5660 
5661  PQclear(res);
5662  destroyPQExpBuffer(query);
5663 
5664  *numNamespaces = ntups;
5665 
5666  return nsinfo;
5667 }
5668 
5669 /*
5670  * findNamespace:
5671  * given a namespace OID, look up the info read by getNamespaces
5672  */
5673 static NamespaceInfo *
5675 {
5676  NamespaceInfo *nsinfo;
5677 
5678  nsinfo = findNamespaceByOid(nsoid);
5679  if (nsinfo == NULL)
5680  pg_fatal("schema with OID %u does not exist", nsoid);
5681  return nsinfo;
5682 }
5683 
5684 /*
5685  * getExtensions:
5686  * read all extensions in the system catalogs and return them in the
5687  * ExtensionInfo* structure
5688  *
5689  * numExtensions is set to the number of extensions read in
5690  */
5691 ExtensionInfo *
5692 getExtensions(Archive *fout, int *numExtensions)
5693 {
5694  DumpOptions *dopt = fout->dopt;
5695  PGresult *res;
5696  int ntups;
5697  int i;
5698  PQExpBuffer query;
5699  ExtensionInfo *extinfo;
5700  int i_tableoid;
5701  int i_oid;
5702  int i_extname;
5703  int i_nspname;
5704  int i_extrelocatable;
5705  int i_extversion;
5706  int i_extconfig;
5707  int i_extcondition;
5708 
5709  query = createPQExpBuffer();
5710 
5711  appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
5712  "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
5713  "FROM pg_extension x "
5714  "JOIN pg_namespace n ON n.oid = x.extnamespace");
5715 
5716  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5717 
5718  ntups = PQntuples(res);
5719 
5720  extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
5721 
5722  i_tableoid = PQfnumber(res, "tableoid");
5723  i_oid = PQfnumber(res, "oid");
5724  i_extname = PQfnumber(res, "extname");
5725  i_nspname = PQfnumber(res, "nspname");
5726  i_extrelocatable = PQfnumber(res, "extrelocatable");
5727  i_extversion = PQfnumber(res, "extversion");
5728  i_extconfig = PQfnumber(res, "extconfig");
5729  i_extcondition = PQfnumber(res, "extcondition");
5730 
5731  for (i = 0; i < ntups; i++)
5732  {
5733  extinfo[i].dobj.objType = DO_EXTENSION;
5734  extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5735  extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5736  AssignDumpId(&extinfo[i].dobj);
5737  extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
5738  extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
5739  extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
5740  extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
5741  extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
5742  extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
5743 
5744  /* Decide whether we want to dump it */
5745  selectDumpableExtension(&(extinfo[i]), dopt);
5746  }
5747 
5748  PQclear(res);
5749  destroyPQExpBuffer(query);
5750 
5751  *numExtensions = ntups;
5752 
5753  return extinfo;
5754 }
5755 
5756 /*
5757  * getTypes:
5758  * read all types in the system catalogs and return them in the
5759  * TypeInfo* structure
5760  *
5761  * numTypes is set to the number of types read in
5762  *
5763  * NB: this must run after getFuncs() because we assume we can do
5764  * findFuncByOid().
5765  */
5766 TypeInfo *
5767 getTypes(Archive *fout, int *numTypes)
5768 {
5769  PGresult *res;
5770  int ntups;
5771  int i;
5772  PQExpBuffer query = createPQExpBuffer();
5773  TypeInfo *tyinfo;
5774  ShellTypeInfo *stinfo;
5775  int i_tableoid;
5776  int i_oid;
5777  int i_typname;
5778  int i_typnamespace;
5779  int i_typacl;
5780  int i_acldefault;
5781  int i_typowner;
5782  int i_typelem;
5783  int i_typrelid;
5784  int i_typrelkind;
5785  int i_typtype;
5786  int i_typisdefined;
5787  int i_isarray;
5788 
5789  /*
5790  * we include even the built-in types because those may be used as array
5791  * elements by user-defined types
5792  *
5793  * we filter out the built-in types when we dump out the types
5794  *
5795  * same approach for undefined (shell) types and array types
5796  *
5797  * Note: as of 8.3 we can reliably detect whether a type is an
5798  * auto-generated array type by checking the element type's typarray.
5799  * (Before that the test is capable of generating false positives.) We
5800  * still check for name beginning with '_', though, so as to avoid the
5801  * cost of the subselect probe for all standard types. This would have to
5802  * be revisited if the backend ever allows renaming of array types.
5803  */
5804  appendPQExpBufferStr(query, "SELECT tableoid, oid, typname, "
5805  "typnamespace, typacl, "
5806  "acldefault('T', typowner) AS acldefault, "
5807  "typowner, "
5808  "typelem, typrelid, "
5809  "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
5810  "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
5811  "typtype, typisdefined, "
5812  "typname[0] = '_' AND typelem != 0 AND "
5813  "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
5814  "FROM pg_type");
5815 
5816  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5817 
5818  ntups = PQntuples(res);
5819 
5820  tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
5821 
5822  i_tableoid = PQfnumber(res, "tableoid");
5823  i_oid = PQfnumber(res, "oid");
5824  i_typname = PQfnumber(res, "typname");
5825  i_typnamespace = PQfnumber(res, "typnamespace");
5826  i_typacl = PQfnumber(res, "typacl");
5827  i_acldefault = PQfnumber(res, "acldefault");
5828  i_typowner = PQfnumber(res, "typowner");
5829  i_typelem = PQfnumber(res, "typelem");
5830  i_typrelid = PQfnumber(res, "typrelid");
5831  i_typrelkind = PQfnumber(res, "typrelkind");
5832  i_typtype = PQfnumber(res, "typtype");
5833  i_typisdefined = PQfnumber(res, "typisdefined");
5834  i_isarray = PQfnumber(res, "isarray");
5835 
5836  for (i = 0; i < ntups; i++)
5837  {
5838  tyinfo[i].dobj.objType = DO_TYPE;
5839  tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5840  tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5841  AssignDumpId(&tyinfo[i].dobj);
5842  tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
5843  tyinfo[i].dobj.namespace =
5844  findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)));
5845  tyinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_typacl));
5846  tyinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
5847  tyinfo[i].dacl.privtype = 0;
5848  tyinfo[i].dacl.initprivs = NULL;
5849  tyinfo[i].ftypname = NULL; /* may get filled later */
5850  tyinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_typowner));
5851  tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
5852  tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
5853  tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
5854  tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
5855  tyinfo[i].shellType = NULL;
5856 
5857  if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
5858  tyinfo[i].isDefined = true;
5859  else
5860  tyinfo[i].isDefined = false;
5861 
5862  if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
5863  tyinfo[i].isArray = true;
5864  else
5865  tyinfo[i].isArray = false;
5866 
5867  if (tyinfo[i].typtype == TYPTYPE_MULTIRANGE)
5868  tyinfo[i].isMultirange = true;
5869  else
5870  tyinfo[i].isMultirange = false;
5871 
5872  /* Decide whether we want to dump it */
5873  selectDumpableType(&tyinfo[i], fout);
5874 
5875  /* Mark whether type has an ACL */
5876  if (!PQgetisnull(res, i, i_typacl))
5877  tyinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
5878 
5879  /*
5880  * If it's a domain, fetch info about its constraints, if any
5881  */
5882  tyinfo[i].nDomChecks = 0;
5883  tyinfo[i].domChecks = NULL;
5884  if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
5885  tyinfo[i].typtype == TYPTYPE_DOMAIN)
5886  getDomainConstraints(fout, &(tyinfo[i]));
5887 
5888  /*
5889  * If it's a base type, make a DumpableObject representing a shell
5890  * definition of the type. We will need to dump that ahead of the I/O
5891  * functions for the type. Similarly, range types need a shell
5892  * definition in case they have a canonicalize function.
5893  *
5894  * Note: the shell type doesn't have a catId. You might think it
5895  * should copy the base type's catId, but then it might capture the
5896  * pg_depend entries for the type, which we don't want.
5897  */
5898  if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
5899  (tyinfo[i].typtype == TYPTYPE_BASE ||
5900  tyinfo[i].typtype == TYPTYPE_RANGE))
5901  {
5902  stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
5903  stinfo->dobj.objType = DO_SHELL_TYPE;
5904  stinfo->dobj.catId = nilCatalogId;
5905  AssignDumpId(&stinfo->dobj);
5906  stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
5907  stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
5908  stinfo->baseType = &(tyinfo[i]);
5909  tyinfo[i].shellType = stinfo;
5910 
5911  /*
5912  * Initially mark the shell type as not to be dumped. We'll only
5913  * dump it if the I/O or canonicalize functions need to be dumped;
5914  * this is taken care of while sorting dependencies.
5915  */
5916  stinfo->dobj.dump = DUMP_COMPONENT_NONE;
5917  }
5918  }
5919 
5920  *numTypes = ntups;
5921 
5922  PQclear(res);
5923 
5924  destroyPQExpBuffer(query);
5925 
5926  return tyinfo;
5927 }
5928 
5929 /*
5930  * getOperators:
5931  * read all operators in the system catalogs and return them in the
5932  * OprInfo* structure
5933  *
5934  * numOprs is set to the number of operators read in
5935  */
5936 OprInfo *
5937 getOperators(Archive *fout, int *numOprs)
5938 {
5939  PGresult *res;
5940  int ntups;
5941  int i;
5942  PQExpBuffer query = createPQExpBuffer();
5943  OprInfo *oprinfo;
5944  int i_tableoid;
5945  int i_oid;
5946  int i_oprname;
5947  int i_oprnamespace;
5948  int i_oprowner;
5949  int i_oprkind;
5950  int i_oprcode;
5951 
5952  /*
5953  * find all operators, including builtin operators; we filter out
5954  * system-defined operators at dump-out time.
5955  */
5956 
5957  appendPQExpBufferStr(query, "SELECT tableoid, oid, oprname, "
5958  "oprnamespace, "
5959  "oprowner, "
5960  "oprkind, "
5961  "oprcode::oid AS oprcode "
5962  "FROM pg_operator");
5963 
5964  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5965 
5966  ntups = PQntuples(res);
5967  *numOprs = ntups;
5968 
5969  oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
5970 
5971  i_tableoid = PQfnumber(res, "tableoid");
5972  i_oid = PQfnumber(res, "oid");
5973  i_oprname = PQfnumber(res, "oprname");
5974  i_oprnamespace = PQfnumber(res, "oprnamespace");
5975  i_oprowner = PQfnumber(res, "oprowner");
5976  i_oprkind = PQfnumber(res, "oprkind");
5977  i_oprcode = PQfnumber(res, "oprcode");
5978 
5979  for (i = 0; i < ntups; i++)
5980  {
5981  oprinfo[i].dobj.objType = DO_OPERATOR;
5982  oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5983  oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5984  AssignDumpId(&oprinfo[i].dobj);
5985  oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
5986  oprinfo[i].dobj.namespace =
5987  findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)));
5988  oprinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_oprowner));
5989  oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
5990  oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
5991 
5992  /* Decide whether we want to dump it */
5993  selectDumpableObject(&(oprinfo[i].dobj), fout);
5994  }
5995 
5996  PQclear(res);
5997 
5998  destroyPQExpBuffer(query);
5999 
6000  return oprinfo;
6001 }
6002 
6003 /*
6004  * getCollations:
6005  * read all collations in the system catalogs and return them in the
6006  * CollInfo* structure
6007  *
6008  * numCollations is set to the number of collations read in
6009  */
6010 CollInfo *
6011 getCollations(Archive *fout, int *numCollations)
6012 {
6013  PGresult *res;
6014  int ntups;
6015  int i;
6016  PQExpBuffer query;
6017  CollInfo *collinfo;
6018  int i_tableoid;
6019  int i_oid;
6020  int i_collname;
6021  int i_collnamespace;
6022  int i_collowner;
6023 
6024  query = createPQExpBuffer();
6025 
6026  /*
6027  * find all collations, including builtin collations; we filter out
6028  * system-defined collations at dump-out time.
6029  */
6030 
6031  appendPQExpBufferStr(query, "SELECT tableoid, oid, collname, "
6032  "collnamespace, "
6033  "collowner "
6034  "FROM pg_collation");
6035 
6036  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6037 
6038  ntups = PQntuples(res);
6039  *numCollations = ntups;
6040 
6041  collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
6042 
6043  i_tableoid = PQfnumber(res, "tableoid");
6044  i_oid = PQfnumber(res, "oid");
6045  i_collname = PQfnumber(res, "collname");
6046  i_collnamespace = PQfnumber(res, "collnamespace");
6047  i_collowner = PQfnumber(res, "collowner");
6048 
6049  for (i = 0; i < ntups; i++)
6050  {
6051  collinfo[i].dobj.objType = DO_COLLATION;
6052  collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6053  collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6054  AssignDumpId(&collinfo[i].dobj);
6055  collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
6056  collinfo[i].dobj.namespace =
6057  findNamespace(atooid(PQgetvalue(res, i, i_collnamespace)));
6058  collinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_collowner));
6059 
6060  /* Decide whether we want to dump it */
6061  selectDumpableObject(&(collinfo[i].dobj), fout);
6062  }
6063 
6064  PQclear(res);
6065 
6066  destroyPQExpBuffer(query);
6067 
6068  return collinfo;
6069 }
6070 
6071 /*
6072  * getConversions:
6073  * read all conversions in the system catalogs and return them in the
6074  * ConvInfo* structure
6075  *
6076  * numConversions is set to the number of conversions read in
6077  */
6078 ConvInfo *
6079 getConversions(Archive *fout, int *numConversions)
6080 {
6081  PGresult *res;
6082  int ntups;
6083  int i;
6084  PQExpBuffer query;
6085  ConvInfo *convinfo;
6086  int i_tableoid;
6087  int i_oid;
6088  int i_conname;
6089  int i_connamespace;
6090  int i_conowner;
6091 
6092  query = createPQExpBuffer();
6093 
6094  /*
6095  * find all conversions, including builtin conversions; we filter out
6096  * system-defined conversions at dump-out time.
6097  */
6098 
6099  appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "
6100  "connamespace, "
6101  "conowner "
6102  "FROM pg_conversion");
6103 
6104  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6105 
6106  ntups = PQntuples(res);
6107  *numConversions = ntups;
6108 
6109  convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
6110 
6111  i_tableoid = PQfnumber(res, "tableoid");
6112  i_oid = PQfnumber(res, "oid");
6113  i_conname = PQfnumber(res, "conname");
6114  i_connamespace = PQfnumber(res, "connamespace");
6115  i_conowner = PQfnumber(res, "conowner");
6116 
6117  for (i = 0; i < ntups; i++)
6118  {
6119  convinfo[i].dobj.objType = DO_CONVERSION;
6120  convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6121  convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6122  AssignDumpId(&convinfo[i].dobj);
6123  convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
6124  convinfo[i].dobj.namespace =
6125  findNamespace(atooid(PQgetvalue(res, i, i_connamespace)));
6126  convinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_conowner));
6127 
6128  /* Decide whether we want to dump it */
6129  selectDumpableObject(&(convinfo[i].dobj), fout);
6130  }
6131 
6132  PQclear(res);
6133 
6134  destroyPQExpBuffer(query);
6135 
6136  return convinfo;
6137 }
6138 
6139 /*
6140  * getAccessMethods:
6141  * read all user-defined access methods in the system catalogs and return
6142  * them in the AccessMethodInfo* structure
6143  *
6144  * numAccessMethods is set to the number of access methods read in
6145  */
6147 getAccessMethods(Archive *fout, int *numAccessMethods)
6148 {
6149  PGresult *res;
6150  int ntups;
6151  int i;
6152  PQExpBuffer query;
6153  AccessMethodInfo *aminfo;
6154  int i_tableoid;
6155  int i_oid;
6156  int i_amname;
6157  int i_amhandler;
6158  int i_amtype;
6159 
6160  /* Before 9.6, there are no user-defined access methods */
6161  if (fout->remoteVersion < 90600)
6162  {
6163  *numAccessMethods = 0;
6164  return NULL;
6165  }
6166 
6167  query = createPQExpBuffer();
6168 
6169  /* Select all access methods from pg_am table */
6170  appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, amtype, "
6171  "amhandler::pg_catalog.regproc AS amhandler "
6172  "FROM pg_am");
6173 
6174  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6175 
6176  ntups = PQntuples(res);
6177  *numAccessMethods = ntups;
6178 
6179  aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
6180 
6181  i_tableoid = PQfnumber(res, "tableoid");
6182  i_oid = PQfnumber(res, "oid");
6183  i_amname = PQfnumber(res, "amname");
6184  i_amhandler = PQfnumber(res, "amhandler");
6185  i_amtype = PQfnumber(res, "amtype");
6186 
6187  for (i = 0; i < ntups; i++)
6188  {
6189  aminfo[i].dobj.objType = DO_ACCESS_METHOD;
6190  aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6191  aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6192  AssignDumpId(&aminfo[i].dobj);
6193  aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
6194  aminfo[i].dobj.namespace = NULL;
6195  aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
6196  aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
6197 
6198  /* Decide whether we want to dump it */
6199  selectDumpableAccessMethod(&(aminfo[i]), fout);
6200  }
6201 
6202  PQclear(res);
6203 
6204  destroyPQExpBuffer(query);
6205 
6206  return aminfo;
6207 }
6208 
6209 
6210 /*
6211  * getOpclasses:
6212  * read all opclasses in the system catalogs and return them in the
6213  * OpclassInfo* structure
6214  *
6215  * numOpclasses is set to the number of opclasses read in
6216  */
6217 OpclassInfo *
6218 getOpclasses(Archive *fout, int *numOpclasses)
6219 {
6220  PGresult *res;
6221  int ntups;
6222  int i;
6223  PQExpBuffer query = createPQExpBuffer();
6224  OpclassInfo *opcinfo;
6225  int i_tableoid;
6226  int i_oid;
6227  int i_opcname;
6228  int i_opcnamespace;
6229  int i_opcowner;
6230 
6231  /*
6232  * find all opclasses, including builtin opclasses; we filter out
6233  * system-defined opclasses at dump-out time.
6234  */
6235 
6236  appendPQExpBufferStr(query, "SELECT tableoid, oid, opcname, "
6237  "opcnamespace, "
6238  "opcowner "
6239  "FROM pg_opclass");
6240 
6241  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6242 
6243  ntups = PQntuples(res);
6244  *numOpclasses = ntups;
6245 
6246  opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
6247 
6248  i_tableoid = PQfnumber(res, "tableoid");
6249  i_oid = PQfnumber(res, "oid");
6250  i_opcname = PQfnumber(res, "opcname");
6251  i_opcnamespace = PQfnumber(res, "opcnamespace");
6252  i_opcowner = PQfnumber(res, "opcowner");
6253 
6254  for (i = 0; i < ntups; i++)
6255  {
6256  opcinfo[i].dobj.objType = DO_OPCLASS;
6257  opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6258  opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6259  AssignDumpId(&opcinfo[i].dobj);
6260  opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
6261  opcinfo[i].dobj.namespace =
6262  findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)));
6263  opcinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opcowner));
6264 
6265  /* Decide whether we want to dump it */
6266  selectDumpableObject(&(opcinfo[i].dobj), fout);
6267  }
6268 
6269  PQclear(res);
6270 
6271  destroyPQExpBuffer(query);
6272 
6273  return opcinfo;
6274 }
6275 
6276 /*
6277  * getOpfamilies:
6278  * read all opfamilies in the system catalogs and return them in the
6279  * OpfamilyInfo* structure
6280  *
6281  * numOpfamilies is set to the number of opfamilies read in
6282  */
6283 OpfamilyInfo *
6284 getOpfamilies(Archive *fout, int *numOpfamilies)
6285 {
6286  PGresult *res;
6287  int ntups;
6288  int i;
6289  PQExpBuffer query;
6290  OpfamilyInfo *opfinfo;
6291  int i_tableoid;
6292  int i_oid;
6293  int i_opfname;
6294  int i_opfnamespace;
6295  int i_opfowner;
6296 
6297  query = createPQExpBuffer();
6298 
6299  /*
6300  * find all opfamilies, including builtin opfamilies; we filter out
6301  * system-defined opfamilies at dump-out time.
6302  */
6303 
6304  appendPQExpBufferStr(query, "SELECT tableoid, oid, opfname, "
6305  "opfnamespace, "
6306  "opfowner "
6307  "FROM pg_opfamily");
6308 
6309  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6310 
6311  ntups = PQntuples(res);
6312  *numOpfamilies = ntups;
6313 
6314  opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
6315 
6316  i_tableoid = PQfnumber(res, "tableoid");
6317  i_oid = PQfnumber(res, "oid");
6318  i_opfname = PQfnumber(res, "opfname");
6319  i_opfnamespace = PQfnumber(res, "opfnamespace");
6320  i_opfowner = PQfnumber(res, "opfowner");
6321 
6322  for (i = 0; i < ntups; i++)
6323  {
6324  opfinfo[i].dobj.objType = DO_OPFAMILY;
6325  opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6326  opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6327  AssignDumpId(&opfinfo[i].dobj);
6328  opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
6329  opfinfo[i].dobj.namespace =
6330  findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)));
6331  opfinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opfowner));
6332 
6333  /* Decide whether we want to dump it */
6334  selectDumpableObject(&(opfinfo[i].dobj), fout);
6335  }
6336 
6337  PQclear(res);
6338 
6339  destroyPQExpBuffer(query);
6340 
6341  return opfinfo;
6342 }
6343 
6344 /*
6345  * getAggregates:
6346  * read all the user-defined aggregates in the system catalogs and
6347  * return them in the AggInfo* structure
6348  *
6349  * numAggs is set to the number of aggregates read in
6350  */
6351 AggInfo *
6352 getAggregates(Archive *fout, int *numAggs)
6353 {
6354  DumpOptions *dopt = fout->dopt;
6355  PGresult *res;
6356  int ntups;
6357  int i;
6358  PQExpBuffer query = createPQExpBuffer();
6359  AggInfo *agginfo;
6360  int i_tableoid;
6361  int i_oid;
6362  int i_aggname;
6363  int i_aggnamespace;
6364  int i_pronargs;
6365  int i_proargtypes;
6366  int i_proowner;
6367  int i_aggacl;
6368  int i_acldefault;
6369 
6370  /*
6371  * Find all interesting aggregates. See comment in getFuncs() for the
6372  * rationale behind the filtering logic.
6373  */
6374  if (fout->remoteVersion >= 90600)
6375  {
6376  const char *agg_check;
6377 
6378  agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
6379  : "p.proisagg");
6380 
6381  appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
6382  "p.proname AS aggname, "
6383  "p.pronamespace AS aggnamespace, "
6384  "p.pronargs, p.proargtypes, "
6385  "p.proowner, "
6386  "p.proacl AS aggacl, "
6387  "acldefault('f', p.proowner) AS acldefault "
6388  "FROM pg_proc p "
6389  "LEFT JOIN pg_init_privs pip ON "
6390  "(p.oid = pip.objoid "
6391  "AND pip.classoid = 'pg_proc'::regclass "
6392  "AND pip.objsubid = 0) "
6393  "WHERE %s AND ("
6394  "p.pronamespace != "
6395  "(SELECT oid FROM pg_namespace "
6396  "WHERE nspname = 'pg_catalog') OR "
6397  "p.proacl IS DISTINCT FROM pip.initprivs",
6398  agg_check);
6399  if (dopt->binary_upgrade)
6400  appendPQExpBufferStr(query,
6401  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6402  "classid = 'pg_proc'::regclass AND "
6403  "objid = p.oid AND "
6404  "refclassid = 'pg_extension'::regclass AND "
6405  "deptype = 'e')");
6406  appendPQExpBufferChar(query, ')');
6407  }
6408  else
6409  {
6410  appendPQExpBufferStr(query, "SELECT tableoid, oid, proname AS aggname, "
6411  "pronamespace AS aggnamespace, "
6412  "pronargs, proargtypes, "
6413  "proowner, "
6414  "proacl AS aggacl, "
6415  "acldefault('f', proowner) AS acldefault "
6416  "FROM pg_proc p "
6417  "WHERE proisagg AND ("
6418  "pronamespace != "
6419  "(SELECT oid FROM pg_namespace "
6420  "WHERE nspname = 'pg_catalog')");
6421  if (dopt->binary_upgrade)
6422  appendPQExpBufferStr(query,
6423  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6424  "classid = 'pg_proc'::regclass AND "
6425  "objid = p.oid AND "
6426  "refclassid = 'pg_extension'::regclass AND "
6427  "deptype = 'e')");
6428  appendPQExpBufferChar(query, ')');
6429  }
6430 
6431  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6432 
6433  ntups = PQntuples(res);
6434  *numAggs = ntups;
6435 
6436  agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
6437 
6438  i_tableoid = PQfnumber(res, "tableoid");
6439  i_oid = PQfnumber(res, "oid");
6440  i_aggname = PQfnumber(res, "aggname");
6441  i_aggnamespace = PQfnumber(res, "aggnamespace");
6442  i_pronargs = PQfnumber(res, "pronargs");
6443  i_proargtypes = PQfnumber(res, "proargtypes");
6444  i_proowner = PQfnumber(res, "proowner");
6445  i_aggacl = PQfnumber(res, "aggacl");
6446  i_acldefault = PQfnumber(res, "acldefault");
6447 
6448  for (i = 0; i < ntups; i++)
6449  {
6450  agginfo[i].aggfn.dobj.objType = DO_AGG;
6451  agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6452  agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6453  AssignDumpId(&agginfo[i].aggfn.dobj);
6454  agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
6455  agginfo[i].aggfn.dobj.namespace =
6456  findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)));
6457  agginfo[i].aggfn.dacl.acl = pg_strdup(PQgetvalue(res, i, i_aggacl));
6458  agginfo[i].aggfn.dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6459  agginfo[i].aggfn.dacl.privtype = 0;
6460  agginfo[i].aggfn.dacl.initprivs = NULL;
6461  agginfo[i].aggfn.rolname = getRoleName(PQgetvalue(res, i, i_proowner));
6462  agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
6463  agginfo[i].aggfn.prorettype = InvalidOid; /* not saved */
6464  agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
6465  if (agginfo[i].aggfn.nargs == 0)
6466  agginfo[i].aggfn.argtypes = NULL;
6467  else
6468  {
6469  agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
6470  parseOidArray(PQgetvalue(res, i, i_proargtypes),
6471  agginfo[i].aggfn.argtypes,
6472  agginfo[i].aggfn.nargs);
6473  }
6474  agginfo[i].aggfn.postponed_def = false; /* might get set during sort */
6475 
6476  /* Decide whether we want to dump it */
6477  selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
6478 
6479  /* Mark whether aggregate has an ACL */
6480  if (!PQgetisnull(res, i, i_aggacl))
6481  agginfo[i].aggfn.dobj.components |= DUMP_COMPONENT_ACL;
6482  }
6483 
6484  PQclear(res);
6485 
6486  destroyPQExpBuffer(query);
6487 
6488  return agginfo;
6489 }
6490 
6491 /*
6492  * getFuncs:
6493  * read all the user-defined functions in the system catalogs and
6494  * return them in the FuncInfo* structure
6495  *
6496  * numFuncs is set to the number of functions read in
6497  */
6498 FuncInfo *
6499 getFuncs(Archive *fout, int *numFuncs)
6500 {
6501  DumpOptions *dopt = fout->dopt;
6502  PGresult *res;
6503  int ntups;
6504  int i;
6505  PQExpBuffer query = createPQExpBuffer();
6506  FuncInfo *finfo;
6507  int i_tableoid;
6508  int i_oid;
6509  int i_proname;
6510  int i_pronamespace;
6511  int i_proowner;
6512  int i_prolang;
6513  int i_pronargs;
6514  int i_proargtypes;
6515  int i_prorettype;
6516  int i_proacl;
6517  int i_acldefault;
6518 
6519  /*
6520  * Find all interesting functions. This is a bit complicated:
6521  *
6522  * 1. Always exclude aggregates; those are handled elsewhere.
6523  *
6524  * 2. Always exclude functions that are internally dependent on something
6525  * else, since presumably those will be created as a result of creating
6526  * the something else. This currently acts only to suppress constructor
6527  * functions for range types. Note this is OK only because the
6528  * constructors don't have any dependencies the range type doesn't have;
6529  * otherwise we might not get creation ordering correct.
6530  *
6531  * 3. Otherwise, we normally exclude functions in pg_catalog. However, if
6532  * they're members of extensions and we are in binary-upgrade mode then
6533  * include them, since we want to dump extension members individually in
6534  * that mode. Also, if they are used by casts or transforms then we need
6535  * to gather the information about them, though they won't be dumped if
6536  * they are built-in. Also, in 9.6 and up, include functions in
6537  * pg_catalog if they have an ACL different from what's shown in
6538  * pg_init_privs (so we have to join to pg_init_privs; annoying).
6539  */
6540  if (fout->remoteVersion >= 90600)
6541  {
6542  const char *not_agg_check;
6543 
6544  not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
6545  : "NOT p.proisagg");
6546 
6547  appendPQExpBuffer(query,
6548  "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
6549  "p.pronargs, p.proargtypes, p.prorettype, "
6550  "p.proacl, "
6551  "acldefault('f', p.proowner) AS acldefault, "
6552  "p.pronamespace, "
6553  "p.proowner "
6554  "FROM pg_proc p "
6555  "LEFT JOIN pg_init_privs pip ON "
6556  "(p.oid = pip.objoid "
6557  "AND pip.classoid = 'pg_proc'::regclass "
6558  "AND pip.objsubid = 0) "
6559  "WHERE %s"
6560  "\n AND NOT EXISTS (SELECT 1 FROM pg_depend "
6561  "WHERE classid = 'pg_proc'::regclass AND "
6562  "objid = p.oid AND deptype = 'i')"
6563  "\n AND ("
6564  "\n pronamespace != "
6565  "(SELECT oid FROM pg_namespace "
6566  "WHERE nspname = 'pg_catalog')"
6567  "\n OR EXISTS (SELECT 1 FROM pg_cast"
6568  "\n WHERE pg_cast.oid > %u "
6569  "\n AND p.oid = pg_cast.castfunc)"
6570  "\n OR EXISTS (SELECT 1 FROM pg_transform"
6571  "\n WHERE pg_transform.oid > %u AND "
6572  "\n (p.oid = pg_transform.trffromsql"
6573  "\n OR p.oid = pg_transform.trftosql))",
6574  not_agg_check,
6577  if (dopt->binary_upgrade)
6578  appendPQExpBufferStr(query,
6579  "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6580  "classid = 'pg_proc'::regclass AND "
6581  "objid = p.oid AND "
6582  "refclassid = 'pg_extension'::regclass AND "
6583  "deptype = 'e')");
6584  appendPQExpBufferStr(query,
6585  "\n OR p.proacl IS DISTINCT FROM pip.initprivs");
6586  appendPQExpBufferChar(query, ')');
6587  }
6588  else
6589  {
6590  appendPQExpBuffer(query,
6591  "SELECT tableoid, oid, proname, prolang, "
6592  "pronargs, proargtypes, prorettype, proacl, "
6593  "acldefault('f', proowner) AS acldefault, "
6594  "pronamespace, "
6595  "proowner "
6596  "FROM pg_proc p "
6597  "WHERE NOT proisagg"
6598  "\n AND NOT EXISTS (SELECT 1 FROM pg_depend "
6599  "WHERE classid = 'pg_proc'::regclass AND "
6600  "objid = p.oid AND deptype = 'i')"
6601  "\n AND ("
6602  "\n pronamespace != "
6603  "(SELECT oid FROM pg_namespace "
6604  "WHERE nspname = 'pg_catalog')"
6605  "\n OR EXISTS (SELECT 1 FROM pg_cast"
6606  "\n WHERE pg_cast.oid > '%u'::oid"
6607  "\n AND p.oid = pg_cast.castfunc)",
6609 
6610  if (fout->remoteVersion >= 90500)
6611  appendPQExpBuffer(query,
6612  "\n OR EXISTS (SELECT 1 FROM pg_transform"
6613  "\n WHERE pg_transform.oid > '%u'::oid"
6614  "\n AND (p.oid = pg_transform.trffromsql"
6615  "\n OR p.oid = pg_transform.trftosql))",
6617 
6618  if (dopt->binary_upgrade)
6619  appendPQExpBufferStr(query,
6620  "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6621  "classid = 'pg_proc'::regclass AND "
6622  "objid = p.oid AND "
6623  "refclassid = 'pg_extension'::regclass AND "
6624  "deptype = 'e')");
6625  appendPQExpBufferChar(query, ')');
6626  }
6627 
6628  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6629 
6630  ntups = PQntuples(res);
6631 
6632  *numFuncs = ntups;
6633 
6634  finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
6635 
6636  i_tableoid = PQfnumber(res, "tableoid");
6637  i_oid = PQfnumber(res, "oid");
6638  i_proname = PQfnumber(res, "proname");
6639  i_pronamespace = PQfnumber(res, "pronamespace");
6640  i_proowner = PQfnumber(res, "proowner");
6641  i_prolang = PQfnumber(res, "prolang");
6642  i_pronargs = PQfnumber(res, "pronargs");
6643  i_proargtypes = PQfnumber(res, "proargtypes");
6644  i_prorettype = PQfnumber(res, "prorettype");
6645  i_proacl = PQfnumber(res, "proacl");
6646  i_acldefault = PQfnumber(res, "acldefault");
6647 
6648  for (i = 0; i < ntups; i++)
6649  {
6650  finfo[i].dobj.objType = DO_FUNC;
6651  finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6652  finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6653  AssignDumpId(&finfo[i].dobj);
6654  finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
6655  finfo[i].dobj.namespace =
6656  findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)));
6657  finfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_proacl));
6658  finfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6659  finfo[i].dacl.privtype = 0;
6660  finfo[i].dacl.initprivs = NULL;
6661  finfo[i].rolname = getRoleName(PQgetvalue(res, i, i_proowner));
6662  finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
6663  finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
6664  finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
6665  if (finfo[i].nargs == 0)
6666  finfo[i].argtypes = NULL;
6667  else
6668  {
6669  finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
6670  parseOidArray(PQgetvalue(res, i, i_proargtypes),
6671  finfo[i].argtypes, finfo[i].nargs);
6672  }
6673  finfo[i].postponed_def = false; /* might get set during sort */
6674 
6675  /* Decide whether we want to dump it */
6676  selectDumpableObject(&(finfo[i].dobj), fout);
6677 
6678  /* Mark whether function has an ACL */
6679  if (!PQgetisnull(res, i, i_proacl))
6680  finfo[i].dobj.components |= DUMP_COMPONENT_ACL;
6681  }
6682 
6683  PQclear(res);
6684 
6685  destroyPQExpBuffer(query);
6686 
6687  return finfo;
6688 }
6689 
6690 /*
6691  * getTables
6692  * read all the tables (no indexes) in the system catalogs,
6693  * and return them as an array of TableInfo structures
6694  *
6695  * *numTables is set to the number of tables read in
6696  */
6697 TableInfo *
6698 getTables(Archive *fout, int *numTables)
6699 {
6700  DumpOptions *dopt = fout->dopt;
6701  PGresult *res;
6702  int ntups;
6703  int i;
6704  PQExpBuffer query = createPQExpBuffer();
6705  TableInfo *tblinfo;
6706  int i_reltableoid;
6707  int i_reloid;
6708  int i_relname;
6709  int i_relnamespace;
6710  int i_relkind;
6711  int i_reltype;
6712  int i_relowner;
6713  int i_relchecks;
6714  int i_relhasindex;
6715  int i_relhasrules;
6716  int i_relpages;
6717  int i_toastpages;
6718  int i_owning_tab;
6719  int i_owning_col;
6720  int i_reltablespace;
6721  int i_relhasoids;
6722  int i_relhastriggers;
6723  int i_relpersistence;
6724  int i_relispopulated;
6725  int i_relreplident;
6726  int i_relrowsec;
6727  int i_relforcerowsec;
6728  int i_relfrozenxid;
6729  int i_toastfrozenxid;
6730  int i_toastoid;
6731  int i_relminmxid;
6732  int i_toastminmxid;
6733  int i_reloptions;
6734  int i_checkoption;
6735  int i_toastreloptions;
6736  int i_reloftype;
6737  int i_foreignserver;
6738  int i_amname;
6739  int i_is_identity_sequence;
6740  int i_relacl;
6741  int i_acldefault;
6742  int i_ispartition;
6743 
6744  /*
6745  * Find all the tables and table-like objects.
6746  *
6747  * We must fetch all tables in this phase because otherwise we cannot
6748  * correctly identify inherited columns, owned sequences, etc.
6749  *
6750  * We include system catalogs, so that we can work if a user table is
6751  * defined to inherit from a system catalog (pretty weird, but...)
6752  *
6753  * Note: in this phase we should collect only a minimal amount of
6754  * information about each table, basically just enough to decide if it is
6755  * interesting. In particular, since we do not yet have lock on any user
6756  * table, we MUST NOT invoke any server-side data collection functions
6757  * (for instance, pg_get_partkeydef()). Those are likely to fail or give
6758  * wrong answers if any concurrent DDL is happening.
6759  */
6760 
6761  appendPQExpBufferStr(query,
6762  "SELECT c.tableoid, c.oid, c.relname, "
6763  "c.relnamespace, c.relkind, c.reltype, "
6764  "c.relowner, "
6765  "c.relchecks, "
6766  "c.relhasindex, c.relhasrules, c.relpages, "
6767  "c.relhastriggers, "
6768  "c.relpersistence, "
6769  "c.reloftype, "
6770  "c.relacl, "
6771  "acldefault(CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
6772  " THEN 's'::\"char\" ELSE 'r'::\"char\" END, c.relowner) AS acldefault, "
6773  "CASE WHEN c.relkind = " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN "
6774  "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
6775  "ELSE 0 END AS foreignserver, "
6776  "c.relfrozenxid, tc.relfrozenxid AS tfrozenxid, "
6777  "tc.oid AS toid, "
6778  "tc.relpages AS toastpages, "
6779  "tc.reloptions AS toast_reloptions, "
6780  "d.refobjid AS owning_tab, "
6781  "d.refobjsubid AS owning_col, "
6782  "tsp.spcname AS reltablespace, ");
6783 
6784  if (fout->remoteVersion >= 120000)
6785  appendPQExpBufferStr(query,
6786  "false AS relhasoids, ");
6787  else
6788  appendPQExpBufferStr(query,
6789  "c.relhasoids, ");
6790 
6791  if (fout->remoteVersion >= 90300)
6792  appendPQExpBufferStr(query,
6793  "c.relispopulated, ");
6794  else
6795  appendPQExpBufferStr(query,
6796  "'t' as relispopulated, ");
6797 
6798  if (fout->remoteVersion >= 90400)
6799  appendPQExpBufferStr(query,
6800  "c.relreplident, ");
6801  else
6802  appendPQExpBufferStr(query,
6803  "'d' AS relreplident, ");
6804 
6805  if (fout->remoteVersion >= 90500)
6806  appendPQExpBufferStr(query,
6807  "c.relrowsecurity, c.relforcerowsecurity, ");
6808  else
6809  appendPQExpBufferStr(query,
6810  "false AS relrowsecurity, "
6811  "false AS relforcerowsecurity, ");
6812 
6813  if (fout->remoteVersion >= 90300)
6814  appendPQExpBufferStr(query,
6815  "c.relminmxid, tc.relminmxid AS tminmxid, ");
6816  else
6817  appendPQExpBufferStr(query,
6818  "0 AS relminmxid, 0 AS tminmxid, ");
6819 
6820  if (fout->remoteVersion >= 90300)
6821  appendPQExpBufferStr(query,
6822  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6823  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6824  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, ");
6825  else
6826  appendPQExpBufferStr(query,
6827  "c.reloptions, NULL AS checkoption, ");
6828 
6829  if (fout->remoteVersion >= 90600)
6830  appendPQExpBufferStr(query,
6831  "am.amname, ");
6832  else
6833  appendPQExpBufferStr(query,
6834  "NULL AS amname, ");
6835 
6836  if (fout->remoteVersion >= 90600)
6837  appendPQExpBufferStr(query,
6838  "(d.deptype = 'i') IS TRUE AS is_identity_sequence, ");
6839  else
6840  appendPQExpBufferStr(query,
6841  "false AS is_identity_sequence, ");
6842 
6843  if (fout->remoteVersion >= 100000)
6844  appendPQExpBufferStr(query,
6845  "c.relispartition AS ispartition ");
6846  else
6847  appendPQExpBufferStr(query,
6848  "false AS ispartition ");
6849 
6850  /*
6851  * Left join to pg_depend to pick up dependency info linking sequences to
6852  * their owning column, if any (note this dependency is AUTO except for
6853  * identity sequences, where it's INTERNAL). Also join to pg_tablespace to
6854  * collect the spcname.
6855  */
6856  appendPQExpBufferStr(query,
6857  "\nFROM pg_class c\n"
6858  "LEFT JOIN pg_depend d ON "
6859  "(c.relkind = " CppAsString2(RELKIND_SEQUENCE) " AND "
6860  "d.classid = 'pg_class'::regclass AND d.objid = c.oid AND "
6861  "d.objsubid = 0 AND "
6862  "d.refclassid = 'pg_class'::regclass AND d.deptype IN ('a', 'i'))\n"
6863  "LEFT JOIN pg_tablespace tsp ON (tsp.oid = c.reltablespace)\n");
6864 
6865  /*
6866  * In 9.6 and up, left join to pg_am to pick up the amname.
6867  */
6868  if (fout->remoteVersion >= 90600)
6869  appendPQExpBufferStr(query,
6870  "LEFT JOIN pg_am am ON (c.relam = am.oid)\n");
6871 
6872  /*
6873  * We purposefully ignore toast OIDs for partitioned tables; the reason is
6874  * that versions 10 and 11 have them, but later versions do not, so
6875  * emitting them causes the upgrade to fail.
6876  */
6877  appendPQExpBufferStr(query,
6878  "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid"
6879  " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE)
6880  " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
6881 
6882  /*
6883  * Restrict to interesting relkinds (in particular, not indexes). Not all
6884  * relkinds are possible in older servers, but it's not worth the trouble
6885  * to emit a version-dependent list.
6886  *
6887  * Composite-type table entries won't be dumped as such, but we have to
6888  * make a DumpableObject for them so that we can track dependencies of the
6889  * composite type (pg_depend entries for columns of the composite type
6890  * link to the pg_class entry not the pg_type entry).
6891  */
6892  appendPQExpBufferStr(query,
6893  "WHERE c.relkind IN ("
6894  CppAsString2(RELKIND_RELATION) ", "
6895  CppAsString2(RELKIND_SEQUENCE) ", "
6896  CppAsString2(RELKIND_VIEW) ", "
6897  CppAsString2(RELKIND_COMPOSITE_TYPE) ", "
6898  CppAsString2(RELKIND_MATVIEW) ", "
6899  CppAsString2(RELKIND_FOREIGN_TABLE) ", "
6900  CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n"
6901  "ORDER BY c.oid");
6902 
6903  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6904 
6905  ntups = PQntuples(res);
6906 
6907  *numTables = ntups;
6908 
6909  /*
6910  * Extract data from result and lock dumpable tables. We do the locking
6911  * before anything else, to minimize the window wherein a table could
6912  * disappear under us.
6913  *
6914  * Note that we have to save info about all tables here, even when dumping
6915  * only one, because we don't yet know which tables might be inheritance
6916  * ancestors of the target table.
6917  */
6918  tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
6919 
6920  i_reltableoid = PQfnumber(res, "tableoid");
6921  i_reloid = PQfnumber(res, "oid");
6922  i_relname = PQfnumber(res, "relname");
6923  i_relnamespace = PQfnumber(res, "relnamespace");
6924  i_relkind = PQfnumber(res, "relkind");
6925  i_reltype = PQfnumber(res, "reltype");
6926  i_relowner = PQfnumber(res, "relowner");
6927  i_relchecks = PQfnumber(res, "relchecks");
6928  i_relhasindex = PQfnumber(res, "relhasindex");
6929  i_relhasrules = PQfnumber(res, "relhasrules");
6930  i_relpages = PQfnumber(res, "relpages");
6931  i_toastpages = PQfnumber(res, "toastpages");
6932  i_owning_tab = PQfnumber(res, "owning_tab");
6933  i_owning_col = PQfnumber(res, "owning_col");
6934  i_reltablespace = PQfnumber(res, "reltablespace");
6935  i_relhasoids = PQfnumber(res, "relhasoids");
6936  i_relhastriggers = PQfnumber(res, "relhastriggers");
6937  i_relpersistence = PQfnumber(res, "relpersistence");
6938  i_relispopulated = PQfnumber(res, "relispopulated");
6939  i_relreplident = PQfnumber(res, "relreplident");
6940  i_relrowsec = PQfnumber(res, "relrowsecurity");
6941  i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
6942  i_relfrozenxid = PQfnumber(res, "relfrozenxid");
6943  i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
6944  i_toastoid = PQfnumber(res, "toid");
6945  i_relminmxid = PQfnumber(res, "relminmxid");
6946  i_toastminmxid = PQfnumber(res, "tminmxid");
6947  i_reloptions = PQfnumber(res, "reloptions");
6948  i_checkoption = PQfnumber(res, "checkoption");
6949  i_toastreloptions = PQfnumber(res, "toast_reloptions");
6950  i_reloftype = PQfnumber(res, "reloftype");
6951  i_foreignserver = PQfnumber(res, "foreignserver");
6952  i_amname = PQfnumber(res, "amname");
6953  i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
6954  i_relacl = PQfnumber(res, "relacl");
6955  i_acldefault = PQfnumber(res, "acldefault");
6956  i_ispartition = PQfnumber(res, "ispartition");
6957 
6958  if (dopt->lockWaitTimeout)
6959  {
6960  /*
6961  * Arrange to fail instead of waiting forever for a table lock.
6962  *
6963  * NB: this coding assumes that the only queries issued within the
6964  * following loop are LOCK TABLEs; else the timeout may be undesirably
6965  * applied to other things too.
6966  */
6967  resetPQExpBuffer(query);
6968  appendPQExpBufferStr(query, "SET statement_timeout = ");
6970  ExecuteSqlStatement(fout, query->data);
6971  }
6972 
6973  resetPQExpBuffer(query);
6974 
6975  for (i = 0; i < ntups; i++)
6976  {
6977  tblinfo[i].dobj.objType = DO_TABLE;
6978  tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
6979  tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
6980  AssignDumpId(&tblinfo[i].dobj);
6981  tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
6982  tblinfo[i].dobj.namespace =
6983  findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)));
6984  tblinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_relacl));
6985  tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6986  tblinfo[i].dacl.privtype = 0;
6987  tblinfo[i].dacl.initprivs = NULL;
6988  tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
6989  tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
6990  tblinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_relowner));
6991  tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
6992  tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
6993  tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
6994  tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
6995  if (PQgetisnull(res, i, i_toastpages))
6996  tblinfo[i].toastpages = 0;
6997  else
6998  tblinfo[i].toastpages = atoi(PQgetvalue(res, i, i_toastpages));
6999  if (PQgetisnull(res, i, i_owning_tab))
7000  {
7001  tblinfo[i].owning_tab = InvalidOid;
7002  tblinfo[i].owning_col = 0;
7003  }
7004  else
7005  {
7006  tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
7007  tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
7008  }
7009  tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
7010  tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
7011  tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
7012  tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
7013  tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
7014  tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
7015  tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
7016  tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
7017  tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
7018  tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
7019  tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
7020  tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
7021  tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
7022  tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
7023  if (PQgetisnull(res, i, i_checkoption))
7024  tblinfo[i].checkoption = NULL;
7025  else
7026  tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
7027  tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
7028  tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
7029  tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver));
7030  if (PQgetisnull(res, i, i_amname))
7031  tblinfo[i].amname = NULL;
7032  else
7033  tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
7034  tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
7035  tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
7036 
7037  /* other fields were zeroed above */
7038 
7039  /*
7040  * Decide whether we want to dump this table.
7041  */
7042  if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
7043  tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
7044  else
7045  selectDumpableTable(&tblinfo[i], fout);
7046 
7047  /*
7048  * Now, consider the table "interesting" if we need to dump its
7049  * definition or its data. Later on, we'll skip a lot of data
7050  * collection for uninteresting tables.
7051  *
7052  * Note: the "interesting" flag will also be set by flagInhTables for
7053  * parents of interesting tables, so that we collect necessary
7054  * inheritance info even when the parents are not themselves being
7055  * dumped. This is the main reason why we need an "interesting" flag
7056  * that's separate from the components-to-dump bitmask.
7057  */
7058  tblinfo[i].interesting = (tblinfo[i].dobj.dump &
7060  DUMP_COMPONENT_DATA)) != 0;
7061 
7062  tblinfo[i].dummy_view = false; /* might get set during sort */
7063  tblinfo[i].postponed_def = false; /* might get set during sort */
7064 
7065  /* Tables have data */
7066  tblinfo[i].dobj.components |= DUMP_COMPONENT_DATA;
7067 
7068  /* Mark whether table has an ACL */
7069  if (!PQgetisnull(res, i, i_relacl))
7070  tblinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
7071  tblinfo[i].hascolumnACLs = false; /* may get set later */
7072 
7073  /*
7074  * Read-lock target tables to make sure they aren't DROPPED or altered
7075  * in schema before we get around to dumping them.
7076  *
7077  * Note that we don't explicitly lock parents of the target tables; we
7078  * assume our lock on the child is enough to prevent schema
7079  * alterations to parent tables.
7080  *
7081  * NOTE: it'd be kinda nice to lock other relations too, not only
7082  * plain or partitioned tables, but the backend doesn't presently
7083  * allow that.
7084  *
7085  * We only need to lock the table for certain components; see
7086  * pg_dump.h
7087  */
7088  if ((tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK) &&
7089  (tblinfo[i].relkind == RELKIND_RELATION ||
7090  tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE))
7091  {
7092  /*
7093  * Tables are locked in batches. When dumping from a remote
7094  * server this can save a significant amount of time by reducing
7095  * the number of round trips.
7096  */
7097  if (query->len == 0)
7098  appendPQExpBuffer(query, "LOCK TABLE %s",
7099  fmtQualifiedDumpable(&tblinfo[i]));
7100  else
7101  {
7102  appendPQExpBuffer(query, ", %s",
7103  fmtQualifiedDumpable(&tblinfo[i]));
7104 
7105  /* Arbitrarily end a batch when query length reaches 100K. */
7106  if (query->len >= 100000)
7107  {
7108  /* Lock another batch of tables. */
7109  appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
7110  ExecuteSqlStatement(fout, query->data);
7111  resetPQExpBuffer(query);
7112  }
7113  }
7114  }
7115  }
7116 
7117  if (query->len != 0)
7118  {
7119  /* Lock the tables in the last batch. */
7120  appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
7121  ExecuteSqlStatement(fout, query->data);
7122  }
7123 
7124  if (dopt->lockWaitTimeout)
7125  {
7126  ExecuteSqlStatement(fout, "SET statement_timeout = 0");
7127  }
7128 
7129  PQclear(res);
7130 
7131  destroyPQExpBuffer(query);
7132 
7133  return tblinfo;
7134 }
7135 
7136 /*
7137  * getOwnedSeqs
7138  * identify owned sequences and mark them as dumpable if owning table is
7139  *
7140  * We used to do this in getTables(), but it's better to do it after the
7141  * index used by findTableByOid() has been set up.
7142  */
7143 void
7144 getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
7145 {
7146  int i;
7147 
7148  /*
7149  * Force sequences that are "owned" by table columns to be dumped whenever
7150  * their owning table is being dumped.
7151  */
7152  for (i = 0; i < numTables; i++)
7153  {
7154  TableInfo *seqinfo = &tblinfo[i];
7155  TableInfo *owning_tab;
7156 
7157  if (!OidIsValid(seqinfo->owning_tab))
7158  continue; /* not an owned sequence */
7159 
7160  owning_tab = findTableByOid(seqinfo->owning_tab);
7161  if (owning_tab == NULL)
7162  pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
7163  seqinfo->owning_tab, seqinfo->dobj.catId.oid);
7164 
7165  /*
7166  * Only dump identity sequences if we're going to dump the table that
7167  * it belongs to.
7168  */
7169  if (owning_tab->dobj.dump == DUMP_COMPONENT_NONE &&
7170  seqinfo->is_identity_sequence)
7171  {
7172  seqinfo->dobj.dump = DUMP_COMPONENT_NONE;
7173  continue;
7174  }
7175 
7176  /*
7177  * Otherwise we need to dump the components that are being dumped for
7178  * the table and any components which the sequence is explicitly
7179  * marked with.
7180  *
7181  * We can't simply use the set of components which are being dumped
7182  * for the table as the table might be in an extension (and only the
7183  * non-extension components, eg: ACLs if changed, security labels, and
7184  * policies, are being dumped) while the sequence is not (and
7185  * therefore the definition and other components should also be
7186  * dumped).
7187  *
7188  * If the sequence is part of the extension then it should be properly
7189  * marked by checkExtensionMembership() and this will be a no-op as
7190  * the table will be equivalently marked.
7191  */
7192  seqinfo->dobj.dump = seqinfo->dobj.dump | owning_tab->dobj.dump;
7193 
7194  if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
7195  seqinfo->interesting = true;
7196  }
7197 }
7198 
7199 /*
7200  * getInherits
7201  * read all the inheritance information
7202  * from the system catalogs return them in the InhInfo* structure
7203  *
7204  * numInherits is set to the number of pairs read in
7205  */
7206 InhInfo *
7207 getInherits(Archive *fout, int *numInherits)
7208 {
7209  PGresult *res;
7210  int ntups;
7211  int i;
7212  PQExpBuffer query = createPQExpBuffer();
7213  InhInfo *inhinfo;
7214 
7215  int i_inhrelid;
7216  int i_inhparent;
7217 
7218  /* find all the inheritance information */
7219  appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
7220 
7221  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7222 
7223  ntups = PQntuples(res);
7224 
7225  *numInherits = ntups;
7226 
7227  inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
7228 
7229  i_inhrelid = PQfnumber(res, "inhrelid");
7230  i_inhparent = PQfnumber(res, "inhparent");
7231 
7232  for (i = 0; i < ntups; i++)
7233  {
7234  inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
7235  inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
7236  }
7237 
7238  PQclear(res);
7239 
7240  destroyPQExpBuffer(query);
7241 
7242  return inhinfo;
7243 }
7244 
7245 /*
7246  * getPartitioningInfo
7247  * get information about partitioning
7248  *
7249  * For the most part, we only collect partitioning info about tables we
7250  * intend to dump. However, this function has to consider all partitioned
7251  * tables in the database, because we need to know about parents of partitions
7252  * we are going to dump even if the parents themselves won't be dumped.
7253  *
7254  * Specifically, what we need to know is whether each partitioned table
7255  * has an "unsafe" partitioning scheme that requires us to force
7256  * load-via-partition-root mode for its children. Currently the only case
7257  * for which we force that is hash partitioning on enum columns, since the
7258  * hash codes depend on enum value OIDs which won't be replicated across
7259  * dump-and-reload. There are other cases in which load-via-partition-root
7260  * might be necessary, but we expect users to cope with them.
7261  */
7262 void
7264 {
7265  PQExpBuffer query;
7266  PGresult *res;
7267  int ntups;
7268 
7269  /* hash partitioning didn't exist before v11 */
7270  if (fout->remoteVersion < 110000)
7271  return;
7272  /* needn't bother if schema-only dump */
7273  if (fout->dopt->schemaOnly)
7274  return;
7275 
7276  query = createPQExpBuffer();
7277 
7278  /*
7279  * Unsafe partitioning schemes are exactly those for which hash enum_ops
7280  * appears among the partition opclasses. We needn't check partstrat.
7281  *
7282  * Note that this query may well retrieve info about tables we aren't
7283  * going to dump and hence have no lock on. That's okay since we need not
7284  * invoke any unsafe server-side functions.
7285  */
7286  appendPQExpBufferStr(query,
7287  "SELECT partrelid FROM pg_partitioned_table WHERE\n"
7288  "(SELECT c.oid FROM pg_opclass c JOIN pg_am a "
7289  "ON c.opcmethod = a.oid\n"
7290  "WHERE opcname = 'enum_ops' "
7291  "AND opcnamespace = 'pg_catalog'::regnamespace "
7292  "AND amname = 'hash') = ANY(partclass)");
7293 
7294  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7295 
7296  ntups = PQntuples(res);
7297 
7298  for (int i = 0; i < ntups; i++)
7299  {
7300  Oid tabrelid = atooid(PQgetvalue(res, i, 0));
7301  TableInfo *tbinfo;
7302 
7303  tbinfo = findTableByOid(tabrelid);
7304  if (tbinfo == NULL)
7305  pg_fatal("failed sanity check, table OID %u appearing in pg_partitioned_table not found",
7306  tabrelid);
7307  tbinfo->unsafe_partitions = true;
7308  }
7309 
7310  PQclear(res);
7311 
7312  destroyPQExpBuffer(query);
7313 }
7314 
7315 /*
7316  * getIndexes
7317  * get information about every index on a dumpable table
7318  *
7319  * Note: index data is not returned directly to the caller, but it
7320  * does get entered into the DumpableObject tables.
7321  */
7322 void
7323 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
7324 {
7325  PQExpBuffer query = createPQExpBuffer();
7326  PQExpBuffer tbloids = createPQExpBuffer();
7327  PGresult *res;
7328  int ntups;
7329  int curtblindx;
7330  IndxInfo *indxinfo;
7331  int i_tableoid,
7332  i_oid,
7333  i_indrelid,
7334  i_indexname,
7335  i_parentidx,
7336  i_indexdef,
7337  i_indnkeyatts,
7338  i_indnatts,
7339  i_indkey,
7340  i_indisclustered,
7341  i_indisreplident,
7342  i_indnullsnotdistinct,
7343  i_contype,
7344  i_conname,
7345  i_condeferrable,
7346  i_condeferred,
7347  i_conperiod,
7348  i_contableoid,
7349  i_conoid,
7350  i_condef,
7351  i_tablespace,
7352  i_indreloptions,
7353  i_indstatcols,
7354  i_indstatvals;
7355 
7356  /*
7357  * We want to perform just one query against pg_index. However, we
7358  * mustn't try to select every row of the catalog and then sort it out on
7359  * the client side, because some of the server-side functions we need
7360  * would be unsafe to apply to tables we don't have lock on. Hence, we
7361  * build an array of the OIDs of tables we care about (and now have lock
7362  * on!), and use a WHERE clause to constrain which rows are selected.
7363  */
7364  appendPQExpBufferChar(tbloids, '{');
7365  for (int i = 0; i < numTables; i++)
7366  {
7367  TableInfo *tbinfo = &tblinfo[i];
7368 
7369  if (!tbinfo->hasindex)
7370  continue;
7371 
7372  /*
7373  * We can ignore indexes of uninteresting tables.
7374  */
7375  if (!tbinfo->interesting)
7376  continue;
7377 
7378  /* OK, we need info for this table */
7379  if (tbloids->len > 1) /* do we have more than the '{'? */
7380  appendPQExpBufferChar(tbloids, ',');
7381  appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
7382  }
7383  appendPQExpBufferChar(tbloids, '}');
7384 
7385  appendPQExpBufferStr(query,
7386  "SELECT t.tableoid, t.oid, i.indrelid, "
7387  "t.relname AS indexname, "
7388  "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
7389  "i.indkey, i.indisclustered, "
7390  "c.contype, c.conname, "
7391  "c.condeferrable, c.condeferred, "
7392  "c.tableoid AS contableoid, "
7393  "c.oid AS conoid, "
7394  "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
7395  "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
7396  "t.reloptions AS indreloptions, ");
7397 
7398 
7399  if (fout->remoteVersion >= 90400)
7400  appendPQExpBufferStr(query,
7401  "i.indisreplident, ");
7402  else
7403  appendPQExpBufferStr(query,
7404  "false AS indisreplident, ");
7405 
7406  if (fout->remoteVersion >= 110000)
7407  appendPQExpBufferStr(query,
7408  "inh.inhparent AS parentidx, "
7409  "i.indnkeyatts AS indnkeyatts, "
7410  "i.indnatts AS indnatts, "
7411  "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
7412  " FROM pg_catalog.pg_attribute "
7413  " WHERE attrelid = i.indexrelid AND "
7414  " attstattarget >= 0) AS indstatcols, "
7415  "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
7416  " FROM pg_catalog.pg_attribute "
7417  " WHERE attrelid = i.indexrelid AND "
7418  " attstattarget >= 0) AS indstatvals, ");
7419  else
7420  appendPQExpBufferStr(query,
7421  "0 AS parentidx, "
7422  "i.indnatts AS indnkeyatts, "
7423  "i.indnatts AS indnatts, "
7424  "'' AS indstatcols, "
7425  "'' AS indstatvals, ");
7426 
7427  if (fout->remoteVersion >= 150000)
7428  appendPQExpBufferStr(query,
7429  "i.indnullsnotdistinct, ");
7430  else
7431  appendPQExpBufferStr(query,
7432  "false AS indnullsnotdistinct, ");
7433 
7434  if (fout->remoteVersion >= 170000)
7435  appendPQExpBufferStr(query,
7436  "c.conperiod ");
7437  else
7438  appendPQExpBufferStr(query,
7439  "NULL AS conperiod ");
7440 
7441  /*
7442  * The point of the messy-looking outer join is to find a constraint that
7443  * is related by an internal dependency link to the index. If we find one,
7444  * create a CONSTRAINT entry linked to the INDEX entry. We assume an
7445  * index won't have more than one internal dependency.
7446  *
7447  * Note: the check on conrelid is redundant, but useful because that
7448  * column is indexed while conindid is not.
7449  */
7450  if (fout->remoteVersion >= 110000)
7451  {
7452  appendPQExpBuffer(query,
7453  "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
7454  "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
7455  "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
7456  "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
7457  "LEFT JOIN pg_catalog.pg_constraint c "
7458  "ON (i.indrelid = c.conrelid AND "
7459  "i.indexrelid = c.conindid AND "
7460  "c.contype IN ('p','u','x')) "
7461  "LEFT JOIN pg_catalog.pg_inherits inh "
7462  "ON (inh.inhrelid = indexrelid) "
7463  "WHERE (i.indisvalid OR t2.relkind = 'p') "
7464  "AND i.indisready "
7465  "ORDER BY i.indrelid, indexname",
7466  tbloids->data);
7467  }
7468  else
7469  {
7470  /*
7471  * the test on indisready is necessary in 9.2, and harmless in
7472  * earlier/later versions
7473  */
7474  appendPQExpBuffer(query,
7475  "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
7476  "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
7477  "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
7478  "LEFT JOIN pg_catalog.pg_constraint c "
7479  "ON (i.indrelid = c.conrelid AND "
7480  "i.indexrelid = c.conindid AND "
7481  "c.contype IN ('p','u','x')) "
7482  "WHERE i.indisvalid AND i.indisready "
7483  "ORDER BY i.indrelid, indexname",
7484  tbloids->data);
7485  }
7486 
7487  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7488 
7489  ntups = PQntuples(res);
7490 
7491  i_tableoid = PQfnumber(res, "tableoid");
7492  i_oid = PQfnumber(res, "oid");
7493  i_indrelid = PQfnumber(res, "indrelid");
7494  i_indexname = PQfnumber(res, "indexname");
7495  i_parentidx = PQfnumber(res, "parentidx");
7496  i_indexdef = PQfnumber(res, "indexdef");
7497  i_indnkeyatts = PQfnumber(res, "indnkeyatts");
7498  i_indnatts = PQfnumber(res, "indnatts");
7499  i_indkey = PQfnumber(res, "indkey");
7500  i_indisclustered = PQfnumber(res, "indisclustered");
7501  i_indisreplident = PQfnumber(res, "indisreplident");
7502  i_indnullsnotdistinct = PQfnumber(res, "indnullsnotdistinct");
7503  i_contype = PQfnumber(res, "contype");
7504  i_conname = PQfnumber(res, "conname");
7505  i_condeferrable = PQfnumber(res, "condeferrable");
7506  i_condeferred = PQfnumber(res, "condeferred");
7507  i_conperiod = PQfnumber(res, "conperiod");
7508  i_contableoid = PQfnumber(res, "contableoid");
7509  i_conoid = PQfnumber(res, "conoid");
7510  i_condef = PQfnumber(res, "condef");
7511  i_tablespace = PQfnumber(res, "tablespace");
7512  i_indreloptions = PQfnumber(res, "indreloptions");
7513  i_indstatcols = PQfnumber(res, "indstatcols");
7514  i_indstatvals = PQfnumber(res, "indstatvals");
7515 
7516  indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
7517 
7518  /*
7519  * Outer loop iterates once per table, not once per row. Incrementing of
7520  * j is handled by the inner loop.
7521  */
7522  curtblindx = -1;
7523  for (int j = 0; j < ntups;)
7524  {
7525  Oid indrelid = atooid(PQgetvalue(res, j, i_indrelid));
7526  TableInfo *tbinfo = NULL;
7527  int numinds;
7528 
7529  /* Count rows for this table */
7530  for (numinds = 1; numinds < ntups - j; numinds++)
7531  if (atooid(PQgetvalue(res, j + numinds, i_indrelid)) != indrelid)
7532  break;
7533 
7534  /*
7535  * Locate the associated TableInfo; we rely on tblinfo[] being in OID
7536  * order.
7537  */
7538  while (++curtblindx < numTables)
7539  {
7540  tbinfo = &tblinfo[curtblindx];
7541  if (tbinfo->dobj.catId.oid == indrelid)
7542  break;
7543  }
7544  if (curtblindx >= numTables)
7545  pg_fatal("unrecognized table OID %u", indrelid);
7546  /* cross-check that we only got requested tables */
7547  if (!tbinfo->hasindex ||
7548  !tbinfo->interesting)
7549  pg_fatal("unexpected index data for table \"%s\"",
7550  tbinfo->dobj.name);
7551 
7552  /* Save data for this table */
7553  tbinfo->indexes = indxinfo + j;
7554  tbinfo->numIndexes = numinds;
7555 
7556  for (int c = 0; c < numinds; c++, j++)
7557  {
7558  char contype;
7559 
7560  indxinfo[j].dobj.objType = DO_INDEX;
7561  indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
7562  indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7563  AssignDumpId(&indxinfo[j].dobj);
7564  indxinfo[j].dobj.dump = tbinfo->dobj.dump;
7565  indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
7566  indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7567  indxinfo[j].indextable = tbinfo;
7568  indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
7569  indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
7570  indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
7571  indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
7572  indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
7573  indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
7574  indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
7575  indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
7576  parseOidArray(PQgetvalue(res, j, i_indkey),
7577  indxinfo[j].indkeys, indxinfo[j].indnattrs);
7578  indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
7579  indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
7580  indxinfo[j].indnullsnotdistinct = (PQgetvalue(res, j, i_indnullsnotdistinct)[0] == 't');
7581  indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
7582  indxinfo[j].partattaches = (SimplePtrList)
7583  {
7584  NULL, NULL
7585  };
7586  contype = *(PQgetvalue(res, j, i_contype));
7587 
7588  if (contype == 'p' || contype == 'u' || contype == 'x')
7589  {
7590  /*
7591  * If we found a constraint matching the index, create an
7592  * entry for it.
7593  */
7594  ConstraintInfo *constrinfo;
7595 
7596  constrinfo = (ConstraintInfo *) pg_malloc(sizeof(ConstraintInfo));
7597  constrinfo->dobj.objType = DO_CONSTRAINT;
7598  constrinfo->dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7599  constrinfo->dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7600  AssignDumpId(&constrinfo->dobj);
7601  constrinfo->dobj.dump = tbinfo->dobj.dump;
7602  constrinfo->dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7603  constrinfo->dobj.namespace = tbinfo->dobj.namespace;
7604  constrinfo->contable = tbinfo;
7605  constrinfo->condomain = NULL;
7606  constrinfo->contype = contype;
7607  if (contype == 'x')
7608  constrinfo->condef = pg_strdup(PQgetvalue(res, j, i_condef));
7609  else
7610  constrinfo->condef = NULL;
7611  constrinfo->confrelid = InvalidOid;
7612  constrinfo->conindex = indxinfo[j].dobj.dumpId;
7613  constrinfo->condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
7614  constrinfo->condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
7615  constrinfo->conperiod = *(PQgetvalue(res, j, i_conperiod)) == 't';
7616  constrinfo->conislocal = true;
7617  constrinfo->separate = true;
7618 
7619  indxinfo[j].indexconstraint = constrinfo->dobj.dumpId;
7620  }
7621  else
7622  {
7623  /* Plain secondary index */
7624  indxinfo[j].indexconstraint = 0;
7625  }
7626  }
7627  }
7628 
7629  PQclear(res);
7630 
7631  destroyPQExpBuffer(query);
7632  destroyPQExpBuffer(tbloids);
7633 }
7634 
7635 /*
7636  * getExtendedStatistics
7637  * get information about extended-statistics objects.
7638  *
7639  * Note: extended statistics data is not returned directly to the caller, but
7640  * it does get entered into the DumpableObject tables.
7641  */
7642 void
7644 {
7645  PQExpBuffer query;
7646  PGresult *res;
7647  StatsExtInfo *statsextinfo;
7648  int ntups;
7649  int i_tableoid;
7650  int i_oid;
7651  int i_stxname;
7652  int i_stxnamespace;
7653  int i_stxowner;
7654  int i_stxrelid;
7655  int i_stattarget;
7656  int i;
7657 
7658  /* Extended statistics were new in v10 */
7659  if (fout->remoteVersion < 100000)
7660  return;
7661 
7662  query = createPQExpBuffer();
7663 
7664  if (fout->remoteVersion < 130000)
7665  appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
7666  "stxnamespace, stxowner, stxrelid, NULL AS stxstattarget "
7667  "FROM pg_catalog.pg_statistic_ext");
7668  else
7669  appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
7670  "stxnamespace, stxowner, stxrelid, stxstattarget "
7671  "FROM pg_catalog.pg_statistic_ext");
7672 
7673  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7674 
7675  ntups = PQntuples(res);
7676 
7677  i_tableoid = PQfnumber(res, "tableoid");
7678  i_oid = PQfnumber(res, "oid");
7679  i_stxname = PQfnumber(res, "stxname");
7680  i_stxnamespace = PQfnumber(res, "stxnamespace");
7681  i_stxowner = PQfnumber(res, "stxowner");
7682  i_stxrelid = PQfnumber(res, "stxrelid");
7683  i_stattarget = PQfnumber(res, "stxstattarget");
7684 
7685  statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
7686 
7687  for (i = 0; i < ntups; i++)
7688  {
7689  statsextinfo[i].dobj.objType = DO_STATSEXT;
7690  statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7691  statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7692  AssignDumpId(&statsextinfo[i].dobj);
7693  statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
7694  statsextinfo[i].dobj.namespace =
7695  findNamespace(atooid(PQgetvalue(res, i, i_stxnamespace)));
7696  statsextinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_stxowner));
7697  statsextinfo[i].stattable =
7698  findTableByOid(atooid(PQgetvalue(res, i, i_stxrelid)));
7699  if (PQgetisnull(res, i, i_stattarget))
7700  statsextinfo[i].stattarget = -1;
7701  else
7702  statsextinfo[i].stattarget = atoi(PQgetvalue(res, i, i_stattarget));
7703 
7704  /* Decide whether we want to dump it */
7705  selectDumpableStatisticsObject(&(statsextinfo[i]), fout);
7706  }
7707 
7708  PQclear(res);
7709  destroyPQExpBuffer(query);
7710 }
7711 
7712 /*
7713  * getConstraints
7714  *
7715  * Get info about constraints on dumpable tables.
7716  *
7717  * Currently handles foreign keys only.
7718  * Unique and primary key constraints are handled with indexes,
7719  * while check constraints are processed in getTableAttrs().
7720  */
7721 void
7722 getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
7723 {
7724  PQExpBuffer query = createPQExpBuffer();
7725  PQExpBuffer tbloids = createPQExpBuffer();
7726  PGresult *res;
7727  int ntups;
7728  int curtblindx;
7729  TableInfo *tbinfo = NULL;
7730  ConstraintInfo *constrinfo;
7731  int i_contableoid,
7732  i_conoid,
7733  i_conrelid,
7734  i_conname,
7735  i_confrelid,
7736  i_conindid,
7737  i_condef;
7738 
7739  /*
7740  * We want to perform just one query against pg_constraint. However, we
7741  * mustn't try to select every row of the catalog and then sort it out on
7742  * the client side, because some of the server-side functions we need
7743  * would be unsafe to apply to tables we don't have lock on. Hence, we
7744  * build an array of the OIDs of tables we care about (and now have lock
7745  * on!), and use a WHERE clause to constrain which rows are selected.
7746  */
7747  appendPQExpBufferChar(tbloids, '{');
7748  for (int i = 0; i < numTables; i++)
7749  {
7750  TableInfo *tinfo = &tblinfo[i];
7751 
7752  /*
7753  * For partitioned tables, foreign keys have no triggers so they must
7754  * be included anyway in case some foreign keys are defined.
7755  */
7756  if ((!tinfo->hastriggers &&
7757  tinfo->relkind != RELKIND_PARTITIONED_TABLE) ||
7758  !(tinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7759  continue;
7760 
7761  /* OK, we need info for this table */
7762  if (tbloids->len > 1) /* do we have more than the '{'? */
7763  appendPQExpBufferChar(tbloids, ',');
7764  appendPQExpBuffer(tbloids, "%u", tinfo->dobj.catId.oid);
7765  }
7766  appendPQExpBufferChar(tbloids, '}');
7767 
7768  appendPQExpBufferStr(query,
7769  "SELECT c.tableoid, c.oid, "
7770  "conrelid, conname, confrelid, ");
7771  if (fout->remoteVersion >= 110000)
7772  appendPQExpBufferStr(query, "conindid, ");
7773  else
7774  appendPQExpBufferStr(query, "0 AS conindid, ");
7775  appendPQExpBuffer(query,
7776  "pg_catalog.pg_get_constraintdef(c.oid) AS condef\n"
7777  "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
7778  "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
7779  "WHERE contype = 'f' ",
7780  tbloids->data);
7781  if (fout->remoteVersion >= 110000)
7782  appendPQExpBufferStr(query,
7783  "AND conparentid = 0 ");
7784  appendPQExpBufferStr(query,
7785  "ORDER BY conrelid, conname");
7786 
7787  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7788 
7789  ntups = PQntuples(res);
7790 
7791  i_contableoid = PQfnumber(res, "tableoid");
7792  i_conoid = PQfnumber(res, "oid");
7793  i_conrelid = PQfnumber(res, "conrelid");
7794  i_conname = PQfnumber(res, "conname");
7795  i_confrelid = PQfnumber(res, "confrelid");
7796  i_conindid = PQfnumber(res, "conindid");
7797  i_condef = PQfnumber(res, "condef");
7798 
7799  constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7800 
7801  curtblindx = -1;
7802  for (int j = 0; j < ntups; j++)
7803  {
7804  Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
7805  TableInfo *reftable;
7806 
7807  /*
7808  * Locate the associated TableInfo; we rely on tblinfo[] being in OID
7809  * order.
7810  */
7811  if (tbinfo == NULL || tbinfo->dobj.catId.oid != conrelid)
7812  {
7813  while (++curtblindx < numTables)
7814  {
7815  tbinfo = &tblinfo[curtblindx];
7816  if (tbinfo->dobj.catId.oid == conrelid)
7817  break;
7818  }
7819  if (curtblindx >= numTables)
7820  pg_fatal("unrecognized table OID %u", conrelid);
7821  }
7822 
7823  constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
7824  constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7825  constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7826  AssignDumpId(&constrinfo[j].dobj);
7827  constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7828  constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7829  constrinfo[j].contable = tbinfo;
7830  constrinfo[j].condomain = NULL;
7831  constrinfo[j].contype = 'f';
7832  constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
7833  constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
7834  constrinfo[j].conindex = 0;
7835  constrinfo[j].condeferrable = false;
7836  constrinfo[j].condeferred = false;
7837  constrinfo[j].conislocal = true;
7838  constrinfo[j].separate = true;
7839 
7840  /*
7841  * Restoring an FK that points to a partitioned table requires that
7842  * all partition indexes have been attached beforehand. Ensure that
7843  * happens by making the constraint depend on each index partition
7844  * attach object.
7845  */
7846  reftable = findTableByOid(constrinfo[j].confrelid);
7847  if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)
7848  {
7849  Oid indexOid = atooid(PQgetvalue(res, j, i_conindid));
7850 
7851  if (indexOid != InvalidOid)
7852  {
7853  for (int k = 0; k < reftable->numIndexes; k++)
7854  {
7855  IndxInfo *refidx;
7856 
7857  /* not our index? */
7858  if (reftable->indexes[k].dobj.catId.oid != indexOid)
7859  continue;
7860 
7861  refidx = &reftable->indexes[k];
7862  addConstrChildIdxDeps(&constrinfo[j].dobj, refidx);
7863  break;
7864  }
7865  }
7866  }
7867  }
7868 
7869  PQclear(res);
7870 
7871  destroyPQExpBuffer(query);
7872  destroyPQExpBuffer(tbloids);
7873 }
7874 
7875 /*
7876  * addConstrChildIdxDeps
7877  *
7878  * Recursive subroutine for getConstraints
7879  *
7880  * Given an object representing a foreign key constraint and an index on the
7881  * partitioned table it references, mark the constraint object as dependent
7882  * on the DO_INDEX_ATTACH object of each index partition, recursively
7883  * drilling down to their partitions if any. This ensures that the FK is not
7884  * restored until the index is fully marked valid.
7885  */
7886 static void
7888 {
7889  SimplePtrListCell *cell;
7890 
7891  Assert(dobj->objType == DO_FK_CONSTRAINT);
7892 
7893  for (cell = refidx->partattaches.head; cell; cell = cell->next)
7894  {
7895  IndexAttachInfo *attach = (IndexAttachInfo *) cell->ptr;
7896 
7897  addObjectDependency(dobj, attach->dobj.dumpId);
7898 
7899  if (attach->partitionIdx->partattaches.head != NULL)
7900  addConstrChildIdxDeps(dobj, attach->partitionIdx);
7901  }
7902 }
7903 
7904 /*
7905  * getDomainConstraints
7906  *
7907  * Get info about constraints on a domain.
7908  */
7909 static void
7911 {
7912  int i;
7913  ConstraintInfo *constrinfo;
7914  PQExpBuffer query = createPQExpBuffer();
7915  PGresult *res;
7916  int i_tableoid,
7917  i_oid,
7918  i_conname,
7919  i_consrc;
7920  int ntups;
7921 
7923  {
7924  /* Set up query for constraint-specific details */
7925  appendPQExpBufferStr(query,
7926  "PREPARE getDomainConstraints(pg_catalog.oid) AS\n"
7927  "SELECT tableoid, oid, conname, "
7928  "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7929  "convalidated "
7930  "FROM pg_catalog.pg_constraint "
7931  "WHERE contypid = $1 AND contype = 'c' "
7932  "ORDER BY conname");
7933 
7934  ExecuteSqlStatement(fout, query->data);
7935 
7937  }
7938 
7939  printfPQExpBuffer(query,
7940  "EXECUTE getDomainConstraints('%u')",
7941  tyinfo->dobj.catId.oid);
7942 
7943  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7944 
7945  ntups = PQntuples(res);
7946 
7947  i_tableoid = PQfnumber(res, "tableoid");
7948  i_oid = PQfnumber(res, "oid");
7949  i_conname = PQfnumber(res, "conname");
7950  i_consrc = PQfnumber(res, "consrc");
7951 
7952  constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7953 
7954  tyinfo->nDomChecks = ntups;
7955  tyinfo->domChecks = constrinfo;
7956 
7957  for (i = 0; i < ntups; i++)
7958  {
7959  bool validated = PQgetvalue(res, i, 4)[0] == 't';
7960 
7961  constrinfo[i].dobj.objType = DO_CONSTRAINT;
7962  constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7963  constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7964  AssignDumpId(&constrinfo[i].dobj);
7965  constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
7966  constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
7967  constrinfo[i].contable = NULL;
7968  constrinfo[i].condomain = tyinfo;
7969  constrinfo[i].contype = 'c';
7970  constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
7971  constrinfo[i].confrelid = InvalidOid;
7972  constrinfo[i].conindex = 0;
7973  constrinfo[i].condeferrable = false;
7974  constrinfo[i].condeferred = false;
7975  constrinfo[i].conislocal = true;
7976 
7977  constrinfo[i].separate = !validated;
7978 
7979  /*
7980  * Make the domain depend on the constraint, ensuring it won't be
7981  * output till any constraint dependencies are OK. If the constraint
7982  * has not been validated, it's going to be dumped after the domain
7983  * anyway, so this doesn't matter.
7984  */
7985  if (validated)
7986  addObjectDependency(&tyinfo->dobj,
7987  constrinfo[i].dobj.dumpId);
7988  }
7989 
7990  PQclear(res);
7991 
7992  destroyPQExpBuffer(query);
7993 }
7994 
7995 /*
7996  * getRules
7997  * get basic information about every rule in the system
7998  *
7999  * numRules is set to the number of rules read in
8000  */
8001 RuleInfo *
8002 getRules(Archive *fout, int *numRules)
8003 {
8004  PGresult *res;
8005  int ntups;
8006  int i;
8007  PQExpBuffer query = createPQExpBuffer();
8008  RuleInfo *ruleinfo;
8009  int i_tableoid;
8010  int i_oid;
8011  int i_rulename;
8012  int i_ruletable;
8013  int i_ev_type;
8014  int i_is_instead;
8015  int i_ev_enabled;
8016 
8017  appendPQExpBufferStr(query, "SELECT "
8018  "tableoid, oid, rulename, "
8019  "ev_class AS ruletable, ev_type, is_instead, "
8020  "ev_enabled "
8021  "FROM pg_rewrite "
8022  "ORDER BY oid");
8023 
8024  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8025 
8026  ntups = PQntuples(res);
8027 
8028  *numRules = ntups;
8029 
8030  ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
8031 
8032  i_tableoid = PQfnumber(res, "tableoid");
8033  i_oid = PQfnumber(res, "oid");
8034  i_rulename = PQfnumber(res, "rulename");
8035  i_ruletable = PQfnumber(res, "ruletable");
8036  i_ev_type = PQfnumber(res, "ev_type");
8037  i_is_instead = PQfnumber(res, "is_instead");
8038  i_ev_enabled = PQfnumber(res, "ev_enabled");
8039 
8040  for (i = 0; i < ntups; i++)
8041  {
8042  Oid ruletableoid;
8043 
8044  ruleinfo[i].dobj.objType = DO_RULE;
8045  ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8046  ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8047  AssignDumpId(&ruleinfo[i].dobj);
8048  ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
8049  ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
8050  ruleinfo[i].ruletable = findTableByOid(ruletableoid);
8051  if (ruleinfo[i].ruletable == NULL)
8052  pg_fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
8053  ruletableoid, ruleinfo[i].dobj.catId.oid);
8054  ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
8055  ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
8056  ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
8057  ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
8058  ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
8059  if (ruleinfo[i].ruletable)
8060  {
8061  /*
8062  * If the table is a view or materialized view, force its ON
8063  * SELECT rule to be sorted before the view itself --- this
8064  * ensures that any dependencies for the rule affect the table's
8065  * positioning. Other rules are forced to appear after their
8066  * table.
8067  */
8068  if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
8069  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
8070  ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
8071  {
8072  addObjectDependency(&ruleinfo[i].ruletable->dobj,
8073  ruleinfo[i].dobj.dumpId);
8074  /* We'll merge the rule into CREATE VIEW, if possible */
8075  ruleinfo[i].separate = false;
8076  }
8077  else
8078  {
8079  addObjectDependency(&ruleinfo[i].dobj,
8080  ruleinfo[i].ruletable->dobj.dumpId);
8081  ruleinfo[i].separate = true;
8082  }
8083  }
8084  else
8085  ruleinfo[i].separate = true;
8086  }
8087 
8088  PQclear(res);
8089 
8090  destroyPQExpBuffer(query);
8091 
8092  return ruleinfo;
8093 }
8094 
8095 /*
8096  * getTriggers
8097  * get information about every trigger on a dumpable table
8098  *
8099  * Note: trigger data is not returned directly to the caller, but it
8100  * does get entered into the DumpableObject tables.
8101  */
8102 void
8103 getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
8104 {
8105  PQExpBuffer query = createPQExpBuffer();
8106  PQExpBuffer tbloids = createPQExpBuffer();
8107  PGresult *res;
8108  int ntups;
8109  int curtblindx;
8110  TriggerInfo *tginfo;
8111  int i_tableoid,
8112  i_oid,
8113  i_tgrelid,
8114  i_tgname,
8115  i_tgenabled,
8116  i_tgispartition,
8117  i_tgdef;
8118 
8119  /*
8120  * We want to perform just one query against pg_trigger. However, we
8121  * mustn't try to select every row of the catalog and then sort it out on
8122  * the client side, because some of the server-side functions we need
8123  * would be unsafe to apply to tables we don't have lock on. Hence, we
8124  * build an array of the OIDs of tables we care about (and now have lock
8125  * on!), and use a WHERE clause to constrain which rows are selected.
8126  */
8127  appendPQExpBufferChar(tbloids, '{');
8128  for (int i = 0; i < numTables; i++)
8129  {
8130  TableInfo *tbinfo = &tblinfo[i];
8131 
8132  if (!tbinfo->hastriggers ||
8133  !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
8134  continue;
8135 
8136  /* OK, we need info for this table */
8137  if (tbloids->len > 1) /* do we have more than the '{'? */
8138  appendPQExpBufferChar(tbloids, ',');
8139  appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
8140  }
8141  appendPQExpBufferChar(tbloids, '}');
8142 
8143  if (fout->remoteVersion >= 150000)
8144  {
8145  /*
8146  * NB: think not to use pretty=true in pg_get_triggerdef. It could
8147  * result in non-forward-compatible dumps of WHEN clauses due to
8148  * under-parenthesization.
8149  *
8150  * NB: We need to see partition triggers in case the tgenabled flag
8151  * has been changed from the parent.
8152  */
8153  appendPQExpBuffer(query,
8154  "SELECT t.tgrelid, t.tgname, "
8155  "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8156  "t.tgenabled, t.tableoid, t.oid, "
8157  "t.tgparentid <> 0 AS tgispartition\n"
8158  "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8159  "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8160  "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
8161  "WHERE ((NOT t.tgisinternal AND t.tgparentid = 0) "
8162  "OR t.tgenabled != u.tgenabled) "
8163  "ORDER BY t.tgrelid, t.tgname",
8164  tbloids->data);
8165  }
8166  else if (fout->remoteVersion >= 130000)
8167  {
8168  /*
8169  * NB: think not to use pretty=true in pg_get_triggerdef. It could
8170  * result in non-forward-compatible dumps of WHEN clauses due to
8171  * under-parenthesization.
8172  *
8173  * NB: We need to see tgisinternal triggers in partitions, in case the
8174  * tgenabled flag has been changed from the parent.
8175  */
8176  appendPQExpBuffer(query,
8177  "SELECT t.tgrelid, t.tgname, "
8178  "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8179  "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition\n"
8180  "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8181  "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8182  "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
8183  "WHERE (NOT t.tgisinternal OR t.tgenabled != u.tgenabled) "
8184  "ORDER BY t.tgrelid, t.tgname",
8185  tbloids->data);
8186  }
8187  else if (fout->remoteVersion >= 110000)
8188  {
8189  /*
8190  * NB: We need to see tgisinternal triggers in partitions, in case the
8191  * tgenabled flag has been changed from the parent. No tgparentid in
8192  * version 11-12, so we have to match them via pg_depend.
8193  *
8194  * See above about pretty=true in pg_get_triggerdef.
8195  */
8196  appendPQExpBuffer(query,
8197  "SELECT t.tgrelid, t.tgname, "
8198  "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8199  "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition "
8200  "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8201  "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8202  "LEFT JOIN pg_catalog.pg_depend AS d ON "
8203  " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
8204  " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
8205  " d.objid = t.oid "
8206  "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "
8207  "WHERE (NOT t.tgisinternal OR t.tgenabled != pt.tgenabled) "
8208  "ORDER BY t.tgrelid, t.tgname",
8209  tbloids->data);
8210  }
8211  else
8212  {
8213  /* See above about pretty=true in pg_get_triggerdef */
8214  appendPQExpBuffer(query,
8215  "SELECT t.tgrelid, t.tgname, "
8216  "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8217  "t.tgenabled, false as tgispartition, "
8218  "t.tableoid, t.oid "
8219  "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8220  "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8221  "WHERE NOT tgisinternal "
8222  "ORDER BY t.tgrelid, t.tgname",
8223  tbloids->data);
8224  }
8225 
8226  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8227 
8228  ntups = PQntuples(res);
8229 
8230  i_tableoid = PQfnumber(res, "tableoid");
8231  i_oid = PQfnumber(res, "oid");
8232  i_tgrelid = PQfnumber(res, "tgrelid");
8233  i_tgname = PQfnumber(res, "tgname");
8234  i_tgenabled = PQfnumber(res, "tgenabled");
8235  i_tgispartition = PQfnumber(res, "tgispartition");
8236  i_tgdef = PQfnumber(res, "tgdef");
8237 
8238  tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
8239 
8240  /*
8241  * Outer loop iterates once per table, not once per row. Incrementing of
8242  * j is handled by the inner loop.
8243  */
8244  curtblindx = -1;
8245  for (int j = 0; j < ntups;)
8246  {
8247  Oid tgrelid = atooid(PQgetvalue(res, j, i_tgrelid));
8248  TableInfo *tbinfo = NULL;
8249  int numtrigs;
8250 
8251  /* Count rows for this table */
8252  for (numtrigs = 1; numtrigs < ntups - j; numtrigs++)
8253  if (atooid(PQgetvalue(res, j + numtrigs, i_tgrelid)) != tgrelid)
8254  break;
8255 
8256  /*
8257  * Locate the associated TableInfo; we rely on tblinfo[] being in OID
8258  * order.
8259  */
8260  while (++curtblindx < numTables)
8261  {
8262  tbinfo = &tblinfo[curtblindx];
8263  if (tbinfo->dobj.catId.oid == tgrelid)
8264  break;
8265  }
8266  if (curtblindx >= numTables)
8267  pg_fatal("unrecognized table OID %u", tgrelid);
8268 
8269  /* Save data for this table */
8270  tbinfo->triggers = tginfo + j;
8271  tbinfo->numTriggers = numtrigs;
8272 
8273  for (int c = 0; c < numtrigs; c++, j++)
8274  {
8275  tginfo[j].dobj.objType = DO_TRIGGER;
8276  tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
8277  tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
8278  AssignDumpId(&tginfo[j].dobj);
8279  tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
8280  tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
8281  tginfo[j].tgtable = tbinfo;
8282  tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
8283  tginfo[j].tgispartition = *(PQgetvalue(res, j, i_tgispartition)) == 't';
8284  tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
8285  }
8286  }
8287 
8288  PQclear(res);
8289 
8290  destroyPQExpBuffer(query);
8291  destroyPQExpBuffer(tbloids);
8292 }
8293 
8294 /*
8295  * getEventTriggers
8296  * get information about event triggers
8297  */
8299 getEventTriggers(Archive *fout, int *numEventTriggers)
8300 {
8301  int i;
8302  PQExpBuffer query;
8303  PGresult *res;
8304  EventTriggerInfo *evtinfo;
8305  int i_tableoid,
8306  i_oid,
8307  i_evtname,
8308  i_evtevent,
8309  i_evtowner,
8310  i_evttags,
8311  i_evtfname,
8312  i_evtenabled;
8313  int ntups;
8314 
8315  /* Before 9.3, there are no event triggers */
8316  if (fout->remoteVersion < 90300)
8317  {
8318  *numEventTriggers = 0;
8319  return NULL;
8320  }
8321 
8322  query = createPQExpBuffer();
8323 
8324  appendPQExpBufferStr(query,
8325  "SELECT e.tableoid, e.oid, evtname, evtenabled, "
8326  "evtevent, evtowner, "
8327  "array_to_string(array("
8328  "select quote_literal(x) "
8329  " from unnest(evttags) as t(x)), ', ') as evttags, "
8330  "e.evtfoid::regproc as evtfname "
8331  "FROM pg_event_trigger e "
8332  "ORDER BY e.oid");
8333 
8334  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8335 
8336  ntups = PQntuples(res);
8337 
8338  *numEventTriggers = ntups;
8339 
8340  evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
8341 
8342  i_tableoid = PQfnumber(res, "tableoid");
8343  i_oid = PQfnumber(res, "oid");
8344  i_evtname = PQfnumber(res, "evtname");
8345  i_evtevent = PQfnumber(res, "evtevent");
8346  i_evtowner = PQfnumber(res, "evtowner");
8347  i_evttags = PQfnumber(res, "evttags");
8348  i_evtfname = PQfnumber(res, "evtfname");
8349  i_evtenabled = PQfnumber(res, "evtenabled");
8350 
8351  for (i = 0; i < ntups; i++)
8352  {
8353  evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
8354  evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8355  evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8356  AssignDumpId(&evtinfo[i].dobj);
8357  evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
8358  evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
8359  evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
8360  evtinfo[i].evtowner = getRoleName(PQgetvalue(res, i, i_evtowner));
8361  evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
8362  evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
8363  evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
8364 
8365  /* Decide whether we want to dump it */
8366  selectDumpableObject(&(evtinfo[i].dobj), fout);
8367  }
8368 
8369  PQclear(res);
8370 
8371  destroyPQExpBuffer(query);
8372 
8373  return evtinfo;
8374 }
8375 
8376 /*
8377  * getProcLangs
8378  * get basic information about every procedural language in the system
8379  *
8380  * numProcLangs is set to the number of langs read in
8381  *
8382  * NB: this must run after getFuncs() because we assume we can do
8383  * findFuncByOid().
8384  */
8385 ProcLangInfo *
8386 getProcLangs(Archive *fout, int *numProcLangs)
8387 {
8388  PGresult *res;
8389  int ntups;
8390  int i;
8391  PQExpBuffer query = createPQExpBuffer();
8392  ProcLangInfo *planginfo;
8393  int i_tableoid;
8394  int i_oid;
8395  int i_lanname;
8396  int i_lanpltrusted;
8397  int i_lanplcallfoid;
8398  int i_laninline;
8399  int i_lanvalidator;
8400  int i_lanacl;
8401  int i_acldefault;
8402  int i_lanowner;
8403 
8404  appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8405  "lanname, lanpltrusted, lanplcallfoid, "
8406  "laninline, lanvalidator, "
8407  "lanacl, "
8408  "acldefault('l', lanowner) AS acldefault, "
8409  "lanowner "
8410  "FROM pg_language "
8411  "WHERE lanispl "
8412  "ORDER BY oid");
8413 
8414  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8415 
8416  ntups = PQntuples(res);
8417 
8418  *numProcLangs = ntups;
8419 
8420  planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
8421 
8422  i_tableoid = PQfnumber(res, "tableoid");
8423  i_oid = PQfnumber(res, "oid");
8424  i_lanname = PQfnumber(res, "lanname");
8425  i_lanpltrusted = PQfnumber(res, "lanpltrusted");
8426  i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
8427  i_laninline = PQfnumber(res, "laninline");
8428  i_lanvalidator = PQfnumber(res, "lanvalidator");
8429  i_lanacl = PQfnumber(res, "lanacl");
8430  i_acldefault = PQfnumber(res, "acldefault");
8431  i_lanowner = PQfnumber(res, "lanowner");
8432 
8433  for (i = 0; i < ntups; i++)
8434  {
8435  planginfo[i].dobj.objType = DO_PROCLANG;
8436  planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8437  planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8438  AssignDumpId(&planginfo[i].dobj);
8439 
8440  planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
8441  planginfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lanacl));
8442  planginfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
8443  planginfo[i].dacl.privtype = 0;
8444  planginfo[i].dacl.initprivs = NULL;
8445  planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
8446  planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
8447  planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
8448  planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
8449  planginfo[i].lanowner = getRoleName(PQgetvalue(res, i, i_lanowner));
8450 
8451  /* Decide whether we want to dump it */
8452  selectDumpableProcLang(&(planginfo[i]), fout);
8453 
8454  /* Mark whether language has an ACL */
8455  if (!PQgetisnull(res, i, i_lanacl))
8456  planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
8457  }
8458 
8459  PQclear(res);
8460 
8461  destroyPQExpBuffer(query);
8462 
8463  return planginfo;
8464 }
8465 
8466 /*
8467  * getCasts
8468  * get basic information about most casts in the system
8469  *
8470  * numCasts is set to the number of casts read in
8471  *
8472  * Skip casts from a range to its multirange, since we'll create those
8473  * automatically.
8474  */
8475 CastInfo *
8476 getCasts(Archive *fout, int *numCasts)
8477 {
8478  PGresult *res;
8479  int ntups;
8480  int i;
8481  PQExpBuffer query = createPQExpBuffer();
8482  CastInfo *castinfo;
8483  int i_tableoid;
8484  int i_oid;
8485  int i_castsource;
8486  int i_casttarget;
8487  int i_castfunc;
8488  int i_castcontext;
8489  int i_castmethod;
8490 
8491  if (fout->remoteVersion >= 140000)
8492  {
8493  appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8494  "castsource, casttarget, castfunc, castcontext, "
8495  "castmethod "
8496  "FROM pg_cast c "
8497  "WHERE NOT EXISTS ( "
8498  "SELECT 1 FROM pg_range r "
8499  "WHERE c.castsource = r.rngtypid "
8500  "AND c.casttarget = r.rngmultitypid "
8501  ") "
8502  "ORDER BY 3,4");
8503  }
8504  else
8505  {
8506  appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8507  "castsource, casttarget, castfunc, castcontext, "
8508  "castmethod "
8509  "FROM pg_cast ORDER BY 3,4");
8510  }
8511 
8512  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8513 
8514  ntups = PQntuples(res);
8515 
8516  *numCasts = ntups;
8517 
8518  castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
8519 
8520  i_tableoid = PQfnumber(res, "tableoid");
8521  i_oid = PQfnumber(res, "oid");
8522  i_castsource = PQfnumber(res, "castsource");
8523  i_casttarget = PQfnumber(res, "casttarget");
8524  i_castfunc = PQfnumber(res, "castfunc");
8525  i_castcontext = PQfnumber(res, "castcontext");
8526  i_castmethod = PQfnumber(res, "castmethod");
8527 
8528  for (i = 0; i < ntups; i++)
8529  {
8530  PQExpBufferData namebuf;
8531  TypeInfo *sTypeInfo;
8532  TypeInfo *tTypeInfo;
8533 
8534  castinfo[i].dobj.objType = DO_CAST;
8535  castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8536  castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8537  AssignDumpId(&castinfo[i].dobj);
8538  castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
8539  castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
8540  castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
8541  castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
8542  castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
8543 
8544  /*
8545  * Try to name cast as concatenation of typnames. This is only used
8546  * for purposes of sorting. If we fail to find either type, the name
8547  * will be an empty string.
8548  */
8549  initPQExpBuffer(&namebuf);
8550  sTypeInfo = findTypeByOid(castinfo[i].castsource);
8551  tTypeInfo = findTypeByOid(castinfo[i].casttarget);
8552  if (sTypeInfo && tTypeInfo)
8553  appendPQExpBuffer(&namebuf, "%s %s",
8554  sTypeInfo->dobj.name, tTypeInfo->dobj.name);
8555  castinfo[i].dobj.name = namebuf.data;
8556 
8557  /* Decide whether we want to dump it */
8558  selectDumpableCast(&(castinfo[i]), fout);
8559  }
8560 
8561  PQclear(res);
8562 
8563  destroyPQExpBuffer(query);
8564 
8565  return castinfo;
8566 }
8567 
8568 static char *
8570 {
8571  PQExpBuffer query;
8572  PGresult *res;
8573  char *lanname;
8574 
8575  query = createPQExpBuffer();
8576  appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
8577  res = ExecuteSqlQueryForSingleRow(fout, query->data);
8578  lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
8579  destroyPQExpBuffer(query);
8580  PQclear(res);
8581 
8582  return lanname;
8583 }
8584 
8585 /*
8586  * getTransforms
8587  * get basic information about every transform in the system
8588  *
8589  * numTransforms is set to the number of transforms read in
8590  */
8591 TransformInfo *
8592 getTransforms(Archive *fout, int *numTransforms)
8593 {
8594  PGresult *res;
8595  int ntups;
8596  int i;
8597  PQExpBuffer query;
8598  TransformInfo *transforminfo;
8599  int i_tableoid;
8600  int i_oid;
8601  int i_trftype;
8602  int i_trflang;
8603  int i_trffromsql;
8604  int i_trftosql;
8605 
8606  /* Transforms didn't exist pre-9.5 */
8607  if (fout->remoteVersion < 90500)
8608  {
8609  *numTransforms = 0;
8610  return NULL;
8611  }
8612 
8613  query = createPQExpBuffer();
8614 
8615  appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8616  "trftype, trflang, trffromsql::oid, trftosql::oid "
8617  "FROM pg_transform "
8618  "ORDER BY 3,4");
8619 
8620  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8621 
8622  ntups = PQntuples(res);
8623 
8624  *numTransforms = ntups;
8625 
8626  transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
8627 
8628  i_tableoid = PQfnumber(res, "tableoid");
8629  i_oid = PQfnumber(res, "oid");
8630  i_trftype = PQfnumber(res, "trftype");
8631  i_trflang = PQfnumber(res, "trflang");
8632  i_trffromsql = PQfnumber(res, "trffromsql");
8633  i_trftosql = PQfnumber(res, "trftosql");
8634 
8635  for (i = 0; i < ntups; i++)
8636  {
8637  PQExpBufferData namebuf;
8638  TypeInfo *typeInfo;
8639  char *lanname;
8640 
8641  transforminfo[i].dobj.objType = DO_TRANSFORM;
8642  transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8643  transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8644  AssignDumpId(&transforminfo[i].dobj);
8645  transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
8646  transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
8647  transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
8648  transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
8649 
8650  /*
8651  * Try to name transform as concatenation of type and language name.
8652  * This is only used for purposes of sorting. If we fail to find
8653  * either, the name will be an empty string.
8654  */
8655  initPQExpBuffer(&namebuf);
8656  typeInfo = findTypeByOid(transforminfo[i].trftype);
8657  lanname = get_language_name(fout, transforminfo[i].trflang);
8658  if (typeInfo && lanname)
8659  appendPQExpBuffer(&namebuf, "%s %s",
8660  typeInfo->dobj.name, lanname);
8661  transforminfo[i].dobj.name = namebuf.data;
8662  free(lanname);
8663 
8664  /* Decide whether we want to dump it */
8665  selectDumpableObject(&(transforminfo[i].dobj), fout);
8666  }
8667 
8668  PQclear(res);
8669 
8670  destroyPQExpBuffer(query);
8671 
8672  return transforminfo;
8673 }
8674 
8675 /*
8676  * getTableAttrs -
8677  * for each interesting table, read info about its attributes
8678  * (names, types, default values, CHECK constraints, etc)
8679  *
8680  * modifies tblinfo
8681  */
8682 void
8683 getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
8684 {
8685  DumpOptions *dopt = fout->dopt;
8687  PQExpBuffer tbloids = createPQExpBuffer();
8688  PQExpBuffer checkoids = createPQExpBuffer();
8689  PGresult *res;
8690  int ntups;
8691  int curtblindx;
8692  int i_attrelid;
8693  int i_attnum;
8694  int i_attname;
8695  int i_atttypname;
8696  int i_attstattarget;
8697  int i_attstorage;
8698  int i_typstorage;
8699  int i_attidentity;
8700  int i_attgenerated;
8701  int i_attisdropped;
8702  int i_attlen;
8703  int i_attalign;
8704  int i_attislocal;
8705  int i_notnull_name;
8706  int i_notnull_noinherit;
8707  int i_notnull_is_pk;
8708  int i_notnull_inh;
8709  int i_attoptions;
8710  int i_attcollation;
8711  int i_attcompression;
8712  int i_attfdwoptions;
8713  int i_attmissingval;
8714  int i_atthasdef;
8715 
8716  /*
8717  * We want to perform just one query against pg_attribute, and then just
8718  * one against pg_attrdef (for DEFAULTs) and two against pg_constraint
8719  * (for CHECK constraints and for NOT NULL constraints). However, we
8720  * mustn't try to select every row of those catalogs and then sort it out
8721  * on the client side, because some of the server-side functions we need
8722  * would be unsafe to apply to tables we don't have lock on. Hence, we
8723  * build an array of the OIDs of tables we care about (and now have lock
8724  * on!), and use a WHERE clause to constrain which rows are selected.
8725  */
8726  appendPQExpBufferChar(tbloids, '{');
8727  appendPQExpBufferChar(checkoids, '{');
8728  for (int i = 0; i < numTables; i++)
8729  {
8730  TableInfo *tbinfo = &tblinfo[i];
8731 
8732  /* Don't bother to collect info for sequences */
8733  if (tbinfo->relkind == RELKIND_SEQUENCE)
8734  continue;
8735 
8736  /* Don't bother with uninteresting tables, either */
8737  if (!tbinfo->interesting)
8738  continue;
8739 
8740  /* OK, we need info for this table */
8741  if (tbloids->len > 1) /* do we have more than the '{'? */
8742  appendPQExpBufferChar(tbloids, ',');
8743  appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
8744 
8745  if (tbinfo->ncheck > 0)
8746  {
8747  /* Also make a list of the ones with check constraints */
8748  if (checkoids->len > 1) /* do we have more than the '{'? */
8749  appendPQExpBufferChar(checkoids, ',');
8750  appendPQExpBuffer(checkoids, "%u", tbinfo->dobj.catId.oid);
8751  }
8752  }
8753  appendPQExpBufferChar(tbloids, '}');
8754  appendPQExpBufferChar(checkoids, '}');
8755 
8756  /*
8757  * Find all the user attributes and their types.
8758  *
8759  * Since we only want to dump COLLATE clauses for attributes whose
8760  * collation is different from their type's default, we use a CASE here to
8761  * suppress uninteresting attcollations cheaply.
8762  */
8764  "SELECT\n"
8765  "a.attrelid,\n"
8766  "a.attnum,\n"
8767  "a.attname,\n"
8768  "a.attstattarget,\n"
8769  "a.attstorage,\n"
8770  "t.typstorage,\n"
8771  "a.atthasdef,\n"
8772  "a.attisdropped,\n"
8773  "a.attlen,\n"
8774  "a.attalign,\n"
8775  "a.attislocal,\n"
8776  "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n"
8777  "array_to_string(a.attoptions, ', ') AS attoptions,\n"
8778  "CASE WHEN a.attcollation <> t.typcollation "
8779  "THEN a.attcollation ELSE 0 END AS attcollation,\n"
8780  "pg_catalog.array_to_string(ARRAY("
8781  "SELECT pg_catalog.quote_ident(option_name) || "
8782  "' ' || pg_catalog.quote_literal(option_value) "
8783  "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
8784  "ORDER BY option_name"
8785  "), E',\n ') AS attfdwoptions,\n");
8786 
8787  /*
8788  * Find out any NOT NULL markings for each column. In 17 and up we read
8789  * pg_constraint to obtain the constraint name. notnull_noinherit is set
8790  * according to the NO INHERIT property. For versions prior to 17, we
8791  * store an empty string as the name when a constraint is marked as
8792  * attnotnull (this cues dumpTableSchema to print the NOT NULL clause
8793  * without a name); also, such cases are never NO INHERIT.
8794  *
8795  * We track in notnull_inh whether the constraint was defined directly in
8796  * this table or via an ancestor, for binary upgrade.
8797  *
8798  * Lastly, we need to know if the PK for the table involves each column;
8799  * for columns that are there we need a NOT NULL marking even if there's
8800  * no explicit constraint, to avoid the table having to be scanned for
8801  * NULLs after the data is loaded when the PK is created, later in the
8802  * dump; for this case we add throwaway constraints that are dropped once
8803  * the PK is created.
8804  *
8805  * Another complication arises from columns that have attnotnull set, but
8806  * for which no corresponding not-null nor PK constraint exists. This can
8807  * happen if, for example, a primary key is dropped indirectly -- say,
8808  * because one of its columns is dropped. This is an irregular condition,
8809  * so we don't work hard to preserve it, and instead act as though an
8810  * unnamed not-null constraint exists.
8811  */
8812  if (fout->remoteVersion >= 170000)
8814  "CASE WHEN co.conname IS NOT NULL THEN co.conname "
8815  " WHEN a.attnotnull AND copk.conname IS NULL THEN '' ELSE NULL END AS notnull_name,\n"
8816  "CASE WHEN co.conname IS NOT NULL THEN co.connoinherit "
8817  " WHEN a.attnotnull THEN false ELSE NULL END AS notnull_noinherit,\n"
8818  "copk.conname IS NOT NULL as notnull_is_pk,\n"
8819  "CASE WHEN co.conname IS NOT NULL THEN "
8820  " coalesce(NOT co.conislocal, true) "
8821  "ELSE false END as notnull_inh,\n");
8822  else
8824  "CASE WHEN a.attnotnull THEN '' ELSE NULL END AS notnull_name,\n"
8825  "false AS notnull_noinherit,\n"
8826  "copk.conname IS NOT NULL AS notnull_is_pk,\n"
8827  "NOT a.attislocal AS notnull_inh,\n");
8828 
8829  if (fout->remoteVersion >= 140000)
8831  "a.attcompression AS attcompression,\n");
8832  else
8834  "'' AS attcompression,\n");
8835 
8836  if (fout->remoteVersion >= 100000)
8838  "a.attidentity,\n");
8839  else
8841  "'' AS attidentity,\n");
8842 
8843  if (fout->remoteVersion >= 110000)
8845  "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
8846  "THEN a.attmissingval ELSE null END AS attmissingval,\n");
8847  else
8849  "NULL AS attmissingval,\n");
8850 
8851  if (fout->remoteVersion >= 120000)
8853  "a.attgenerated\n");
8854  else
8856  "'' AS attgenerated\n");
8857 
8858  /* need left join to pg_type to not fail on dropped columns ... */
8860  "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8861  "JOIN pg_catalog.pg_attribute a ON (src.tbloid = a.attrelid) "
8862  "LEFT JOIN pg_catalog.pg_type t "
8863  "ON (a.atttypid = t.oid)\n",
8864  tbloids->data);
8865 
8866  /*
8867  * In versions 16 and up, we need pg_constraint for explicit NOT NULL
8868  * entries. Also, we need to know if the NOT NULL for each column is
8869  * backing a primary key.
8870  */
8871  if (fout->remoteVersion >= 170000)
8873  " LEFT JOIN pg_catalog.pg_constraint co ON "
8874  "(a.attrelid = co.conrelid\n"
8875  " AND co.contype = 'n' AND "
8876  "co.conkey = array[a.attnum])\n");
8877 
8879  "LEFT JOIN pg_catalog.pg_constraint copk ON "
8880  "(copk.conrelid = src.tbloid\n"
8881  " AND copk.contype = 'p' AND "
8882  "copk.conkey @> array[a.attnum])\n"
8883  "WHERE a.attnum > 0::pg_catalog.int2\n"
8884  "ORDER BY a.attrelid, a.attnum");
8885 
8886  res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8887 
8888  ntups = PQntuples(res);
8889 
8890  i_attrelid = PQfnumber(res, "attrelid");
8891  i_attnum = PQfnumber(res, "attnum");
8892  i_attname = PQfnumber(res, "attname");
8893  i_atttypname = PQfnumber(res, "atttypname");
8894  i_attstattarget = PQfnumber(res, "attstattarget");
8895  i_attstorage = PQfnumber(res, "attstorage");
8896  i_typstorage = PQfnumber(res, "typstorage");
8897  i_attidentity = PQfnumber(res, "attidentity");
8898  i_attgenerated = PQfnumber(res, "attgenerated");
8899  i_attisdropped = PQfnumber(res, "attisdropped");
8900  i_attlen = PQfnumber(res, "attlen");
8901  i_attalign = PQfnumber(res, "attalign");
8902  i_attislocal = PQfnumber(res, "attislocal");
8903  i_notnull_name = PQfnumber(res, "notnull_name");
8904  i_notnull_noinherit = PQfnumber(res, "notnull_noinherit");
8905  i_notnull_is_pk = PQfnumber(res, "notnull_is_pk");
8906  i_notnull_inh = PQfnumber(res, "notnull_inh");
8907  i_attoptions = PQfnumber(res, "attoptions");
8908  i_attcollation = PQfnumber(res, "attcollation");
8909  i_attcompression = PQfnumber(res, "attcompression");
8910  i_attfdwoptions = PQfnumber(res, "attfdwoptions");
8911  i_attmissingval = PQfnumber(res, "attmissingval");
8912  i_atthasdef = PQfnumber(res, "atthasdef");
8913 
8914  /* Within the next loop, we'll accumulate OIDs of tables with defaults */
8915  resetPQExpBuffer(tbloids);
8916  appendPQExpBufferChar(tbloids, '{');
8917 
8918  /*
8919  * Outer loop iterates once per table, not once per row. Incrementing of
8920  * r is handled by the inner loop.
8921  */
8922  curtblindx = -1;
8923  for (int r = 0; r < ntups;)
8924  {
8925  Oid attrelid = atooid(PQgetvalue(res, r, i_attrelid));
8926  TableInfo *tbinfo = NULL;
8927  int numatts;
8928  bool hasdefaults;
8929  int notnullcount;
8930 
8931  /* Count rows for this table */
8932  for (numatts = 1; numatts < ntups - r; numatts++)
8933  if (atooid(PQgetvalue(res, r + numatts, i_attrelid)) != attrelid)
8934  break;
8935 
8936  /*
8937  * Locate the associated TableInfo; we rely on tblinfo[] being in OID
8938  * order.
8939  */
8940  while (++curtblindx < numTables)
8941  {
8942  tbinfo = &tblinfo[curtblindx];
8943  if (tbinfo->dobj.catId.oid == attrelid)
8944  break;
8945  }
8946  if (curtblindx >= numTables)
8947  pg_fatal("unrecognized table OID %u", attrelid);
8948  /* cross-check that we only got requested tables */
8949  if (tbinfo->relkind == RELKIND_SEQUENCE ||
8950  !tbinfo->interesting)
8951  pg_fatal("unexpected column data for table \"%s\"",
8952  tbinfo->dobj.name);
8953 
8954  notnullcount = 0;
8955 
8956  /* Save data for this table */
8957  tbinfo->numatts = numatts;
8958  tbinfo->attnames = (char **) pg_malloc(numatts * sizeof(char *));
8959  tbinfo->atttypnames = (char **) pg_malloc(numatts * sizeof(char *));
8960  tbinfo->attstattarget = (int *) pg_malloc(numatts * sizeof(int));
8961  tbinfo->attstorage = (char *) pg_malloc(numatts * sizeof(char));
8962  tbinfo->typstorage = (char *) pg_malloc(numatts * sizeof(char));
8963  tbinfo->attidentity = (char *) pg_malloc(numatts * sizeof(char));
8964  tbinfo->attgenerated = (char *) pg_malloc(numatts * sizeof(char));
8965  tbinfo->attisdropped = (bool *) pg_malloc(numatts * sizeof(bool));
8966  tbinfo->attlen = (int *) pg_malloc(numatts * sizeof(int));
8967  tbinfo->attalign = (char *) pg_malloc(numatts * sizeof(char));
8968  tbinfo->attislocal = (bool *) pg_malloc(numatts * sizeof(bool));
8969  tbinfo->attoptions = (char **) pg_malloc(numatts * sizeof(char *));
8970  tbinfo->attcollation = (Oid *) pg_malloc(numatts * sizeof(Oid));
8971  tbinfo->attcompression = (char *) pg_malloc(numatts * sizeof(char));
8972  tbinfo->attfdwoptions = (char **) pg_malloc(numatts * sizeof(char *));
8973  tbinfo->attmissingval = (char **) pg_malloc(numatts * sizeof(char *));
8974  tbinfo->notnull_constrs = (char **) pg_malloc(numatts * sizeof(char *));
8975  tbinfo->notnull_noinh = (bool *) pg_malloc(numatts * sizeof(bool));
8976  tbinfo->notnull_throwaway = (bool *) pg_malloc(numatts * sizeof(bool));
8977  tbinfo->notnull_inh = (bool *) pg_malloc(numatts * sizeof(bool));
8978  tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(numatts * sizeof(AttrDefInfo *));
8979  hasdefaults = false;
8980 
8981  for (int j = 0; j < numatts; j++, r++)
8982  {
8983  bool use_named_notnull = false;
8984  bool use_unnamed_notnull = false;
8985  bool use_throwaway_notnull = false;
8986 
8987  if (j + 1 != atoi(PQgetvalue(res, r, i_attnum)))
8988  pg_fatal("invalid column numbering in table \"%s\"",
8989  tbinfo->dobj.name);
8990  tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, r, i_attname));
8991  tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, r, i_atttypname));
8992  if (PQgetisnull(res, r, i_attstattarget))
8993  tbinfo->attstattarget[j] = -1;
8994  else
8995  tbinfo->attstattarget[j] = atoi(PQgetvalue(res, r, i_attstattarget));
8996  tbinfo->attstorage[j] = *(PQgetvalue(res, r, i_attstorage));
8997  tbinfo->typstorage[j] = *(PQgetvalue(res, r, i_typstorage));
8998  tbinfo->attidentity[j] = *(PQgetvalue(res, r, i_attidentity));
8999  tbinfo->attgenerated[j] = *(PQgetvalue(res, r, i_attgenerated));
9000  tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
9001  tbinfo->attisdropped[j] = (PQgetvalue(res, r, i_attisdropped)[0] == 't');
9002  tbinfo->attlen[j] = atoi(PQgetvalue(res, r, i_attlen));
9003  tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign));
9004  tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't');
9005 
9006  /*
9007  * Not-null constraints require a jumping through a few hoops.
9008  * First, if the user has specified a constraint name that's not
9009  * the system-assigned default name, then we need to preserve
9010  * that. But if they haven't, then we don't want to use the
9011  * verbose syntax in the dump output. (Also, in versions prior to
9012  * 17, there was no constraint name at all.)
9013  *
9014  * (XXX Comparing the name this way to a supposed default name is
9015  * a bit of a hack, but it beats having to store a boolean flag in
9016  * pg_constraint just for this, or having to compute the knowledge
9017  * at pg_dump time from the server.)
9018  *
9019  * We also need to know if a column is part of the primary key. In
9020  * that case, we want to mark the column as not-null at table
9021  * creation time, so that the table doesn't have to be scanned to
9022  * check for nulls when the PK is created afterwards; this is
9023  * especially critical during pg_upgrade (where the data would not
9024  * be scanned at all otherwise.) If the column is part of the PK
9025  * and does not have any other not-null constraint, then we
9026  * fabricate a throwaway constraint name that we later use to
9027  * remove the constraint after the PK has been created.
9028  *
9029  * For inheritance child tables, we don't want to print not-null
9030  * when the constraint was defined at the parent level instead of
9031  * locally.
9032  */
9033 
9034  /*
9035  * We use notnull_inh to suppress unwanted not-null constraints in
9036  * inheritance children, when said constraints come from the
9037  * parent(s).
9038  */
9039  tbinfo->notnull_inh[j] = PQgetvalue(res, r, i_notnull_inh)[0] == 't';
9040 
9041  if (fout->remoteVersion < 170000)
9042  {
9043  if (!PQgetisnull(res, r, i_notnull_name) &&
9044  dopt->binary_upgrade &&
9045  !tbinfo->ispartition &&
9046  tbinfo->notnull_inh[j])
9047  {
9048  use_named_notnull = true;
9049  /* XXX should match ChooseConstraintName better */
9050  tbinfo->notnull_constrs[j] =
9051  psprintf("%s_%s_not_null", tbinfo->dobj.name,
9052  tbinfo->attnames[j]);
9053  }
9054  else if (PQgetvalue(res, r, i_notnull_is_pk)[0] == 't')
9055  use_throwaway_notnull = true;
9056  else if (!PQgetisnull(res, r, i_notnull_name))
9057  use_unnamed_notnull = true;
9058  }
9059  else
9060  {
9061  if (!PQgetisnull(res, r, i_notnull_name))
9062  {
9063  /*
9064  * In binary upgrade of inheritance child tables, must
9065  * have a constraint name that we can UPDATE later.
9066  */
9067  if (dopt->binary_upgrade &&
9068  !tbinfo->ispartition &&
9069  tbinfo->notnull_inh[j])
9070  {
9071  use_named_notnull = true;
9072  tbinfo->notnull_constrs[j] =
9073  pstrdup(PQgetvalue(res, r, i_notnull_name));
9074 
9075  }
9076  else
9077  {
9078  char *default_name;
9079 
9080  /* XXX should match ChooseConstraintName better */
9081  default_name = psprintf("%s_%s_not_null", tbinfo->dobj.name,
9082  tbinfo->attnames[j]);
9083  if (strcmp(default_name,
9084  PQgetvalue(res, r, i_notnull_name)) == 0)
9085  use_unnamed_notnull = true;
9086  else
9087  {
9088  use_named_notnull = true;
9089  tbinfo->notnull_constrs[j] =
9090  pstrdup(PQgetvalue(res, r, i_notnull_name));
9091  }
9092  }
9093  }
9094  else if (PQgetvalue(res, r, i_notnull_is_pk)[0] == 't')
9095  use_throwaway_notnull = true;
9096  }
9097 
9098  if (use_unnamed_notnull)
9099  {
9100  tbinfo->notnull_constrs[j] = "";
9101  tbinfo->notnull_throwaway[j] = false;
9102  }
9103  else if (use_named_notnull)
9104  {
9105  /* The name itself has already been determined */
9106  tbinfo->notnull_throwaway[j] = false;
9107  }
9108  else if (use_throwaway_notnull)
9109  {
9110  /*
9111  * Give this constraint a throwaway name.
9112  */
9113  tbinfo->notnull_constrs[j] =
9114  psprintf("pgdump_throwaway_notnull_%d", notnullcount++);
9115  tbinfo->notnull_throwaway[j] = true;
9116  tbinfo->notnull_inh[j] = false;
9117  }
9118  else
9119  {
9120  tbinfo->notnull_constrs[j] = NULL;
9121  tbinfo->notnull_throwaway[j] = false;
9122  }
9123 
9124  /*
9125  * Throwaway constraints must always be NO INHERIT; otherwise do
9126  * what the catalog says.
9127  */
9128  tbinfo->notnull_noinh[j] = use_throwaway_notnull ||
9129  PQgetvalue(res, r, i_notnull_noinherit)[0] == 't';
9130 
9131  tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, r, i_attoptions));
9132  tbinfo->attcollation[j] = atooid(PQgetvalue(res, r, i_attcollation));
9133  tbinfo->attcompression[j] = *(PQgetvalue(res, r, i_attcompression));
9134  tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, r, i_attfdwoptions));
9135  tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, r, i_attmissingval));
9136  tbinfo->attrdefs[j] = NULL; /* fix below */
9137  if (PQgetvalue(res, r, i_atthasdef)[0] == 't')
9138  hasdefaults = true;
9139  }
9140 
9141  if (hasdefaults)
9142  {
9143  /* Collect OIDs of interesting tables that have defaults */
9144  if (tbloids->len > 1) /* do we have more than the '{'? */
9145  appendPQExpBufferChar(tbloids, ',');
9146  appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
9147  }
9148  }
9149 
9150  PQclear(res);
9151 
9152  /*
9153  * Now get info about column defaults. This is skipped for a data-only
9154  * dump, as it is only needed for table schemas.
9155  */
9156  if (!dopt->dataOnly && tbloids->len > 1)
9157  {
9158  AttrDefInfo *attrdefs;
9159  int numDefaults;
9160  TableInfo *tbinfo = NULL;
9161 
9162  pg_log_info("finding table default expressions");
9163 
9164  appendPQExpBufferChar(tbloids, '}');
9165 
9166  printfPQExpBuffer(q, "SELECT a.tableoid, a.oid, adrelid, adnum, "
9167  "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc\n"
9168  "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
9169  "JOIN pg_catalog.pg_attrdef a ON (src.tbloid = a.adrelid)\n"
9170  "ORDER BY a.adrelid, a.adnum",
9171  tbloids->data);
9172 
9173  res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
9174 
9175  numDefaults = PQntuples(res);
9176  attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
9177 
9178  curtblindx = -1;
9179  for (int j = 0; j < numDefaults; j++)
9180  {
9181  Oid adtableoid = atooid(PQgetvalue(res, j, 0));
9182  Oid adoid = atooid(PQgetvalue(res, j, 1));
9183  Oid adrelid = atooid(PQgetvalue(res, j, 2));
9184  int adnum = atoi(PQgetvalue(res, j, 3));
9185  char *adsrc = PQgetvalue(res, j, 4);
9186 
9187  /*
9188  * Locate the associated TableInfo; we rely on tblinfo[] being in
9189  * OID order.
9190  */
9191  if (tbinfo == NULL || tbinfo->dobj.catId.oid != adrelid)
9192  {
9193  while (++curtblindx < numTables)
9194  {
9195  tbinfo = &tblinfo[curtblindx];
9196  if (tbinfo->dobj.catId.oid == adrelid)
9197  break;
9198  }
9199  if (curtblindx >= numTables)
9200  pg_fatal("unrecognized table OID %u", adrelid);
9201  }
9202 
9203  if (adnum <= 0 || adnum > tbinfo->numatts)
9204  pg_fatal("invalid adnum value %d for table \"%s\"",
9205  adnum, tbinfo->dobj.name);
9206 
9207  /*
9208  * dropped columns shouldn't have defaults, but just in case,
9209  * ignore 'em
9210  */
9211  if (tbinfo->attisdropped[adnum - 1])
9212  continue;
9213 
9214  attrdefs[j].dobj.objType = DO_ATTRDEF;
9215  attrdefs[j].dobj.catId.tableoid = adtableoid;
9216  attrdefs[j].dobj.catId.oid = adoid;
9217  AssignDumpId(&attrdefs[j].dobj);
9218  attrdefs[j].adtable = tbinfo;
9219  attrdefs[j].adnum = adnum;
9220  attrdefs[j].adef_expr = pg_strdup(adsrc);
9221 
9222  attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
9223  attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
9224 
9225  attrdefs[j].dobj.dump = tbinfo->dobj.dump;
9226 
9227  /*
9228  * Figure out whether the default/generation expression should be
9229  * dumped as part of the main CREATE TABLE (or similar) command or
9230  * as a separate ALTER TABLE (or similar) command. The preference
9231  * is to put it into the CREATE command, but in some cases that's
9232  * not possible.
9233  */
9234  if (tbinfo->attgenerated[adnum - 1])
9235  {
9236  /*
9237  * Column generation expressions cannot be dumped separately,
9238  * because there is no syntax for it. By setting separate to
9239  * false here we prevent the "default" from being processed as
9240  * its own dumpable object. Later, flagInhAttrs() will mark
9241  * it as not to be dumped at all, if possible (that is, if it
9242  * can be inherited from a parent).
9243  */
9244  attrdefs[j].separate = false;
9245  }
9246  else if (tbinfo->relkind == RELKIND_VIEW)
9247  {
9248  /*
9249  * Defaults on a VIEW must always be dumped as separate ALTER
9250  * TABLE commands.
9251  */
9252  attrdefs[j].separate = true;
9253  }
9254  else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
9255  {
9256  /* column will be suppressed, print default separately */
9257  attrdefs[j].separate = true;
9258  }
9259  else
9260  {
9261  attrdefs[j].separate = false;
9262  }
9263 
9264  if (!attrdefs[j].separate)
9265  {
9266  /*
9267  * Mark the default as needing to appear before the table, so
9268  * that any dependencies it has must be emitted before the
9269  * CREATE TABLE. If this is not possible, we'll change to
9270  * "separate" mode while sorting dependencies.
9271  */
9272  addObjectDependency(&tbinfo->dobj,
9273  attrdefs[j].dobj.dumpId);
9274  }
9275 
9276  tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
9277  }
9278 
9279  PQclear(res);
9280  }
9281 
9282  /*
9283  * Get info about table CHECK constraints. This is skipped for a
9284  * data-only dump, as it is only needed for table schemas.
9285  */
9286  if (!dopt->dataOnly && checkoids->len > 2)
9287  {
9288  ConstraintInfo *constrs;
9289  int numConstrs;
9290  int i_tableoid;
9291  int i_oid;
9292  int i_conrelid;
9293  int i_conname;
9294  int i_consrc;
9295  int i_conislocal;
9296  int i_convalidated;
9297 
9298  pg_log_info("finding table check constraints");
9299 
9300  resetPQExpBuffer(q);
9302  "SELECT c.tableoid, c.oid, conrelid, conname, "
9303  "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
9304  "conislocal, convalidated "
9305  "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
9306  "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
9307  "WHERE contype = 'c' "
9308  "ORDER BY c.conrelid, c.conname",
9309  checkoids->data);
9310 
9311  res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
9312 
9313  numConstrs = PQntuples(res);
9314  constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
9315 
9316  i_tableoid = PQfnumber(res, "tableoid");
9317  i_oid = PQfnumber(res, "oid");
9318  i_conrelid = PQfnumber(res, "conrelid");
9319  i_conname = PQfnumber(res, "conname");
9320  i_consrc = PQfnumber(res, "consrc");
9321  i_conislocal = PQfnumber(res, "conislocal");
9322  i_convalidated = PQfnumber(res, "convalidated");
9323 
9324  /* As above, this loop iterates once per table, not once per row */
9325  curtblindx = -1;
9326  for (int j = 0; j < numConstrs;)
9327  {
9328  Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
9329  TableInfo *tbinfo = NULL;
9330  int numcons;
9331 
9332  /* Count rows for this table */
9333  for (numcons = 1; numcons < numConstrs - j; numcons++)
9334  if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
9335  break;
9336 
9337  /*
9338  * Locate the associated TableInfo; we rely on tblinfo[] being in
9339  * OID order.
9340  */
9341  while (++curtblindx < numTables)
9342  {
9343  tbinfo = &tblinfo[curtblindx];
9344  if (tbinfo->dobj.catId.oid == conrelid)
9345  break;
9346  }
9347  if (curtblindx >= numTables)
9348  pg_fatal("unrecognized table OID %u", conrelid);
9349 
9350  if (numcons != tbinfo->ncheck)
9351  {
9352  pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
9353  "expected %d check constraints on table \"%s\" but found %d",
9354  tbinfo->ncheck),
9355  tbinfo->ncheck, tbinfo->dobj.name, numcons);
9356  pg_log_error_hint("The system catalogs might be corrupted.");
9357  exit_nicely(1);
9358  }
9359 
9360  tbinfo->checkexprs = constrs + j;
9361 
9362  for (int c = 0; c < numcons; c++, j++)
9363  {
9364  bool validated = PQgetvalue(res, j, i_convalidated)[0] == 't';
9365 
9366  constrs[j].dobj.objType = DO_CONSTRAINT;
9367  constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
9368  constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
9369  AssignDumpId(&constrs[j].dobj);
9370  constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
9371  constrs[j].dobj.namespace = tbinfo->dobj.namespace;
9372  constrs[j].contable = tbinfo;
9373  constrs[j].condomain = NULL;
9374  constrs[j].contype = 'c';
9375  constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
9376  constrs[j].confrelid = InvalidOid;
9377  constrs[j].conindex = 0;
9378  constrs[j].condeferrable = false;
9379  constrs[j].condeferred = false;
9380  constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
9381 
9382  /*
9383  * An unvalidated constraint needs to be dumped separately, so
9384  * that potentially-violating existing data is loaded before
9385  * the constraint.
9386  */
9387  constrs[j].separate = !validated;
9388 
9389  constrs[j].dobj.dump = tbinfo->dobj.dump;
9390 
9391  /*
9392  * Mark the constraint as needing to appear before the table
9393  * --- this is so that any other dependencies of the
9394  * constraint will be emitted before we try to create the
9395  * table. If the constraint is to be dumped separately, it
9396  * will be dumped after data is loaded anyway, so don't do it.
9397  * (There's an automatic dependency in the opposite direction
9398  * anyway, so don't need to add one manually here.)
9399  */
9400  if (!constrs[j].separate)
9401  addObjectDependency(&tbinfo->dobj,
9402  constrs[j].dobj.dumpId);
9403 
9404  /*
9405  * We will detect later whether the constraint must be split
9406  * out from the table definition.
9407  */
9408  }
9409  }
9410 
9411  PQclear(res);
9412  }
9413 
9414  destroyPQExpBuffer(q);
9415  destroyPQExpBuffer(tbloids);
9416  destroyPQExpBuffer(checkoids);
9417 }
9418 
9419 /*
9420  * Test whether a column should be printed as part of table's CREATE TABLE.
9421  * Column number is zero-based.
9422  *
9423  * Normally this is always true, but it's false for dropped columns, as well
9424  * as those that were inherited without any local definition. (If we print
9425  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
9426  * For partitions, it's always true, because we want the partitions to be
9427  * created independently and ATTACH PARTITION used afterwards.
9428  *
9429  * In binary_upgrade mode, we must print all columns and fix the attislocal/
9430  * attisdropped state later, so as to keep control of the physical column
9431  * order.
9432  *
9433  * This function exists because there are scattered nonobvious places that
9434  * must be kept in sync with this decision.
9435  */
9436 bool
9437 shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
9438 {
9439  if (dopt->binary_upgrade)
9440  return true;
9441  if (tbinfo->attisdropped[colno])
9442  return false;
9443  return (tbinfo->attislocal[colno] || tbinfo->ispartition);
9444 }
9445 
9446 
9447 /*
9448  * getTSParsers:
9449  * read all text search parsers in the system catalogs and return them
9450  * in the TSParserInfo* structure
9451  *
9452  * numTSParsers is set to the number of parsers read in
9453  */
9454 TSParserInfo *
9455 getTSParsers(Archive *fout, int *numTSParsers)
9456 {
9457  PGresult *res;
9458  int ntups;
9459  int i;
9460  PQExpBuffer query;
9461  TSParserInfo *prsinfo;
9462  int i_tableoid;
9463  int i_oid;
9464  int i_prsname;
9465  int i_prsnamespace;
9466  int i_prsstart;
9467  int i_prstoken;
9468  int i_prsend;
9469  int i_prsheadline;
9470  int i_prslextype;
9471 
9472  query = createPQExpBuffer();
9473 
9474  /*
9475  * find all text search objects, including builtin ones; we filter out
9476  * system-defined objects at dump-out time.
9477  */
9478 
9479  appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
9480  "prsstart::oid, prstoken::oid, "
9481  "prsend::oid, prsheadline::oid, prslextype::oid "
9482  "FROM pg_ts_parser");
9483 
9484  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9485 
9486  ntups = PQntuples(res);
9487  *numTSParsers = ntups;
9488 
9489  prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
9490 
9491  i_tableoid = PQfnumber(res, "tableoid");
9492  i_oid = PQfnumber(res, "oid");
9493  i_prsname = PQfnumber(res, "prsname");
9494  i_prsnamespace = PQfnumber(res, "prsnamespace");
9495  i_prsstart = PQfnumber(res, "prsstart");
9496  i_prstoken = PQfnumber(res, "prstoken");
9497  i_prsend = PQfnumber(res, "prsend");
9498  i_prsheadline = PQfnumber(res, "prsheadline");
9499  i_prslextype = PQfnumber(res, "prslextype");
9500 
9501  for (i = 0; i < ntups; i++)
9502  {
9503  prsinfo[i].dobj.objType = DO_TSPARSER;
9504  prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9505  prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9506  AssignDumpId(&prsinfo[i].dobj);
9507  prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
9508  prsinfo[i].dobj.namespace =
9509  findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)));
9510  prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
9511  prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
9512  prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
9513  prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
9514  prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
9515 
9516  /* Decide whether we want to dump it */
9517  selectDumpableObject(&(prsinfo[i].dobj), fout);
9518  }
9519 
9520  PQclear(res);
9521 
9522  destroyPQExpBuffer(query);
9523 
9524  return prsinfo;
9525 }
9526 
9527 /*
9528  * getTSDictionaries:
9529  * read all text search dictionaries in the system catalogs and return them
9530  * in the TSDictInfo* structure
9531  *
9532  * numTSDicts is set to the number of dictionaries read in
9533  */
9534 TSDictInfo *
9535 getTSDictionaries(Archive *fout, int *numTSDicts)
9536 {
9537  PGresult *res;
9538  int ntups;
9539  int i;
9540  PQExpBuffer query;
9541  TSDictInfo *dictinfo;
9542  int i_tableoid;
9543  int i_oid;
9544  int i_dictname;
9545  int i_dictnamespace;
9546  int i_dictowner;
9547  int i_dicttemplate;
9548  int i_dictinitoption;
9549 
9550  query = createPQExpBuffer();
9551 
9552  appendPQExpBufferStr(query, "SELECT tableoid, oid, dictname, "
9553  "dictnamespace, dictowner, "
9554  "dicttemplate, dictinitoption "
9555  "FROM pg_ts_dict");
9556 
9557  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9558 
9559  ntups = PQntuples(res);
9560  *numTSDicts = ntups;
9561 
9562  dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
9563 
9564  i_tableoid = PQfnumber(res, "tableoid");
9565  i_oid = PQfnumber(res, "oid");
9566  i_dictname = PQfnumber(res, "dictname");
9567  i_dictnamespace = PQfnumber(res, "dictnamespace");
9568  i_dictowner = PQfnumber(res, "dictowner");
9569  i_dictinitoption = PQfnumber(res, "dictinitoption");
9570  i_dicttemplate = PQfnumber(res, "dicttemplate");
9571 
9572  for (i = 0; i < ntups; i++)
9573  {
9574  dictinfo[i].dobj.objType = DO_TSDICT;
9575  dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9576  dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9577  AssignDumpId(&dictinfo[i].dobj);
9578  dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
9579  dictinfo[i].dobj.namespace =
9580  findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)));
9581  dictinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_dictowner));
9582  dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
9583  if (PQgetisnull(res, i, i_dictinitoption))
9584  dictinfo[i].dictinitoption = NULL;
9585  else
9586  dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
9587 
9588  /* Decide whether we want to dump it */
9589  selectDumpableObject(&(dictinfo[i].dobj), fout);
9590  }
9591 
9592  PQclear(res);
9593 
9594  destroyPQExpBuffer(query);
9595 
9596  return dictinfo;
9597 }
9598 
9599 /*
9600  * getTSTemplates:
9601  * read all text search templates in the system catalogs and return them
9602  * in the TSTemplateInfo* structure
9603  *
9604  * numTSTemplates is set to the number of templates read in
9605  */
9607 getTSTemplates(Archive *fout, int *numTSTemplates)
9608 {
9609  PGresult *res;
9610  int ntups;
9611  int i;
9612  PQExpBuffer query;
9613  TSTemplateInfo *tmplinfo;
9614  int i_tableoid;
9615  int i_oid;
9616  int i_tmplname;
9617  int i_tmplnamespace;
9618  int i_tmplinit;
9619  int i_tmpllexize;
9620 
9621  query = createPQExpBuffer();
9622 
9623  appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
9624  "tmplnamespace, tmplinit::oid, tmpllexize::oid "
9625  "FROM pg_ts_template");
9626 
9627  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9628 
9629  ntups = PQntuples(res);
9630  *numTSTemplates = ntups;
9631 
9632  tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
9633 
9634  i_tableoid = PQfnumber(res, "tableoid");
9635  i_oid = PQfnumber(res, "oid");
9636  i_tmplname = PQfnumber(res, "tmplname");
9637  i_tmplnamespace = PQfnumber(res, "tmplnamespace");
9638  i_tmplinit = PQfnumber(res, "tmplinit");
9639  i_tmpllexize = PQfnumber(res, "tmpllexize");
9640 
9641  for (i = 0; i < ntups; i++)
9642  {
9643  tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
9644  tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9645  tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9646  AssignDumpId(&tmplinfo[i].dobj);
9647  tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
9648  tmplinfo[i].dobj.namespace =
9649  findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)));
9650  tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
9651  tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
9652 
9653  /* Decide whether we want to dump it */
9654  selectDumpableObject(&(tmplinfo[i].dobj), fout);
9655  }
9656 
9657  PQclear(res);
9658 
9659  destroyPQExpBuffer(query);
9660 
9661  return tmplinfo;
9662 }
9663 
9664 /*
9665  * getTSConfigurations:
9666  * read all text search configurations in the system catalogs and return
9667  * them in the TSConfigInfo* structure
9668  *
9669  * numTSConfigs is set to the number of configurations read in
9670  */
9671 TSConfigInfo *
9672 getTSConfigurations(Archive *fout, int *numTSConfigs)
9673 {
9674  PGresult *res;
9675  int ntups;
9676  int i;
9677  PQExpBuffer query;
9678  TSConfigInfo *cfginfo;
9679  int i_tableoid;
9680  int i_oid;
9681  int i_cfgname;
9682  int i_cfgnamespace;
9683  int i_cfgowner;
9684  int i_cfgparser;
9685 
9686  query = createPQExpBuffer();
9687 
9688  appendPQExpBufferStr(query, "SELECT tableoid, oid, cfgname, "
9689  "cfgnamespace, cfgowner, cfgparser "
9690  "FROM pg_ts_config");
9691 
9692  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9693 
9694  ntups = PQntuples(res);
9695  *numTSConfigs = ntups;
9696 
9697  cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
9698 
9699  i_tableoid = PQfnumber(res, "tableoid");
9700  i_oid = PQfnumber(res, "oid");
9701  i_cfgname = PQfnumber(res, "cfgname");
9702  i_cfgnamespace = PQfnumber(res, "cfgnamespace");
9703  i_cfgowner = PQfnumber(res, "cfgowner");
9704  i_cfgparser = PQfnumber(res, "cfgparser");
9705 
9706  for (i = 0; i < ntups; i++)
9707  {
9708  cfginfo[i].dobj.objType = DO_TSCONFIG;
9709  cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9710  cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9711  AssignDumpId(&cfginfo[i].dobj);
9712  cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
9713  cfginfo[i].dobj.namespace =
9714  findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)));
9715  cfginfo[i].rolname = getRoleName(PQgetvalue(res, i, i_cfgowner));
9716  cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
9717 
9718  /* Decide whether we want to dump it */
9719  selectDumpableObject(&(cfginfo[i].dobj), fout);
9720  }
9721 
9722  PQclear(res);
9723 
9724  destroyPQExpBuffer(query);
9725 
9726  return cfginfo;
9727 }
9728 
9729 /*
9730  * getForeignDataWrappers:
9731  * read all foreign-data wrappers in the system catalogs and return
9732  * them in the FdwInfo* structure
9733  *
9734  * numForeignDataWrappers is set to the number of fdws read in
9735  */
9736 FdwInfo *
9737 getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
9738 {
9739  PGresult *res;
9740  int ntups;
9741  int i;
9742  PQExpBuffer query;
9743  FdwInfo *fdwinfo;
9744  int i_tableoid;
9745  int i_oid;
9746  int i_fdwname;
9747  int i_fdwowner;
9748  int i_fdwhandler;
9749  int i_fdwvalidator;
9750  int i_fdwacl;
9751  int i_acldefault;
9752  int i_fdwoptions;
9753 
9754  query = createPQExpBuffer();
9755 
9756  appendPQExpBufferStr(query, "SELECT tableoid, oid, fdwname, "
9757  "fdwowner, "
9758  "fdwhandler::pg_catalog.regproc, "
9759  "fdwvalidator::pg_catalog.regproc, "
9760  "fdwacl, "
9761  "acldefault('F', fdwowner) AS acldefault, "
9762  "array_to_string(ARRAY("
9763  "SELECT quote_ident(option_name) || ' ' || "
9764  "quote_literal(option_value) "
9765  "FROM pg_options_to_table(fdwoptions) "
9766  "ORDER BY option_name"
9767  "), E',\n ') AS fdwoptions "
9768  "FROM pg_foreign_data_wrapper");
9769 
9770  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9771 
9772  ntups = PQntuples(res);
9773  *numForeignDataWrappers = ntups;
9774 
9775  fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
9776 
9777  i_tableoid = PQfnumber(res, "tableoid");
9778  i_oid = PQfnumber(res, "oid");
9779  i_fdwname = PQfnumber(res, "fdwname");
9780  i_fdwowner = PQfnumber(res, "fdwowner");
9781  i_fdwhandler = PQfnumber(res, "fdwhandler");
9782  i_fdwvalidator = PQfnumber(res, "fdwvalidator");
9783  i_fdwacl = PQfnumber(res, "fdwacl");
9784  i_acldefault = PQfnumber(res, "acldefault");
9785  i_fdwoptions = PQfnumber(res, "fdwoptions");
9786 
9787  for (i = 0; i < ntups; i++)
9788  {
9789  fdwinfo[i].dobj.objType = DO_FDW;
9790  fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9791  fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9792  AssignDumpId(&fdwinfo[i].dobj);
9793  fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
9794  fdwinfo[i].dobj.namespace = NULL;
9795  fdwinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
9796  fdwinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
9797  fdwinfo[i].dacl.privtype = 0;
9798  fdwinfo[i].dacl.initprivs = NULL;
9799  fdwinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_fdwowner));
9800  fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
9801  fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
9802  fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
9803 
9804  /* Decide whether we want to dump it */
9805  selectDumpableObject(&(fdwinfo[i].dobj), fout);
9806 
9807  /* Mark whether FDW has an ACL */
9808  if (!PQgetisnull(res, i, i_fdwacl))
9809  fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
9810  }
9811 
9812  PQclear(res);
9813 
9814  destroyPQExpBuffer(query);
9815 
9816  return fdwinfo;
9817 }
9818 
9819 /*
9820  * getForeignServers:
9821  * read all foreign servers in the system catalogs and return
9822  * them in the ForeignServerInfo * structure
9823  *
9824  * numForeignServers is set to the number of servers read in
9825  */
9827 getForeignServers(Archive *fout, int *numForeignServers)
9828 {
9829  PGresult *res;
9830  int ntups;
9831  int i;
9832  PQExpBuffer query;
9833  ForeignServerInfo *srvinfo;
9834  int i_tableoid;
9835  int i_oid;
9836  int i_srvname;
9837  int i_srvowner;
9838  int i_srvfdw;
9839  int i_srvtype;
9840  int i_srvversion;
9841  int i_srvacl;
9842  int i_acldefault;
9843  int i_srvoptions;
9844 
9845  query = createPQExpBuffer();
9846 
9847  appendPQExpBufferStr(query, "SELECT tableoid, oid, srvname, "
9848  "srvowner, "
9849  "srvfdw, srvtype, srvversion, srvacl, "
9850  "acldefault('S', srvowner) AS acldefault, "
9851  "array_to_string(ARRAY("
9852  "SELECT quote_ident(option_name) || ' ' || "
9853  "quote_literal(option_value) "
9854  "FROM pg_options_to_table(srvoptions) "
9855  "ORDER BY option_name"
9856  "), E',\n ') AS srvoptions "
9857  "FROM pg_foreign_server");
9858 
9859  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9860 
9861  ntups = PQntuples(res);
9862  *numForeignServers = ntups;
9863 
9864  srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
9865 
9866  i_tableoid = PQfnumber(res, "tableoid");
9867  i_oid = PQfnumber(res, "oid");
9868  i_srvname = PQfnumber(res, "srvname");
9869  i_srvowner = PQfnumber(res, "srvowner");
9870  i_srvfdw = PQfnumber(res, "srvfdw");
9871  i_srvtype = PQfnumber(res, "srvtype");
9872  i_srvversion = PQfnumber(res, "srvversion");
9873  i_srvacl = PQfnumber(res, "srvacl");
9874  i_acldefault = PQfnumber(res, "acldefault");
9875  i_srvoptions = PQfnumber(res, "srvoptions");
9876 
9877  for (i = 0; i < ntups; i++)
9878  {
9879  srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
9880  srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9881  srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9882  AssignDumpId(&srvinfo[i].dobj);
9883  srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
9884  srvinfo[i].dobj.namespace = NULL;
9885  srvinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_srvacl));
9886  srvinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
9887  srvinfo[i].dacl.privtype = 0;
9888  srvinfo[i].dacl.initprivs = NULL;
9889  srvinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_srvowner));
9890  srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
9891  srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
9892  srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
9893  srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
9894 
9895  /* Decide whether we want to dump it */
9896  selectDumpableObject(&(srvinfo[i].dobj), fout);
9897 
9898  /* Servers have user mappings */
9900 
9901  /* Mark whether server has an ACL */
9902  if (!PQgetisnull(res, i, i_srvacl))
9903  srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
9904  }
9905 
9906  PQclear(res);
9907 
9908  destroyPQExpBuffer(query);
9909 
9910  return srvinfo;
9911 }
9912 
9913 /*
9914  * getDefaultACLs:
9915  * read all default ACL information in the system catalogs and return
9916  * them in the DefaultACLInfo structure
9917  *
9918  * numDefaultACLs is set to the number of ACLs read in
9919  */
9921 getDefaultACLs(Archive *fout, int *numDefaultACLs)
9922 {
9923  DumpOptions *dopt = fout->dopt;
9924  DefaultACLInfo *daclinfo;
9925  PQExpBuffer query;
9926  PGresult *res;
9927  int i_oid;
9928  int i_tableoid;
9929  int i_defaclrole;
9930  int i_defaclnamespace;
9931  int i_defaclobjtype;
9932  int i_defaclacl;
9933  int i_acldefault;
9934  int i,
9935  ntups;
9936 
9937  query = createPQExpBuffer();
9938 
9939  /*
9940  * Global entries (with defaclnamespace=0) replace the hard-wired default
9941  * ACL for their object type. We should dump them as deltas from the
9942  * default ACL, since that will be used as a starting point for
9943  * interpreting the ALTER DEFAULT PRIVILEGES commands. On the other hand,
9944  * non-global entries can only add privileges not revoke them. We must
9945  * dump those as-is (i.e., as deltas from an empty ACL).
9946  *
9947  * We can use defaclobjtype as the object type for acldefault(), except
9948  * for the case of 'S' (DEFACLOBJ_SEQUENCE) which must be converted to
9949  * 's'.
9950  */
9951  appendPQExpBufferStr(query,
9952  "SELECT oid, tableoid, "
9953  "defaclrole, "
9954  "defaclnamespace, "
9955  "defaclobjtype, "
9956  "defaclacl, "
9957  "CASE WHEN defaclnamespace = 0 THEN "
9958  "acldefault(CASE WHEN defaclobjtype = 'S' "
9959  "THEN 's'::\"char\" ELSE defaclobjtype END, "
9960  "defaclrole) ELSE '{}' END AS acldefault "
9961  "FROM pg_default_acl");
9962 
9963  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9964 
9965  ntups = PQntuples(res);
9966  *numDefaultACLs = ntups;
9967 
9968  daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
9969 
9970  i_oid = PQfnumber(res, "oid");
9971  i_tableoid = PQfnumber(res, "tableoid");
9972  i_defaclrole = PQfnumber(res, "defaclrole");
9973  i_defaclnamespace = PQfnumber(res, "defaclnamespace");
9974  i_defaclobjtype = PQfnumber(res, "defaclobjtype");
9975  i_defaclacl = PQfnumber(res, "defaclacl");
9976  i_acldefault = PQfnumber(res, "acldefault");
9977 
9978  for (i = 0; i < ntups; i++)
9979  {
9980  Oid nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
9981 
9982  daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
9983  daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9984  daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9985  AssignDumpId(&daclinfo[i].dobj);
9986  /* cheesy ... is it worth coming up with a better object name? */
9987  daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
9988 
9989  if (nspid != InvalidOid)
9990  daclinfo[i].dobj.namespace = findNamespace(nspid);
9991  else
9992  daclinfo[i].dobj.namespace = NULL;
9993 
9994  daclinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
9995  daclinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
9996  daclinfo[i].dacl.privtype = 0;
9997  daclinfo[i].dacl.initprivs = NULL;
9998  daclinfo[i].defaclrole = getRoleName(PQgetvalue(res, i, i_defaclrole));
9999  daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
10000 
10001  /* Default ACLs are ACLs, of course */
10002  daclinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
10003 
10004  /* Decide whether we want to dump it */
10005  selectDumpableDefaultACL(&(daclinfo[i]), dopt);
10006  }
10007 
10008  PQclear(res);
10009 
10010  destroyPQExpBuffer(query);
10011 
10012  return daclinfo;
10013 }
10014 
10015 /*
10016  * getRoleName -- look up the name of a role, given its OID
10017  *
10018  * In current usage, we don't expect failures, so error out for a bad OID.
10019  */
10020 static const char *
10021 getRoleName(const char *roleoid_str)
10022 {
10023  Oid roleoid = atooid(roleoid_str);
10024 
10025  /*
10026  * Do binary search to find the appropriate item.
10027  */
10028  if (nrolenames > 0)
10029  {
10030  RoleNameItem *low = &rolenames[0];
10031  RoleNameItem *high = &rolenames[nrolenames - 1];
10032 
10033  while (low <= high)
10034  {
10035  RoleNameItem *middle = low + (high - low) / 2;
10036 
10037  if (roleoid < middle->roleoid)
10038  high = middle - 1;
10039  else if (roleoid > middle->roleoid)
10040  low = middle + 1;
10041  else
10042  return middle->rolename; /* found a match */
10043  }
10044  }
10045 
10046  pg_fatal("role with OID %u does not exist", roleoid);
10047  return NULL; /* keep compiler quiet */
10048 }
10049 
10050 /*
10051  * collectRoleNames --
10052  *
10053  * Construct a table of all known roles.
10054  * The table is sorted by OID for speed in lookup.
10055  */
10056 static void
10058 {
10059  PGresult *res;
10060  const char *query;
10061  int i;
10062 
10063  query = "SELECT oid, rolname FROM pg_catalog.pg_roles ORDER BY 1";
10064 
10065  res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
10066 
10068 
10070 
10071  for (i = 0; i < nrolenames; i++)
10072  {
10075  }
10076 
10077  PQclear(res);
10078 }
10079 
10080 /*
10081  * getAdditionalACLs
10082  *
10083  * We have now created all the DumpableObjects, and collected the ACL data
10084  * that appears in the directly-associated catalog entries. However, there's
10085  * more ACL-related info to collect. If any of a table's columns have ACLs,
10086  * we must set the TableInfo's DUMP_COMPONENT_ACL components flag, as well as
10087  * its hascolumnACLs flag (we won't store the ACLs themselves here, though).
10088  * Also, in versions having the pg_init_privs catalog, read that and load the
10089  * information into the relevant DumpableObjects.
10090  */
10091 static void
10093 {
10094  PQExpBuffer query = createPQExpBuffer();
10095  PGresult *res;
10096  int ntups,
10097  i;
10098 
10099  /* Check for per-column ACLs */
10100  appendPQExpBufferStr(query,
10101  "SELECT DISTINCT attrelid FROM pg_attribute "
10102  "WHERE attacl IS NOT NULL");
10103 
10104  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10105 
10106  ntups = PQntuples(res);
10107  for (i = 0; i < ntups; i++)
10108  {
10109  Oid relid = atooid(PQgetvalue(res, i, 0));
10110  TableInfo *tblinfo;
10111 
10112  tblinfo = findTableByOid(relid);
10113  /* OK to ignore tables we haven't got a DumpableObject for */
10114  if (tblinfo)
10115  {
10116  tblinfo->dobj.components |= DUMP_COMPONENT_ACL;
10117  tblinfo->hascolumnACLs = true;
10118  }
10119  }
10120  PQclear(res);
10121 
10122  /* Fetch initial-privileges data */
10123  if (fout->remoteVersion >= 90600)
10124  {
10125  printfPQExpBuffer(query,
10126  "SELECT objoid, classoid, objsubid, privtype, initprivs "
10127  "FROM pg_init_privs");
10128 
10129  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10130 
10131  ntups = PQntuples(res);
10132  for (i = 0; i < ntups; i++)
10133  {
10134  Oid objoid = atooid(PQgetvalue(res, i, 0));
10135  Oid classoid = atooid(PQgetvalue(res, i, 1));
10136  int objsubid = atoi(PQgetvalue(res, i, 2));
10137  char privtype = *(PQgetvalue(res, i, 3));
10138  char *initprivs = PQgetvalue(res, i, 4);
10139  CatalogId objId;
10140  DumpableObject *dobj;
10141 
10142  objId.tableoid = classoid;
10143  objId.oid = objoid;
10144  dobj = findObjectByCatalogId(objId);
10145  /* OK to ignore entries we haven't got a DumpableObject for */
10146  if (dobj)
10147  {
10148  /* Cope with sub-object initprivs */
10149  if (objsubid != 0)
10150  {
10151  if (dobj->objType == DO_TABLE)
10152  {
10153  /* For a column initprivs, set the table's ACL flags */
10154  dobj->components |= DUMP_COMPONENT_ACL;
10155  ((TableInfo *) dobj)->hascolumnACLs = true;
10156  }
10157  else
10158  pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
10159  classoid, objoid, objsubid);
10160  continue;
10161  }
10162 
10163  /*
10164  * We ignore any pg_init_privs.initprivs entry for the public
10165  * schema, as explained in getNamespaces().
10166  */
10167  if (dobj->objType == DO_NAMESPACE &&
10168  strcmp(dobj->name, "public") == 0)
10169  continue;
10170 
10171  /* Else it had better be of a type we think has ACLs */
10172  if (dobj->objType == DO_NAMESPACE ||
10173  dobj->objType == DO_TYPE ||
10174  dobj->objType == DO_FUNC ||
10175  dobj->objType == DO_AGG ||
10176  dobj->objType == DO_TABLE ||
10177  dobj->objType == DO_PROCLANG ||
10178  dobj->objType == DO_FDW ||
10179  dobj->objType == DO_FOREIGN_SERVER)
10180  {
10181  DumpableObjectWithAcl *daobj = (DumpableObjectWithAcl *) dobj;
10182 
10183  daobj->dacl.privtype = privtype;
10184  daobj->dacl.initprivs = pstrdup(initprivs);
10185  }
10186  else
10187  pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
10188  classoid, objoid, objsubid);
10189  }
10190  }
10191  PQclear(res);
10192  }
10193 
10194  destroyPQExpBuffer(query);
10195 }
10196 
10197 /*
10198  * dumpCommentExtended --
10199  *
10200  * This routine is used to dump any comments associated with the
10201  * object handed to this routine. The routine takes the object type
10202  * and object name (ready to print, except for schema decoration), plus
10203  * the namespace and owner of the object (for labeling the ArchiveEntry),
10204  * plus catalog ID and subid which are the lookup key for pg_description,
10205  * plus the dump ID for the object (for setting a dependency).
10206  * If a matching pg_description entry is found, it is dumped.
10207  *
10208  * Note: in some cases, such as comments for triggers and rules, the "type"
10209  * string really looks like, e.g., "TRIGGER name ON". This is a bit of a hack
10210  * but it doesn't seem worth complicating the API for all callers to make
10211  * it cleaner.
10212  *
10213  * Note: although this routine takes a dumpId for dependency purposes,
10214  * that purpose is just to mark the dependency in the emitted dump file
10215  * for possible future use by pg_restore. We do NOT use it for determining
10216  * ordering of the comment in the dump file, because this routine is called
10217  * after dependency sorting occurs. This routine should be called just after
10218  * calling ArchiveEntry() for the specified object.
10219  */
10220 static void
10221 dumpCommentExtended(Archive *fout, const char *type,
10222  const char *name, const char *namespace,
10223  const char *owner, CatalogId catalogId,
10224  int subid, DumpId dumpId,
10225  const char *initdb_comment)
10226 {
10227  DumpOptions *dopt = fout->dopt;
10229  int ncomments;
10230 
10231  /* do nothing, if --no-comments is supplied */
10232  if (dopt->no_comments)
10233  return;
10234 
10235  /* Comments are schema not data ... except LO comments are data */
10236  if (strcmp(type, "LARGE OBJECT") != 0)
10237  {
10238  if (dopt->dataOnly)
10239  return;
10240  }
10241  else
10242  {
10243  /* We do dump LO comments in binary-upgrade mode */
10244  if (dopt->schemaOnly && !dopt->binary_upgrade)
10245  return;
10246  }
10247 
10248  /* Search for comments associated with catalogId, using table */
10249  ncomments = findComments(catalogId.tableoid, catalogId.oid,
10250  &comments);
10251 
10252  /* Is there one matching the subid? */
10253  while (ncomments > 0)
10254  {
10255  if (comments->objsubid == subid)
10256  break;
10257  comments++;
10258  ncomments--;
10259  }
10260 
10261  if (initdb_comment != NULL)
10262  {
10263  static CommentItem empty_comment = {.descr = ""};
10264 
10265  /*
10266  * initdb creates this object with a comment. Skip dumping the
10267  * initdb-provided comment, which would complicate matters for
10268  * non-superuser use of pg_dump. When the DBA has removed initdb's
10269  * comment, replicate that.
10270  */
10271  if (ncomments == 0)
10272  {
10273  comments = &empty_comment;
10274  ncomments = 1;
10275  }
10276  else if (strcmp(comments->descr, initdb_comment) == 0)
10277  ncomments = 0;
10278  }
10279 
10280  /* If a comment exists, build COMMENT ON statement */
10281  if (ncomments > 0)
10282  {
10283  PQExpBuffer query = createPQExpBuffer();
10285 
10286  appendPQExpBuffer(query, "COMMENT ON %s ", type);
10287  if (namespace && *namespace)
10288  appendPQExpBuffer(query, "%s.", fmtId(namespace));
10289  appendPQExpBuffer(query, "%s IS ", name);
10290  appendStringLiteralAH(query, comments->descr, fout);
10291  appendPQExpBufferStr(query, ";\n");
10292 
10293  appendPQExpBuffer(tag, "%s %s", type, name);
10294 
10295  /*
10296  * We mark comments as SECTION_NONE because they really belong in the
10297  * same section as their parent, whether that is pre-data or
10298  * post-data.
10299  */
10301  ARCHIVE_OPTS(.tag = tag->data,
10302  .namespace = namespace,
10303  .owner = owner,
10304  .description = "COMMENT",
10305  .section = SECTION_NONE,
10306  .createStmt = query->data,
10307  .deps = &dumpId,
10308  .nDeps = 1));
10309 
10310  destroyPQExpBuffer(query);
10311  destroyPQExpBuffer(tag);
10312  }
10313 }
10314 
10315 /*
10316  * dumpComment --
10317  *
10318  * Typical simplification of the above function.
10319  */
10320 static inline void
10321 dumpComment(Archive *fout, const char *type,
10322  const char *name, const char *namespace,
10323  const char *owner, CatalogId catalogId,
10324  int subid, DumpId dumpId)
10325 {
10326  dumpCommentExtended(fout, type, name, namespace, owner,
10327  catalogId, subid, dumpId, NULL);
10328 }
10329 
10330 /*
10331  * dumpTableComment --
10332  *
10333  * As above, but dump comments for both the specified table (or view)
10334  * and its columns.
10335  */
10336 static void
10337 dumpTableComment(Archive *fout, const TableInfo *tbinfo,
10338  const char *reltypename)
10339 {
10340  DumpOptions *dopt = fout->dopt;
10342  int ncomments;
10343  PQExpBuffer query;
10344  PQExpBuffer tag;
10345 
10346  /* do nothing, if --no-comments is supplied */
10347  if (dopt->no_comments)
10348  return;
10349 
10350  /* Comments are SCHEMA not data */
10351  if (dopt->dataOnly)
10352  return;
10353 
10354  /* Search for comments associated with relation, using table */
10356  tbinfo->dobj.catId.oid,
10357  &comments);
10358 
10359  /* If comments exist, build COMMENT ON statements */
10360  if (ncomments <= 0)
10361  return;
10362 
10363  query = createPQExpBuffer();
10364  tag = createPQExpBuffer();
10365 
10366  while (ncomments > 0)
10367  {
10368  const char *descr = comments->descr;
10369  int objsubid = comments->objsubid;
10370 
10371  if (objsubid == 0)
10372  {
10373  resetPQExpBuffer(tag);
10374  appendPQExpBuffer(tag, "%s %s", reltypename,
10375  fmtId(tbinfo->dobj.name));
10376 
10377  resetPQExpBuffer(query);
10378  appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
10379  fmtQualifiedDumpable(tbinfo));
10380  appendStringLiteralAH(query, descr, fout);
10381  appendPQExpBufferStr(query, ";\n");
10382 
10384  ARCHIVE_OPTS(.tag = tag->data,
10385  .namespace = tbinfo->dobj.namespace->dobj.name,
10386  .owner = tbinfo->rolname,
10387  .description = "COMMENT",
10388  .section = SECTION_NONE,
10389  .createStmt = query->data,
10390  .deps = &(tbinfo->dobj.dumpId),
10391  .nDeps = 1));
10392  }
10393  else if (objsubid > 0 && objsubid <= tbinfo->numatts)
10394  {
10395  resetPQExpBuffer(tag);
10396  appendPQExpBuffer(tag, "COLUMN %s.",
10397  fmtId(tbinfo->dobj.name));
10398  appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
10399 
10400  resetPQExpBuffer(query);
10401  appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
10402  fmtQualifiedDumpable(tbinfo));
10403  appendPQExpBuffer(query, "%s IS ",
10404  fmtId(tbinfo->attnames[objsubid - 1]));
10405  appendStringLiteralAH(query, descr, fout);
10406  appendPQExpBufferStr(query, ";\n");
10407 
10409  ARCHIVE_OPTS(.tag = tag->data,
10410  .namespace = tbinfo->dobj.namespace->dobj.name,
10411  .owner = tbinfo->rolname,
10412  .description = "COMMENT",
10413  .section = SECTION_NONE,
10414  .createStmt = query->data,
10415  .deps = &(tbinfo->dobj.dumpId),
10416  .nDeps = 1));
10417  }
10418 
10419  comments++;
10420  ncomments--;
10421  }
10422 
10423  destroyPQExpBuffer(query);
10424  destroyPQExpBuffer(tag);
10425 }
10426 
10427 /*
10428  * findComments --
10429  *
10430  * Find the comment(s), if any, associated with the given object. All the
10431  * objsubid values associated with the given classoid/objoid are found with
10432  * one search.
10433  */
10434 static int
10435 findComments(Oid classoid, Oid objoid, CommentItem **items)
10436 {
10437  CommentItem *middle = NULL;
10438  CommentItem *low;
10439  CommentItem *high;
10440  int nmatch;
10441 
10442  /*
10443  * Do binary search to find some item matching the object.
10444  */
10445  low = &comments[0];
10446  high = &comments[ncomments - 1];
10447  while (low <= high)
10448  {
10449  middle = low + (high - low) / 2;
10450 
10451  if (classoid < middle->classoid)
10452  high = middle - 1;
10453  else if (classoid > middle->classoid)
10454  low = middle + 1;
10455  else if (objoid < middle->objoid)
10456  high = middle - 1;
10457  else if (objoid > middle->objoid)
10458  low = middle + 1;
10459  else
10460  break; /* found a match */
10461  }
10462 
10463  if (low > high) /* no matches */
10464  {
10465  *items = NULL;
10466  return 0;
10467  }
10468 
10469  /*
10470  * Now determine how many items match the object. The search loop
10471  * invariant still holds: only items between low and high inclusive could
10472  * match.
10473  */
10474  nmatch = 1;
10475  while (middle > low)
10476  {
10477  if (classoid != middle[-1].classoid ||
10478  objoid != middle[-1].objoid)
10479  break;
10480  middle--;
10481  nmatch++;
10482  }
10483 
10484  *items = middle;
10485 
10486  middle += nmatch;
10487  while (middle <= high)
10488  {
10489  if (classoid != middle->classoid ||
10490  objoid != middle->objoid)
10491  break;
10492  middle++;
10493  nmatch++;
10494  }
10495 
10496  return nmatch;
10497 }
10498 
10499 /*
10500  * collectComments --
10501  *
10502  * Construct a table of all comments available for database objects;
10503  * also set the has-comment component flag for each relevant object.
10504  *
10505  * We used to do per-object queries for the comments, but it's much faster
10506  * to pull them all over at once, and on most databases the memory cost
10507  * isn't high.
10508  *
10509  * The table is sorted by classoid/objid/objsubid for speed in lookup.
10510  */
10511 static void
10513 {
10514  PGresult *res;
10515  PQExpBuffer query;
10516  int i_description;
10517  int i_classoid;
10518  int i_objoid;
10519  int i_objsubid;
10520  int ntups;
10521  int i;
10522  DumpableObject *dobj;
10523 
10524  query = createPQExpBuffer();
10525 
10526  appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
10527  "FROM pg_catalog.pg_description "
10528  "ORDER BY classoid, objoid, objsubid");
10529 
10530  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10531 
10532  /* Construct lookup table containing OIDs in numeric form */
10533 
10534  i_description = PQfnumber(res, "description");
10535  i_classoid = PQfnumber(res, "classoid");
10536  i_objoid = PQfnumber(res, "objoid");
10537  i_objsubid = PQfnumber(res, "objsubid");
10538 
10539  ntups = PQntuples(res);
10540 
10541  comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
10542  ncomments = 0;
10543  dobj = NULL;
10544 
10545  for (i = 0; i < ntups; i++)
10546  {
10547  CatalogId objId;
10548  int subid;
10549 
10550  objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
10551  objId.oid = atooid(PQgetvalue(res, i, i_objoid));
10552  subid = atoi(PQgetvalue(res, i, i_objsubid));
10553 
10554  /* We needn't remember comments that don't match any dumpable object */
10555  if (dobj == NULL ||
10556  dobj->catId.tableoid != objId.tableoid ||
10557  dobj->catId.oid != objId.oid)
10558  dobj = findObjectByCatalogId(objId);
10559  if (dobj == NULL)
10560  continue;
10561 
10562  /*
10563  * Comments on columns of composite types are linked to the type's
10564  * pg_class entry, but we need to set the DUMP_COMPONENT_COMMENT flag
10565  * in the type's own DumpableObject.
10566  */
10567  if (subid != 0 && dobj->objType == DO_TABLE &&
10568  ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
10569  {
10570  TypeInfo *cTypeInfo;
10571 
10572  cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
10573  if (cTypeInfo)
10574  cTypeInfo->dobj.components |= DUMP_COMPONENT_COMMENT;
10575  }
10576  else
10577  dobj->components |= DUMP_COMPONENT_COMMENT;
10578 
10579  comments[ncomments].descr = pg_strdup(PQgetvalue(res, i, i_description));
10581  comments[ncomments].objoid = objId.oid;
10582  comments[ncomments].objsubid = subid;
10583  ncomments++;
10584  }
10585 
10586  PQclear(res);
10587  destroyPQExpBuffer(query);
10588 }
10589 
10590 /*
10591  * dumpDumpableObject
10592  *
10593  * This routine and its subsidiaries are responsible for creating
10594  * ArchiveEntries (TOC objects) for each object to be dumped.
10595  */
10596 static void
10598 {
10599  /*
10600  * Clear any dump-request bits for components that don't exist for this
10601  * object. (This makes it safe to initially use DUMP_COMPONENT_ALL as the
10602  * request for every kind of object.)
10603  */
10604  dobj->dump &= dobj->components;
10605 
10606  /* Now, short-circuit if there's nothing to be done here. */
10607  if (dobj->dump == 0)
10608  return;
10609 
10610  switch (dobj->objType)
10611  {
10612  case DO_NAMESPACE:
10613  dumpNamespace(fout, (const NamespaceInfo *) dobj);
10614  break;
10615  case DO_EXTENSION:
10616  dumpExtension(fout, (const ExtensionInfo *) dobj);
10617  break;
10618  case DO_TYPE:
10619  dumpType(fout, (const TypeInfo *) dobj);
10620  break;
10621  case DO_SHELL_TYPE:
10622  dumpShellType(fout, (const ShellTypeInfo *) dobj);
10623  break;
10624  case DO_FUNC:
10625  dumpFunc(fout, (const FuncInfo *) dobj);
10626  break;
10627  case DO_AGG:
10628  dumpAgg(fout, (const AggInfo *) dobj);
10629  break;
10630  case DO_OPERATOR:
10631  dumpOpr(fout, (const OprInfo *) dobj);
10632  break;
10633  case DO_ACCESS_METHOD:
10634  dumpAccessMethod(fout, (const AccessMethodInfo *) dobj);
10635  break;
10636  case DO_OPCLASS:
10637  dumpOpclass(fout, (const OpclassInfo *) dobj);
10638  break;
10639  case DO_OPFAMILY:
10640  dumpOpfamily(fout, (const OpfamilyInfo *) dobj);
10641  break;
10642  case DO_COLLATION:
10643  dumpCollation(fout, (const CollInfo *) dobj);
10644  break;
10645  case DO_CONVERSION:
10646  dumpConversion(fout, (const ConvInfo *) dobj);
10647  break;
10648  case DO_TABLE:
10649  dumpTable(fout, (const TableInfo *) dobj);
10650  break;
10651  case DO_TABLE_ATTACH:
10652  dumpTableAttach(fout, (const TableAttachInfo *) dobj);
10653  break;
10654  case DO_ATTRDEF:
10655  dumpAttrDef(fout, (const AttrDefInfo *) dobj);
10656  break;
10657  case DO_INDEX:
10658  dumpIndex(fout, (const IndxInfo *) dobj);
10659  break;
10660  case DO_INDEX_ATTACH:
10661  dumpIndexAttach(fout, (const IndexAttachInfo *) dobj);
10662  break;
10663  case DO_STATSEXT:
10664  dumpStatisticsExt(fout, (const StatsExtInfo *) dobj);
10665  break;
10666  case DO_REFRESH_MATVIEW:
10667  refreshMatViewData(fout, (const TableDataInfo *) dobj);
10668  break;
10669  case DO_RULE:
10670  dumpRule(fout, (const RuleInfo *) dobj);
10671  break;
10672  case DO_TRIGGER:
10673  dumpTrigger(fout, (const TriggerInfo *) dobj);
10674  break;
10675  case DO_EVENT_TRIGGER:
10676  dumpEventTrigger(fout, (const EventTriggerInfo *) dobj);
10677  break;
10678  case DO_CONSTRAINT:
10679  dumpConstraint(fout, (const ConstraintInfo *) dobj);
10680  break;
10681  case DO_FK_CONSTRAINT:
10682  dumpConstraint(fout, (const ConstraintInfo *) dobj);
10683  break;
10684  case DO_PROCLANG:
10685  dumpProcLang(fout, (const ProcLangInfo *) dobj);
10686  break;
10687  case DO_CAST:
10688  dumpCast(fout, (const CastInfo *) dobj);
10689  break;
10690  case DO_TRANSFORM:
10691  dumpTransform(fout, (const TransformInfo *) dobj);
10692  break;
10693  case DO_SEQUENCE_SET:
10694  dumpSequenceData(fout, (const TableDataInfo *) dobj);
10695  break;
10696  case DO_TABLE_DATA:
10697  dumpTableData(fout, (const TableDataInfo *) dobj);
10698  break;
10699  case DO_DUMMY_TYPE:
10700  /* table rowtypes and array types are never dumped separately */
10701  break;
10702  case DO_TSPARSER:
10703  dumpTSParser(fout, (const TSParserInfo *) dobj);
10704  break;
10705  case DO_TSDICT:
10706  dumpTSDictionary(fout, (const TSDictInfo *) dobj);
10707  break;
10708  case DO_TSTEMPLATE:
10709  dumpTSTemplate(fout, (const TSTemplateInfo *) dobj);
10710  break;
10711  case DO_TSCONFIG:
10712  dumpTSConfig(fout, (const TSConfigInfo *) dobj);
10713  break;
10714  case DO_FDW:
10715  dumpForeignDataWrapper(fout, (const FdwInfo *) dobj);
10716  break;
10717  case DO_FOREIGN_SERVER:
10718  dumpForeignServer(fout, (const ForeignServerInfo *) dobj);
10719  break;
10720  case DO_DEFAULT_ACL:
10721  dumpDefaultACL(fout, (const DefaultACLInfo *) dobj);
10722  break;
10723  case DO_LARGE_OBJECT:
10724  dumpLO(fout, (const LoInfo *) dobj);
10725  break;
10726  case DO_LARGE_OBJECT_DATA:
10727  if (dobj->dump & DUMP_COMPONENT_DATA)
10728  {
10729  LoInfo *loinfo;
10730  TocEntry *te;
10731 
10732  loinfo = (LoInfo *) findObjectByDumpId(dobj->dependencies[0]);
10733  if (loinfo == NULL)
10734  pg_fatal("missing metadata for large objects \"%s\"",
10735  dobj->name);
10736 
10737  te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
10738  ARCHIVE_OPTS(.tag = dobj->name,
10739  .owner = loinfo->rolname,
10740  .description = "BLOBS",
10741  .section = SECTION_DATA,
10742  .deps = dobj->dependencies,
10743  .nDeps = dobj->nDeps,
10744  .dumpFn = dumpLOs,
10745  .dumpArg = loinfo));
10746 
10747  /*
10748  * Set the TocEntry's dataLength in case we are doing a
10749  * parallel dump and want to order dump jobs by table size.
10750  * (We need some size estimate for every TocEntry with a
10751  * DataDumper function.) We don't currently have any cheap
10752  * way to estimate the size of LOs, but fortunately it doesn't
10753  * matter too much as long as we get large batches of LOs
10754  * processed reasonably early. Assume 8K per blob.
10755  */
10756  te->dataLength = loinfo->numlos * (pgoff_t) 8192;
10757  }
10758  break;
10759  case DO_POLICY:
10760  dumpPolicy(fout, (const PolicyInfo *) dobj);
10761  break;
10762  case DO_PUBLICATION:
10763  dumpPublication(fout, (const PublicationInfo *) dobj);
10764  break;
10765  case DO_PUBLICATION_REL:
10766  dumpPublicationTable(fout, (const PublicationRelInfo *) dobj);
10767  break;
10770  (const PublicationSchemaInfo *) dobj);
10771  break;
10772  case DO_SUBSCRIPTION:
10773  dumpSubscription(fout, (const SubscriptionInfo *) dobj);
10774  break;
10775  case DO_SUBSCRIPTION_REL:
10776  dumpSubscriptionTable(fout, (const SubRelInfo *) dobj);
10777  break;
10778  case DO_PRE_DATA_BOUNDARY:
10779  case DO_POST_DATA_BOUNDARY:
10780  /* never dumped, nothing to do */
10781  break;
10782  }
10783 }
10784 
10785 /*
10786  * dumpNamespace
10787  * writes out to fout the queries to recreate a user-defined namespace
10788  */
10789 static void
10790 dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
10791 {
10792  DumpOptions *dopt = fout->dopt;
10793  PQExpBuffer q;
10794  PQExpBuffer delq;
10795  char *qnspname;
10796 
10797  /* Do nothing in data-only dump */
10798  if (dopt->dataOnly)
10799  return;
10800 
10801  q = createPQExpBuffer();
10802  delq = createPQExpBuffer();
10803 
10804  qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
10805 
10806  if (nspinfo->create)
10807  {
10808  appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
10809  appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
10810  }
10811  else
10812  {
10813  /* see selectDumpableNamespace() */
10814  appendPQExpBufferStr(delq,
10815  "-- *not* dropping schema, since initdb creates it\n");
10817  "-- *not* creating schema, since initdb creates it\n");
10818  }
10819 
10820  if (dopt->binary_upgrade)
10822  "SCHEMA", qnspname, NULL);
10823 
10824  if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10825  ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
10826  ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
10827  .owner = nspinfo->rolname,
10828  .description = "SCHEMA",
10829  .section = SECTION_PRE_DATA,
10830  .createStmt = q->data,
10831  .dropStmt = delq->data));
10832 
10833  /* Dump Schema Comments and Security Labels */
10834  if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10835  {
10836  const char *initdb_comment = NULL;
10837 
10838  if (!nspinfo->create && strcmp(qnspname, "public") == 0)
10839  initdb_comment = "standard public schema";
10840  dumpCommentExtended(fout, "SCHEMA", qnspname,
10841  NULL, nspinfo->rolname,
10842  nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId,
10843  initdb_comment);
10844  }
10845 
10846  if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10847  dumpSecLabel(fout, "SCHEMA", qnspname,
10848  NULL, nspinfo->rolname,
10849  nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
10850 
10851  if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
10852  dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
10853  qnspname, NULL, NULL,
10854  NULL, nspinfo->rolname, &nspinfo->dacl);
10855 
10856  free(qnspname);
10857 
10858  destroyPQExpBuffer(q);
10859  destroyPQExpBuffer(delq);
10860 }
10861 
10862 /*
10863  * dumpExtension
10864  * writes out to fout the queries to recreate an extension
10865  */
10866 static void
10867 dumpExtension(Archive *fout, const ExtensionInfo *extinfo)
10868 {
10869  DumpOptions *dopt = fout->dopt;
10870  PQExpBuffer q;
10871  PQExpBuffer delq;
10872  char *qextname;
10873 
10874  /* Do nothing in data-only dump */
10875  if (dopt->dataOnly)
10876  return;
10877 
10878  q = createPQExpBuffer();
10879  delq = createPQExpBuffer();
10880 
10881  qextname = pg_strdup(fmtId(extinfo->dobj.name));
10882 
10883  appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
10884 
10885  if (!dopt->binary_upgrade)
10886  {
10887  /*
10888  * In a regular dump, we simply create the extension, intentionally
10889  * not specifying a version, so that the destination installation's
10890  * default version is used.
10891  *
10892  * Use of IF NOT EXISTS here is unlike our behavior for other object
10893  * types; but there are various scenarios in which it's convenient to
10894  * manually create the desired extension before restoring, so we
10895  * prefer to allow it to exist already.
10896  */
10897  appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
10898  qextname, fmtId(extinfo->namespace));
10899  }
10900  else
10901  {
10902  /*
10903  * In binary-upgrade mode, it's critical to reproduce the state of the
10904  * database exactly, so our procedure is to create an empty extension,
10905  * restore all the contained objects normally, and add them to the
10906  * extension one by one. This function performs just the first of
10907  * those steps. binary_upgrade_extension_member() takes care of
10908  * adding member objects as they're created.
10909  */
10910  int i;
10911  int n;
10912 
10913  appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
10914 
10915  /*
10916  * We unconditionally create the extension, so we must drop it if it
10917  * exists. This could happen if the user deleted 'plpgsql' and then
10918  * readded it, causing its oid to be greater than g_last_builtin_oid.
10919  */
10920  appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
10921 
10923  "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
10924  appendStringLiteralAH(q, extinfo->dobj.name, fout);
10925  appendPQExpBufferStr(q, ", ");
10926  appendStringLiteralAH(q, extinfo->namespace, fout);
10927  appendPQExpBufferStr(q, ", ");
10928  appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
10929  appendStringLiteralAH(q, extinfo->extversion, fout);
10930  appendPQExpBufferStr(q, ", ");
10931 
10932  /*
10933  * Note that we're pushing extconfig (an OID array) back into
10934  * pg_extension exactly as-is. This is OK because pg_class OIDs are
10935  * preserved in binary upgrade.
10936  */
10937  if (strlen(extinfo->extconfig) > 2)
10938  appendStringLiteralAH(q, extinfo->extconfig, fout);
10939  else
10940  appendPQExpBufferStr(q, "NULL");
10941  appendPQExpBufferStr(q, ", ");
10942  if (strlen(extinfo->extcondition) > 2)
10943  appendStringLiteralAH(q, extinfo->extcondition, fout);
10944  else
10945  appendPQExpBufferStr(q, "NULL");
10946  appendPQExpBufferStr(q, ", ");
10947  appendPQExpBufferStr(q, "ARRAY[");
10948  n = 0;
10949  for (i = 0; i < extinfo->dobj.nDeps; i++)
10950  {
10951  DumpableObject *extobj;
10952 
10953  extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
10954  if (extobj && extobj->objType == DO_EXTENSION)
10955  {
10956  if (n++ > 0)
10957  appendPQExpBufferChar(q, ',');
10958  appendStringLiteralAH(q, extobj->name, fout);
10959  }
10960  }
10961  appendPQExpBufferStr(q, "]::pg_catalog.text[]");
10962  appendPQExpBufferStr(q, ");\n");
10963  }
10964 
10965  if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10966  ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
10967  ARCHIVE_OPTS(.tag = extinfo->dobj.name,
10968  .description = "EXTENSION",
10969  .section = SECTION_PRE_DATA,
10970  .createStmt = q->data,
10971  .dropStmt = delq->data));
10972 
10973  /* Dump Extension Comments and Security Labels */
10974  if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10975  dumpComment(fout, "EXTENSION", qextname,
10976  NULL, "",
10977  extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
10978 
10979  if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10980  dumpSecLabel(fout, "EXTENSION", qextname,
10981  NULL, "",
10982  extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
10983 
10984  free(qextname);
10985 
10986  destroyPQExpBuffer(q);
10987  destroyPQExpBuffer(delq);
10988 }
10989 
10990 /*
10991  * dumpType
10992  * writes out to fout the queries to recreate a user-defined type
10993  */
10994 static void
10995 dumpType(Archive *fout, const TypeInfo *tyinfo)
10996 {
10997  DumpOptions *dopt = fout->dopt;
10998 
10999  /* Do nothing in data-only dump */
11000  if (dopt->dataOnly)
11001  return;
11002 
11003  /* Dump out in proper style */
11004  if (tyinfo->typtype == TYPTYPE_BASE)
11005  dumpBaseType(fout, tyinfo);
11006  else if (tyinfo->typtype == TYPTYPE_DOMAIN)
11007  dumpDomain(fout, tyinfo);
11008  else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
11009  dumpCompositeType(fout, tyinfo);
11010  else if (tyinfo->typtype == TYPTYPE_ENUM)
11011  dumpEnumType(fout, tyinfo);
11012  else if (tyinfo->typtype == TYPTYPE_RANGE)
11013  dumpRangeType(fout, tyinfo);
11014  else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
11015  dumpUndefinedType(fout, tyinfo);
11016  else
11017  pg_log_warning("typtype of data type \"%s\" appears to be invalid",
11018  tyinfo->dobj.name);
11019 }
11020 
11021 /*
11022  * dumpEnumType
11023  * writes out to fout the queries to recreate a user-defined enum type
11024  */
11025 static void
11026 dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
11027 {
11028  DumpOptions *dopt = fout->dopt;
11030  PQExpBuffer delq = createPQExpBuffer();
11031  PQExpBuffer query = createPQExpBuffer();
11032  PGresult *res;
11033  int num,
11034  i;
11035  Oid enum_oid;
11036  char *qtypname;
11037  char *qualtypname;
11038  char *label;
11039  int i_enumlabel;
11040  int i_oid;
11041 
11042  if (!fout->is_prepared[PREPQUERY_DUMPENUMTYPE])
11043  {
11044  /* Set up query for enum-specific details */
11045  appendPQExpBufferStr(query,
11046  "PREPARE dumpEnumType(pg_catalog.oid) AS\n"
11047  "SELECT oid, enumlabel "
11048  "FROM pg_catalog.pg_enum "
11049  "WHERE enumtypid = $1 "
11050  "ORDER BY enumsortorder");
11051 
11052  ExecuteSqlStatement(fout, query->data);
11053 
11054  fout->is_prepared[PREPQUERY_DUMPENUMTYPE] = true;
11055  }
11056 
11057  printfPQExpBuffer(query,
11058  "EXECUTE dumpEnumType('%u')",
11059  tyinfo->dobj.catId.oid);
11060 
11061  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11062 
11063  num = PQntuples(res);
11064 
11065  qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
11066  qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
11067 
11068  /*
11069  * CASCADE shouldn't be required here as for normal types since the I/O
11070  * functions are generic and do not get dropped.
11071  */
11072  appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
11073 
11074  if (dopt->binary_upgrade)
11076  tyinfo->dobj.catId.oid,
11077  false, false);
11078 
11079  appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
11080  qualtypname);
11081 
11082  if (!dopt->binary_upgrade)
11083  {
11084  i_enumlabel = PQfnumber(res, "enumlabel");
11085 
11086  /* Labels with server-assigned oids */
11087  for (i = 0; i < num; i++)
11088  {
11089  label = PQgetvalue(res, i, i_enumlabel);
11090  if (i > 0)
11091  appendPQExpBufferChar(q, ',');
11092  appendPQExpBufferStr(q, "\n ");
11093  appendStringLiteralAH(q, label, fout);
11094  }
11095  }
11096 
11097  appendPQExpBufferStr(q, "\n);\n");
11098 
11099  if (dopt->binary_upgrade)
11100  {
11101  i_oid = PQfnumber(res, "oid");
11102  i_enumlabel = PQfnumber(res, "enumlabel");
11103 
11104  /* Labels with dump-assigned (preserved) oids */
11105  for (i = 0; i < num; i++)
11106  {
11107  enum_oid = atooid(PQgetvalue(res, i, i_oid));
11108  label = PQgetvalue(res, i, i_enumlabel);
11109 
11110  if (i == 0)
11111  appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
11113  "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
11114  enum_oid);
11115  appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
11116  appendStringLiteralAH(q, label, fout);
11117  appendPQExpBufferStr(q, ";\n\n");
11118  }
11119  }
11120 
11121  if (dopt->binary_upgrade)
11123  "TYPE", qtypname,
11124  tyinfo->dobj.namespace->dobj.name);
11125 
11126  if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11127  ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
11128  ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
11129  .namespace = tyinfo->dobj.namespace->dobj.name,
11130  .owner = tyinfo->rolname,
11131  .description = "TYPE",
11132  .section = SECTION_PRE_DATA,
11133  .createStmt = q->data,
11134  .dropStmt = delq->data));
11135 
11136  /* Dump Type Comments and Security Labels */
11137  if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11138  dumpComment(fout, "TYPE", qtypname,
11139  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11140  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11141 
11142  if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11143  dumpSecLabel(fout, "TYPE", qtypname,
11144  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11145  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11146 
11147  if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
11148  dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
11149  qtypname, NULL,
11150  tyinfo->dobj.namespace->dobj.name,
11151  NULL, tyinfo->rolname, &tyinfo->dacl);
11152 
11153  PQclear(res);
11154  destroyPQExpBuffer(q);
11155  destroyPQExpBuffer(delq);
11156  destroyPQExpBuffer(query);
11157  free(qtypname);
11158  free(qualtypname);
11159 }
11160 
11161 /*
11162  * dumpRangeType
11163  * writes out to fout the queries to recreate a user-defined range type
11164  */
11165 static void
11166 dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
11167 {
11168  DumpOptions *dopt = fout->dopt;
11170  PQExpBuffer delq = createPQExpBuffer();
11171  PQExpBuffer query = createPQExpBuffer();
11172  PGresult *res;
11173  Oid collationOid;
11174  char *qtypname;
11175  char *qualtypname;
11176  char *procname;
11177 
11179  {
11180  /* Set up query for range-specific details */
11181  appendPQExpBufferStr(query,
11182  "PREPARE dumpRangeType(pg_catalog.oid) AS\n");
11183 
11184  appendPQExpBufferStr(query,
11185  "SELECT ");
11186 
11187  if (fout->remoteVersion >= 140000)
11188  appendPQExpBufferStr(query,
11189  "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, ");
11190  else
11191  appendPQExpBufferStr(query,
11192  "NULL AS rngmultitype, ");
11193 
11194  appendPQExpBufferStr(query,
11195  "pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
11196  "opc.opcname AS opcname, "
11197  "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
11198  " WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
11199  "opc.opcdefault, "
11200  "CASE WHEN rngcollation = st.typcollation THEN 0 "
11201  " ELSE rngcollation END AS collation, "
11202  "rngcanonical, rngsubdiff "
11203  "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
11204  " pg_catalog.pg_opclass opc "
11205  "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
11206  "rngtypid = $1");
11207 
11208  ExecuteSqlStatement(fout, query->data);
11209 
11210  fout->is_prepared[PREPQUERY_DUMPRANGETYPE] = true;
11211  }
11212 
11213  printfPQExpBuffer(query,
11214  "EXECUTE dumpRangeType('%u')",
11215  tyinfo->dobj.catId.oid);
11216 
11217  res = ExecuteSqlQueryForSingleRow(fout, query->data);
11218 
11219  qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
11220  qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
11221 
11222  /*
11223  * CASCADE shouldn't be required here as for normal types since the I/O
11224  * functions are generic and do not get dropped.
11225  */
11226  appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
11227 
11228  if (dopt->binary_upgrade)
11230  tyinfo->dobj.catId.oid,
11231  false, true);
11232 
11233  appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
11234  qualtypname);
11235 
11236  appendPQExpBuffer(q, "\n subtype = %s",
11237  PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
11238 
11239  if (!PQgetisnull(res, 0, PQfnumber(res, "rngmultitype")))
11240  appendPQExpBuffer(q, ",\n multirange_type_name = %s",
11241  PQgetvalue(res, 0, PQfnumber(res, "rngmultitype")));
11242 
11243  /* print subtype_opclass only if not default for subtype */
11244  if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
11245  {
11246  char *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
11247  char *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
11248 
11249  appendPQExpBuffer(q, ",\n subtype_opclass = %s.",
11250  fmtId(nspname));
11251  appendPQExpBufferStr(q, fmtId(opcname));
11252  }
11253 
11254  collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
11255  if (OidIsValid(collationOid))
11256  {
11257  CollInfo *coll = findCollationByOid(collationOid);
11258 
11259  if (coll)
11260  appendPQExpBuffer(q, ",\n collation = %s",
11261  fmtQualifiedDumpable(coll));
11262  }
11263 
11264  procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
11265  if (strcmp(procname, "-") != 0)
11266  appendPQExpBuffer(q, ",\n canonical = %s", procname);
11267 
11268  procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
11269  if (strcmp(procname, "-") != 0)
11270  appendPQExpBuffer(q, ",\n subtype_diff = %s", procname);
11271 
11272  appendPQExpBufferStr(q, "\n);\n");
11273 
11274  if (dopt->binary_upgrade)
11276  "TYPE", qtypname,
11277  tyinfo->dobj.namespace->dobj.name);
11278 
11279  if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11280  ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
11281  ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
11282  .namespace = tyinfo->dobj.namespace->dobj.name,
11283  .owner = tyinfo->rolname,
11284  .description = "TYPE",
11285  .section = SECTION_PRE_DATA,
11286  .createStmt = q->data,
11287  .dropStmt = delq->data));
11288 
11289  /* Dump Type Comments and Security Labels */
11290  if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11291  dumpComment(fout, "TYPE", qtypname,
11292  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11293  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11294 
11295  if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11296  dumpSecLabel(fout, "TYPE", qtypname,
11297  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11298  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11299 
11300  if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
11301  dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
11302  qtypname, NULL,
11303  tyinfo->dobj.namespace->dobj.name,
11304  NULL, tyinfo->rolname, &tyinfo->dacl);
11305 
11306  PQclear(res);
11307  destroyPQExpBuffer(q);
11308  destroyPQExpBuffer(delq);
11309  destroyPQExpBuffer(query);
11310  free(qtypname);
11311  free(qualtypname);
11312 }
11313 
11314 /*
11315  * dumpUndefinedType
11316  * writes out to fout the queries to recreate a !typisdefined type
11317  *
11318  * This is a shell type, but we use different terminology to distinguish
11319  * this case from where we have to emit a shell type definition to break
11320  * circular dependencies. An undefined type shouldn't ever have anything
11321  * depending on it.
11322  */
11323 static void
11324 dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo)
11325 {
11326  DumpOptions *dopt = fout->dopt;
11328  PQExpBuffer delq = createPQExpBuffer();
11329  char *qtypname;
11330  char *qualtypname;
11331 
11332  qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
11333  qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
11334 
11335  appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
11336 
11337  if (dopt->binary_upgrade)
11339  tyinfo->dobj.catId.oid,
11340  false, false);
11341 
11342  appendPQExpBuffer(q, "CREATE TYPE %s;\n",
11343  qualtypname);
11344 
11345  if (dopt->binary_upgrade)
11347  "TYPE", qtypname,
11348  tyinfo->dobj.namespace->dobj.name);
11349 
11350  if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11351  ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
11352  ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
11353  .namespace = tyinfo->dobj.namespace->dobj.name,
11354  .owner = tyinfo->rolname,
11355  .description = "TYPE",
11356  .section = SECTION_PRE_DATA,
11357  .createStmt = q->data,
11358  .dropStmt = delq->data));
11359 
11360  /* Dump Type Comments and Security Labels */
11361  if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11362  dumpComment(fout, "TYPE", qtypname,
11363  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11364  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11365 
11366  if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11367  dumpSecLabel(fout, "TYPE", qtypname,
11368  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11369  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11370 
11371  if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
11372  dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
11373  qtypname, NULL,
11374  tyinfo->dobj.namespace->dobj.name,
11375  NULL, tyinfo->rolname, &tyinfo->dacl);
11376 
11377  destroyPQExpBuffer(q);
11378  destroyPQExpBuffer(delq);
11379  free(qtypname);
11380  free(qualtypname);
11381 }
11382 
11383 /*
11384  * dumpBaseType
11385  * writes out to fout the queries to recreate a user-defined base type
11386  */
11387 static void
11388 dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
11389 {
11390  DumpOptions *dopt = fout->dopt;
11392  PQExpBuffer delq = createPQExpBuffer();
11393  PQExpBuffer query = createPQExpBuffer();
11394  PGresult *res;
11395  char *qtypname;
11396  char *qualtypname;
11397  char *typlen;
11398  char *typinput;
11399  char *typoutput;
11400  char *typreceive;
11401  char *typsend;
11402  char *typmodin;
11403  char *typmodout;
11404  char *typanalyze;
11405  char *typsubscript;
11406  Oid typreceiveoid;
11407  Oid typsendoid;
11408  Oid typmodinoid;
11409  Oid typmodoutoid;
11410  Oid typanalyzeoid;
11411  Oid typsubscriptoid;
11412  char *typcategory;
11413  char *typispreferred;
11414  char *typdelim;
11415  char *typbyval;
11416  char *typalign;
11417  char *typstorage;
11418  char *typcollatable;
11419  char *typdefault;
11420  bool typdefault_is_literal = false;
11421 
11422  if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])
11423  {
11424  /* Set up query for type-specific details */
11425  appendPQExpBufferStr(query,
11426  "PREPARE dumpBaseType(pg_catalog.oid) AS\n"
11427  "SELECT typlen, "
11428  "typinput, typoutput, typreceive, typsend, "
11429  "typreceive::pg_catalog.oid AS typreceiveoid, "
11430  "typsend::pg_catalog.oid AS typsendoid, "
11431  "typanalyze, "
11432  "typanalyze::pg_catalog.oid AS typanalyzeoid, "
11433  "typdelim, typbyval, typalign, typstorage, "
11434  "typmodin, typmodout, "
11435  "typmodin::pg_catalog.oid AS typmodinoid, "
11436  "typmodout::pg_catalog.oid AS typmodoutoid, "
11437  "typcategory, typispreferred, "
11438  "(typcollation <> 0) AS typcollatable, "
11439  "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault, ");
11440 
11441  if (fout->remoteVersion >= 140000)
11442  appendPQExpBufferStr(query,
11443  "typsubscript, "
11444  "typsubscript::pg_catalog.oid AS typsubscriptoid ");
11445  else
11446  appendPQExpBufferStr(query,
11447  "'-' AS typsubscript, 0 AS typsubscriptoid ");
11448 
11449  appendPQExpBufferStr(query, "FROM pg_catalog.pg_type "
11450  "WHERE oid = $1");
11451 
11452  ExecuteSqlStatement(fout, query->data);
11453 
11454  fout->is_prepared[PREPQUERY_DUMPBASETYPE] = true;
11455  }
11456 
11457  printfPQExpBuffer(query,
11458  "EXECUTE dumpBaseType('%u')",
11459  tyinfo->dobj.catId.oid);
11460 
11461  res = ExecuteSqlQueryForSingleRow(fout, query->data);
11462 
11463  typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
11464  typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
11465  typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
11466  typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
11467  typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
11468  typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
11469  typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
11470  typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
11471  typsubscript = PQgetvalue(res, 0, PQfnumber(res, "typsubscript"));
11472  typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
11473  typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
11474  typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
11475  typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
11476  typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
11477  typsubscriptoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsubscriptoid")));
11478  typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
11479  typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
11480  typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
11481  typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
11482  typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
11483  typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
11484  typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
11485  if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
11486  typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
11487  else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
11488  {
11489  typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
11490  typdefault_is_literal = true; /* it needs quotes */
11491  }
11492  else
11493  typdefault = NULL;
11494 
11495  qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
11496  qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
11497 
11498  /*
11499  * The reason we include CASCADE is that the circular dependency between
11500  * the type and its I/O functions makes it impossible to drop the type any
11501  * other way.
11502  */
11503  appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
11504 
11505  /*
11506  * We might already have a shell type, but setting pg_type_oid is
11507  * harmless, and in any case we'd better set the array type OID.
11508  */
11509  if (dopt->binary_upgrade)
11511  tyinfo->dobj.catId.oid,
11512  false, false);
11513 
11515  "CREATE TYPE %s (\n"
11516  " INTERNALLENGTH = %s",
11517  qualtypname,
11518  (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
11519 
11520  /* regproc result is sufficiently quoted already */
11521  appendPQExpBuffer(q, ",\n INPUT = %s", typinput);
11522  appendPQExpBuffer(q, ",\n OUTPUT = %s", typoutput);
11523  if (OidIsValid(typreceiveoid))
11524  appendPQExpBuffer(q, ",\n RECEIVE = %s", typreceive);
11525  if (OidIsValid(typsendoid))
11526  appendPQExpBuffer(q, ",\n SEND = %s", typsend);
11527  if (OidIsValid(typmodinoid))
11528  appendPQExpBuffer(q, ",\n TYPMOD_IN = %s", typmodin);
11529  if (OidIsValid(typmodoutoid))
11530  appendPQExpBuffer(q, ",\n TYPMOD_OUT = %s", typmodout);
11531  if (OidIsValid(typanalyzeoid))
11532  appendPQExpBuffer(q, ",\n ANALYZE = %s", typanalyze);
11533 
11534  if (strcmp(typcollatable, "t") == 0)
11535  appendPQExpBufferStr(q, ",\n COLLATABLE = true");
11536 
11537  if (typdefault != NULL)
11538  {
11539  appendPQExpBufferStr(q, ",\n DEFAULT = ");
11540  if (typdefault_is_literal)
11541  appendStringLiteralAH(q, typdefault, fout);
11542  else
11543  appendPQExpBufferStr(q, typdefault);
11544  }
11545 
11546  if (OidIsValid(typsubscriptoid))
11547  appendPQExpBuffer(q, ",\n SUBSCRIPT = %s", typsubscript);
11548 
11549  if (OidIsValid(tyinfo->typelem))
11550  appendPQExpBuffer(q, ",\n ELEMENT = %s",
11551  getFormattedTypeName(fout, tyinfo->typelem,
11552  zeroIsError));
11553 
11554  if (strcmp(typcategory, "U") != 0)
11555  {
11556  appendPQExpBufferStr(q, ",\n CATEGORY = ");
11557  appendStringLiteralAH(q, typcategory, fout);
11558  }
11559 
11560  if (strcmp(typispreferred, "t") == 0)
11561  appendPQExpBufferStr(q, ",\n PREFERRED = true");
11562 
11563  if (typdelim && strcmp(typdelim, ",") != 0)
11564  {
11565  appendPQExpBufferStr(q, ",\n DELIMITER = ");
11566  appendStringLiteralAH(q, typdelim, fout);
11567  }
11568 
11569  if (*typalign == TYPALIGN_CHAR)
11570  appendPQExpBufferStr(q, ",\n ALIGNMENT = char");
11571  else if (*typalign == TYPALIGN_SHORT)
11572  appendPQExpBufferStr(q, ",\n ALIGNMENT = int2");
11573  else if (*typalign == TYPALIGN_INT)
11574  appendPQExpBufferStr(q, ",\n ALIGNMENT = int4");
11575  else if (*typalign == TYPALIGN_DOUBLE)
11576  appendPQExpBufferStr(q, ",\n ALIGNMENT = double");
11577 
11578  if (*typstorage == TYPSTORAGE_PLAIN)
11579  appendPQExpBufferStr(q, ",\n STORAGE = plain");
11580  else if (*typstorage == TYPSTORAGE_EXTERNAL)
11581  appendPQExpBufferStr(q, ",\n STORAGE = external");
11582  else if (*typstorage == TYPSTORAGE_EXTENDED)
11583  appendPQExpBufferStr(q, ",\n STORAGE = extended");
11584  else if (*typstorage == TYPSTORAGE_MAIN)
11585  appendPQExpBufferStr(q, ",\n STORAGE = main");
11586 
11587  if (strcmp(typbyval, "t") == 0)
11588  appendPQExpBufferStr(q, ",\n PASSEDBYVALUE");
11589 
11590  appendPQExpBufferStr(q, "\n);\n");
11591 
11592  if (dopt->binary_upgrade)
11594  "TYPE", qtypname,
11595  tyinfo->dobj.namespace->dobj.name);
11596 
11597  if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11598  ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
11599  ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
11600  .namespace = tyinfo->dobj.namespace->dobj.name,
11601  .owner = tyinfo->rolname,
11602  .description = "TYPE",
11603  .section = SECTION_PRE_DATA,
11604  .createStmt = q->data,
11605  .dropStmt = delq->data));
11606 
11607  /* Dump Type Comments and Security Labels */
11608  if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11609  dumpComment(fout, "TYPE", qtypname,
11610  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11611  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11612 
11613  if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11614  dumpSecLabel(fout, "TYPE", qtypname,
11615  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11616  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11617 
11618  if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
11619  dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
11620  qtypname, NULL,
11621  tyinfo->dobj.namespace->dobj.name,
11622  NULL, tyinfo->rolname, &tyinfo->dacl);
11623 
11624  PQclear(res);
11625  destroyPQExpBuffer(q);
11626  destroyPQExpBuffer(delq);
11627  destroyPQExpBuffer(query);
11628  free(qtypname);
11629  free(qualtypname);
11630 }
11631 
11632 /*
11633  * dumpDomain
11634  * writes out to fout the queries to recreate a user-defined domain
11635  */
11636 static void
11637 dumpDomain(Archive *fout, const TypeInfo *tyinfo)
11638 {
11639  DumpOptions *dopt = fout->dopt;
11641  PQExpBuffer delq = createPQExpBuffer();
11642  PQExpBuffer query = createPQExpBuffer();
11643  PGresult *res;
11644  int i;
11645  char *qtypname;
11646  char *qualtypname;
11647  char *typnotnull;
11648  char *typdefn;
11649  char *typdefault;
11650  Oid typcollation;
11651  bool typdefault_is_literal = false;
11652 
11653  if (!fout->is_prepared[PREPQUERY_DUMPDOMAIN])
11654  {
11655  /* Set up query for domain-specific details */
11656  appendPQExpBufferStr(query,
11657  "PREPARE dumpDomain(pg_catalog.oid) AS\n");
11658 
11659  appendPQExpBufferStr(query, "SELECT t.typnotnull, "
11660  "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
11661  "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
11662  "t.typdefault, "
11663  "CASE WHEN t.typcollation <> u.typcollation "
11664  "THEN t.typcollation ELSE 0 END AS typcollation "
11665  "FROM pg_catalog.pg_type t "
11666  "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
11667  "WHERE t.oid = $1");
11668 
11669  ExecuteSqlStatement(fout, query->data);
11670 
11671  fout->is_prepared[PREPQUERY_DUMPDOMAIN] = true;
11672  }
11673 
11674  printfPQExpBuffer(query,
11675  "EXECUTE dumpDomain('%u')",
11676  tyinfo->dobj.catId.oid);
11677 
11678  res = ExecuteSqlQueryForSingleRow(fout, query->data);
11679 
11680  typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
11681  typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
11682  if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
11683  typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
11684  else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
11685  {
11686  typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
11687  typdefault_is_literal = true; /* it needs quotes */
11688  }
11689  else
11690  typdefault = NULL;
11691  typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
11692 
11693  if (dopt->binary_upgrade)
11695  tyinfo->dobj.catId.oid,
11696  true, /* force array type */
11697  false); /* force multirange type */
11698 
11699  qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
11700  qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
11701 
11703  "CREATE DOMAIN %s AS %s",
11704  qualtypname,
11705  typdefn);
11706 
11707  /* Print collation only if different from base type's collation */
11708  if (OidIsValid(typcollation))
11709  {
11710  CollInfo *coll;
11711 
11712  coll = findCollationByOid(typcollation);
11713  if (coll)
11714  appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
11715  }
11716 
11717  if (typnotnull[0] == 't')
11718  appendPQExpBufferStr(q, " NOT NULL");
11719 
11720  if (typdefault != NULL)
11721  {
11722  appendPQExpBufferStr(q, " DEFAULT ");
11723  if (typdefault_is_literal)
11724  appendStringLiteralAH(q, typdefault, fout);
11725  else
11726  appendPQExpBufferStr(q, typdefault);
11727  }
11728 
11729  PQclear(res);
11730 
11731  /*
11732  * Add any CHECK constraints for the domain
11733  */
11734  for (i = 0; i < tyinfo->nDomChecks; i++)
11735  {
11736  ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
11737 
11738  if (!domcheck->separate)
11739  appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
11740  fmtId(domcheck->dobj.name), domcheck->condef);
11741  }
11742 
11743  appendPQExpBufferStr(q, ";\n");
11744 
11745  appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
11746 
11747  if (dopt->binary_upgrade)
11749  "DOMAIN", qtypname,
11750  tyinfo->dobj.namespace->dobj.name);
11751 
11752  if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11753  ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
11754  ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
11755  .namespace = tyinfo->dobj.namespace->dobj.name,
11756  .owner = tyinfo->rolname,
11757  .description = "DOMAIN",
11758  .section = SECTION_PRE_DATA,
11759  .createStmt = q->data,
11760  .dropStmt = delq->data));
11761 
11762  /* Dump Domain Comments and Security Labels */
11763  if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11764  dumpComment(fout, "DOMAIN", qtypname,
11765  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11766  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11767 
11768  if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11769  dumpSecLabel(fout, "DOMAIN", qtypname,
11770  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11771  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11772 
11773  if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
11774  dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
11775  qtypname, NULL,
11776  tyinfo->dobj.namespace->dobj.name,
11777  NULL, tyinfo->rolname, &tyinfo->dacl);
11778 
11779  /* Dump any per-constraint comments */
11780  for (i = 0; i < tyinfo->nDomChecks; i++)
11781  {
11782  ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
11783  PQExpBuffer conprefix = createPQExpBuffer();
11784 
11785  appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
11786  fmtId(domcheck->dobj.name));
11787 
11788  if (domcheck->dobj.dump & DUMP_COMPONENT_COMMENT)
11789  dumpComment(fout, conprefix->data, qtypname,
11790  tyinfo->dobj.namespace->dobj.name,
11791  tyinfo->rolname,
11792  domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
11793 
11794  destroyPQExpBuffer(conprefix);
11795  }
11796 
11797  destroyPQExpBuffer(q);
11798  destroyPQExpBuffer(delq);
11799  destroyPQExpBuffer(query);
11800  free(qtypname);
11801  free(qualtypname);
11802 }
11803 
11804 /*
11805  * dumpCompositeType
11806  * writes out to fout the queries to recreate a user-defined stand-alone
11807  * composite type
11808  */
11809 static void
11810 dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
11811 {
11812  DumpOptions *dopt = fout->dopt;
11814  PQExpBuffer dropped = createPQExpBuffer();
11815  PQExpBuffer delq = createPQExpBuffer();
11816  PQExpBuffer query = createPQExpBuffer();
11817  PGresult *res;
11818  char *qtypname;
11819  char *qualtypname;
11820  int ntups;
11821  int i_attname;
11822  int i_atttypdefn;
11823  int i_attlen;
11824  int i_attalign;
11825  int i_attisdropped;
11826  int i_attcollation;
11827  int i;
11828  int actual_atts;
11829 
11831  {
11832  /*
11833  * Set up query for type-specific details.
11834  *
11835  * Since we only want to dump COLLATE clauses for attributes whose
11836  * collation is different from their type's default, we use a CASE
11837  * here to suppress uninteresting attcollations cheaply. atttypid
11838  * will be 0 for dropped columns; collation does not matter for those.
11839  */
11840  appendPQExpBufferStr(query,
11841  "PREPARE dumpCompositeType(pg_catalog.oid) AS\n"
11842  "SELECT a.attname, a.attnum, "
11843  "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
11844  "a.attlen, a.attalign, a.attisdropped, "
11845  "CASE WHEN a.attcollation <> at.typcollation "
11846  "THEN a.attcollation ELSE 0 END AS attcollation "
11847  "FROM pg_catalog.pg_type ct "
11848  "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
11849  "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
11850  "WHERE ct.oid = $1 "
11851  "ORDER BY a.attnum");
11852 
11853  ExecuteSqlStatement(fout, query->data);
11854 
11856  }
11857 
11858  printfPQExpBuffer(query,
11859  "EXECUTE dumpCompositeType('%u')",
11860  tyinfo->dobj.catId.oid);
11861 
11862  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11863 
11864  ntups = PQntuples(res);
11865 
11866  i_attname = PQfnumber(res, "attname");
11867  i_atttypdefn = PQfnumber(res, "atttypdefn");
11868  i_attlen = PQfnumber(res, "attlen");
11869  i_attalign = PQfnumber(res, "attalign");
11870  i_attisdropped = PQfnumber(res, "attisdropped");
11871  i_attcollation = PQfnumber(res, "attcollation");
11872 
11873  if (dopt->binary_upgrade)
11874  {
11876  tyinfo->dobj.catId.oid,
11877  false, false);
11878  binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid, false);
11879  }
11880 
11881  qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
11882  qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
11883 
11884  appendPQExpBuffer(q, "CREATE TYPE %s AS (",
11885  qualtypname);
11886 
11887  actual_atts = 0;
11888  for (i = 0; i < ntups; i++)
11889  {
11890  char *attname;
11891  char *atttypdefn;
11892  char *attlen;
11893  char *attalign;
11894  bool attisdropped;
11895  Oid attcollation;
11896 
11897  attname = PQgetvalue(res, i, i_attname);
11898  atttypdefn = PQgetvalue(res, i, i_atttypdefn);
11899  attlen = PQgetvalue(res, i, i_attlen);
11900  attalign = PQgetvalue(res, i, i_attalign);
11901  attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
11902  attcollation = atooid(PQgetvalue(res, i, i_attcollation));
11903 
11904  if (attisdropped && !dopt->binary_upgrade)
11905  continue;
11906 
11907  /* Format properly if not first attr */
11908  if (actual_atts++ > 0)
11909  appendPQExpBufferChar(q, ',');
11910  appendPQExpBufferStr(q, "\n\t");
11911 
11912  if (!attisdropped)
11913  {
11914  appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
11915 
11916  /* Add collation if not default for the column type */
11917  if (OidIsValid(attcollation))
11918  {
11919  CollInfo *coll;
11920 
11921  coll = findCollationByOid(attcollation);
11922  if (coll)
11923  appendPQExpBuffer(q, " COLLATE %s",
11924  fmtQualifiedDumpable(coll));
11925  }
11926  }
11927  else
11928  {
11929  /*
11930  * This is a dropped attribute and we're in binary_upgrade mode.
11931  * Insert a placeholder for it in the CREATE TYPE command, and set
11932  * length and alignment with direct UPDATE to the catalogs
11933  * afterwards. See similar code in dumpTableSchema().
11934  */
11935  appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
11936 
11937  /* stash separately for insertion after the CREATE TYPE */
11938  appendPQExpBufferStr(dropped,
11939  "\n-- For binary upgrade, recreate dropped column.\n");
11940  appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
11941  "SET attlen = %s, "
11942  "attalign = '%s', attbyval = false\n"
11943  "WHERE attname = ", attlen, attalign);
11944  appendStringLiteralAH(dropped, attname, fout);
11945  appendPQExpBufferStr(dropped, "\n AND attrelid = ");
11946  appendStringLiteralAH(dropped, qualtypname, fout);
11947  appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
11948 
11949  appendPQExpBuffer(dropped, "ALTER TYPE %s ",
11950  qualtypname);
11951  appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
11952  fmtId(attname));
11953  }
11954  }
11955  appendPQExpBufferStr(q, "\n);\n");
11956  appendPQExpBufferStr(q, dropped->data);
11957 
11958  appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
11959 
11960  if (dopt->binary_upgrade)
11962  "TYPE", qtypname,
11963  tyinfo->dobj.namespace->dobj.name);
11964 
11965  if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11966  ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
11967  ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
11968  .namespace = tyinfo->dobj.namespace->dobj.name,
11969  .owner = tyinfo->rolname,
11970  .description = "TYPE",
11971  .section = SECTION_PRE_DATA,
11972  .createStmt = q->data,
11973  .dropStmt = delq->data));
11974 
11975 
11976  /* Dump Type Comments and Security Labels */
11977  if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11978  dumpComment(fout, "TYPE", qtypname,
11979  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11980  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11981 
11982  if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11983  dumpSecLabel(fout, "TYPE", qtypname,
11984  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11985  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11986 
11987  if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
11988  dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
11989  qtypname, NULL,
11990  tyinfo->dobj.namespace->dobj.name,
11991  NULL, tyinfo->rolname, &tyinfo->dacl);
11992 
11993  /* Dump any per-column comments */
11994  if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11995  dumpCompositeTypeColComments(fout, tyinfo, res);
11996 
11997  PQclear(res);
11998  destroyPQExpBuffer(q);
11999  destroyPQExpBuffer(dropped);
12000  destroyPQExpBuffer(delq);
12001  destroyPQExpBuffer(query);
12002  free(qtypname);
12003  free(qualtypname);
12004 }
12005 
12006 /*
12007  * dumpCompositeTypeColComments
12008  * writes out to fout the queries to recreate comments on the columns of
12009  * a user-defined stand-alone composite type.
12010  *
12011  * The caller has already made a query to collect the names and attnums
12012  * of the type's columns, so we just pass that result into here rather
12013  * than reading them again.
12014  */
12015 static void
12017  PGresult *res)
12018 {
12020  int ncomments;
12021  PQExpBuffer query;
12022  PQExpBuffer target;
12023  int i;
12024  int ntups;
12025  int i_attname;
12026  int i_attnum;
12027  int i_attisdropped;
12028 
12029  /* do nothing, if --no-comments is supplied */
12030  if (fout->dopt->no_comments)
12031  return;
12032 
12033  /* Search for comments associated with type's pg_class OID */
12034  ncomments = findComments(RelationRelationId, tyinfo->typrelid,
12035  &comments);
12036 
12037  /* If no comments exist, we're done */
12038  if (ncomments <= 0)
12039  return;
12040 
12041  /* Build COMMENT ON statements */
12042  query = createPQExpBuffer();
12043  target = createPQExpBuffer();
12044 
12045  ntups = PQntuples(res);
12046  i_attnum = PQfnumber(res, "attnum");
12047  i_attname = PQfnumber(res, "attname");
12048  i_attisdropped = PQfnumber(res, "attisdropped");
12049  while (ncomments > 0)
12050  {
12051  const char *attname;
12052 
12053  attname = NULL;
12054  for (i = 0; i < ntups; i++)
12055  {
12056  if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid &&
12057  PQgetvalue(res, i, i_attisdropped)[0] != 't')
12058  {
12059  attname = PQgetvalue(res, i, i_attname);
12060  break;
12061  }
12062  }
12063  if (attname) /* just in case we don't find it */
12064  {
12065  const char *descr = comments->descr;
12066 
12067  resetPQExpBuffer(target);
12068  appendPQExpBuffer(target, "COLUMN %s.",
12069  fmtId(tyinfo->dobj.name));
12071 
12072  resetPQExpBuffer(query);
12073  appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
12074  fmtQualifiedDumpable(tyinfo));
12075  appendPQExpBuffer(query, "%s IS ", fmtId(attname));
12076  appendStringLiteralAH(query, descr, fout);
12077  appendPQExpBufferStr(query, ";\n");
12078 
12080  ARCHIVE_OPTS(.tag = target->data,
12081  .namespace = tyinfo->dobj.namespace->dobj.name,
12082  .owner = tyinfo->rolname,
12083  .description = "COMMENT",
12084  .section = SECTION_NONE,
12085  .createStmt = query->data,
12086  .deps = &(tyinfo->dobj.dumpId),
12087  .nDeps = 1));
12088  }
12089 
12090  comments++;
12091  ncomments--;
12092  }
12093 
12094  destroyPQExpBuffer(query);
12095  destroyPQExpBuffer(target);
12096 }
12097 
12098 /*
12099  * dumpShellType
12100  * writes out to fout the queries to create a shell type
12101  *
12102  * We dump a shell definition in advance of the I/O functions for the type.
12103  */
12104 static void
12105 dumpShellType(Archive *fout, const ShellTypeInfo *stinfo)
12106 {
12107  DumpOptions *dopt = fout->dopt;
12108  PQExpBuffer q;
12109 
12110  /* Do nothing in data-only dump */
12111  if (dopt->dataOnly)
12112  return;
12113 
12114  q = createPQExpBuffer();
12115 
12116  /*
12117  * Note the lack of a DROP command for the shell type; any required DROP
12118  * is driven off the base type entry, instead. This interacts with
12119  * _printTocEntry()'s use of the presence of a DROP command to decide
12120  * whether an entry needs an ALTER OWNER command. We don't want to alter
12121  * the shell type's owner immediately on creation; that should happen only
12122  * after it's filled in, otherwise the backend complains.
12123  */
12124 
12125  if (dopt->binary_upgrade)
12127  stinfo->baseType->dobj.catId.oid,
12128  false, false);
12129 
12130  appendPQExpBuffer(q, "CREATE TYPE %s;\n",
12131  fmtQualifiedDumpable(stinfo));
12132 
12133  if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12134  ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
12135  ARCHIVE_OPTS(.tag = stinfo->dobj.name,
12136  .namespace = stinfo->dobj.namespace->dobj.name,
12137  .owner = stinfo->baseType->rolname,
12138  .description = "SHELL TYPE",
12139  .section = SECTION_PRE_DATA,
12140  .createStmt = q->data));
12141 
12142  destroyPQExpBuffer(q);
12143 }
12144 
12145 /*
12146  * dumpProcLang
12147  * writes out to fout the queries to recreate a user-defined
12148  * procedural language
12149  */
12150 static void
12151 dumpProcLang(Archive *fout, const ProcLangInfo *plang)
12152 {
12153  DumpOptions *dopt = fout->dopt;
12154  PQExpBuffer defqry;
12155  PQExpBuffer delqry;
12156  bool useParams;
12157  char *qlanname;
12158  FuncInfo *funcInfo;
12159  FuncInfo *inlineInfo = NULL;
12160  FuncInfo *validatorInfo = NULL;
12161 
12162  /* Do nothing in data-only dump */
12163  if (dopt->dataOnly)
12164  return;
12165 
12166  /*
12167  * Try to find the support function(s). It is not an error if we don't
12168  * find them --- if the functions are in the pg_catalog schema, as is
12169  * standard in 8.1 and up, then we won't have loaded them. (In this case
12170  * we will emit a parameterless CREATE LANGUAGE command, which will
12171  * require PL template knowledge in the backend to reload.)
12172  */
12173 
12174  funcInfo = findFuncByOid(plang->lanplcallfoid);
12175  if (funcInfo != NULL && !funcInfo->dobj.dump)
12176  funcInfo = NULL; /* treat not-dumped same as not-found */
12177 
12178  if (OidIsValid(plang->laninline))
12179  {
12180  inlineInfo = findFuncByOid(plang->laninline);
12181  if (inlineInfo != NULL && !inlineInfo->dobj.dump)
12182  inlineInfo = NULL;
12183  }
12184 
12185  if (OidIsValid(plang->lanvalidator))
12186  {
12187  validatorInfo = findFuncByOid(plang->lanvalidator);
12188  if (validatorInfo != NULL && !validatorInfo->dobj.dump)
12189  validatorInfo = NULL;
12190  }
12191 
12192  /*
12193  * If the functions are dumpable then emit a complete CREATE LANGUAGE with
12194  * parameters. Otherwise, we'll write a parameterless command, which will
12195  * be interpreted as CREATE EXTENSION.
12196  */
12197  useParams = (funcInfo != NULL &&
12198  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
12199  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
12200 
12201  defqry = createPQExpBuffer();
12202  delqry = createPQExpBuffer();
12203 
12204  qlanname = pg_strdup(fmtId(plang->dobj.name));
12205 
12206  appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
12207  qlanname);
12208 
12209  if (useParams)
12210  {
12211  appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
12212  plang->lanpltrusted ? "TRUSTED " : "",
12213  qlanname);
12214  appendPQExpBuffer(defqry, " HANDLER %s",
12215  fmtQualifiedDumpable(funcInfo));
12216  if (OidIsValid(plang->laninline))
12217  appendPQExpBuffer(defqry, " INLINE %s",
12218  fmtQualifiedDumpable(inlineInfo));
12219  if (OidIsValid(plang->lanvalidator))
12220  appendPQExpBuffer(defqry, " VALIDATOR %s",
12221  fmtQualifiedDumpable(validatorInfo));
12222  }
12223  else
12224  {
12225  /*
12226  * If not dumping parameters, then use CREATE OR REPLACE so that the
12227  * command will not fail if the language is preinstalled in the target
12228  * database.
12229  *
12230  * Modern servers will interpret this as CREATE EXTENSION IF NOT
12231  * EXISTS; perhaps we should emit that instead? But it might just add
12232  * confusion.
12233  */
12234  appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
12235  qlanname);
12236  }
12237  appendPQExpBufferStr(defqry, ";\n");
12238 
12239  if (dopt->binary_upgrade)
12240  binary_upgrade_extension_member(defqry, &plang->dobj,
12241  "LANGUAGE", qlanname, NULL);
12242 
12243  if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
12244  ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
12245  ARCHIVE_OPTS(.tag = plang->dobj.name,
12246  .owner = plang->lanowner,
12247  .description = "PROCEDURAL LANGUAGE",
12248  .section = SECTION_PRE_DATA,
12249  .createStmt = defqry->data,
12250  .dropStmt = delqry->data,
12251  ));
12252 
12253  /* Dump Proc Lang Comments and Security Labels */
12254  if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
12255  dumpComment(fout, "LANGUAGE", qlanname,
12256  NULL, plang->lanowner,
12257  plang->dobj.catId, 0, plang->dobj.dumpId);
12258 
12259  if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
12260  dumpSecLabel(fout, "LANGUAGE", qlanname,
12261  NULL, plang->lanowner,
12262  plang->dobj.catId, 0, plang->dobj.dumpId);
12263 
12264  if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
12265  dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
12266  qlanname, NULL, NULL,
12267  NULL, plang->lanowner, &plang->dacl);
12268 
12269  free(qlanname);
12270 
12271  destroyPQExpBuffer(defqry);
12272  destroyPQExpBuffer(delqry);
12273 }
12274 
12275 /*
12276  * format_function_arguments: generate function name and argument list
12277  *
12278  * This is used when we can rely on pg_get_function_arguments to format
12279  * the argument list. Note, however, that pg_get_function_arguments
12280  * does not special-case zero-argument aggregates.
12281  */
12282 static char *
12283 format_function_arguments(const FuncInfo *finfo, const char *funcargs, bool is_agg)
12284 {
12286 
12287  initPQExpBuffer(&fn);
12288  appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
12289  if (is_agg && finfo->nargs == 0)
12290  appendPQExpBufferStr(&fn, "(*)");
12291  else
12292  appendPQExpBuffer(&fn, "(%s)", funcargs);
12293  return fn.data;
12294 }
12295 
12296 /*
12297  * format_function_signature: generate function name and argument list
12298  *
12299  * Only a minimal list of input argument types is generated; this is
12300  * sufficient to reference the function, but not to define it.
12301  *
12302  * If honor_quotes is false then the function name is never quoted.
12303  * This is appropriate for use in TOC tags, but not in SQL commands.
12304  */
12305 static char *
12306 format_function_signature(Archive *fout, const FuncInfo *finfo, bool honor_quotes)
12307 {
12309  int j;
12310 
12311  initPQExpBuffer(&fn);
12312  if (honor_quotes)
12313  appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
12314  else
12315  appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
12316  for (j = 0; j < finfo->nargs; j++)
12317  {
12318  if (j > 0)
12319  appendPQExpBufferStr(&fn, ", ");
12320 
12322  getFormattedTypeName(fout, finfo->argtypes[j],
12323  zeroIsError));
12324  }
12325  appendPQExpBufferChar(&fn, ')');
12326  return fn.data;
12327 }
12328 
12329 
12330 /*
12331  * dumpFunc:
12332  * dump out one function
12333  */
12334 static void
12335 dumpFunc(Archive *fout, const FuncInfo *finfo)
12336 {
12337  DumpOptions *dopt = fout->dopt;
12338  PQExpBuffer query;
12339  PQExpBuffer q;
12340  PQExpBuffer delqry;
12341  PQExpBuffer asPart;
12342  PGresult *res;
12343  char *funcsig; /* identity signature */
12344  char *funcfullsig = NULL; /* full signature */
12345  char *funcsig_tag;
12346  char *qual_funcsig;
12347  char *proretset;
12348  char *prosrc;
12349  char *probin;
12350  char *prosqlbody;
12351  char *funcargs;
12352  char *funciargs;
12353  char *funcresult;
12354  char *protrftypes;
12355  char *prokind;
12356  char *provolatile;
12357  char *proisstrict;
12358  char *prosecdef;
12359  char *proleakproof;
12360  char *proconfig;
12361  char *procost;
12362  char *prorows;
12363  char *prosupport;
12364  char *proparallel;
12365  char *lanname;
12366  char **configitems = NULL;
12367  int nconfigitems = 0;
12368  const char *keyword;
12369 
12370  /* Do nothing in data-only dump */
12371  if (dopt->dataOnly)
12372  return;
12373 
12374  query = createPQExpBuffer();
12375  q = createPQExpBuffer();
12376  delqry = createPQExpBuffer();
12377  asPart = createPQExpBuffer();
12378 
12379  if (!fout->is_prepared[PREPQUERY_DUMPFUNC])
12380  {
12381  /* Set up query for function-specific details */
12382  appendPQExpBufferStr(query,
12383  "PREPARE dumpFunc(pg_catalog.oid) AS\n");
12384 
12385  appendPQExpBufferStr(query,
12386  "SELECT\n"
12387  "proretset,\n"
12388  "prosrc,\n"
12389  "probin,\n"
12390  "provolatile,\n"
12391  "proisstrict,\n"
12392  "prosecdef,\n"
12393  "lanname,\n"
12394  "proconfig,\n"
12395  "procost,\n"
12396  "prorows,\n"
12397  "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
12398  "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n"
12399  "pg_catalog.pg_get_function_result(p.oid) AS funcresult,\n"
12400  "proleakproof,\n");
12401 
12402  if (fout->remoteVersion >= 90500)
12403  appendPQExpBufferStr(query,
12404  "array_to_string(protrftypes, ' ') AS protrftypes,\n");
12405  else
12406  appendPQExpBufferStr(query,
12407  "NULL AS protrftypes,\n");
12408 
12409  if (fout->remoteVersion >= 90600)
12410  appendPQExpBufferStr(query,
12411  "proparallel,\n");
12412  else
12413  appendPQExpBufferStr(query,
12414  "'u' AS proparallel,\n");
12415 
12416  if (fout->remoteVersion >= 110000)
12417  appendPQExpBufferStr(query,
12418  "prokind,\n");
12419  else
12420  appendPQExpBufferStr(query,
12421  "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind,\n");
12422 
12423  if (fout->remoteVersion >= 120000)
12424  appendPQExpBufferStr(query,
12425  "prosupport,\n");
12426  else
12427  appendPQExpBufferStr(query,
12428  "'-' AS prosupport,\n");
12429 
12430  if (fout->remoteVersion >= 140000)
12431  appendPQExpBufferStr(query,
12432  "pg_get_function_sqlbody(p.oid) AS prosqlbody\n");
12433  else
12434  appendPQExpBufferStr(query,
12435  "NULL AS prosqlbody\n");
12436 
12437  appendPQExpBufferStr(query,
12438  "FROM pg_catalog.pg_proc p, pg_catalog.pg_language l\n"
12439  "WHERE p.oid = $1 "
12440  "AND l.oid = p.prolang");
12441 
12442  ExecuteSqlStatement(fout, query->data);
12443 
12444  fout->is_prepared[PREPQUERY_DUMPFUNC] = true;
12445  }
12446 
12447  printfPQExpBuffer(query,
12448  "EXECUTE dumpFunc('%u')",
12449  finfo->dobj.catId.oid);
12450 
12451  res = ExecuteSqlQueryForSingleRow(fout, query->data);
12452 
12453  proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
12454  if (PQgetisnull(res, 0, PQfnumber(res, "prosqlbody")))
12455  {
12456  prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
12457  probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
12458  prosqlbody = NULL;
12459  }
12460  else
12461  {
12462  prosrc = NULL;
12463  probin = NULL;
12464  prosqlbody = PQgetvalue(res, 0, PQfnumber(res, "prosqlbody"));
12465  }
12466  funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
12467  funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
12468  funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
12469  protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
12470  prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
12471  provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
12472  proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
12473  prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
12474  proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
12475  proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
12476  procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
12477  prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
12478  prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
12479  proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
12480  lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
12481 
12482  /*
12483  * See backend/commands/functioncmds.c for details of how the 'AS' clause
12484  * is used.
12485  */
12486  if (prosqlbody)
12487  {
12488  appendPQExpBufferStr(asPart, prosqlbody);
12489  }
12490  else if (probin[0] != '\0')
12491  {
12492  appendPQExpBufferStr(asPart, "AS ");
12493  appendStringLiteralAH(asPart, probin, fout);
12494  if (prosrc[0] != '\0')
12495  {
12496  appendPQExpBufferStr(asPart, ", ");
12497 
12498  /*
12499  * where we have bin, use dollar quoting if allowed and src
12500  * contains quote or backslash; else use regular quoting.
12501  */
12502  if (dopt->disable_dollar_quoting ||
12503  (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
12504  appendStringLiteralAH(asPart, prosrc, fout);
12505  else
12506  appendStringLiteralDQ(asPart, prosrc, NULL);
12507  }
12508  }
12509  else
12510  {
12511  appendPQExpBufferStr(asPart, "AS ");
12512  /* with no bin, dollar quote src unconditionally if allowed */
12513  if (dopt->disable_dollar_quoting)
12514  appendStringLiteralAH(asPart, prosrc, fout);
12515  else
12516  appendStringLiteralDQ(asPart, prosrc, NULL);
12517  }
12518 
12519  if (*proconfig)
12520  {
12521  if (!parsePGArray(proconfig, &configitems, &nconfigitems))
12522  pg_fatal("could not parse %s array", "proconfig");
12523  }
12524  else
12525  {
12526  configitems = NULL;
12527  nconfigitems = 0;
12528  }
12529 
12530  funcfullsig = format_function_arguments(finfo, funcargs, false);
12531  funcsig = format_function_arguments(finfo, funciargs, false);
12532 
12533  funcsig_tag = format_function_signature(fout, finfo, false);
12534 
12535  qual_funcsig = psprintf("%s.%s",
12536  fmtId(finfo->dobj.namespace->dobj.name),
12537  funcsig);
12538 
12539  if (prokind[0] == PROKIND_PROCEDURE)
12540  keyword = "PROCEDURE";
12541  else
12542  keyword = "FUNCTION"; /* works for window functions too */
12543 
12544  appendPQExpBuffer(delqry, "DROP %s %s;\n",
12545  keyword, qual_funcsig);
12546 
12547  appendPQExpBuffer(q, "CREATE %s %s.%s",
12548  keyword,
12549  fmtId(finfo->dobj.namespace->dobj.name),
12550  funcfullsig ? funcfullsig :
12551  funcsig);
12552 
12553  if (prokind[0] == PROKIND_PROCEDURE)
12554  /* no result type to output */ ;
12555  else if (funcresult)
12556  appendPQExpBuffer(q, " RETURNS %s", funcresult);
12557  else
12558  appendPQExpBuffer(q, " RETURNS %s%s",
12559  (proretset[0] == 't') ? "SETOF " : "",
12560  getFormattedTypeName(fout, finfo->prorettype,
12561  zeroIsError));
12562 
12563  appendPQExpBuffer(q, "\n LANGUAGE %s", fmtId(lanname));
12564 
12565  if (*protrftypes)
12566  {
12567  Oid *typeids = palloc(FUNC_MAX_ARGS * sizeof(Oid));
12568  int i;
12569 
12570  appendPQExpBufferStr(q, " TRANSFORM ");
12571  parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
12572  for (i = 0; typeids[i]; i++)
12573  {
12574  if (i != 0)
12575  appendPQExpBufferStr(q, ", ");
12576  appendPQExpBuffer(q, "FOR TYPE %s",
12577  getFormattedTypeName(fout, typeids[i], zeroAsNone));
12578  }
12579  }
12580 
12581  if (prokind[0] == PROKIND_WINDOW)
12582  appendPQExpBufferStr(q, " WINDOW");
12583 
12584  if (provolatile[0] != PROVOLATILE_VOLATILE)
12585  {
12586  if (provolatile[0] == PROVOLATILE_IMMUTABLE)
12587  appendPQExpBufferStr(q, " IMMUTABLE");
12588  else if (provolatile[0] == PROVOLATILE_STABLE)
12589  appendPQExpBufferStr(q, " STABLE");
12590  else if (provolatile[0] != PROVOLATILE_VOLATILE)
12591  pg_fatal("unrecognized provolatile value for function \"%s\"",
12592  finfo->dobj.name);
12593  }
12594 
12595  if (proisstrict[0] == 't')
12596  appendPQExpBufferStr(q, " STRICT");
12597 
12598  if (prosecdef[0] == 't')
12599  appendPQExpBufferStr(q, " SECURITY DEFINER");
12600 
12601  if (proleakproof[0] == 't')
12602  appendPQExpBufferStr(q, " LEAKPROOF");
12603 
12604  /*
12605  * COST and ROWS are emitted only if present and not default, so as not to
12606  * break backwards-compatibility of the dump without need. Keep this code
12607  * in sync with the defaults in functioncmds.c.
12608  */
12609  if (strcmp(procost, "0") != 0)
12610  {
12611  if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
12612  {
12613  /* default cost is 1 */
12614  if (strcmp(procost, "1") != 0)
12615  appendPQExpBuffer(q, " COST %s", procost);
12616  }
12617  else
12618  {
12619  /* default cost is 100 */
12620  if (strcmp(procost, "100") != 0)
12621  appendPQExpBuffer(q, " COST %s", procost);
12622  }
12623  }
12624  if (proretset[0] == 't' &&
12625  strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
12626  appendPQExpBuffer(q, " ROWS %s", prorows);
12627 
12628  if (strcmp(prosupport, "-") != 0)
12629  {
12630  /* We rely on regprocout to provide quoting and qualification */
12631  appendPQExpBuffer(q, " SUPPORT %s", prosupport);
12632  }
12633 
12634  if (proparallel[0] != PROPARALLEL_UNSAFE)
12635  {
12636  if (proparallel[0] == PROPARALLEL_SAFE)
12637  appendPQExpBufferStr(q, " PARALLEL SAFE");
12638  else if (proparallel[0] == PROPARALLEL_RESTRICTED)
12639  appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
12640  else if (proparallel[0] != PROPARALLEL_UNSAFE)
12641  pg_fatal("unrecognized proparallel value for function \"%s\"",
12642  finfo->dobj.name);
12643  }
12644 
12645  for (int i = 0; i < nconfigitems; i++)
12646  {
12647  /* we feel free to scribble on configitems[] here */
12648  char *configitem = configitems[i];
12649  char *pos;
12650 
12651  pos = strchr(configitem, '=');
12652  if (pos == NULL)
12653  continue;
12654  *pos++ = '\0';
12655  appendPQExpBuffer(q, "\n SET %s TO ", fmtId(configitem));
12656 
12657  /*
12658  * Variables that are marked GUC_LIST_QUOTE were already fully quoted
12659  * by flatten_set_variable_args() before they were put into the
12660  * proconfig array. However, because the quoting rules used there
12661  * aren't exactly like SQL's, we have to break the list value apart
12662  * and then quote the elements as string literals. (The elements may
12663  * be double-quoted as-is, but we can't just feed them to the SQL
12664  * parser; it would do the wrong thing with elements that are
12665  * zero-length or longer than NAMEDATALEN.)
12666  *
12667  * Variables that are not so marked should just be emitted as simple
12668  * string literals. If the variable is not known to
12669  * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
12670  * to use GUC_LIST_QUOTE for extension variables.
12671  */
12672  if (variable_is_guc_list_quote(configitem))
12673  {
12674  char **namelist;
12675  char **nameptr;
12676 
12677  /* Parse string into list of identifiers */
12678  /* this shouldn't fail really */
12679  if (SplitGUCList(pos, ',', &namelist))
12680  {
12681  for (nameptr = namelist; *nameptr; nameptr++)
12682  {
12683  if (nameptr != namelist)
12684  appendPQExpBufferStr(q, ", ");
12685  appendStringLiteralAH(q, *nameptr, fout);
12686  }
12687  }
12688  pg_free(namelist);
12689  }
12690  else
12691  appendStringLiteralAH(q, pos, fout);
12692  }
12693 
12694  appendPQExpBuffer(q, "\n %s;\n", asPart->data);
12695 
12696  append_depends_on_extension(fout, q, &finfo->dobj,
12697  "pg_catalog.pg_proc", keyword,
12698  qual_funcsig);
12699 
12700  if (dopt->binary_upgrade)
12702  keyword, funcsig,
12703  finfo->dobj.namespace->dobj.name);
12704 
12705  if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12706  ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
12707  ARCHIVE_OPTS(.tag = funcsig_tag,
12708  .namespace = finfo->dobj.namespace->dobj.name,
12709  .owner = finfo->rolname,
12710  .description = keyword,
12711  .section = finfo->postponed_def ?
12713  .createStmt = q->data,
12714  .dropStmt = delqry->data));
12715 
12716  /* Dump Function Comments and Security Labels */
12717  if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12718  dumpComment(fout, keyword, funcsig,
12719  finfo->dobj.namespace->dobj.name, finfo->rolname,
12720  finfo->dobj.catId, 0, finfo->dobj.dumpId);
12721 
12722  if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
12723  dumpSecLabel(fout, keyword, funcsig,
12724  finfo->dobj.namespace->dobj.name, finfo->rolname,
12725  finfo->dobj.catId, 0, finfo->dobj.dumpId);
12726 
12727  if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
12728  dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, keyword,
12729  funcsig, NULL,
12730  finfo->dobj.namespace->dobj.name,
12731  NULL, finfo->rolname, &finfo->dacl);
12732 
12733  PQclear(res);
12734 
12735  destroyPQExpBuffer(query);
12736  destroyPQExpBuffer(q);
12737  destroyPQExpBuffer(delqry);
12738  destroyPQExpBuffer(asPart);
12739  free(funcsig);
12740  free(funcfullsig);
12741  free(funcsig_tag);
12742  free(qual_funcsig);
12743  free(configitems);
12744 }
12745 
12746 
12747 /*
12748  * Dump a user-defined cast
12749  */
12750 static void
12751 dumpCast(Archive *fout, const CastInfo *cast)
12752 {
12753  DumpOptions *dopt = fout->dopt;
12754  PQExpBuffer defqry;
12755  PQExpBuffer delqry;
12756  PQExpBuffer labelq;
12757  PQExpBuffer castargs;
12758  FuncInfo *funcInfo = NULL;
12759  const char *sourceType;
12760  const char *targetType;
12761 
12762  /* Do nothing in data-only dump */
12763  if (dopt->dataOnly)
12764  return;
12765 
12766  /* Cannot dump if we don't have the cast function's info */
12767  if (OidIsValid(cast->castfunc))
12768  {
12769  funcInfo = findFuncByOid(cast->castfunc);
12770  if (funcInfo == NULL)
12771  pg_fatal("could not find function definition for function with OID %u",
12772  cast->castfunc);
12773  }
12774 
12775  defqry = createPQExpBuffer();
12776  delqry = createPQExpBuffer();
12777  labelq = createPQExpBuffer();
12778  castargs = createPQExpBuffer();
12779 
12780  sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
12781  targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
12782  appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
12783  sourceType, targetType);
12784 
12785  appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
12786  sourceType, targetType);
12787 
12788  switch (cast->castmethod)
12789  {
12790  case COERCION_METHOD_BINARY:
12791  appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
12792  break;
12793  case COERCION_METHOD_INOUT:
12794  appendPQExpBufferStr(defqry, "WITH INOUT");
12795  break;
12796  case COERCION_METHOD_FUNCTION:
12797  if (funcInfo)
12798  {
12799  char *fsig = format_function_signature(fout, funcInfo, true);
12800 
12801  /*
12802  * Always qualify the function name (format_function_signature
12803  * won't qualify it).
12804  */
12805  appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
12806  fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
12807  free(fsig);
12808  }
12809  else
12810  pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
12811  break;
12812  default:
12813  pg_log_warning("bogus value in pg_cast.castmethod field");
12814  }
12815 
12816  if (cast->castcontext == 'a')
12817  appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
12818  else if (cast->castcontext == 'i')
12819  appendPQExpBufferStr(defqry, " AS IMPLICIT");
12820  appendPQExpBufferStr(defqry, ";\n");
12821 
12822  appendPQExpBuffer(labelq, "CAST (%s AS %s)",
12823  sourceType, targetType);
12824 
12825  appendPQExpBuffer(castargs, "(%s AS %s)",
12826  sourceType, targetType);
12827 
12828  if (dopt->binary_upgrade)
12829  binary_upgrade_extension_member(defqry, &cast->dobj,
12830  "CAST", castargs->data, NULL);
12831 
12832  if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
12833  ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
12834  ARCHIVE_OPTS(.tag = labelq->data,
12835  .description = "CAST",
12836  .section = SECTION_PRE_DATA,
12837  .createStmt = defqry->data,
12838  .dropStmt = delqry->data));
12839 
12840  /* Dump Cast Comments */
12841  if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
12842  dumpComment(fout, "CAST", castargs->data,
12843  NULL, "",
12844  cast->dobj.catId, 0, cast->dobj.dumpId);
12845 
12846  destroyPQExpBuffer(defqry);
12847  destroyPQExpBuffer(delqry);
12848  destroyPQExpBuffer(labelq);
12849  destroyPQExpBuffer(castargs);
12850 }
12851 
12852 /*
12853  * Dump a transform
12854  */
12855 static void
12856 dumpTransform(Archive *fout, const TransformInfo *transform)
12857 {
12858  DumpOptions *dopt = fout->dopt;
12859  PQExpBuffer defqry;
12860  PQExpBuffer delqry;
12861  PQExpBuffer labelq;
12862  PQExpBuffer transformargs;
12863  FuncInfo *fromsqlFuncInfo = NULL;
12864  FuncInfo *tosqlFuncInfo = NULL;
12865  char *lanname;
12866  const char *transformType;
12867 
12868  /* Do nothing in data-only dump */
12869  if (dopt->dataOnly)
12870  return;
12871 
12872  /* Cannot dump if we don't have the transform functions' info */
12873  if (OidIsValid(transform->trffromsql))
12874  {
12875  fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
12876  if (fromsqlFuncInfo == NULL)
12877  pg_fatal("could not find function definition for function with OID %u",
12878  transform->trffromsql);
12879  }
12880  if (OidIsValid(transform->trftosql))
12881  {
12882  tosqlFuncInfo = findFuncByOid(transform->trftosql);
12883  if (tosqlFuncInfo == NULL)
12884  pg_fatal("could not find function definition for function with OID %u",
12885  transform->trftosql);
12886  }
12887 
12888  defqry = createPQExpBuffer();
12889  delqry = createPQExpBuffer();
12890  labelq = createPQExpBuffer();
12891  transformargs = createPQExpBuffer();
12892 
12893  lanname = get_language_name(fout, transform->trflang);
12894  transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
12895 
12896  appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
12897  transformType, lanname);
12898 
12899  appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
12900  transformType, lanname);
12901 
12902  if (!transform->trffromsql && !transform->trftosql)
12903  pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
12904 
12905  if (transform->trffromsql)
12906  {
12907  if (fromsqlFuncInfo)
12908  {
12909  char *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
12910 
12911  /*
12912  * Always qualify the function name (format_function_signature
12913  * won't qualify it).
12914  */
12915  appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
12916  fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
12917  free(fsig);
12918  }
12919  else
12920  pg_log_warning("bogus value in pg_transform.trffromsql field");
12921  }
12922 
12923  if (transform->trftosql)
12924  {
12925  if (transform->trffromsql)
12926  appendPQExpBufferStr(defqry, ", ");
12927 
12928  if (tosqlFuncInfo)
12929  {
12930  char *fsig = format_function_signature(fout, tosqlFuncInfo, true);
12931 
12932  /*
12933  * Always qualify the function name (format_function_signature
12934  * won't qualify it).
12935  */
12936  appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
12937  fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
12938  free(fsig);
12939  }
12940  else
12941  pg_log_warning("bogus value in pg_transform.trftosql field");
12942  }
12943 
12944  appendPQExpBufferStr(defqry, ");\n");
12945 
12946  appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
12947  transformType, lanname);
12948 
12949  appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
12950  transformType, lanname);
12951 
12952  if (dopt->binary_upgrade)
12953  binary_upgrade_extension_member(defqry, &transform->dobj,
12954  "TRANSFORM", transformargs->data, NULL);
12955 
12956  if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
12957  ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
12958  ARCHIVE_OPTS(.tag = labelq->data,
12959  .description = "TRANSFORM",
12960  .section = SECTION_PRE_DATA,
12961  .createStmt = defqry->data,
12962  .dropStmt = delqry->data,
12963  .deps = transform->dobj.dependencies,
12964  .nDeps = transform->dobj.nDeps));
12965 
12966  /* Dump Transform Comments */
12967  if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
12968  dumpComment(fout, "TRANSFORM", transformargs->data,
12969  NULL, "",
12970  transform->dobj.catId, 0, transform->dobj.dumpId);
12971 
12972  free(lanname);
12973  destroyPQExpBuffer(defqry);
12974  destroyPQExpBuffer(delqry);
12975  destroyPQExpBuffer(labelq);
12976  destroyPQExpBuffer(transformargs);
12977 }
12978 
12979 
12980 /*
12981  * dumpOpr
12982  * write out a single operator definition
12983  */
12984 static void
12985 dumpOpr(Archive *fout, const OprInfo *oprinfo)
12986 {
12987  DumpOptions *dopt = fout->dopt;
12988  PQExpBuffer query;
12989  PQExpBuffer q;
12990  PQExpBuffer delq;
12992  PQExpBuffer details;
12993  PGresult *res;
12994  int i_oprkind;
12995  int i_oprcode;
12996  int i_oprleft;
12997  int i_oprright;
12998  int i_oprcom;
12999  int i_oprnegate;
13000  int i_oprrest;
13001  int i_oprjoin;
13002  int i_oprcanmerge;
13003  int i_oprcanhash;
13004  char *oprkind;
13005  char *oprcode;
13006  char *oprleft;
13007  char *oprright;
13008  char *oprcom;
13009  char *oprnegate;
13010  char *oprrest;
13011  char *oprjoin;
13012  char *oprcanmerge;
13013  char *oprcanhash;
13014  char *oprregproc;
13015  char *oprref;
13016 
13017  /* Do nothing in data-only dump */
13018  if (dopt->dataOnly)
13019  return;
13020 
13021  /*
13022  * some operators are invalid because they were the result of user
13023  * defining operators before commutators exist
13024  */
13025  if (!OidIsValid(oprinfo->oprcode))
13026  return;
13027 
13028  query = createPQExpBuffer();
13029  q = createPQExpBuffer();
13030  delq = createPQExpBuffer();
13032  details = createPQExpBuffer();
13033 
13034  if (!fout->is_prepared[PREPQUERY_DUMPOPR])
13035  {
13036  /* Set up query for operator-specific details */
13037  appendPQExpBufferStr(query,
13038  "PREPARE dumpOpr(pg_catalog.oid) AS\n"
13039  "SELECT oprkind, "
13040  "oprcode::pg_catalog.regprocedure, "
13041  "oprleft::pg_catalog.regtype, "
13042  "oprright::pg_catalog.regtype, "
13043  "oprcom, "
13044  "oprnegate, "
13045  "oprrest::pg_catalog.regprocedure, "
13046  "oprjoin::pg_catalog.regprocedure, "
13047  "oprcanmerge, oprcanhash "
13048  "FROM pg_catalog.pg_operator "
13049  "WHERE oid = $1");
13050 
13051  ExecuteSqlStatement(fout, query->data);
13052 
13053  fout->is_prepared[PREPQUERY_DUMPOPR] = true;
13054  }
13055 
13056  printfPQExpBuffer(query,
13057  "EXECUTE dumpOpr('%u')",
13058  oprinfo->dobj.catId.oid);
13059 
13060  res = ExecuteSqlQueryForSingleRow(fout, query->data);
13061 
13062  i_oprkind = PQfnumber(res, "oprkind");
13063  i_oprcode = PQfnumber(res, "oprcode");
13064  i_oprleft = PQfnumber(res, "oprleft");
13065  i_oprright = PQfnumber(res, "oprright");
13066  i_oprcom = PQfnumber(res, "oprcom");
13067  i_oprnegate = PQfnumber(res, "oprnegate");
13068  i_oprrest = PQfnumber(res, "oprrest");
13069  i_oprjoin = PQfnumber(res, "oprjoin");
13070  i_oprcanmerge = PQfnumber(res, "oprcanmerge");
13071  i_oprcanhash = PQfnumber(res, "oprcanhash");
13072 
13073  oprkind = PQgetvalue(res, 0, i_oprkind);
13074  oprcode = PQgetvalue(res, 0, i_oprcode);
13075  oprleft = PQgetvalue(res, 0, i_oprleft);
13076  oprright = PQgetvalue(res, 0, i_oprright);
13077  oprcom = PQgetvalue(res, 0, i_oprcom);
13078  oprnegate = PQgetvalue(res, 0, i_oprnegate);
13079  oprrest = PQgetvalue(res, 0, i_oprrest);
13080  oprjoin = PQgetvalue(res, 0, i_oprjoin);
13081  oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
13082  oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
13083 
13084  /* In PG14 upwards postfix operator support does not exist anymore. */
13085  if (strcmp(oprkind, "r") == 0)
13086  pg_log_warning("postfix operators are not supported anymore (operator \"%s\")",
13087  oprcode);
13088 
13089  oprregproc = convertRegProcReference(oprcode);
13090  if (oprregproc)
13091  {
13092  appendPQExpBuffer(details, " FUNCTION = %s", oprregproc);
13093  free(oprregproc);
13094  }
13095 
13096  appendPQExpBuffer(oprid, "%s (",
13097  oprinfo->dobj.name);
13098 
13099  /*
13100  * right unary means there's a left arg and left unary means there's a
13101  * right arg. (Although the "r" case is dead code for PG14 and later,
13102  * continue to support it in case we're dumping from an old server.)
13103  */
13104  if (strcmp(oprkind, "r") == 0 ||
13105  strcmp(oprkind, "b") == 0)
13106  {
13107  appendPQExpBuffer(details, ",\n LEFTARG = %s", oprleft);
13108  appendPQExpBufferStr(oprid, oprleft);
13109  }
13110  else
13111  appendPQExpBufferStr(oprid, "NONE");
13112 
13113  if (strcmp(oprkind, "l") == 0 ||
13114  strcmp(oprkind, "b") == 0)
13115  {
13116  appendPQExpBuffer(details, ",\n RIGHTARG = %s", oprright);
13117  appendPQExpBuffer(oprid, ", %s)", oprright);
13118  }
13119  else
13120  appendPQExpBufferStr(oprid, ", NONE)");
13121 
13122  oprref = getFormattedOperatorName(oprcom);
13123  if (oprref)
13124  {
13125  appendPQExpBuffer(details, ",\n COMMUTATOR = %s", oprref);
13126  free(oprref);
13127  }
13128 
13129  oprref = getFormattedOperatorName(oprnegate);
13130  if (oprref)
13131  {
13132  appendPQExpBuffer(details, ",\n NEGATOR = %s", oprref);
13133  free(oprref);
13134  }
13135 
13136  if (strcmp(oprcanmerge, "t") == 0)
13137  appendPQExpBufferStr(details, ",\n MERGES");
13138 
13139  if (strcmp(oprcanhash, "t") == 0)
13140  appendPQExpBufferStr(details, ",\n HASHES");
13141 
13142  oprregproc = convertRegProcReference(oprrest);
13143  if (oprregproc)
13144  {
13145  appendPQExpBuffer(details, ",\n RESTRICT = %s", oprregproc);
13146  free(oprregproc);
13147  }
13148 
13149  oprregproc = convertRegProcReference(oprjoin);
13150  if (oprregproc)
13151  {
13152  appendPQExpBuffer(details, ",\n JOIN = %s", oprregproc);
13153  free(oprregproc);
13154  }
13155 
13156  appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
13157  fmtId(oprinfo->dobj.namespace->dobj.name),
13158  oprid->data);
13159 
13160  appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
13161  fmtId(oprinfo->dobj.namespace->dobj.name),
13162  oprinfo->dobj.name, details->data);
13163 
13164  if (dopt->binary_upgrade)
13166  "OPERATOR", oprid->data,
13167  oprinfo->dobj.namespace->dobj.name);
13168 
13169  if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13170  ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
13171  ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
13172  .namespace = oprinfo->dobj.namespace->dobj.name,
13173  .owner = oprinfo->rolname,
13174  .description = "OPERATOR",
13175  .section = SECTION_PRE_DATA,
13176  .createStmt = q->data,
13177  .dropStmt = delq->data));
13178 
13179  /* Dump Operator Comments */
13180  if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13181  dumpComment(fout, "OPERATOR", oprid->data,
13182  oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
13183  oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
13184 
13185  PQclear(res);
13186 
13187  destroyPQExpBuffer(query);
13188  destroyPQExpBuffer(q);
13189  destroyPQExpBuffer(delq);
13191  destroyPQExpBuffer(details);
13192 }
13193 
13194 /*
13195  * Convert a function reference obtained from pg_operator
13196  *
13197  * Returns allocated string of what to print, or NULL if function references
13198  * is InvalidOid. Returned string is expected to be free'd by the caller.
13199  *
13200  * The input is a REGPROCEDURE display; we have to strip the argument-types
13201  * part.
13202  */
13203 static char *
13204 convertRegProcReference(const char *proc)
13205 {
13206  char *name;
13207  char *paren;
13208  bool inquote;
13209 
13210  /* In all cases "-" means a null reference */
13211  if (strcmp(proc, "-") == 0)
13212  return NULL;
13213 
13214  name = pg_strdup(proc);
13215  /* find non-double-quoted left paren */
13216  inquote = false;
13217  for (paren = name; *paren; paren++)
13218  {
13219  if (*paren == '(' && !inquote)
13220  {
13221  *paren = '\0';
13222  break;
13223  }
13224  if (*paren == '"')
13225  inquote = !inquote;
13226  }
13227  return name;
13228 }
13229 
13230 /*
13231  * getFormattedOperatorName - retrieve the operator name for the
13232  * given operator OID (presented in string form).
13233  *
13234  * Returns an allocated string, or NULL if the given OID is invalid.
13235  * Caller is responsible for free'ing result string.
13236  *
13237  * What we produce has the format "OPERATOR(schema.oprname)". This is only
13238  * useful in commands where the operator's argument types can be inferred from
13239  * context. We always schema-qualify the name, though. The predecessor to
13240  * this code tried to skip the schema qualification if possible, but that led
13241  * to wrong results in corner cases, such as if an operator and its negator
13242  * are in different schemas.
13243  */
13244 static char *
13245 getFormattedOperatorName(const char *oproid)
13246 {
13247  OprInfo *oprInfo;
13248 
13249  /* In all cases "0" means a null reference */
13250  if (strcmp(oproid, "0") == 0)
13251  return NULL;
13252 
13253  oprInfo = findOprByOid(atooid(oproid));
13254  if (oprInfo == NULL)
13255  {
13256  pg_log_warning("could not find operator with OID %s",
13257  oproid);
13258  return NULL;
13259  }
13260 
13261  return psprintf("OPERATOR(%s.%s)",
13262  fmtId(oprInfo->dobj.namespace->dobj.name),
13263  oprInfo->dobj.name);
13264 }
13265 
13266 /*
13267  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
13268  *
13269  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
13270  * argument lists of these functions are predetermined. Note that the
13271  * caller should ensure we are in the proper schema, because the results
13272  * are search path dependent!
13273  */
13274 static char *
13276 {
13277  char *result;
13278  char query[128];
13279  PGresult *res;
13280 
13281  snprintf(query, sizeof(query),
13282  "SELECT '%u'::pg_catalog.regproc", funcOid);
13283  res = ExecuteSqlQueryForSingleRow(fout, query);
13284 
13285  result = pg_strdup(PQgetvalue(res, 0, 0));
13286 
13287  PQclear(res);
13288 
13289  return result;
13290 }
13291 
13292 /*
13293  * dumpAccessMethod
13294  * write out a single access method definition
13295  */
13296 static void
13298 {
13299  DumpOptions *dopt = fout->dopt;
13300  PQExpBuffer q;
13301  PQExpBuffer delq;
13302  char *qamname;
13303 
13304  /* Do nothing in data-only dump */
13305  if (dopt->dataOnly)
13306  return;
13307 
13308  q = createPQExpBuffer();
13309  delq = createPQExpBuffer();
13310 
13311  qamname = pg_strdup(fmtId(aminfo->dobj.name));
13312 
13313  appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
13314 
13315  switch (aminfo->amtype)
13316  {
13317  case AMTYPE_INDEX:
13318  appendPQExpBufferStr(q, "TYPE INDEX ");
13319  break;
13320  case AMTYPE_TABLE:
13321  appendPQExpBufferStr(q, "TYPE TABLE ");
13322  break;
13323  default:
13324  pg_log_warning("invalid type \"%c\" of access method \"%s\"",
13325  aminfo->amtype, qamname);
13326  destroyPQExpBuffer(q);
13327  destroyPQExpBuffer(delq);
13328  free(qamname);
13329  return;
13330  }
13331 
13332  appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
13333 
13334  appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
13335  qamname);
13336 
13337  if (dopt->binary_upgrade)
13339  "ACCESS METHOD", qamname, NULL);
13340 
13341  if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13342  ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
13343  ARCHIVE_OPTS(.tag = aminfo->dobj.name,
13344  .description = "ACCESS METHOD",
13345  .section = SECTION_PRE_DATA,
13346  .createStmt = q->data,
13347  .dropStmt = delq->data));
13348 
13349  /* Dump Access Method Comments */
13350  if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13351  dumpComment(fout, "ACCESS METHOD", qamname,
13352  NULL, "",
13353  aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
13354 
13355  destroyPQExpBuffer(q);
13356  destroyPQExpBuffer(delq);
13357  free(qamname);
13358 }
13359 
13360 /*
13361  * dumpOpclass
13362  * write out a single operator class definition
13363  */
13364 static void
13365 dumpOpclass(Archive *fout, const OpclassInfo *opcinfo)
13366 {
13367  DumpOptions *dopt = fout->dopt;
13368  PQExpBuffer query;
13369  PQExpBuffer q;
13370  PQExpBuffer delq;
13371  PQExpBuffer nameusing;
13372  PGresult *res;
13373  int ntups;
13374  int i_opcintype;
13375  int i_opckeytype;
13376  int i_opcdefault;
13377  int i_opcfamily;
13378  int i_opcfamilyname;
13379  int i_opcfamilynsp;
13380  int i_amname;
13381  int i_amopstrategy;
13382  int i_amopopr;
13383  int i_sortfamily;
13384  int i_sortfamilynsp;
13385  int i_amprocnum;
13386  int i_amproc;
13387  int i_amproclefttype;
13388  int i_amprocrighttype;
13389  char *opcintype;
13390  char *opckeytype;
13391  char *opcdefault;
13392  char *opcfamily;
13393  char *opcfamilyname;
13394  char *opcfamilynsp;
13395  char *amname;
13396  char *amopstrategy;
13397  char *amopopr;
13398  char *sortfamily;
13399  char *sortfamilynsp;
13400  char *amprocnum;
13401  char *amproc;
13402  char *amproclefttype;
13403  char *amprocrighttype;
13404  bool needComma;
13405  int i;
13406 
13407  /* Do nothing in data-only dump */
13408  if (dopt->dataOnly)
13409  return;
13410 
13411  query = createPQExpBuffer();
13412  q = createPQExpBuffer();
13413  delq = createPQExpBuffer();
13414  nameusing = createPQExpBuffer();
13415 
13416  /* Get additional fields from the pg_opclass row */
13417  appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
13418  "opckeytype::pg_catalog.regtype, "
13419  "opcdefault, opcfamily, "
13420  "opfname AS opcfamilyname, "
13421  "nspname AS opcfamilynsp, "
13422  "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
13423  "FROM pg_catalog.pg_opclass c "
13424  "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
13425  "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
13426  "WHERE c.oid = '%u'::pg_catalog.oid",
13427  opcinfo->dobj.catId.oid);
13428 
13429  res = ExecuteSqlQueryForSingleRow(fout, query->data);
13430 
13431  i_opcintype = PQfnumber(res, "opcintype");
13432  i_opckeytype = PQfnumber(res, "opckeytype");
13433  i_opcdefault = PQfnumber(res, "opcdefault");
13434  i_opcfamily = PQfnumber(res, "opcfamily");
13435  i_opcfamilyname = PQfnumber(res, "opcfamilyname");
13436  i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
13437  i_amname = PQfnumber(res, "amname");
13438 
13439  /* opcintype may still be needed after we PQclear res */
13440  opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
13441  opckeytype = PQgetvalue(res, 0, i_opckeytype);
13442  opcdefault = PQgetvalue(res, 0, i_opcdefault);
13443  /* opcfamily will still be needed after we PQclear res */
13444  opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
13445  opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
13446  opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
13447  /* amname will still be needed after we PQclear res */
13448  amname = pg_strdup(PQgetvalue(res, 0, i_amname));
13449 
13450  appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
13451  fmtQualifiedDumpable(opcinfo));
13452  appendPQExpBuffer(delq, " USING %s;\n",
13453  fmtId(amname));
13454 
13455  /* Build the fixed portion of the CREATE command */
13456  appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n ",
13457  fmtQualifiedDumpable(opcinfo));
13458  if (strcmp(opcdefault, "t") == 0)
13459  appendPQExpBufferStr(q, "DEFAULT ");
13460  appendPQExpBuffer(q, "FOR TYPE %s USING %s",
13461  opcintype,
13462  fmtId(amname));
13463  if (strlen(opcfamilyname) > 0)
13464  {
13465  appendPQExpBufferStr(q, " FAMILY ");
13466  appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
13467  appendPQExpBufferStr(q, fmtId(opcfamilyname));
13468  }
13469  appendPQExpBufferStr(q, " AS\n ");
13470 
13471  needComma = false;
13472 
13473  if (strcmp(opckeytype, "-") != 0)
13474  {
13475  appendPQExpBuffer(q, "STORAGE %s",
13476  opckeytype);
13477  needComma = true;
13478  }
13479 
13480  PQclear(res);
13481 
13482  /*
13483  * Now fetch and print the OPERATOR entries (pg_amop rows).
13484  *
13485  * Print only those opfamily members that are tied to the opclass by
13486  * pg_depend entries.
13487  */
13488  resetPQExpBuffer(query);
13489  appendPQExpBuffer(query, "SELECT amopstrategy, "
13490  "amopopr::pg_catalog.regoperator, "
13491  "opfname AS sortfamily, "
13492  "nspname AS sortfamilynsp "
13493  "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
13494  "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
13495  "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
13496  "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
13497  "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
13498  "AND refobjid = '%u'::pg_catalog.oid "
13499  "AND amopfamily = '%s'::pg_catalog.oid "
13500  "ORDER BY amopstrategy",
13501  opcinfo->dobj.catId.oid,
13502  opcfamily);
13503 
13504  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13505 
13506  ntups = PQntuples(res);
13507 
13508  i_amopstrategy = PQfnumber(res, "amopstrategy");
13509  i_amopopr = PQfnumber(res, "amopopr");
13510  i_sortfamily = PQfnumber(res, "sortfamily");
13511  i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
13512 
13513  for (i = 0; i < ntups; i++)
13514  {
13515  amopstrategy = PQgetvalue(res, i, i_amopstrategy);
13516  amopopr = PQgetvalue(res, i, i_amopopr);
13517  sortfamily = PQgetvalue(res, i, i_sortfamily);
13518  sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
13519 
13520  if (needComma)
13521  appendPQExpBufferStr(q, " ,\n ");
13522 
13523  appendPQExpBuffer(q, "OPERATOR %s %s",
13524  amopstrategy, amopopr);
13525 
13526  if (strlen(sortfamily) > 0)
13527  {
13528  appendPQExpBufferStr(q, " FOR ORDER BY ");
13529  appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
13530  appendPQExpBufferStr(q, fmtId(sortfamily));
13531  }
13532 
13533  needComma = true;
13534  }
13535 
13536  PQclear(res);
13537 
13538  /*
13539  * Now fetch and print the FUNCTION entries (pg_amproc rows).
13540  *
13541  * Print only those opfamily members that are tied to the opclass by
13542  * pg_depend entries.
13543  *
13544  * We print the amproclefttype/amprocrighttype even though in most cases
13545  * the backend could deduce the right values, because of the corner case
13546  * of a btree sort support function for a cross-type comparison.
13547  */
13548  resetPQExpBuffer(query);
13549 
13550  appendPQExpBuffer(query, "SELECT amprocnum, "
13551  "amproc::pg_catalog.regprocedure, "
13552  "amproclefttype::pg_catalog.regtype, "
13553  "amprocrighttype::pg_catalog.regtype "
13554  "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
13555  "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
13556  "AND refobjid = '%u'::pg_catalog.oid "
13557  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
13558  "AND objid = ap.oid "
13559  "ORDER BY amprocnum",
13560  opcinfo->dobj.catId.oid);
13561 
13562  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13563 
13564  ntups = PQntuples(res);
13565 
13566  i_amprocnum = PQfnumber(res, "amprocnum");
13567  i_amproc = PQfnumber(res, "amproc");
13568  i_amproclefttype = PQfnumber(res, "amproclefttype");
13569  i_amprocrighttype = PQfnumber(res, "amprocrighttype");
13570 
13571  for (i = 0; i < ntups; i++)
13572  {
13573  amprocnum = PQgetvalue(res, i, i_amprocnum);
13574  amproc = PQgetvalue(res, i, i_amproc);
13575  amproclefttype = PQgetvalue(res, i, i_amproclefttype);
13576  amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
13577 
13578  if (needComma)
13579  appendPQExpBufferStr(q, " ,\n ");
13580 
13581  appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
13582 
13583  if (*amproclefttype && *amprocrighttype)
13584  appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
13585 
13586  appendPQExpBuffer(q, " %s", amproc);
13587 
13588  needComma = true;
13589  }
13590 
13591  PQclear(res);
13592 
13593  /*
13594  * If needComma is still false it means we haven't added anything after
13595  * the AS keyword. To avoid printing broken SQL, append a dummy STORAGE
13596  * clause with the same datatype. This isn't sanctioned by the
13597  * documentation, but actually DefineOpClass will treat it as a no-op.
13598  */
13599  if (!needComma)
13600  appendPQExpBuffer(q, "STORAGE %s", opcintype);
13601 
13602  appendPQExpBufferStr(q, ";\n");
13603 
13604  appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
13605  appendPQExpBuffer(nameusing, " USING %s",
13606  fmtId(amname));
13607 
13608  if (dopt->binary_upgrade)
13610  "OPERATOR CLASS", nameusing->data,
13611  opcinfo->dobj.namespace->dobj.name);
13612 
13613  if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13614  ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
13615  ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
13616  .namespace = opcinfo->dobj.namespace->dobj.name,
13617  .owner = opcinfo->rolname,
13618  .description = "OPERATOR CLASS",
13619  .section = SECTION_PRE_DATA,
13620  .createStmt = q->data,
13621  .dropStmt = delq->data));
13622 
13623  /* Dump Operator Class Comments */
13624  if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13625  dumpComment(fout, "OPERATOR CLASS", nameusing->data,
13626  opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
13627  opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
13628 
13629  free(opcintype);
13630  free(opcfamily);
13631  free(amname);
13632  destroyPQExpBuffer(query);
13633  destroyPQExpBuffer(q);
13634  destroyPQExpBuffer(delq);
13635  destroyPQExpBuffer(nameusing);
13636 }
13637 
13638 /*
13639  * dumpOpfamily
13640  * write out a single operator family definition
13641  *
13642  * Note: this also dumps any "loose" operator members that aren't bound to a
13643  * specific opclass within the opfamily.
13644  */
13645 static void
13646 dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo)
13647 {
13648  DumpOptions *dopt = fout->dopt;
13649  PQExpBuffer query;
13650  PQExpBuffer q;
13651  PQExpBuffer delq;
13652  PQExpBuffer nameusing;
13653  PGresult *res;
13654  PGresult *res_ops;
13655  PGresult *res_procs;
13656  int ntups;
13657  int i_amname;
13658  int i_amopstrategy;
13659  int i_amopopr;
13660  int i_sortfamily;
13661  int i_sortfamilynsp;
13662  int i_amprocnum;
13663  int i_amproc;
13664  int i_amproclefttype;
13665  int i_amprocrighttype;
13666  char *amname;
13667  char *amopstrategy;
13668  char *amopopr;
13669  char *sortfamily;
13670  char *sortfamilynsp;
13671  char *amprocnum;
13672  char *amproc;
13673  char *amproclefttype;
13674  char *amprocrighttype;
13675  bool needComma;
13676  int i;
13677 
13678  /* Do nothing in data-only dump */
13679  if (dopt->dataOnly)
13680  return;
13681 
13682  query = createPQExpBuffer();
13683  q = createPQExpBuffer();
13684  delq = createPQExpBuffer();
13685  nameusing = createPQExpBuffer();
13686 
13687  /*
13688  * Fetch only those opfamily members that are tied directly to the
13689  * opfamily by pg_depend entries.
13690  */
13691  appendPQExpBuffer(query, "SELECT amopstrategy, "
13692  "amopopr::pg_catalog.regoperator, "
13693  "opfname AS sortfamily, "
13694  "nspname AS sortfamilynsp "
13695  "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
13696  "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
13697  "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
13698  "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
13699  "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13700  "AND refobjid = '%u'::pg_catalog.oid "
13701  "AND amopfamily = '%u'::pg_catalog.oid "
13702  "ORDER BY amopstrategy",
13703  opfinfo->dobj.catId.oid,
13704  opfinfo->dobj.catId.oid);
13705 
13706  res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13707 
13708  resetPQExpBuffer(query);
13709 
13710  appendPQExpBuffer(query, "SELECT amprocnum, "
13711  "amproc::pg_catalog.regprocedure, "
13712  "amproclefttype::pg_catalog.regtype, "
13713  "amprocrighttype::pg_catalog.regtype "
13714  "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
13715  "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13716  "AND refobjid = '%u'::pg_catalog.oid "
13717  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
13718  "AND objid = ap.oid "
13719  "ORDER BY amprocnum",
13720  opfinfo->dobj.catId.oid);
13721 
13722  res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13723 
13724  /* Get additional fields from the pg_opfamily row */
13725  resetPQExpBuffer(query);
13726 
13727  appendPQExpBuffer(query, "SELECT "
13728  "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
13729  "FROM pg_catalog.pg_opfamily "
13730  "WHERE oid = '%u'::pg_catalog.oid",
13731  opfinfo->dobj.catId.oid);
13732 
13733  res = ExecuteSqlQueryForSingleRow(fout, query->data);
13734 
13735  i_amname = PQfnumber(res, "amname");
13736 
13737  /* amname will still be needed after we PQclear res */
13738  amname = pg_strdup(PQgetvalue(res, 0, i_amname));
13739 
13740  appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
13741  fmtQualifiedDumpable(opfinfo));
13742  appendPQExpBuffer(delq, " USING %s;\n",
13743  fmtId(amname));
13744 
13745  /* Build the fixed portion of the CREATE command */
13746  appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
13747  fmtQualifiedDumpable(opfinfo));
13748  appendPQExpBuffer(q, " USING %s;\n",
13749  fmtId(amname));
13750 
13751  PQclear(res);
13752 
13753  /* Do we need an ALTER to add loose members? */
13754  if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
13755  {
13756  appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
13757  fmtQualifiedDumpable(opfinfo));
13758  appendPQExpBuffer(q, " USING %s ADD\n ",
13759  fmtId(amname));
13760 
13761  needComma = false;
13762 
13763  /*
13764  * Now fetch and print the OPERATOR entries (pg_amop rows).
13765  */
13766  ntups = PQntuples(res_ops);
13767 
13768  i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
13769  i_amopopr = PQfnumber(res_ops, "amopopr");
13770  i_sortfamily = PQfnumber(res_ops, "sortfamily");
13771  i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
13772 
13773  for (i = 0; i < ntups; i++)
13774  {
13775  amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
13776  amopopr = PQgetvalue(res_ops, i, i_amopopr);
13777  sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
13778  sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
13779 
13780  if (needComma)
13781  appendPQExpBufferStr(q, " ,\n ");
13782 
13783  appendPQExpBuffer(q, "OPERATOR %s %s",
13784  amopstrategy, amopopr);
13785 
13786  if (strlen(sortfamily) > 0)
13787  {
13788  appendPQExpBufferStr(q, " FOR ORDER BY ");
13789  appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
13790  appendPQExpBufferStr(q, fmtId(sortfamily));
13791  }
13792 
13793  needComma = true;
13794  }
13795 
13796  /*
13797  * Now fetch and print the FUNCTION entries (pg_amproc rows).
13798  */
13799  ntups = PQntuples(res_procs);
13800 
13801  i_amprocnum = PQfnumber(res_procs, "amprocnum");
13802  i_amproc = PQfnumber(res_procs, "amproc");
13803  i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
13804  i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
13805 
13806  for (i = 0; i < ntups; i++)
13807  {
13808  amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
13809  amproc = PQgetvalue(res_procs, i, i_amproc);
13810  amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
13811  amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
13812 
13813  if (needComma)
13814  appendPQExpBufferStr(q, " ,\n ");
13815 
13816  appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
13817  amprocnum, amproclefttype, amprocrighttype,
13818  amproc);
13819 
13820  needComma = true;
13821  }
13822 
13823  appendPQExpBufferStr(q, ";\n");
13824  }
13825 
13826  appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
13827  appendPQExpBuffer(nameusing, " USING %s",
13828  fmtId(amname));
13829 
13830  if (dopt->binary_upgrade)
13832  "OPERATOR FAMILY", nameusing->data,
13833  opfinfo->dobj.namespace->dobj.name);
13834 
13835  if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13836  ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
13837  ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
13838  .namespace = opfinfo->dobj.namespace->dobj.name,
13839  .owner = opfinfo->rolname,
13840  .description = "OPERATOR FAMILY",
13841  .section = SECTION_PRE_DATA,
13842  .createStmt = q->data,
13843  .dropStmt = delq->data));
13844 
13845  /* Dump Operator Family Comments */
13846  if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13847  dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
13848  opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
13849  opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
13850 
13851  free(amname);
13852  PQclear(res_ops);
13853  PQclear(res_procs);
13854  destroyPQExpBuffer(query);
13855  destroyPQExpBuffer(q);
13856  destroyPQExpBuffer(delq);
13857  destroyPQExpBuffer(nameusing);
13858 }
13859 
13860 /*
13861  * dumpCollation
13862  * write out a single collation definition
13863  */
13864 static void
13865 dumpCollation(Archive *fout, const CollInfo *collinfo)
13866 {
13867  DumpOptions *dopt = fout->dopt;
13868  PQExpBuffer query;
13869  PQExpBuffer q;
13870  PQExpBuffer delq;
13871  char *qcollname;
13872  PGresult *res;
13873  int i_collprovider;
13874  int i_collisdeterministic;
13875  int i_collcollate;
13876  int i_collctype;
13877  int i_colllocale;
13878  int i_collicurules;
13879  const char *collprovider;
13880  const char *collcollate;
13881  const char *collctype;
13882  const char *colllocale;
13883  const char *collicurules;
13884 
13885  /* Do nothing in data-only dump */
13886  if (dopt->dataOnly)
13887  return;
13888 
13889  query = createPQExpBuffer();
13890  q = createPQExpBuffer();
13891  delq = createPQExpBuffer();
13892 
13893  qcollname = pg_strdup(fmtId(collinfo->dobj.name));
13894 
13895  /* Get collation-specific details */
13896  appendPQExpBufferStr(query, "SELECT ");
13897 
13898  if (fout->remoteVersion >= 100000)
13899  appendPQExpBufferStr(query,
13900  "collprovider, "
13901  "collversion, ");
13902  else
13903  appendPQExpBufferStr(query,
13904  "'c' AS collprovider, "
13905  "NULL AS collversion, ");
13906 
13907  if (fout->remoteVersion >= 120000)
13908  appendPQExpBufferStr(query,
13909  "collisdeterministic, ");
13910  else
13911  appendPQExpBufferStr(query,
13912  "true AS collisdeterministic, ");
13913 
13914  if (fout->remoteVersion >= 170000)
13915  appendPQExpBufferStr(query,
13916  "colllocale, ");
13917  else if (fout->remoteVersion >= 150000)
13918  appendPQExpBufferStr(query,
13919  "colliculocale AS colllocale, ");
13920  else
13921  appendPQExpBufferStr(query,
13922  "NULL AS colllocale, ");
13923 
13924  if (fout->remoteVersion >= 160000)
13925  appendPQExpBufferStr(query,
13926  "collicurules, ");
13927  else
13928  appendPQExpBufferStr(query,
13929  "NULL AS collicurules, ");
13930 
13931  appendPQExpBuffer(query,
13932  "collcollate, "
13933  "collctype "
13934  "FROM pg_catalog.pg_collation c "
13935  "WHERE c.oid = '%u'::pg_catalog.oid",
13936  collinfo->dobj.catId.oid);
13937 
13938  res = ExecuteSqlQueryForSingleRow(fout, query->data);
13939 
13940  i_collprovider = PQfnumber(res, "collprovider");
13941  i_collisdeterministic = PQfnumber(res, "collisdeterministic");
13942  i_collcollate = PQfnumber(res, "collcollate");
13943  i_collctype = PQfnumber(res, "collctype");
13944  i_colllocale = PQfnumber(res, "colllocale");
13945  i_collicurules = PQfnumber(res, "collicurules");
13946 
13947  collprovider = PQgetvalue(res, 0, i_collprovider);
13948 
13949  if (!PQgetisnull(res, 0, i_collcollate))
13950  collcollate = PQgetvalue(res, 0, i_collcollate);
13951  else
13952  collcollate = NULL;
13953 
13954  if (!PQgetisnull(res, 0, i_collctype))
13955  collctype = PQgetvalue(res, 0, i_collctype);
13956  else
13957  collctype = NULL;
13958 
13959  /*
13960  * Before version 15, collcollate and collctype were of type NAME and
13961  * non-nullable. Treat empty strings as NULL for consistency.
13962  */
13963  if (fout->remoteVersion < 150000)
13964  {
13965  if (collcollate[0] == '\0')
13966  collcollate = NULL;
13967  if (collctype[0] == '\0')
13968  collctype = NULL;
13969  }
13970 
13971  if (!PQgetisnull(res, 0, i_colllocale))
13972  colllocale = PQgetvalue(res, 0, i_colllocale);
13973  else
13974  colllocale = NULL;
13975 
13976  if (!PQgetisnull(res, 0, i_collicurules))
13977  collicurules = PQgetvalue(res, 0, i_collicurules);
13978  else
13979  collicurules = NULL;
13980 
13981  appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
13982  fmtQualifiedDumpable(collinfo));
13983 
13984  appendPQExpBuffer(q, "CREATE COLLATION %s (",
13985  fmtQualifiedDumpable(collinfo));
13986 
13987  appendPQExpBufferStr(q, "provider = ");
13988  if (collprovider[0] == 'b')
13989  appendPQExpBufferStr(q, "builtin");
13990  else if (collprovider[0] == 'c')
13991  appendPQExpBufferStr(q, "libc");
13992  else if (collprovider[0] == 'i')
13993  appendPQExpBufferStr(q, "icu");
13994  else if (collprovider[0] == 'd')
13995  /* to allow dumping pg_catalog; not accepted on input */
13996  appendPQExpBufferStr(q, "default");
13997  else
13998  pg_fatal("unrecognized collation provider: %s",
13999  collprovider);
14000 
14001  if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
14002  appendPQExpBufferStr(q, ", deterministic = false");
14003 
14004  if (collprovider[0] == 'd')
14005  {
14006  if (collcollate || collctype || colllocale || collicurules)
14007  pg_log_warning("invalid collation \"%s\"", qcollname);
14008 
14009  /* no locale -- the default collation cannot be reloaded anyway */
14010  }
14011  else if (collprovider[0] == 'b')
14012  {
14013  if (collcollate || collctype || !colllocale || collicurules)
14014  pg_log_warning("invalid collation \"%s\"", qcollname);
14015 
14016  appendPQExpBufferStr(q, ", locale = ");
14017  appendStringLiteralAH(q, colllocale ? colllocale : "",
14018  fout);
14019  }
14020  else if (collprovider[0] == 'i')
14021  {
14022  if (fout->remoteVersion >= 150000)
14023  {
14024  if (collcollate || collctype || !colllocale)
14025  pg_log_warning("invalid collation \"%s\"", qcollname);
14026 
14027  appendPQExpBufferStr(q, ", locale = ");
14028  appendStringLiteralAH(q, colllocale ? colllocale : "",
14029  fout);
14030  }
14031  else
14032  {
14033  if (!collcollate || !collctype || colllocale ||
14034  strcmp(collcollate, collctype) != 0)
14035  pg_log_warning("invalid collation \"%s\"", qcollname);
14036 
14037  appendPQExpBufferStr(q, ", locale = ");
14038  appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
14039  }
14040 
14041  if (collicurules)
14042  {
14043  appendPQExpBufferStr(q, ", rules = ");
14044  appendStringLiteralAH(q, collicurules ? collicurules : "", fout);
14045  }
14046  }
14047  else if (collprovider[0] == 'c')
14048  {
14049  if (colllocale || collicurules || !collcollate || !collctype)
14050  pg_log_warning("invalid collation \"%s\"", qcollname);
14051 
14052  if (collcollate && collctype && strcmp(collcollate, collctype) == 0)
14053  {
14054  appendPQExpBufferStr(q, ", locale = ");
14055  appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
14056  }
14057  else
14058  {
14059  appendPQExpBufferStr(q, ", lc_collate = ");
14060  appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
14061  appendPQExpBufferStr(q, ", lc_ctype = ");
14062  appendStringLiteralAH(q, collctype ? collctype : "", fout);
14063  }
14064  }
14065  else
14066  pg_fatal("unrecognized collation provider: %s", collprovider);
14067 
14068  /*
14069  * For binary upgrade, carry over the collation version. For normal
14070  * dump/restore, omit the version, so that it is computed upon restore.
14071  */
14072  if (dopt->binary_upgrade)
14073  {
14074  int i_collversion;
14075 
14076  i_collversion = PQfnumber(res, "collversion");
14077  if (!PQgetisnull(res, 0, i_collversion))
14078  {
14079  appendPQExpBufferStr(q, ", version = ");
14081  PQgetvalue(res, 0, i_collversion),
14082  fout);
14083  }
14084  }
14085 
14086  appendPQExpBufferStr(q, ");\n");
14087 
14088  if (dopt->binary_upgrade)
14089  binary_upgrade_extension_member(q, &collinfo->dobj,
14090  "COLLATION", qcollname,
14091  collinfo->dobj.namespace->dobj.name);
14092 
14093  if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14094  ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
14095  ARCHIVE_OPTS(.tag = collinfo->dobj.name,
14096  .namespace = collinfo->dobj.namespace->dobj.name,
14097  .owner = collinfo->rolname,
14098  .description = "COLLATION",
14099  .section = SECTION_PRE_DATA,
14100  .createStmt = q->data,
14101  .dropStmt = delq->data));
14102 
14103  /* Dump Collation Comments */
14104  if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14105  dumpComment(fout, "COLLATION", qcollname,
14106  collinfo->dobj.namespace->dobj.name, collinfo->rolname,
14107  collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
14108 
14109  PQclear(res);
14110 
14111  destroyPQExpBuffer(query);
14112  destroyPQExpBuffer(q);
14113  destroyPQExpBuffer(delq);
14114  free(qcollname);
14115 }
14116 
14117 /*
14118  * dumpConversion
14119  * write out a single conversion definition
14120  */
14121 static void
14122 dumpConversion(Archive *fout, const ConvInfo *convinfo)
14123 {
14124  DumpOptions *dopt = fout->dopt;
14125  PQExpBuffer query;
14126  PQExpBuffer q;
14127  PQExpBuffer delq;
14128  char *qconvname;
14129  PGresult *res;
14130  int i_conforencoding;
14131  int i_contoencoding;
14132  int i_conproc;
14133  int i_condefault;
14134  const char *conforencoding;
14135  const char *contoencoding;
14136  const char *conproc;
14137  bool condefault;
14138 
14139  /* Do nothing in data-only dump */
14140  if (dopt->dataOnly)
14141  return;
14142 
14143  query = createPQExpBuffer();
14144  q = createPQExpBuffer();
14145  delq = createPQExpBuffer();
14146 
14147  qconvname = pg_strdup(fmtId(convinfo->dobj.name));
14148 
14149  /* Get conversion-specific details */
14150  appendPQExpBuffer(query, "SELECT "
14151  "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
14152  "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
14153  "conproc, condefault "
14154  "FROM pg_catalog.pg_conversion c "
14155  "WHERE c.oid = '%u'::pg_catalog.oid",
14156  convinfo->dobj.catId.oid);
14157 
14158  res = ExecuteSqlQueryForSingleRow(fout, query->data);
14159 
14160  i_conforencoding = PQfnumber(res, "conforencoding");
14161  i_contoencoding = PQfnumber(res, "contoencoding");
14162  i_conproc = PQfnumber(res, "conproc");
14163  i_condefault = PQfnumber(res, "condefault");
14164 
14165  conforencoding = PQgetvalue(res, 0, i_conforencoding);
14166  contoencoding = PQgetvalue(res, 0, i_contoencoding);
14167  conproc = PQgetvalue(res, 0, i_conproc);
14168  condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
14169 
14170  appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
14171  fmtQualifiedDumpable(convinfo));
14172 
14173  appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
14174  (condefault) ? "DEFAULT " : "",
14175  fmtQualifiedDumpable(convinfo));
14176  appendStringLiteralAH(q, conforencoding, fout);
14177  appendPQExpBufferStr(q, " TO ");
14178  appendStringLiteralAH(q, contoencoding, fout);
14179  /* regproc output is already sufficiently quoted */
14180  appendPQExpBuffer(q, " FROM %s;\n", conproc);
14181 
14182  if (dopt->binary_upgrade)
14183  binary_upgrade_extension_member(q, &convinfo->dobj,
14184  "CONVERSION", qconvname,
14185  convinfo->dobj.namespace->dobj.name);
14186 
14187  if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14188  ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
14189  ARCHIVE_OPTS(.tag = convinfo->dobj.name,
14190  .namespace = convinfo->dobj.namespace->dobj.name,
14191  .owner = convinfo->rolname,
14192  .description = "CONVERSION",
14193  .section = SECTION_PRE_DATA,
14194  .createStmt = q->data,
14195  .dropStmt = delq->data));
14196 
14197  /* Dump Conversion Comments */
14198  if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14199  dumpComment(fout, "CONVERSION", qconvname,
14200  convinfo->dobj.namespace->dobj.name, convinfo->rolname,
14201  convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
14202 
14203  PQclear(res);
14204 
14205  destroyPQExpBuffer(query);
14206  destroyPQExpBuffer(q);
14207  destroyPQExpBuffer(delq);
14208  free(qconvname);
14209 }
14210 
14211 /*
14212  * format_aggregate_signature: generate aggregate name and argument list
14213  *
14214  * The argument type names are qualified if needed. The aggregate name
14215  * is never qualified.
14216  */
14217 static char *
14218 format_aggregate_signature(const AggInfo *agginfo, Archive *fout, bool honor_quotes)
14219 {
14221  int j;
14222 
14223  initPQExpBuffer(&buf);
14224  if (honor_quotes)
14225  appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
14226  else
14227  appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
14228 
14229  if (agginfo->aggfn.nargs == 0)
14230  appendPQExpBufferStr(&buf, "(*)");
14231  else
14232  {
14233  appendPQExpBufferChar(&buf, '(');
14234  for (j = 0; j < agginfo->aggfn.nargs; j++)
14235  appendPQExpBuffer(&buf, "%s%s",
14236  (j > 0) ? ", " : "",
14237  getFormattedTypeName(fout,
14238  agginfo->aggfn.argtypes[j],
14239  zeroIsError));
14240  appendPQExpBufferChar(&buf, ')');
14241  }
14242  return buf.data;
14243 }
14244 
14245 /*
14246  * dumpAgg
14247  * write out a single aggregate definition
14248  */
14249 static void
14250 dumpAgg(Archive *fout, const AggInfo *agginfo)
14251 {
14252  DumpOptions *dopt = fout->dopt;
14253  PQExpBuffer query;
14254  PQExpBuffer q;
14255  PQExpBuffer delq;
14256  PQExpBuffer details;
14257  char *aggsig; /* identity signature */
14258  char *aggfullsig = NULL; /* full signature */
14259  char *aggsig_tag;
14260  PGresult *res;
14261  int i_agginitval;
14262  int i_aggminitval;
14263  const char *aggtransfn;
14264  const char *aggfinalfn;
14265  const char *aggcombinefn;
14266  const char *aggserialfn;
14267  const char *aggdeserialfn;
14268  const char *aggmtransfn;
14269  const char *aggminvtransfn;
14270  const char *aggmfinalfn;
14271  bool aggfinalextra;
14272  bool aggmfinalextra;
14273  char aggfinalmodify;
14274  char aggmfinalmodify;
14275  const char *aggsortop;
14276  char *aggsortconvop;
14277  char aggkind;
14278  const char *aggtranstype;
14279  const char *aggtransspace;
14280  const char *aggmtranstype;
14281  const char *aggmtransspace;
14282  const char *agginitval;
14283  const char *aggminitval;
14284  const char *proparallel;
14285  char defaultfinalmodify;
14286 
14287  /* Do nothing in data-only dump */
14288  if (dopt->dataOnly)
14289  return;
14290 
14291  query = createPQExpBuffer();
14292  q = createPQExpBuffer();
14293  delq = createPQExpBuffer();
14294  details = createPQExpBuffer();
14295 
14296  if (!fout->is_prepared[PREPQUERY_DUMPAGG])
14297  {
14298  /* Set up query for aggregate-specific details */
14299  appendPQExpBufferStr(query,
14300  "PREPARE dumpAgg(pg_catalog.oid) AS\n");
14301 
14302  appendPQExpBufferStr(query,
14303  "SELECT "
14304  "aggtransfn,\n"
14305  "aggfinalfn,\n"
14306  "aggtranstype::pg_catalog.regtype,\n"
14307  "agginitval,\n"
14308  "aggsortop,\n"
14309  "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
14310  "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n");
14311 
14312  if (fout->remoteVersion >= 90400)
14313  appendPQExpBufferStr(query,
14314  "aggkind,\n"
14315  "aggmtransfn,\n"
14316  "aggminvtransfn,\n"
14317  "aggmfinalfn,\n"
14318  "aggmtranstype::pg_catalog.regtype,\n"
14319  "aggfinalextra,\n"
14320  "aggmfinalextra,\n"
14321  "aggtransspace,\n"
14322  "aggmtransspace,\n"
14323  "aggminitval,\n");
14324  else
14325  appendPQExpBufferStr(query,
14326  "'n' AS aggkind,\n"
14327  "'-' AS aggmtransfn,\n"
14328  "'-' AS aggminvtransfn,\n"
14329  "'-' AS aggmfinalfn,\n"
14330  "0 AS aggmtranstype,\n"
14331  "false AS aggfinalextra,\n"
14332  "false AS aggmfinalextra,\n"
14333  "0 AS aggtransspace,\n"
14334  "0 AS aggmtransspace,\n"
14335  "NULL AS aggminitval,\n");
14336 
14337  if (fout->remoteVersion >= 90600)
14338  appendPQExpBufferStr(query,
14339  "aggcombinefn,\n"
14340  "aggserialfn,\n"
14341  "aggdeserialfn,\n"
14342  "proparallel,\n");
14343  else
14344  appendPQExpBufferStr(query,
14345  "'-' AS aggcombinefn,\n"
14346  "'-' AS aggserialfn,\n"
14347  "'-' AS aggdeserialfn,\n"
14348  "'u' AS proparallel,\n");
14349 
14350  if (fout->remoteVersion >= 110000)
14351  appendPQExpBufferStr(query,
14352  "aggfinalmodify,\n"
14353  "aggmfinalmodify\n");
14354  else
14355  appendPQExpBufferStr(query,
14356  "'0' AS aggfinalmodify,\n"
14357  "'0' AS aggmfinalmodify\n");
14358 
14359  appendPQExpBufferStr(query,
14360  "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
14361  "WHERE a.aggfnoid = p.oid "
14362  "AND p.oid = $1");
14363 
14364  ExecuteSqlStatement(fout, query->data);
14365 
14366  fout->is_prepared[PREPQUERY_DUMPAGG] = true;
14367  }
14368 
14369  printfPQExpBuffer(query,
14370  "EXECUTE dumpAgg('%u')",
14371  agginfo->aggfn.dobj.catId.oid);
14372 
14373  res = ExecuteSqlQueryForSingleRow(fout, query->data);
14374 
14375  i_agginitval = PQfnumber(res, "agginitval");
14376  i_aggminitval = PQfnumber(res, "aggminitval");
14377 
14378  aggtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggtransfn"));
14379  aggfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggfinalfn"));
14380  aggcombinefn = PQgetvalue(res, 0, PQfnumber(res, "aggcombinefn"));
14381  aggserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggserialfn"));
14382  aggdeserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggdeserialfn"));
14383  aggmtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggmtransfn"));
14384  aggminvtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggminvtransfn"));
14385  aggmfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalfn"));
14386  aggfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggfinalextra"))[0] == 't');
14387  aggmfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggmfinalextra"))[0] == 't');
14388  aggfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggfinalmodify"))[0];
14389  aggmfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalmodify"))[0];
14390  aggsortop = PQgetvalue(res, 0, PQfnumber(res, "aggsortop"));
14391  aggkind = PQgetvalue(res, 0, PQfnumber(res, "aggkind"))[0];
14392  aggtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggtranstype"));
14393  aggtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggtransspace"));
14394  aggmtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggmtranstype"));
14395  aggmtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggmtransspace"));
14396  agginitval = PQgetvalue(res, 0, i_agginitval);
14397  aggminitval = PQgetvalue(res, 0, i_aggminitval);
14398  proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
14399 
14400  {
14401  char *funcargs;
14402  char *funciargs;
14403 
14404  funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
14405  funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
14406  aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
14407  aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
14408  }
14409 
14410  aggsig_tag = format_aggregate_signature(agginfo, fout, false);
14411 
14412  /* identify default modify flag for aggkind (must match DefineAggregate) */
14413  defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
14414  /* replace omitted flags for old versions */
14415  if (aggfinalmodify == '0')
14416  aggfinalmodify = defaultfinalmodify;
14417  if (aggmfinalmodify == '0')
14418  aggmfinalmodify = defaultfinalmodify;
14419 
14420  /* regproc and regtype output is already sufficiently quoted */
14421  appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
14422  aggtransfn, aggtranstype);
14423 
14424  if (strcmp(aggtransspace, "0") != 0)
14425  {
14426  appendPQExpBuffer(details, ",\n SSPACE = %s",
14427  aggtransspace);
14428  }
14429 
14430  if (!PQgetisnull(res, 0, i_agginitval))
14431  {
14432  appendPQExpBufferStr(details, ",\n INITCOND = ");
14433  appendStringLiteralAH(details, agginitval, fout);
14434  }
14435 
14436  if (strcmp(aggfinalfn, "-") != 0)
14437  {
14438  appendPQExpBuffer(details, ",\n FINALFUNC = %s",
14439  aggfinalfn);
14440  if (aggfinalextra)
14441  appendPQExpBufferStr(details, ",\n FINALFUNC_EXTRA");
14442  if (aggfinalmodify != defaultfinalmodify)
14443  {
14444  switch (aggfinalmodify)
14445  {
14446  case AGGMODIFY_READ_ONLY:
14447  appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = READ_ONLY");
14448  break;
14449  case AGGMODIFY_SHAREABLE:
14450  appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = SHAREABLE");
14451  break;
14452  case AGGMODIFY_READ_WRITE:
14453  appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = READ_WRITE");
14454  break;
14455  default:
14456  pg_fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
14457  agginfo->aggfn.dobj.name);
14458  break;
14459  }
14460  }
14461  }
14462 
14463  if (strcmp(aggcombinefn, "-") != 0)
14464  appendPQExpBuffer(details, ",\n COMBINEFUNC = %s", aggcombinefn);
14465 
14466  if (strcmp(aggserialfn, "-") != 0)
14467  appendPQExpBuffer(details, ",\n SERIALFUNC = %s", aggserialfn);
14468 
14469  if (strcmp(aggdeserialfn, "-") != 0)
14470  appendPQExpBuffer(details, ",\n DESERIALFUNC = %s", aggdeserialfn);
14471 
14472  if (strcmp(aggmtransfn, "-") != 0)
14473  {
14474  appendPQExpBuffer(details, ",\n MSFUNC = %s,\n MINVFUNC = %s,\n MSTYPE = %s",
14475  aggmtransfn,
14476  aggminvtransfn,
14477  aggmtranstype);
14478  }
14479 
14480  if (strcmp(aggmtransspace, "0") != 0)
14481  {
14482  appendPQExpBuffer(details, ",\n MSSPACE = %s",
14483  aggmtransspace);
14484  }
14485 
14486  if (!PQgetisnull(res, 0, i_aggminitval))
14487  {
14488  appendPQExpBufferStr(details, ",\n MINITCOND = ");
14489  appendStringLiteralAH(details, aggminitval, fout);
14490  }
14491 
14492  if (strcmp(aggmfinalfn, "-") != 0)
14493  {
14494  appendPQExpBuffer(details, ",\n MFINALFUNC = %s",
14495  aggmfinalfn);
14496  if (aggmfinalextra)
14497  appendPQExpBufferStr(details, ",\n MFINALFUNC_EXTRA");
14498  if (aggmfinalmodify != defaultfinalmodify)
14499  {
14500  switch (aggmfinalmodify)
14501  {
14502  case AGGMODIFY_READ_ONLY:
14503  appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = READ_ONLY");
14504  break;
14505  case AGGMODIFY_SHAREABLE:
14506  appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = SHAREABLE");
14507  break;
14508  case AGGMODIFY_READ_WRITE:
14509  appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = READ_WRITE");
14510  break;
14511  default:
14512  pg_fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
14513  agginfo->aggfn.dobj.name);
14514  break;
14515  }
14516  }
14517  }
14518 
14519  aggsortconvop = getFormattedOperatorName(aggsortop);
14520  if (aggsortconvop)
14521  {
14522  appendPQExpBuffer(details, ",\n SORTOP = %s",
14523  aggsortconvop);
14524  free(aggsortconvop);
14525  }
14526 
14527  if (aggkind == AGGKIND_HYPOTHETICAL)
14528  appendPQExpBufferStr(details, ",\n HYPOTHETICAL");
14529 
14530  if (proparallel[0] != PROPARALLEL_UNSAFE)
14531  {
14532  if (proparallel[0] == PROPARALLEL_SAFE)
14533  appendPQExpBufferStr(details, ",\n PARALLEL = safe");
14534  else if (proparallel[0] == PROPARALLEL_RESTRICTED)
14535  appendPQExpBufferStr(details, ",\n PARALLEL = restricted");
14536  else if (proparallel[0] != PROPARALLEL_UNSAFE)
14537  pg_fatal("unrecognized proparallel value for function \"%s\"",
14538  agginfo->aggfn.dobj.name);
14539  }
14540 
14541  appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
14542  fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
14543  aggsig);
14544 
14545  appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
14546  fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
14547  aggfullsig ? aggfullsig : aggsig, details->data);
14548 
14549  if (dopt->binary_upgrade)
14550  binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
14551  "AGGREGATE", aggsig,
14552  agginfo->aggfn.dobj.namespace->dobj.name);
14553 
14554  if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
14555  ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
14556  agginfo->aggfn.dobj.dumpId,
14557  ARCHIVE_OPTS(.tag = aggsig_tag,
14558  .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
14559  .owner = agginfo->aggfn.rolname,
14560  .description = "AGGREGATE",
14561  .section = SECTION_PRE_DATA,
14562  .createStmt = q->data,
14563  .dropStmt = delq->data));
14564 
14565  /* Dump Aggregate Comments */
14566  if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
14567  dumpComment(fout, "AGGREGATE", aggsig,
14568  agginfo->aggfn.dobj.namespace->dobj.name,
14569  agginfo->aggfn.rolname,
14570  agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
14571 
14572  if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
14573  dumpSecLabel(fout, "AGGREGATE", aggsig,
14574  agginfo->aggfn.dobj.namespace->dobj.name,
14575  agginfo->aggfn.rolname,
14576  agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
14577 
14578  /*
14579  * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
14580  * command look like a function's GRANT; in particular this affects the
14581  * syntax for zero-argument aggregates and ordered-set aggregates.
14582  */
14583  free(aggsig);
14584 
14585  aggsig = format_function_signature(fout, &agginfo->aggfn, true);
14586 
14587  if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
14588  dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
14589  "FUNCTION", aggsig, NULL,
14590  agginfo->aggfn.dobj.namespace->dobj.name,
14591  NULL, agginfo->aggfn.rolname, &agginfo->aggfn.dacl);
14592 
14593  free(aggsig);
14594  free(aggfullsig);
14595  free(aggsig_tag);
14596 
14597  PQclear(res);
14598 
14599  destroyPQExpBuffer(query);
14600  destroyPQExpBuffer(q);
14601  destroyPQExpBuffer(delq);
14602  destroyPQExpBuffer(details);
14603 }
14604 
14605 /*
14606  * dumpTSParser
14607  * write out a single text search parser
14608  */
14609 static void
14610 dumpTSParser(Archive *fout, const TSParserInfo *prsinfo)
14611 {
14612  DumpOptions *dopt = fout->dopt;
14613  PQExpBuffer q;
14614  PQExpBuffer delq;
14615  char *qprsname;
14616 
14617  /* Do nothing in data-only dump */
14618  if (dopt->dataOnly)
14619  return;
14620 
14621  q = createPQExpBuffer();
14622  delq = createPQExpBuffer();
14623 
14624  qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
14625 
14626  appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
14627  fmtQualifiedDumpable(prsinfo));
14628 
14629  appendPQExpBuffer(q, " START = %s,\n",
14630  convertTSFunction(fout, prsinfo->prsstart));
14631  appendPQExpBuffer(q, " GETTOKEN = %s,\n",
14632  convertTSFunction(fout, prsinfo->prstoken));
14633  appendPQExpBuffer(q, " END = %s,\n",
14634  convertTSFunction(fout, prsinfo->prsend));
14635  if (prsinfo->prsheadline != InvalidOid)
14636  appendPQExpBuffer(q, " HEADLINE = %s,\n",
14637  convertTSFunction(fout, prsinfo->prsheadline));
14638  appendPQExpBuffer(q, " LEXTYPES = %s );\n",
14639  convertTSFunction(fout, prsinfo->prslextype));
14640 
14641  appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
14642  fmtQualifiedDumpable(prsinfo));
14643 
14644  if (dopt->binary_upgrade)
14646  "TEXT SEARCH PARSER", qprsname,
14647  prsinfo->dobj.namespace->dobj.name);
14648 
14649  if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14650  ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
14651  ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
14652  .namespace = prsinfo->dobj.namespace->dobj.name,
14653  .description = "TEXT SEARCH PARSER",
14654  .section = SECTION_PRE_DATA,
14655  .createStmt = q->data,
14656  .dropStmt = delq->data));
14657 
14658  /* Dump Parser Comments */
14659  if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14660  dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
14661  prsinfo->dobj.namespace->dobj.name, "",
14662  prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
14663 
14664  destroyPQExpBuffer(q);
14665  destroyPQExpBuffer(delq);
14666  free(qprsname);
14667 }
14668 
14669 /*
14670  * dumpTSDictionary
14671  * write out a single text search dictionary
14672  */
14673 static void
14674 dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo)
14675 {
14676  DumpOptions *dopt = fout->dopt;
14677  PQExpBuffer q;
14678  PQExpBuffer delq;
14679  PQExpBuffer query;
14680  char *qdictname;
14681  PGresult *res;
14682  char *nspname;
14683  char *tmplname;
14684 
14685  /* Do nothing in data-only dump */
14686  if (dopt->dataOnly)
14687  return;
14688 
14689  q = createPQExpBuffer();
14690  delq = createPQExpBuffer();
14691  query = createPQExpBuffer();
14692 
14693  qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
14694 
14695  /* Fetch name and namespace of the dictionary's template */
14696  appendPQExpBuffer(query, "SELECT nspname, tmplname "
14697  "FROM pg_ts_template p, pg_namespace n "
14698  "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
14699  dictinfo->dicttemplate);
14700  res = ExecuteSqlQueryForSingleRow(fout, query->data);
14701  nspname = PQgetvalue(res, 0, 0);
14702  tmplname = PQgetvalue(res, 0, 1);
14703 
14704  appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
14705  fmtQualifiedDumpable(dictinfo));
14706 
14707  appendPQExpBufferStr(q, " TEMPLATE = ");
14708  appendPQExpBuffer(q, "%s.", fmtId(nspname));
14709  appendPQExpBufferStr(q, fmtId(tmplname));
14710 
14711  PQclear(res);
14712 
14713  /* the dictinitoption can be dumped straight into the command */
14714  if (dictinfo->dictinitoption)
14715  appendPQExpBuffer(q, ",\n %s", dictinfo->dictinitoption);
14716 
14717  appendPQExpBufferStr(q, " );\n");
14718 
14719  appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
14720  fmtQualifiedDumpable(dictinfo));
14721 
14722  if (dopt->binary_upgrade)
14723  binary_upgrade_extension_member(q, &dictinfo->dobj,
14724  "TEXT SEARCH DICTIONARY", qdictname,
14725  dictinfo->dobj.namespace->dobj.name);
14726 
14727  if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14728  ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
14729  ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
14730  .namespace = dictinfo->dobj.namespace->dobj.name,
14731  .owner = dictinfo->rolname,
14732  .description = "TEXT SEARCH DICTIONARY",
14733  .section = SECTION_PRE_DATA,
14734  .createStmt = q->data,
14735  .dropStmt = delq->data));
14736 
14737  /* Dump Dictionary Comments */
14738  if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14739  dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
14740  dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
14741  dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
14742 
14743  destroyPQExpBuffer(q);
14744  destroyPQExpBuffer(delq);
14745  destroyPQExpBuffer(query);
14746  free(qdictname);
14747 }
14748 
14749 /*
14750  * dumpTSTemplate
14751  * write out a single text search template
14752  */
14753 static void
14754 dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo)
14755 {
14756  DumpOptions *dopt = fout->dopt;
14757  PQExpBuffer q;
14758  PQExpBuffer delq;
14759  char *qtmplname;
14760 
14761  /* Do nothing in data-only dump */
14762  if (dopt->dataOnly)
14763  return;
14764 
14765  q = createPQExpBuffer();
14766  delq = createPQExpBuffer();
14767 
14768  qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
14769 
14770  appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
14771  fmtQualifiedDumpable(tmplinfo));
14772 
14773  if (tmplinfo->tmplinit != InvalidOid)
14774  appendPQExpBuffer(q, " INIT = %s,\n",
14775  convertTSFunction(fout, tmplinfo->tmplinit));
14776  appendPQExpBuffer(q, " LEXIZE = %s );\n",
14777  convertTSFunction(fout, tmplinfo->tmpllexize));
14778 
14779  appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
14780  fmtQualifiedDumpable(tmplinfo));
14781 
14782  if (dopt->binary_upgrade)
14783  binary_upgrade_extension_member(q, &tmplinfo->dobj,
14784  "TEXT SEARCH TEMPLATE", qtmplname,
14785  tmplinfo->dobj.namespace->dobj.name);
14786 
14787  if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14788  ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
14789  ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
14790  .namespace = tmplinfo->dobj.namespace->dobj.name,
14791  .description = "TEXT SEARCH TEMPLATE",
14792  .section = SECTION_PRE_DATA,
14793  .createStmt = q->data,
14794  .dropStmt = delq->data));
14795 
14796  /* Dump Template Comments */
14797  if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14798  dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
14799  tmplinfo->dobj.namespace->dobj.name, "",
14800  tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
14801 
14802  destroyPQExpBuffer(q);
14803  destroyPQExpBuffer(delq);
14804  free(qtmplname);
14805 }
14806 
14807 /*
14808  * dumpTSConfig
14809  * write out a single text search configuration
14810  */
14811 static void
14812 dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo)
14813 {
14814  DumpOptions *dopt = fout->dopt;
14815  PQExpBuffer q;
14816  PQExpBuffer delq;
14817  PQExpBuffer query;
14818  char *qcfgname;
14819  PGresult *res;
14820  char *nspname;
14821  char *prsname;
14822  int ntups,
14823  i;
14824  int i_tokenname;
14825  int i_dictname;
14826 
14827  /* Do nothing in data-only dump */
14828  if (dopt->dataOnly)
14829  return;
14830 
14831  q = createPQExpBuffer();
14832  delq = createPQExpBuffer();
14833  query = createPQExpBuffer();
14834 
14835  qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
14836 
14837  /* Fetch name and namespace of the config's parser */
14838  appendPQExpBuffer(query, "SELECT nspname, prsname "
14839  "FROM pg_ts_parser p, pg_namespace n "
14840  "WHERE p.oid = '%u' AND n.oid = prsnamespace",
14841  cfginfo->cfgparser);
14842  res = ExecuteSqlQueryForSingleRow(fout, query->data);
14843  nspname = PQgetvalue(res, 0, 0);
14844  prsname = PQgetvalue(res, 0, 1);
14845 
14846  appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
14847  fmtQualifiedDumpable(cfginfo));
14848 
14849  appendPQExpBuffer(q, " PARSER = %s.", fmtId(nspname));
14850  appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
14851 
14852  PQclear(res);
14853 
14854  resetPQExpBuffer(query);
14855  appendPQExpBuffer(query,
14856  "SELECT\n"
14857  " ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
14858  " WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
14859  " m.mapdict::pg_catalog.regdictionary AS dictname\n"
14860  "FROM pg_catalog.pg_ts_config_map AS m\n"
14861  "WHERE m.mapcfg = '%u'\n"
14862  "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
14863  cfginfo->cfgparser, cfginfo->dobj.catId.oid);
14864 
14865  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14866  ntups = PQntuples(res);
14867 
14868  i_tokenname = PQfnumber(res, "tokenname");
14869  i_dictname = PQfnumber(res, "dictname");
14870 
14871  for (i = 0; i < ntups; i++)
14872  {
14873  char *tokenname = PQgetvalue(res, i, i_tokenname);
14874  char *dictname = PQgetvalue(res, i, i_dictname);
14875 
14876  if (i == 0 ||
14877  strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
14878  {
14879  /* starting a new token type, so start a new command */
14880  if (i > 0)
14881  appendPQExpBufferStr(q, ";\n");
14882  appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
14883  fmtQualifiedDumpable(cfginfo));
14884  /* tokenname needs quoting, dictname does NOT */
14885  appendPQExpBuffer(q, " ADD MAPPING FOR %s WITH %s",
14886  fmtId(tokenname), dictname);
14887  }
14888  else
14889  appendPQExpBuffer(q, ", %s", dictname);
14890  }
14891 
14892  if (ntups > 0)
14893  appendPQExpBufferStr(q, ";\n");
14894 
14895  PQclear(res);
14896 
14897  appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
14898  fmtQualifiedDumpable(cfginfo));
14899 
14900  if (dopt->binary_upgrade)
14902  "TEXT SEARCH CONFIGURATION", qcfgname,
14903  cfginfo->dobj.namespace->dobj.name);
14904 
14905  if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14906  ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
14907  ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
14908  .namespace = cfginfo->dobj.namespace->dobj.name,
14909  .owner = cfginfo->rolname,
14910  .description = "TEXT SEARCH CONFIGURATION",
14911  .section = SECTION_PRE_DATA,
14912  .createStmt = q->data,
14913  .dropStmt = delq->data));
14914 
14915  /* Dump Configuration Comments */
14916  if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14917  dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
14918  cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
14919  cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
14920 
14921  destroyPQExpBuffer(q);
14922  destroyPQExpBuffer(delq);
14923  destroyPQExpBuffer(query);
14924  free(qcfgname);
14925 }
14926 
14927 /*
14928  * dumpForeignDataWrapper
14929  * write out a single foreign-data wrapper definition
14930  */
14931 static void
14933 {
14934  DumpOptions *dopt = fout->dopt;
14935  PQExpBuffer q;
14936  PQExpBuffer delq;
14937  char *qfdwname;
14938 
14939  /* Do nothing in data-only dump */
14940  if (dopt->dataOnly)
14941  return;
14942 
14943  q = createPQExpBuffer();
14944  delq = createPQExpBuffer();
14945 
14946  qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
14947 
14948  appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
14949  qfdwname);
14950 
14951  if (strcmp(fdwinfo->fdwhandler, "-") != 0)
14952  appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
14953 
14954  if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
14955  appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
14956 
14957  if (strlen(fdwinfo->fdwoptions) > 0)
14958  appendPQExpBuffer(q, " OPTIONS (\n %s\n)", fdwinfo->fdwoptions);
14959 
14960  appendPQExpBufferStr(q, ";\n");
14961 
14962  appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
14963  qfdwname);
14964 
14965  if (dopt->binary_upgrade)
14967  "FOREIGN DATA WRAPPER", qfdwname,
14968  NULL);
14969 
14970  if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14971  ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14972  ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
14973  .owner = fdwinfo->rolname,
14974  .description = "FOREIGN DATA WRAPPER",
14975  .section = SECTION_PRE_DATA,
14976  .createStmt = q->data,
14977  .dropStmt = delq->data));
14978 
14979  /* Dump Foreign Data Wrapper Comments */
14980  if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14981  dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
14982  NULL, fdwinfo->rolname,
14983  fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
14984 
14985  /* Handle the ACL */
14986  if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
14987  dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
14988  "FOREIGN DATA WRAPPER", qfdwname, NULL, NULL,
14989  NULL, fdwinfo->rolname, &fdwinfo->dacl);
14990 
14991  free(qfdwname);
14992 
14993  destroyPQExpBuffer(q);
14994  destroyPQExpBuffer(delq);
14995 }
14996 
14997 /*
14998  * dumpForeignServer
14999  * write out a foreign server definition
15000  */
15001 static void
15003 {
15004  DumpOptions *dopt = fout->dopt;
15005  PQExpBuffer q;
15006  PQExpBuffer delq;
15007  PQExpBuffer query;
15008  PGresult *res;
15009  char *qsrvname;
15010  char *fdwname;
15011 
15012  /* Do nothing in data-only dump */
15013  if (dopt->dataOnly)
15014  return;
15015 
15016  q = createPQExpBuffer();
15017  delq = createPQExpBuffer();
15018  query = createPQExpBuffer();
15019 
15020  qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
15021 
15022  /* look up the foreign-data wrapper */
15023  appendPQExpBuffer(query, "SELECT fdwname "
15024  "FROM pg_foreign_data_wrapper w "
15025  "WHERE w.oid = '%u'",
15026  srvinfo->srvfdw);
15027  res = ExecuteSqlQueryForSingleRow(fout, query->data);
15028  fdwname = PQgetvalue(res, 0, 0);
15029 
15030  appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
15031  if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
15032  {
15033  appendPQExpBufferStr(q, " TYPE ");
15034  appendStringLiteralAH(q, srvinfo->srvtype, fout);
15035  }
15036  if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
15037  {
15038  appendPQExpBufferStr(q, " VERSION ");
15039  appendStringLiteralAH(q, srvinfo->srvversion, fout);
15040  }
15041 
15042  appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
15043  appendPQExpBufferStr(q, fmtId(fdwname));
15044 
15045  if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
15046  appendPQExpBuffer(q, " OPTIONS (\n %s\n)", srvinfo->srvoptions);
15047 
15048  appendPQExpBufferStr(q, ";\n");
15049 
15050  appendPQExpBuffer(delq, "DROP SERVER %s;\n",
15051  qsrvname);
15052 
15053  if (dopt->binary_upgrade)
15055  "SERVER", qsrvname, NULL);
15056 
15057  if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15058  ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
15059  ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
15060  .owner = srvinfo->rolname,
15061  .description = "SERVER",
15062  .section = SECTION_PRE_DATA,
15063  .createStmt = q->data,
15064  .dropStmt = delq->data));
15065 
15066  /* Dump Foreign Server Comments */
15067  if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
15068  dumpComment(fout, "SERVER", qsrvname,
15069  NULL, srvinfo->rolname,
15070  srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
15071 
15072  /* Handle the ACL */
15073  if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
15074  dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
15075  "FOREIGN SERVER", qsrvname, NULL, NULL,
15076  NULL, srvinfo->rolname, &srvinfo->dacl);
15077 
15078  /* Dump user mappings */
15079  if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
15080  dumpUserMappings(fout,
15081  srvinfo->dobj.name, NULL,
15082  srvinfo->rolname,
15083  srvinfo->dobj.catId, srvinfo->dobj.dumpId);
15084 
15085  PQclear(res);
15086 
15087  free(qsrvname);
15088 
15089  destroyPQExpBuffer(q);
15090  destroyPQExpBuffer(delq);
15091  destroyPQExpBuffer(query);
15092 }
15093 
15094 /*
15095  * dumpUserMappings
15096  *
15097  * This routine is used to dump any user mappings associated with the
15098  * server handed to this routine. Should be called after ArchiveEntry()
15099  * for the server.
15100  */
15101 static void
15103  const char *servername, const char *namespace,
15104  const char *owner,
15105  CatalogId catalogId, DumpId dumpId)
15106 {
15107  PQExpBuffer q;
15108  PQExpBuffer delq;
15109  PQExpBuffer query;
15110  PQExpBuffer tag;
15111  PGresult *res;
15112  int ntups;
15113  int i_usename;
15114  int i_umoptions;
15115  int i;
15116 
15117  q = createPQExpBuffer();
15118  tag = createPQExpBuffer();
15119  delq = createPQExpBuffer();
15120  query = createPQExpBuffer();
15121 
15122  /*
15123  * We read from the publicly accessible view pg_user_mappings, so as not
15124  * to fail if run by a non-superuser. Note that the view will show
15125  * umoptions as null if the user hasn't got privileges for the associated
15126  * server; this means that pg_dump will dump such a mapping, but with no
15127  * OPTIONS clause. A possible alternative is to skip such mappings
15128  * altogether, but it's not clear that that's an improvement.
15129  */
15130  appendPQExpBuffer(query,
15131  "SELECT usename, "
15132  "array_to_string(ARRAY("
15133  "SELECT quote_ident(option_name) || ' ' || "
15134  "quote_literal(option_value) "
15135  "FROM pg_options_to_table(umoptions) "
15136  "ORDER BY option_name"
15137  "), E',\n ') AS umoptions "
15138  "FROM pg_user_mappings "
15139  "WHERE srvid = '%u' "
15140  "ORDER BY usename",
15141  catalogId.oid);
15142 
15143  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15144 
15145  ntups = PQntuples(res);
15146  i_usename = PQfnumber(res, "usename");
15147  i_umoptions = PQfnumber(res, "umoptions");
15148 
15149  for (i = 0; i < ntups; i++)
15150  {
15151  char *usename;
15152  char *umoptions;
15153 
15154  usename = PQgetvalue(res, i, i_usename);
15155  umoptions = PQgetvalue(res, i, i_umoptions);
15156 
15157  resetPQExpBuffer(q);
15158  appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
15159  appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
15160 
15161  if (umoptions && strlen(umoptions) > 0)
15162  appendPQExpBuffer(q, " OPTIONS (\n %s\n)", umoptions);
15163 
15164  appendPQExpBufferStr(q, ";\n");
15165 
15166  resetPQExpBuffer(delq);
15167  appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
15168  appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
15169 
15170  resetPQExpBuffer(tag);
15171  appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
15172  usename, servername);
15173 
15175  ARCHIVE_OPTS(.tag = tag->data,
15176  .namespace = namespace,
15177  .owner = owner,
15178  .description = "USER MAPPING",
15179  .section = SECTION_PRE_DATA,
15180  .createStmt = q->data,
15181  .dropStmt = delq->data));
15182  }
15183 
15184  PQclear(res);
15185 
15186  destroyPQExpBuffer(query);
15187  destroyPQExpBuffer(delq);
15188  destroyPQExpBuffer(tag);
15189  destroyPQExpBuffer(q);
15190 }
15191 
15192 /*
15193  * Write out default privileges information
15194  */
15195 static void
15196 dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
15197 {
15198  DumpOptions *dopt = fout->dopt;
15199  PQExpBuffer q;
15200  PQExpBuffer tag;
15201  const char *type;
15202 
15203  /* Do nothing in data-only dump, or if we're skipping ACLs */
15204  if (dopt->dataOnly || dopt->aclsSkip)
15205  return;
15206 
15207  q = createPQExpBuffer();
15208  tag = createPQExpBuffer();
15209 
15210  switch (daclinfo->defaclobjtype)
15211  {
15212  case DEFACLOBJ_RELATION:
15213  type = "TABLES";
15214  break;
15215  case DEFACLOBJ_SEQUENCE:
15216  type = "SEQUENCES";
15217  break;
15218  case DEFACLOBJ_FUNCTION:
15219  type = "FUNCTIONS";
15220  break;
15221  case DEFACLOBJ_TYPE:
15222  type = "TYPES";
15223  break;
15224  case DEFACLOBJ_NAMESPACE:
15225  type = "SCHEMAS";
15226  break;
15227  default:
15228  /* shouldn't get here */
15229  pg_fatal("unrecognized object type in default privileges: %d",
15230  (int) daclinfo->defaclobjtype);
15231  type = ""; /* keep compiler quiet */
15232  }
15233 
15234  appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
15235 
15236  /* build the actual command(s) for this tuple */
15238  daclinfo->dobj.namespace != NULL ?
15239  daclinfo->dobj.namespace->dobj.name : NULL,
15240  daclinfo->dacl.acl,
15241  daclinfo->dacl.acldefault,
15242  daclinfo->defaclrole,
15243  fout->remoteVersion,
15244  q))
15245  pg_fatal("could not parse default ACL list (%s)",
15246  daclinfo->dacl.acl);
15247 
15248  if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
15249  ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
15250  ARCHIVE_OPTS(.tag = tag->data,
15251  .namespace = daclinfo->dobj.namespace ?
15252  daclinfo->dobj.namespace->dobj.name : NULL,
15253  .owner = daclinfo->defaclrole,
15254  .description = "DEFAULT ACL",
15255  .section = SECTION_POST_DATA,
15256  .createStmt = q->data));
15257 
15258  destroyPQExpBuffer(tag);
15259  destroyPQExpBuffer(q);
15260 }
15261 
15262 /*----------
15263  * Write out grant/revoke information
15264  *
15265  * 'objDumpId' is the dump ID of the underlying object.
15266  * 'altDumpId' can be a second dumpId that the ACL entry must also depend on,
15267  * or InvalidDumpId if there is no need for a second dependency.
15268  * 'type' must be one of
15269  * TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
15270  * FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
15271  * 'name' is the formatted name of the object. Must be quoted etc. already.
15272  * 'subname' is the formatted name of the sub-object, if any. Must be quoted.
15273  * (Currently we assume that subname is only provided for table columns.)
15274  * 'nspname' is the namespace the object is in (NULL if none).
15275  * 'tag' is the tag to use for the ACL TOC entry; typically, this is NULL
15276  * to use the default for the object type.
15277  * 'owner' is the owner, NULL if there is no owner (for languages).
15278  * 'dacl' is the DumpableAcl struct for the object.
15279  *
15280  * Returns the dump ID assigned to the ACL TocEntry, or InvalidDumpId if
15281  * no ACL entry was created.
15282  *----------
15283  */
15284 static DumpId
15285 dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
15286  const char *type, const char *name, const char *subname,
15287  const char *nspname, const char *tag, const char *owner,
15288  const DumpableAcl *dacl)
15289 {
15290  DumpId aclDumpId = InvalidDumpId;
15291  DumpOptions *dopt = fout->dopt;
15292  const char *acls = dacl->acl;
15293  const char *acldefault = dacl->acldefault;
15294  char privtype = dacl->privtype;
15295  const char *initprivs = dacl->initprivs;
15296  const char *baseacls;
15297  PQExpBuffer sql;
15298 
15299  /* Do nothing if ACL dump is not enabled */
15300  if (dopt->aclsSkip)
15301  return InvalidDumpId;
15302 
15303  /* --data-only skips ACLs *except* large object ACLs */
15304  if (dopt->dataOnly && strcmp(type, "LARGE OBJECT") != 0)
15305  return InvalidDumpId;
15306 
15307  sql = createPQExpBuffer();
15308 
15309  /*
15310  * In binary upgrade mode, we don't run an extension's script but instead
15311  * dump out the objects independently and then recreate them. To preserve
15312  * any initial privileges which were set on extension objects, we need to
15313  * compute the set of GRANT and REVOKE commands necessary to get from the
15314  * default privileges of an object to its initial privileges as recorded
15315  * in pg_init_privs.
15316  *
15317  * At restore time, we apply these commands after having called
15318  * binary_upgrade_set_record_init_privs(true). That tells the backend to
15319  * copy the results into pg_init_privs. This is how we preserve the
15320  * contents of that catalog across binary upgrades.
15321  */
15322  if (dopt->binary_upgrade && privtype == 'e' &&
15323  initprivs && *initprivs != '\0')
15324  {
15325  appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
15326  if (!buildACLCommands(name, subname, nspname, type,
15327  initprivs, acldefault, owner,
15328  "", fout->remoteVersion, sql))
15329  pg_fatal("could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)",
15330  initprivs, acldefault, name, type);
15331  appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
15332  }
15333 
15334  /*
15335  * Now figure the GRANT and REVOKE commands needed to get to the object's
15336  * actual current ACL, starting from the initprivs if given, else from the
15337  * object-type-specific default. Also, while buildACLCommands will assume
15338  * that a NULL/empty acls string means it needn't do anything, what that
15339  * actually represents is the object-type-specific default; so we need to
15340  * substitute the acldefault string to get the right results in that case.
15341  */
15342  if (initprivs && *initprivs != '\0')
15343  {
15344  baseacls = initprivs;
15345  if (acls == NULL || *acls == '\0')
15346  acls = acldefault;
15347  }
15348  else
15349  baseacls = acldefault;
15350 
15351  if (!buildACLCommands(name, subname, nspname, type,
15352  acls, baseacls, owner,
15353  "", fout->remoteVersion, sql))
15354  pg_fatal("could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)",
15355  acls, baseacls, name, type);
15356 
15357  if (sql->len > 0)
15358  {
15359  PQExpBuffer tagbuf = createPQExpBuffer();
15360  DumpId aclDeps[2];
15361  int nDeps = 0;
15362 
15363  if (tag)
15364  appendPQExpBufferStr(tagbuf, tag);
15365  else if (subname)
15366  appendPQExpBuffer(tagbuf, "COLUMN %s.%s", name, subname);
15367  else
15368  appendPQExpBuffer(tagbuf, "%s %s", type, name);
15369 
15370  aclDeps[nDeps++] = objDumpId;
15371  if (altDumpId != InvalidDumpId)
15372  aclDeps[nDeps++] = altDumpId;
15373 
15374  aclDumpId = createDumpId();
15375 
15376  ArchiveEntry(fout, nilCatalogId, aclDumpId,
15377  ARCHIVE_OPTS(.tag = tagbuf->data,
15378  .namespace = nspname,
15379  .owner = owner,
15380  .description = "ACL",
15381  .section = SECTION_NONE,
15382  .createStmt = sql->data,
15383  .deps = aclDeps,
15384  .nDeps = nDeps));
15385 
15386  destroyPQExpBuffer(tagbuf);
15387  }
15388 
15389  destroyPQExpBuffer(sql);
15390 
15391  return aclDumpId;
15392 }
15393 
15394 /*
15395  * dumpSecLabel
15396  *
15397  * This routine is used to dump any security labels associated with the
15398  * object handed to this routine. The routine takes the object type
15399  * and object name (ready to print, except for schema decoration), plus
15400  * the namespace and owner of the object (for labeling the ArchiveEntry),
15401  * plus catalog ID and subid which are the lookup key for pg_seclabel,
15402  * plus the dump ID for the object (for setting a dependency).
15403  * If a matching pg_seclabel entry is found, it is dumped.
15404  *
15405  * Note: although this routine takes a dumpId for dependency purposes,
15406  * that purpose is just to mark the dependency in the emitted dump file
15407  * for possible future use by pg_restore. We do NOT use it for determining
15408  * ordering of the label in the dump file, because this routine is called
15409  * after dependency sorting occurs. This routine should be called just after
15410  * calling ArchiveEntry() for the specified object.
15411  */
15412 static void
15413 dumpSecLabel(Archive *fout, const char *type, const char *name,
15414  const char *namespace, const char *owner,
15415  CatalogId catalogId, int subid, DumpId dumpId)
15416 {
15417  DumpOptions *dopt = fout->dopt;
15418  SecLabelItem *labels;
15419  int nlabels;
15420  int i;
15421  PQExpBuffer query;
15422 
15423  /* do nothing, if --no-security-labels is supplied */
15424  if (dopt->no_security_labels)
15425  return;
15426 
15427  /*
15428  * Security labels are schema not data ... except large object labels are
15429  * data
15430  */
15431  if (strcmp(type, "LARGE OBJECT") != 0)
15432  {
15433  if (dopt->dataOnly)
15434  return;
15435  }
15436  else
15437  {
15438  /* We do dump large object security labels in binary-upgrade mode */
15439  if (dopt->schemaOnly && !dopt->binary_upgrade)
15440  return;
15441  }
15442 
15443  /* Search for security labels associated with catalogId, using table */
15444  nlabels = findSecLabels(catalogId.tableoid, catalogId.oid, &labels);
15445 
15446  query = createPQExpBuffer();
15447 
15448  for (i = 0; i < nlabels; i++)
15449  {
15450  /*
15451  * Ignore label entries for which the subid doesn't match.
15452  */
15453  if (labels[i].objsubid != subid)
15454  continue;
15455 
15456  appendPQExpBuffer(query,
15457  "SECURITY LABEL FOR %s ON %s ",
15458  fmtId(labels[i].provider), type);
15459  if (namespace && *namespace)
15460  appendPQExpBuffer(query, "%s.", fmtId(namespace));
15461  appendPQExpBuffer(query, "%s IS ", name);
15462  appendStringLiteralAH(query, labels[i].label, fout);
15463  appendPQExpBufferStr(query, ";\n");
15464  }
15465 
15466  if (query->len > 0)
15467  {
15469 
15470  appendPQExpBuffer(tag, "%s %s", type, name);
15472  ARCHIVE_OPTS(.tag = tag->data,
15473  .namespace = namespace,
15474  .owner = owner,
15475  .description = "SECURITY LABEL",
15476  .section = SECTION_NONE,
15477  .createStmt = query->data,
15478  .deps = &dumpId,
15479  .nDeps = 1));
15480  destroyPQExpBuffer(tag);
15481  }
15482 
15483  destroyPQExpBuffer(query);
15484 }
15485 
15486 /*
15487  * dumpTableSecLabel
15488  *
15489  * As above, but dump security label for both the specified table (or view)
15490  * and its columns.
15491  */
15492 static void
15493 dumpTableSecLabel(Archive *fout, const TableInfo *tbinfo, const char *reltypename)
15494 {
15495  DumpOptions *dopt = fout->dopt;
15496  SecLabelItem *labels;
15497  int nlabels;
15498  int i;
15499  PQExpBuffer query;
15500  PQExpBuffer target;
15501 
15502  /* do nothing, if --no-security-labels is supplied */
15503  if (dopt->no_security_labels)
15504  return;
15505 
15506  /* SecLabel are SCHEMA not data */
15507  if (dopt->dataOnly)
15508  return;
15509 
15510  /* Search for comments associated with relation, using table */
15511  nlabels = findSecLabels(tbinfo->dobj.catId.tableoid,
15512  tbinfo->dobj.catId.oid,
15513  &labels);
15514 
15515  /* If security labels exist, build SECURITY LABEL statements */
15516  if (nlabels <= 0)
15517  return;
15518 
15519  query = createPQExpBuffer();
15520  target = createPQExpBuffer();
15521 
15522  for (i = 0; i < nlabels; i++)
15523  {
15524  const char *colname;
15525  const char *provider = labels[i].provider;
15526  const char *label = labels[i].label;
15527  int objsubid = labels[i].objsubid;
15528 
15529  resetPQExpBuffer(target);
15530  if (objsubid == 0)
15531  {
15532  appendPQExpBuffer(target, "%s %s", reltypename,
15533  fmtQualifiedDumpable(tbinfo));
15534  }
15535  else
15536  {
15537  colname = getAttrName(objsubid, tbinfo);
15538  /* first fmtXXX result must be consumed before calling again */
15539  appendPQExpBuffer(target, "COLUMN %s",
15540  fmtQualifiedDumpable(tbinfo));
15541  appendPQExpBuffer(target, ".%s", fmtId(colname));
15542  }
15543  appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
15544  fmtId(provider), target->data);
15545  appendStringLiteralAH(query, label, fout);
15546  appendPQExpBufferStr(query, ";\n");
15547  }
15548  if (query->len > 0)
15549  {
15550  resetPQExpBuffer(target);
15551  appendPQExpBuffer(target, "%s %s", reltypename,
15552  fmtId(tbinfo->dobj.name));
15554  ARCHIVE_OPTS(.tag = target->data,
15555  .namespace = tbinfo->dobj.namespace->dobj.name,
15556  .owner = tbinfo->rolname,
15557  .description = "SECURITY LABEL",
15558  .section = SECTION_NONE,
15559  .createStmt = query->data,
15560  .deps = &(tbinfo->dobj.dumpId),
15561  .nDeps = 1));
15562  }
15563  destroyPQExpBuffer(query);
15564  destroyPQExpBuffer(target);
15565 }
15566 
15567 /*
15568  * findSecLabels
15569  *
15570  * Find the security label(s), if any, associated with the given object.
15571  * All the objsubid values associated with the given classoid/objoid are
15572  * found with one search.
15573  */
15574 static int
15576 {
15577  SecLabelItem *middle = NULL;
15578  SecLabelItem *low;
15579  SecLabelItem *high;
15580  int nmatch;
15581 
15582  if (nseclabels <= 0) /* no labels, so no match is possible */
15583  {
15584  *items = NULL;
15585  return 0;
15586  }
15587 
15588  /*
15589  * Do binary search to find some item matching the object.
15590  */
15591  low = &seclabels[0];
15592  high = &seclabels[nseclabels - 1];
15593  while (low <= high)
15594  {
15595  middle = low + (high - low) / 2;
15596 
15597  if (classoid < middle->classoid)
15598  high = middle - 1;
15599  else if (classoid > middle->classoid)
15600  low = middle + 1;
15601  else if (objoid < middle->objoid)
15602  high = middle - 1;
15603  else if (objoid > middle->objoid)
15604  low = middle + 1;
15605  else
15606  break; /* found a match */
15607  }
15608 
15609  if (low > high) /* no matches */
15610  {
15611  *items = NULL;
15612  return 0;
15613  }
15614 
15615  /*
15616  * Now determine how many items match the object. The search loop
15617  * invariant still holds: only items between low and high inclusive could
15618  * match.
15619  */
15620  nmatch = 1;
15621  while (middle > low)
15622  {
15623  if (classoid != middle[-1].classoid ||
15624  objoid != middle[-1].objoid)
15625  break;
15626  middle--;
15627  nmatch++;
15628  }
15629 
15630  *items = middle;
15631 
15632  middle += nmatch;
15633  while (middle <= high)
15634  {
15635  if (classoid != middle->classoid ||
15636  objoid != middle->objoid)
15637  break;
15638  middle++;
15639  nmatch++;
15640  }
15641 
15642  return nmatch;
15643 }
15644 
15645 /*
15646  * collectSecLabels
15647  *
15648  * Construct a table of all security labels available for database objects;
15649  * also set the has-seclabel component flag for each relevant object.
15650  *
15651  * The table is sorted by classoid/objid/objsubid for speed in lookup.
15652  */
15653 static void
15655 {
15656  PGresult *res;
15657  PQExpBuffer query;
15658  int i_label;
15659  int i_provider;
15660  int i_classoid;
15661  int i_objoid;
15662  int i_objsubid;
15663  int ntups;
15664  int i;
15665  DumpableObject *dobj;
15666 
15667  query = createPQExpBuffer();
15668 
15669  appendPQExpBufferStr(query,
15670  "SELECT label, provider, classoid, objoid, objsubid "
15671  "FROM pg_catalog.pg_seclabel "
15672  "ORDER BY classoid, objoid, objsubid");
15673 
15674  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15675 
15676  /* Construct lookup table containing OIDs in numeric form */
15677  i_label = PQfnumber(res, "label");
15678  i_provider = PQfnumber(res, "provider");
15679  i_classoid = PQfnumber(res, "classoid");
15680  i_objoid = PQfnumber(res, "objoid");
15681  i_objsubid = PQfnumber(res, "objsubid");
15682 
15683  ntups = PQntuples(res);
15684 
15685  seclabels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
15686  nseclabels = 0;
15687  dobj = NULL;
15688 
15689  for (i = 0; i < ntups; i++)
15690  {
15691  CatalogId objId;
15692  int subid;
15693 
15694  objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
15695  objId.oid = atooid(PQgetvalue(res, i, i_objoid));
15696  subid = atoi(PQgetvalue(res, i, i_objsubid));
15697 
15698  /* We needn't remember labels that don't match any dumpable object */
15699  if (dobj == NULL ||
15700  dobj->catId.tableoid != objId.tableoid ||
15701  dobj->catId.oid != objId.oid)
15702  dobj = findObjectByCatalogId(objId);
15703  if (dobj == NULL)
15704  continue;
15705 
15706  /*
15707  * Labels on columns of composite types are linked to the type's
15708  * pg_class entry, but we need to set the DUMP_COMPONENT_SECLABEL flag
15709  * in the type's own DumpableObject.
15710  */
15711  if (subid != 0 && dobj->objType == DO_TABLE &&
15712  ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
15713  {
15714  TypeInfo *cTypeInfo;
15715 
15716  cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
15717  if (cTypeInfo)
15718  cTypeInfo->dobj.components |= DUMP_COMPONENT_SECLABEL;
15719  }
15720  else
15721  dobj->components |= DUMP_COMPONENT_SECLABEL;
15722 
15726  seclabels[nseclabels].objoid = objId.oid;
15727  seclabels[nseclabels].objsubid = subid;
15728  nseclabels++;
15729  }
15730 
15731  PQclear(res);
15732  destroyPQExpBuffer(query);
15733 }
15734 
15735 /*
15736  * dumpTable
15737  * write out to fout the declarations (not data) of a user-defined table
15738  */
15739 static void
15740 dumpTable(Archive *fout, const TableInfo *tbinfo)
15741 {
15742  DumpOptions *dopt = fout->dopt;
15743  DumpId tableAclDumpId = InvalidDumpId;
15744  char *namecopy;
15745 
15746  /* Do nothing in data-only dump */
15747  if (dopt->dataOnly)
15748  return;
15749 
15750  if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15751  {
15752  if (tbinfo->relkind == RELKIND_SEQUENCE)
15753  dumpSequence(fout, tbinfo);
15754  else
15755  dumpTableSchema(fout, tbinfo);
15756  }
15757 
15758  /* Handle the ACL here */
15759  namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
15760  if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15761  {
15762  const char *objtype =
15763  (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
15764 
15765  tableAclDumpId =
15766  dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
15767  objtype, namecopy, NULL,
15768  tbinfo->dobj.namespace->dobj.name,
15769  NULL, tbinfo->rolname, &tbinfo->dacl);
15770  }
15771 
15772  /*
15773  * Handle column ACLs, if any. Note: we pull these with a separate query
15774  * rather than trying to fetch them during getTableAttrs, so that we won't
15775  * miss ACLs on system columns. Doing it this way also allows us to dump
15776  * ACLs for catalogs that we didn't mark "interesting" back in getTables.
15777  */
15778  if ((tbinfo->dobj.dump & DUMP_COMPONENT_ACL) && tbinfo->hascolumnACLs)
15779  {
15780  PQExpBuffer query = createPQExpBuffer();
15781  PGresult *res;
15782  int i;
15783 
15785  {
15786  /* Set up query for column ACLs */
15787  appendPQExpBufferStr(query,
15788  "PREPARE getColumnACLs(pg_catalog.oid) AS\n");
15789 
15790  if (fout->remoteVersion >= 90600)
15791  {
15792  /*
15793  * In principle we should call acldefault('c', relowner) to
15794  * get the default ACL for a column. However, we don't
15795  * currently store the numeric OID of the relowner in
15796  * TableInfo. We could convert the owner name using regrole,
15797  * but that creates a risk of failure due to concurrent role
15798  * renames. Given that the default ACL for columns is empty
15799  * and is likely to stay that way, it's not worth extra cycles
15800  * and risk to avoid hard-wiring that knowledge here.
15801  */
15802  appendPQExpBufferStr(query,
15803  "SELECT at.attname, "
15804  "at.attacl, "
15805  "'{}' AS acldefault, "
15806  "pip.privtype, pip.initprivs "
15807  "FROM pg_catalog.pg_attribute at "
15808  "LEFT JOIN pg_catalog.pg_init_privs pip ON "
15809  "(at.attrelid = pip.objoid "
15810  "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
15811  "AND at.attnum = pip.objsubid) "
15812  "WHERE at.attrelid = $1 AND "
15813  "NOT at.attisdropped "
15814  "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "
15815  "ORDER BY at.attnum");
15816  }
15817  else
15818  {
15819  appendPQExpBufferStr(query,
15820  "SELECT attname, attacl, '{}' AS acldefault, "
15821  "NULL AS privtype, NULL AS initprivs "
15822  "FROM pg_catalog.pg_attribute "
15823  "WHERE attrelid = $1 AND NOT attisdropped "
15824  "AND attacl IS NOT NULL "
15825  "ORDER BY attnum");
15826  }
15827 
15828  ExecuteSqlStatement(fout, query->data);
15829 
15830  fout->is_prepared[PREPQUERY_GETCOLUMNACLS] = true;
15831  }
15832 
15833  printfPQExpBuffer(query,
15834  "EXECUTE getColumnACLs('%u')",
15835  tbinfo->dobj.catId.oid);
15836 
15837  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15838 
15839  for (i = 0; i < PQntuples(res); i++)
15840  {
15841  char *attname = PQgetvalue(res, i, 0);
15842  char *attacl = PQgetvalue(res, i, 1);
15843  char *acldefault = PQgetvalue(res, i, 2);
15844  char privtype = *(PQgetvalue(res, i, 3));
15845  char *initprivs = PQgetvalue(res, i, 4);
15846  DumpableAcl coldacl;
15847  char *attnamecopy;
15848 
15849  coldacl.acl = attacl;
15850  coldacl.acldefault = acldefault;
15851  coldacl.privtype = privtype;
15852  coldacl.initprivs = initprivs;
15853  attnamecopy = pg_strdup(fmtId(attname));
15854 
15855  /*
15856  * Column's GRANT type is always TABLE. Each column ACL depends
15857  * on the table-level ACL, since we can restore column ACLs in
15858  * parallel but the table-level ACL has to be done first.
15859  */
15860  dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
15861  "TABLE", namecopy, attnamecopy,
15862  tbinfo->dobj.namespace->dobj.name,
15863  NULL, tbinfo->rolname, &coldacl);
15864  free(attnamecopy);
15865  }
15866  PQclear(res);
15867  destroyPQExpBuffer(query);
15868  }
15869 
15870  free(namecopy);
15871 }
15872 
15873 /*
15874  * Create the AS clause for a view or materialized view. The semicolon is
15875  * stripped because a materialized view must add a WITH NO DATA clause.
15876  *
15877  * This returns a new buffer which must be freed by the caller.
15878  */
15879 static PQExpBuffer
15880 createViewAsClause(Archive *fout, const TableInfo *tbinfo)
15881 {
15882  PQExpBuffer query = createPQExpBuffer();
15883  PQExpBuffer result = createPQExpBuffer();
15884  PGresult *res;
15885  int len;
15886 
15887  /* Fetch the view definition */
15888  appendPQExpBuffer(query,
15889  "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
15890  tbinfo->dobj.catId.oid);
15891 
15892  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15893 
15894  if (PQntuples(res) != 1)
15895  {
15896  if (PQntuples(res) < 1)
15897  pg_fatal("query to obtain definition of view \"%s\" returned no data",
15898  tbinfo->dobj.name);
15899  else
15900  pg_fatal("query to obtain definition of view \"%s\" returned more than one definition",
15901  tbinfo->dobj.name);
15902  }
15903 
15904  len = PQgetlength(res, 0, 0);
15905 
15906  if (len == 0)
15907  pg_fatal("definition of view \"%s\" appears to be empty (length zero)",
15908  tbinfo->dobj.name);
15909 
15910  /* Strip off the trailing semicolon so that other things may follow. */
15911  Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
15912  appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
15913 
15914  PQclear(res);
15915  destroyPQExpBuffer(query);
15916 
15917  return result;
15918 }
15919 
15920 /*
15921  * Create a dummy AS clause for a view. This is used when the real view
15922  * definition has to be postponed because of circular dependencies.
15923  * We must duplicate the view's external properties -- column names and types
15924  * (including collation) -- so that it works for subsequent references.
15925  *
15926  * This returns a new buffer which must be freed by the caller.
15927  */
15928 static PQExpBuffer
15930 {
15931  PQExpBuffer result = createPQExpBuffer();
15932  int j;
15933 
15934  appendPQExpBufferStr(result, "SELECT");
15935 
15936  for (j = 0; j < tbinfo->numatts; j++)
15937  {
15938  if (j > 0)
15939  appendPQExpBufferChar(result, ',');
15940  appendPQExpBufferStr(result, "\n ");
15941 
15942  appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
15943 
15944  /*
15945  * Must add collation if not default for the type, because CREATE OR
15946  * REPLACE VIEW won't change it
15947  */
15948  if (OidIsValid(tbinfo->attcollation[j]))
15949  {
15950  CollInfo *coll;
15951 
15952  coll = findCollationByOid(tbinfo->attcollation[j]);
15953  if (coll)
15954  appendPQExpBuffer(result, " COLLATE %s",
15955  fmtQualifiedDumpable(coll));
15956  }
15957 
15958  appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
15959  }
15960 
15961  return result;
15962 }
15963 
15964 /*
15965  * dumpTableSchema
15966  * write the declaration (not data) of one user-defined table or view
15967  */
15968 static void
15969 dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
15970 {
15971  DumpOptions *dopt = fout->dopt;
15973  PQExpBuffer delq = createPQExpBuffer();
15974  char *qrelname;
15975  char *qualrelname;
15976  int numParents;
15977  TableInfo **parents;
15978  int actual_atts; /* number of attrs in this CREATE statement */
15979  const char *reltypename;
15980  char *storage;
15981  int j,
15982  k;
15983 
15984  /* We had better have loaded per-column details about this table */
15985  Assert(tbinfo->interesting);
15986 
15987  qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
15988  qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
15989 
15990  if (tbinfo->hasoids)
15991  pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
15992  qrelname);
15993 
15994  if (dopt->binary_upgrade)
15995  binary_upgrade_set_type_oids_by_rel(fout, q, tbinfo);
15996 
15997  /* Is it a table or a view? */
15998  if (tbinfo->relkind == RELKIND_VIEW)
15999  {
16000  PQExpBuffer result;
16001 
16002  /*
16003  * Note: keep this code in sync with the is_view case in dumpRule()
16004  */
16005 
16006  reltypename = "VIEW";
16007 
16008  appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
16009 
16010  if (dopt->binary_upgrade)
16012  tbinfo->dobj.catId.oid, false);
16013 
16014  appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
16015 
16016  if (tbinfo->dummy_view)
16017  result = createDummyViewAsClause(fout, tbinfo);
16018  else
16019  {
16020  if (nonemptyReloptions(tbinfo->reloptions))
16021  {
16022  appendPQExpBufferStr(q, " WITH (");
16023  appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
16024  appendPQExpBufferChar(q, ')');
16025  }
16026  result = createViewAsClause(fout, tbinfo);
16027  }
16028  appendPQExpBuffer(q, " AS\n%s", result->data);
16029  destroyPQExpBuffer(result);
16030 
16031  if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
16032  appendPQExpBuffer(q, "\n WITH %s CHECK OPTION", tbinfo->checkoption);
16033  appendPQExpBufferStr(q, ";\n");
16034  }
16035  else
16036  {
16037  char *partkeydef = NULL;
16038  char *ftoptions = NULL;
16039  char *srvname = NULL;
16040  char *foreign = "";
16041 
16042  /*
16043  * Set reltypename, and collect any relkind-specific data that we
16044  * didn't fetch during getTables().
16045  */
16046  switch (tbinfo->relkind)
16047  {
16048  case RELKIND_PARTITIONED_TABLE:
16049  {
16050  PQExpBuffer query = createPQExpBuffer();
16051  PGresult *res;
16052 
16053  reltypename = "TABLE";
16054 
16055  /* retrieve partition key definition */
16056  appendPQExpBuffer(query,
16057  "SELECT pg_get_partkeydef('%u')",
16058  tbinfo->dobj.catId.oid);
16059  res = ExecuteSqlQueryForSingleRow(fout, query->data);
16060  partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
16061  PQclear(res);
16062  destroyPQExpBuffer(query);
16063  break;
16064  }
16065  case RELKIND_FOREIGN_TABLE:
16066  {
16067  PQExpBuffer query = createPQExpBuffer();
16068  PGresult *res;
16069  int i_srvname;
16070  int i_ftoptions;
16071 
16072  reltypename = "FOREIGN TABLE";
16073 
16074  /* retrieve name of foreign server and generic options */
16075  appendPQExpBuffer(query,
16076  "SELECT fs.srvname, "
16077  "pg_catalog.array_to_string(ARRAY("
16078  "SELECT pg_catalog.quote_ident(option_name) || "
16079  "' ' || pg_catalog.quote_literal(option_value) "
16080  "FROM pg_catalog.pg_options_to_table(ftoptions) "
16081  "ORDER BY option_name"
16082  "), E',\n ') AS ftoptions "
16083  "FROM pg_catalog.pg_foreign_table ft "
16084  "JOIN pg_catalog.pg_foreign_server fs "
16085  "ON (fs.oid = ft.ftserver) "
16086  "WHERE ft.ftrelid = '%u'",
16087  tbinfo->dobj.catId.oid);
16088  res = ExecuteSqlQueryForSingleRow(fout, query->data);
16089  i_srvname = PQfnumber(res, "srvname");
16090  i_ftoptions = PQfnumber(res, "ftoptions");
16091  srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
16092  ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
16093  PQclear(res);
16094  destroyPQExpBuffer(query);
16095 
16096  foreign = "FOREIGN ";
16097  break;
16098  }
16099  case RELKIND_MATVIEW:
16100  reltypename = "MATERIALIZED VIEW";
16101  break;
16102  default:
16103  reltypename = "TABLE";
16104  break;
16105  }
16106 
16107  numParents = tbinfo->numParents;
16108  parents = tbinfo->parents;
16109 
16110  appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
16111 
16112  if (dopt->binary_upgrade)
16114  tbinfo->dobj.catId.oid, false);
16115 
16116  appendPQExpBuffer(q, "CREATE %s%s %s",
16117  tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
16118  "UNLOGGED " : "",
16119  reltypename,
16120  qualrelname);
16121 
16122  /*
16123  * Attach to type, if reloftype; except in case of a binary upgrade,
16124  * we dump the table normally and attach it to the type afterward.
16125  */
16126  if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
16127  appendPQExpBuffer(q, " OF %s",
16128  getFormattedTypeName(fout, tbinfo->reloftype,
16129  zeroIsError));
16130 
16131  if (tbinfo->relkind != RELKIND_MATVIEW)
16132  {
16133  /* Dump the attributes */
16134  actual_atts = 0;
16135  for (j = 0; j < tbinfo->numatts; j++)
16136  {
16137  /*
16138  * Normally, dump if it's locally defined in this table, and
16139  * not dropped. But for binary upgrade, we'll dump all the
16140  * columns, and then fix up the dropped and nonlocal cases
16141  * below.
16142  */
16143  if (shouldPrintColumn(dopt, tbinfo, j))
16144  {
16145  bool print_default;
16146  bool print_notnull;
16147 
16148  /*
16149  * Default value --- suppress if to be printed separately
16150  * or not at all.
16151  */
16152  print_default = (tbinfo->attrdefs[j] != NULL &&
16153  tbinfo->attrdefs[j]->dobj.dump &&
16154  !tbinfo->attrdefs[j]->separate);
16155 
16156  /*
16157  * Not Null constraint --- suppress unless it is locally
16158  * defined, except if partition, or in binary-upgrade case
16159  * where that won't work.
16160  */
16161  print_notnull =
16162  (tbinfo->notnull_constrs[j] != NULL &&
16163  (!tbinfo->notnull_inh[j] || tbinfo->ispartition ||
16164  dopt->binary_upgrade));
16165 
16166  /*
16167  * Skip column if fully defined by reloftype, except in
16168  * binary upgrade
16169  */
16170  if (OidIsValid(tbinfo->reloftype) &&
16171  !print_default && !print_notnull &&
16172  !dopt->binary_upgrade)
16173  continue;
16174 
16175  /* Format properly if not first attr */
16176  if (actual_atts == 0)
16177  appendPQExpBufferStr(q, " (");
16178  else
16179  appendPQExpBufferChar(q, ',');
16180  appendPQExpBufferStr(q, "\n ");
16181  actual_atts++;
16182 
16183  /* Attribute name */
16184  appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
16185 
16186  if (tbinfo->attisdropped[j])
16187  {
16188  /*
16189  * ALTER TABLE DROP COLUMN clears
16190  * pg_attribute.atttypid, so we will not have gotten a
16191  * valid type name; insert INTEGER as a stopgap. We'll
16192  * clean things up later.
16193  */
16194  appendPQExpBufferStr(q, " INTEGER /* dummy */");
16195  /* and skip to the next column */
16196  continue;
16197  }
16198 
16199  /*
16200  * Attribute type; print it except when creating a typed
16201  * table ('OF type_name'), but in binary-upgrade mode,
16202  * print it in that case too.
16203  */
16204  if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
16205  {
16206  appendPQExpBuffer(q, " %s",
16207  tbinfo->atttypnames[j]);
16208  }
16209 
16210  if (print_default)
16211  {
16212  if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
16213  appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
16214  tbinfo->attrdefs[j]->adef_expr);
16215  else
16216  appendPQExpBuffer(q, " DEFAULT %s",
16217  tbinfo->attrdefs[j]->adef_expr);
16218  }
16219 
16220 
16221  if (print_notnull)
16222  {
16223  if (tbinfo->notnull_constrs[j][0] == '\0')
16224  appendPQExpBufferStr(q, " NOT NULL");
16225  else
16226  appendPQExpBuffer(q, " CONSTRAINT %s NOT NULL",
16227  fmtId(tbinfo->notnull_constrs[j]));
16228 
16229  if (tbinfo->notnull_noinh[j])
16230  appendPQExpBufferStr(q, " NO INHERIT");
16231  }
16232 
16233  /* Add collation if not default for the type */
16234  if (OidIsValid(tbinfo->attcollation[j]))
16235  {
16236  CollInfo *coll;
16237 
16238  coll = findCollationByOid(tbinfo->attcollation[j]);
16239  if (coll)
16240  appendPQExpBuffer(q, " COLLATE %s",
16241  fmtQualifiedDumpable(coll));
16242  }
16243  }
16244  }
16245 
16246  /*
16247  * Add non-inherited CHECK constraints, if any.
16248  *
16249  * For partitions, we need to include check constraints even if
16250  * they're not defined locally, because the ALTER TABLE ATTACH
16251  * PARTITION that we'll emit later expects the constraint to be
16252  * there. (No need to fix conislocal: ATTACH PARTITION does that)
16253  */
16254  for (j = 0; j < tbinfo->ncheck; j++)
16255  {
16256  ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
16257 
16258  if (constr->separate ||
16259  (!constr->conislocal && !tbinfo->ispartition))
16260  continue;
16261 
16262  if (actual_atts == 0)
16263  appendPQExpBufferStr(q, " (\n ");
16264  else
16265  appendPQExpBufferStr(q, ",\n ");
16266 
16267  appendPQExpBuffer(q, "CONSTRAINT %s ",
16268  fmtId(constr->dobj.name));
16269  appendPQExpBufferStr(q, constr->condef);
16270 
16271  actual_atts++;
16272  }
16273 
16274  if (actual_atts)
16275  appendPQExpBufferStr(q, "\n)");
16276  else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
16277  {
16278  /*
16279  * No attributes? we must have a parenthesized attribute list,
16280  * even though empty, when not using the OF TYPE syntax.
16281  */
16282  appendPQExpBufferStr(q, " (\n)");
16283  }
16284 
16285  /*
16286  * Emit the INHERITS clause (not for partitions), except in
16287  * binary-upgrade mode.
16288  */
16289  if (numParents > 0 && !tbinfo->ispartition &&
16290  !dopt->binary_upgrade)
16291  {
16292  appendPQExpBufferStr(q, "\nINHERITS (");
16293  for (k = 0; k < numParents; k++)
16294  {
16295  TableInfo *parentRel = parents[k];
16296 
16297  if (k > 0)
16298  appendPQExpBufferStr(q, ", ");
16300  }
16301  appendPQExpBufferChar(q, ')');
16302  }
16303 
16304  if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
16305  appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
16306 
16307  if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
16308  appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
16309  }
16310 
16311  if (nonemptyReloptions(tbinfo->reloptions) ||
16313  {
16314  bool addcomma = false;
16315 
16316  appendPQExpBufferStr(q, "\nWITH (");
16317  if (nonemptyReloptions(tbinfo->reloptions))
16318  {
16319  addcomma = true;
16320  appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
16321  }
16322  if (nonemptyReloptions(tbinfo->toast_reloptions))
16323  {
16324  if (addcomma)
16325  appendPQExpBufferStr(q, ", ");
16326  appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
16327  fout);
16328  }
16329  appendPQExpBufferChar(q, ')');
16330  }
16331 
16332  /* Dump generic options if any */
16333  if (ftoptions && ftoptions[0])
16334  appendPQExpBuffer(q, "\nOPTIONS (\n %s\n)", ftoptions);
16335 
16336  /*
16337  * For materialized views, create the AS clause just like a view. At
16338  * this point, we always mark the view as not populated.
16339  */
16340  if (tbinfo->relkind == RELKIND_MATVIEW)
16341  {
16342  PQExpBuffer result;
16343 
16344  result = createViewAsClause(fout, tbinfo);
16345  appendPQExpBuffer(q, " AS\n%s\n WITH NO DATA;\n",
16346  result->data);
16347  destroyPQExpBuffer(result);
16348  }
16349  else
16350  appendPQExpBufferStr(q, ";\n");
16351 
16352  /* Materialized views can depend on extensions */
16353  if (tbinfo->relkind == RELKIND_MATVIEW)
16354  append_depends_on_extension(fout, q, &tbinfo->dobj,
16355  "pg_catalog.pg_class",
16356  "MATERIALIZED VIEW",
16357  qualrelname);
16358 
16359  /*
16360  * in binary upgrade mode, update the catalog with any missing values
16361  * that might be present.
16362  */
16363  if (dopt->binary_upgrade)
16364  {
16365  for (j = 0; j < tbinfo->numatts; j++)
16366  {
16367  if (tbinfo->attmissingval[j][0] != '\0')
16368  {
16369  appendPQExpBufferStr(q, "\n-- set missing value.\n");
16371  "SELECT pg_catalog.binary_upgrade_set_missing_value(");
16372  appendStringLiteralAH(q, qualrelname, fout);
16373  appendPQExpBufferStr(q, "::pg_catalog.regclass,");
16374  appendStringLiteralAH(q, tbinfo->attnames[j], fout);
16375  appendPQExpBufferChar(q, ',');
16376  appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
16377  appendPQExpBufferStr(q, ");\n\n");
16378  }
16379  }
16380  }
16381 
16382  /*
16383  * To create binary-compatible heap files, we have to ensure the same
16384  * physical column order, including dropped columns, as in the
16385  * original. Therefore, we create dropped columns above and drop them
16386  * here, also updating their attlen/attalign values so that the
16387  * dropped column can be skipped properly. (We do not bother with
16388  * restoring the original attbyval setting.) Also, inheritance
16389  * relationships are set up by doing ALTER TABLE INHERIT rather than
16390  * using an INHERITS clause --- the latter would possibly mess up the
16391  * column order. That also means we have to take care about setting
16392  * attislocal correctly, plus fix up any inherited CHECK constraints.
16393  * Analogously, we set up typed tables using ALTER TABLE / OF here.
16394  *
16395  * We process foreign and partitioned tables here, even though they
16396  * lack heap storage, because they can participate in inheritance
16397  * relationships and we want this stuff to be consistent across the
16398  * inheritance tree. We can exclude indexes, toast tables, sequences
16399  * and matviews, even though they have storage, because we don't
16400  * support altering or dropping columns in them, nor can they be part
16401  * of inheritance trees.
16402  */
16403  if (dopt->binary_upgrade &&
16404  (tbinfo->relkind == RELKIND_RELATION ||
16405  tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
16406  tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
16407  {
16408  for (j = 0; j < tbinfo->numatts; j++)
16409  {
16410  if (tbinfo->attisdropped[j])
16411  {
16412  appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
16413  appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
16414  "SET attlen = %d, "
16415  "attalign = '%c', attbyval = false\n"
16416  "WHERE attname = ",
16417  tbinfo->attlen[j],
16418  tbinfo->attalign[j]);
16419  appendStringLiteralAH(q, tbinfo->attnames[j], fout);
16420  appendPQExpBufferStr(q, "\n AND attrelid = ");
16421  appendStringLiteralAH(q, qualrelname, fout);
16422  appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16423 
16424  if (tbinfo->relkind == RELKIND_RELATION ||
16425  tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
16426  appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16427  qualrelname);
16428  else
16429  appendPQExpBuffer(q, "ALTER FOREIGN TABLE ONLY %s ",
16430  qualrelname);
16431  appendPQExpBuffer(q, "DROP COLUMN %s;\n",
16432  fmtId(tbinfo->attnames[j]));
16433  }
16434  else if (!tbinfo->attislocal[j])
16435  {
16436  appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
16437  appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
16438  "SET attislocal = false\n"
16439  "WHERE attname = ");
16440  appendStringLiteralAH(q, tbinfo->attnames[j], fout);
16441  appendPQExpBufferStr(q, "\n AND attrelid = ");
16442  appendStringLiteralAH(q, qualrelname, fout);
16443  appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16444 
16445  /*
16446  * If a not-null constraint comes from inheritance, reset
16447  * conislocal. The inhcount is fixed later.
16448  */
16449  if (tbinfo->notnull_constrs[j] != NULL &&
16450  !tbinfo->notnull_throwaway[j] &&
16451  tbinfo->notnull_inh[j] &&
16452  !tbinfo->ispartition)
16453  {
16454  appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
16455  "SET conislocal = false\n"
16456  "WHERE contype = 'n' AND conrelid = ");
16457  appendStringLiteralAH(q, qualrelname, fout);
16458  appendPQExpBufferStr(q, "::pg_catalog.regclass AND\n"
16459  "conname = ");
16460  appendStringLiteralAH(q, tbinfo->notnull_constrs[j], fout);
16461  appendPQExpBufferStr(q, ";\n");
16462  }
16463  }
16464  }
16465 
16466  /*
16467  * Add inherited CHECK constraints, if any.
16468  *
16469  * For partitions, they were already dumped, and conislocal
16470  * doesn't need fixing.
16471  */
16472  for (k = 0; k < tbinfo->ncheck; k++)
16473  {
16474  ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
16475 
16476  if (constr->separate || constr->conislocal || tbinfo->ispartition)
16477  continue;
16478 
16479  appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
16480  appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ADD CONSTRAINT %s %s;\n",
16481  foreign, qualrelname,
16482  fmtId(constr->dobj.name),
16483  constr->condef);
16484  appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
16485  "SET conislocal = false\n"
16486  "WHERE contype = 'c' AND conname = ");
16487  appendStringLiteralAH(q, constr->dobj.name, fout);
16488  appendPQExpBufferStr(q, "\n AND conrelid = ");
16489  appendStringLiteralAH(q, qualrelname, fout);
16490  appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16491  }
16492 
16493  if (numParents > 0 && !tbinfo->ispartition)
16494  {
16495  appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
16496  for (k = 0; k < numParents; k++)
16497  {
16498  TableInfo *parentRel = parents[k];
16499 
16500  appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s INHERIT %s;\n", foreign,
16501  qualrelname,
16502  fmtQualifiedDumpable(parentRel));
16503  }
16504  }
16505 
16506  if (OidIsValid(tbinfo->reloftype))
16507  {
16508  appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
16509  appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
16510  qualrelname,
16511  getFormattedTypeName(fout, tbinfo->reloftype,
16512  zeroIsError));
16513  }
16514  }
16515 
16516  /*
16517  * In binary_upgrade mode, arrange to restore the old relfrozenxid and
16518  * relminmxid of all vacuumable relations. (While vacuum.c processes
16519  * TOAST tables semi-independently, here we see them only as children
16520  * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
16521  * child toast table is handled below.)
16522  */
16523  if (dopt->binary_upgrade &&
16524  (tbinfo->relkind == RELKIND_RELATION ||
16525  tbinfo->relkind == RELKIND_MATVIEW))
16526  {
16527  appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
16528  appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
16529  "SET relfrozenxid = '%u', relminmxid = '%u'\n"
16530  "WHERE oid = ",
16531  tbinfo->frozenxid, tbinfo->minmxid);
16532  appendStringLiteralAH(q, qualrelname, fout);
16533  appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16534 
16535  if (tbinfo->toast_oid)
16536  {
16537  /*
16538  * The toast table will have the same OID at restore, so we
16539  * can safely target it by OID.
16540  */
16541  appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
16542  appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
16543  "SET relfrozenxid = '%u', relminmxid = '%u'\n"
16544  "WHERE oid = '%u';\n",
16545  tbinfo->toast_frozenxid,
16546  tbinfo->toast_minmxid, tbinfo->toast_oid);
16547  }
16548  }
16549 
16550  /*
16551  * In binary_upgrade mode, restore matviews' populated status by
16552  * poking pg_class directly. This is pretty ugly, but we can't use
16553  * REFRESH MATERIALIZED VIEW since it's possible that some underlying
16554  * matview is not populated even though this matview is; in any case,
16555  * we want to transfer the matview's heap storage, not run REFRESH.
16556  */
16557  if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
16558  tbinfo->relispopulated)
16559  {
16560  appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
16561  appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
16562  "SET relispopulated = 't'\n"
16563  "WHERE oid = ");
16564  appendStringLiteralAH(q, qualrelname, fout);
16565  appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16566  }
16567 
16568  /*
16569  * Dump additional per-column properties that we can't handle in the
16570  * main CREATE TABLE command.
16571  */
16572  for (j = 0; j < tbinfo->numatts; j++)
16573  {
16574  /* None of this applies to dropped columns */
16575  if (tbinfo->attisdropped[j])
16576  continue;
16577 
16578  /*
16579  * If we didn't dump the column definition explicitly above, and
16580  * it is not-null and did not inherit that property from a parent,
16581  * we have to mark it separately.
16582  */
16583  if (!shouldPrintColumn(dopt, tbinfo, j) &&
16584  tbinfo->notnull_constrs[j] != NULL &&
16585  (!tbinfo->notnull_inh[j] && !tbinfo->ispartition && !dopt->binary_upgrade))
16586  {
16587  /* No constraint name desired? */
16588  if (tbinfo->notnull_constrs[j][0] == '\0')
16590  "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET NOT NULL;\n",
16591  foreign, qualrelname,
16592  fmtId(tbinfo->attnames[j]));
16593  else
16595  "ALTER %sTABLE ONLY %s ADD CONSTRAINT %s NOT NULL %s;\n",
16596  foreign, qualrelname,
16597  tbinfo->notnull_constrs[j],
16598  fmtId(tbinfo->attnames[j]));
16599  }
16600 
16601  /*
16602  * Dump per-column statistics information. We only issue an ALTER
16603  * TABLE statement if the attstattarget entry for this column is
16604  * not the default value.
16605  */
16606  if (tbinfo->attstattarget[j] >= 0)
16607  appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STATISTICS %d;\n",
16608  foreign, qualrelname,
16609  fmtId(tbinfo->attnames[j]),
16610  tbinfo->attstattarget[j]);
16611 
16612  /*
16613  * Dump per-column storage information. The statement is only
16614  * dumped if the storage has been changed from the type's default.
16615  */
16616  if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
16617  {
16618  switch (tbinfo->attstorage[j])
16619  {
16620  case TYPSTORAGE_PLAIN:
16621  storage = "PLAIN";
16622  break;
16623  case TYPSTORAGE_EXTERNAL:
16624  storage = "EXTERNAL";
16625  break;
16626  case TYPSTORAGE_EXTENDED:
16627  storage = "EXTENDED";
16628  break;
16629  case TYPSTORAGE_MAIN:
16630  storage = "MAIN";
16631  break;
16632  default:
16633  storage = NULL;
16634  }
16635 
16636  /*
16637  * Only dump the statement if it's a storage type we recognize
16638  */
16639  if (storage != NULL)
16640  appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STORAGE %s;\n",
16641  foreign, qualrelname,
16642  fmtId(tbinfo->attnames[j]),
16643  storage);
16644  }
16645 
16646  /*
16647  * Dump per-column compression, if it's been set.
16648  */
16649  if (!dopt->no_toast_compression)
16650  {
16651  const char *cmname;
16652 
16653  switch (tbinfo->attcompression[j])
16654  {
16655  case 'p':
16656  cmname = "pglz";
16657  break;
16658  case 'l':
16659  cmname = "lz4";
16660  break;
16661  default:
16662  cmname = NULL;
16663  break;
16664  }
16665 
16666  if (cmname != NULL)
16667  appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET COMPRESSION %s;\n",
16668  foreign, qualrelname,
16669  fmtId(tbinfo->attnames[j]),
16670  cmname);
16671  }
16672 
16673  /*
16674  * Dump per-column attributes.
16675  */
16676  if (tbinfo->attoptions[j][0] != '\0')
16677  appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET (%s);\n",
16678  foreign, qualrelname,
16679  fmtId(tbinfo->attnames[j]),
16680  tbinfo->attoptions[j]);
16681 
16682  /*
16683  * Dump per-column fdw options.
16684  */
16685  if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
16686  tbinfo->attfdwoptions[j][0] != '\0')
16688  "ALTER FOREIGN TABLE %s ALTER COLUMN %s OPTIONS (\n"
16689  " %s\n"
16690  ");\n",
16691  qualrelname,
16692  fmtId(tbinfo->attnames[j]),
16693  tbinfo->attfdwoptions[j]);
16694  } /* end loop over columns */
16695 
16696  free(partkeydef);
16697  free(ftoptions);
16698  free(srvname);
16699  }
16700 
16701  /*
16702  * dump properties we only have ALTER TABLE syntax for
16703  */
16704  if ((tbinfo->relkind == RELKIND_RELATION ||
16705  tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
16706  tbinfo->relkind == RELKIND_MATVIEW) &&
16707  tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
16708  {
16709  if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
16710  {
16711  /* nothing to do, will be set when the index is dumped */
16712  }
16713  else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
16714  {
16715  appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
16716  qualrelname);
16717  }
16718  else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
16719  {
16720  appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
16721  qualrelname);
16722  }
16723  }
16724 
16725  if (tbinfo->forcerowsec)
16726  appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
16727  qualrelname);
16728 
16729  if (dopt->binary_upgrade)
16731  reltypename, qrelname,
16732  tbinfo->dobj.namespace->dobj.name);
16733 
16734  if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16735  {
16736  char *tablespace = NULL;
16737  char *tableam = NULL;
16738 
16739  /*
16740  * _selectTablespace() relies on tablespace-enabled objects in the
16741  * default tablespace to have a tablespace of "" (empty string) versus
16742  * non-tablespace-enabled objects to have a tablespace of NULL.
16743  * getTables() sets tbinfo->reltablespace to "" for the default
16744  * tablespace (not NULL).
16745  */
16746  if (RELKIND_HAS_TABLESPACE(tbinfo->relkind))
16747  tablespace = tbinfo->reltablespace;
16748 
16749  if (RELKIND_HAS_TABLE_AM(tbinfo->relkind) ||
16750  tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
16751  tableam = tbinfo->amname;
16752 
16753  ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
16754  ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
16755  .namespace = tbinfo->dobj.namespace->dobj.name,
16756  .tablespace = tablespace,
16757  .tableam = tableam,
16758  .relkind = tbinfo->relkind,
16759  .owner = tbinfo->rolname,
16760  .description = reltypename,
16761  .section = tbinfo->postponed_def ?
16763  .createStmt = q->data,
16764  .dropStmt = delq->data));
16765  }
16766 
16767  /* Dump Table Comments */
16768  if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16769  dumpTableComment(fout, tbinfo, reltypename);
16770 
16771  /* Dump Table Security Labels */
16772  if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
16773  dumpTableSecLabel(fout, tbinfo, reltypename);
16774 
16775  /* Dump comments on inlined table constraints */
16776  for (j = 0; j < tbinfo->ncheck; j++)
16777  {
16778  ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
16779 
16780  if (constr->separate || !constr->conislocal)
16781  continue;
16782 
16783  if (constr->dobj.dump & DUMP_COMPONENT_COMMENT)
16784  dumpTableConstraintComment(fout, constr);
16785  }
16786 
16787  destroyPQExpBuffer(q);
16788  destroyPQExpBuffer(delq);
16789  free(qrelname);
16790  free(qualrelname);
16791 }
16792 
16793 /*
16794  * dumpTableAttach
16795  * write to fout the commands to attach a child partition
16796  *
16797  * Child partitions are always made by creating them separately
16798  * and then using ATTACH PARTITION, rather than using
16799  * CREATE TABLE ... PARTITION OF. This is important for preserving
16800  * any possible discrepancy in column layout, to allow assigning the
16801  * correct tablespace if different, and so that it's possible to restore
16802  * a partition without restoring its parent. (You'll get an error from
16803  * the ATTACH PARTITION command, but that can be ignored, or skipped
16804  * using "pg_restore -L" if you prefer.) The last point motivates
16805  * treating ATTACH PARTITION as a completely separate ArchiveEntry
16806  * rather than emitting it within the child partition's ArchiveEntry.
16807  */
16808 static void
16809 dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
16810 {
16811  DumpOptions *dopt = fout->dopt;
16812  PQExpBuffer q;
16813  PGresult *res;
16814  char *partbound;
16815 
16816  /* Do nothing in data-only dump */
16817  if (dopt->dataOnly)
16818  return;
16819 
16820  q = createPQExpBuffer();
16821 
16823  {
16824  /* Set up query for partbound details */
16826  "PREPARE dumpTableAttach(pg_catalog.oid) AS\n");
16827 
16829  "SELECT pg_get_expr(c.relpartbound, c.oid) "
16830  "FROM pg_class c "
16831  "WHERE c.oid = $1");
16832 
16833  ExecuteSqlStatement(fout, q->data);
16834 
16835  fout->is_prepared[PREPQUERY_DUMPTABLEATTACH] = true;
16836  }
16837 
16839  "EXECUTE dumpTableAttach('%u')",
16840  attachinfo->partitionTbl->dobj.catId.oid);
16841 
16842  res = ExecuteSqlQueryForSingleRow(fout, q->data);
16843  partbound = PQgetvalue(res, 0, 0);
16844 
16845  /* Perform ALTER TABLE on the parent */
16847  "ALTER TABLE ONLY %s ",
16848  fmtQualifiedDumpable(attachinfo->parentTbl));
16850  "ATTACH PARTITION %s %s;\n",
16851  fmtQualifiedDumpable(attachinfo->partitionTbl),
16852  partbound);
16853 
16854  /*
16855  * There is no point in creating a drop query as the drop is done by table
16856  * drop. (If you think to change this, see also _printTocEntry().)
16857  * Although this object doesn't really have ownership as such, set the
16858  * owner field anyway to ensure that the command is run by the correct
16859  * role at restore time.
16860  */
16861  ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
16862  ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
16863  .namespace = attachinfo->dobj.namespace->dobj.name,
16864  .owner = attachinfo->partitionTbl->rolname,
16865  .description = "TABLE ATTACH",
16866  .section = SECTION_PRE_DATA,
16867  .createStmt = q->data));
16868 
16869  PQclear(res);
16870  destroyPQExpBuffer(q);
16871 }
16872 
16873 /*
16874  * dumpAttrDef --- dump an attribute's default-value declaration
16875  */
16876 static void
16877 dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo)
16878 {
16879  DumpOptions *dopt = fout->dopt;
16880  TableInfo *tbinfo = adinfo->adtable;
16881  int adnum = adinfo->adnum;
16882  PQExpBuffer q;
16883  PQExpBuffer delq;
16884  char *qualrelname;
16885  char *tag;
16886  char *foreign;
16887 
16888  /* Do nothing in data-only dump */
16889  if (dopt->dataOnly)
16890  return;
16891 
16892  /* Skip if not "separate"; it was dumped in the table's definition */
16893  if (!adinfo->separate)
16894  return;
16895 
16896  q = createPQExpBuffer();
16897  delq = createPQExpBuffer();
16898 
16899  qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
16900 
16901  foreign = tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
16902 
16904  "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET DEFAULT %s;\n",
16905  foreign, qualrelname, fmtId(tbinfo->attnames[adnum - 1]),
16906  adinfo->adef_expr);
16907 
16908  appendPQExpBuffer(delq, "ALTER %sTABLE %s ALTER COLUMN %s DROP DEFAULT;\n",
16909  foreign, qualrelname,
16910  fmtId(tbinfo->attnames[adnum - 1]));
16911 
16912  tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
16913 
16914  if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16915  ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
16916  ARCHIVE_OPTS(.tag = tag,
16917  .namespace = tbinfo->dobj.namespace->dobj.name,
16918  .owner = tbinfo->rolname,
16919  .description = "DEFAULT",
16920  .section = SECTION_PRE_DATA,
16921  .createStmt = q->data,
16922  .dropStmt = delq->data));
16923 
16924  free(tag);
16925  destroyPQExpBuffer(q);
16926  destroyPQExpBuffer(delq);
16927  free(qualrelname);
16928 }
16929 
16930 /*
16931  * getAttrName: extract the correct name for an attribute
16932  *
16933  * The array tblInfo->attnames[] only provides names of user attributes;
16934  * if a system attribute number is supplied, we have to fake it.
16935  * We also do a little bit of bounds checking for safety's sake.
16936  */
16937 static const char *
16938 getAttrName(int attrnum, const TableInfo *tblInfo)
16939 {
16940  if (attrnum > 0 && attrnum <= tblInfo->numatts)
16941  return tblInfo->attnames[attrnum - 1];
16942  switch (attrnum)
16943  {
16945  return "ctid";
16947  return "xmin";
16949  return "cmin";
16951  return "xmax";
16953  return "cmax";
16955  return "tableoid";
16956  }
16957  pg_fatal("invalid column number %d for table \"%s\"",
16958  attrnum, tblInfo->dobj.name);
16959  return NULL; /* keep compiler quiet */
16960 }
16961 
16962 /*
16963  * dumpIndex
16964  * write out to fout a user-defined index
16965  */
16966 static void
16967 dumpIndex(Archive *fout, const IndxInfo *indxinfo)
16968 {
16969  DumpOptions *dopt = fout->dopt;
16970  TableInfo *tbinfo = indxinfo->indextable;
16971  bool is_constraint = (indxinfo->indexconstraint != 0);
16972  PQExpBuffer q;
16973  PQExpBuffer delq;
16974  char *qindxname;
16975  char *qqindxname;
16976 
16977  /* Do nothing in data-only dump */
16978  if (dopt->dataOnly)
16979  return;
16980 
16981  q = createPQExpBuffer();
16982  delq = createPQExpBuffer();
16983 
16984  qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
16985  qqindxname = pg_strdup(fmtQualifiedDumpable(indxinfo));
16986 
16987  /*
16988  * If there's an associated constraint, don't dump the index per se, but
16989  * do dump any comment for it. (This is safe because dependency ordering
16990  * will have ensured the constraint is emitted first.) Note that the
16991  * emitted comment has to be shown as depending on the constraint, not the
16992  * index, in such cases.
16993  */
16994  if (!is_constraint)
16995  {
16996  char *indstatcols = indxinfo->indstatcols;
16997  char *indstatvals = indxinfo->indstatvals;
16998  char **indstatcolsarray = NULL;
16999  char **indstatvalsarray = NULL;
17000  int nstatcols = 0;
17001  int nstatvals = 0;
17002 
17003  if (dopt->binary_upgrade)
17005  indxinfo->dobj.catId.oid, true);
17006 
17007  /* Plain secondary index */
17008  appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
17009 
17010  /*
17011  * Append ALTER TABLE commands as needed to set properties that we
17012  * only have ALTER TABLE syntax for. Keep this in sync with the
17013  * similar code in dumpConstraint!
17014  */
17015 
17016  /* If the index is clustered, we need to record that. */
17017  if (indxinfo->indisclustered)
17018  {
17019  appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
17020  fmtQualifiedDumpable(tbinfo));
17021  /* index name is not qualified in this syntax */
17022  appendPQExpBuffer(q, " ON %s;\n",
17023  qindxname);
17024  }
17025 
17026  /*
17027  * If the index has any statistics on some of its columns, generate
17028  * the associated ALTER INDEX queries.
17029  */
17030  if (strlen(indstatcols) != 0 || strlen(indstatvals) != 0)
17031  {
17032  int j;
17033 
17034  if (!parsePGArray(indstatcols, &indstatcolsarray, &nstatcols))
17035  pg_fatal("could not parse index statistic columns");
17036  if (!parsePGArray(indstatvals, &indstatvalsarray, &nstatvals))
17037  pg_fatal("could not parse index statistic values");
17038  if (nstatcols != nstatvals)
17039  pg_fatal("mismatched number of columns and values for index statistics");
17040 
17041  for (j = 0; j < nstatcols; j++)
17042  {
17043  appendPQExpBuffer(q, "ALTER INDEX %s ", qqindxname);
17044 
17045  /*
17046  * Note that this is a column number, so no quotes should be
17047  * used.
17048  */
17049  appendPQExpBuffer(q, "ALTER COLUMN %s ",
17050  indstatcolsarray[j]);
17051  appendPQExpBuffer(q, "SET STATISTICS %s;\n",
17052  indstatvalsarray[j]);
17053  }
17054  }
17055 
17056  /* Indexes can depend on extensions */
17057  append_depends_on_extension(fout, q, &indxinfo->dobj,
17058  "pg_catalog.pg_class",
17059  "INDEX", qqindxname);
17060 
17061  /* If the index defines identity, we need to record that. */
17062  if (indxinfo->indisreplident)
17063  {
17064  appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
17065  fmtQualifiedDumpable(tbinfo));
17066  /* index name is not qualified in this syntax */
17067  appendPQExpBuffer(q, " INDEX %s;\n",
17068  qindxname);
17069  }
17070 
17071  appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
17072 
17073  if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17074  ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
17075  ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
17076  .namespace = tbinfo->dobj.namespace->dobj.name,
17077  .tablespace = indxinfo->tablespace,
17078  .owner = tbinfo->rolname,
17079  .description = "INDEX",
17080  .section = SECTION_POST_DATA,
17081  .createStmt = q->data,
17082  .dropStmt = delq->data));
17083 
17084  free(indstatcolsarray);
17085  free(indstatvalsarray);
17086  }
17087 
17088  /* Dump Index Comments */
17089  if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17090  dumpComment(fout, "INDEX", qindxname,
17091  tbinfo->dobj.namespace->dobj.name,
17092  tbinfo->rolname,
17093  indxinfo->dobj.catId, 0,
17094  is_constraint ? indxinfo->indexconstraint :
17095  indxinfo->dobj.dumpId);
17096 
17097  destroyPQExpBuffer(q);
17098  destroyPQExpBuffer(delq);
17099  free(qindxname);
17100  free(qqindxname);
17101 }
17102 
17103 /*
17104  * dumpIndexAttach
17105  * write out to fout a partitioned-index attachment clause
17106  */
17107 static void
17108 dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo)
17109 {
17110  /* Do nothing in data-only dump */
17111  if (fout->dopt->dataOnly)
17112  return;
17113 
17114  if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
17115  {
17117 
17118  appendPQExpBuffer(q, "ALTER INDEX %s ",
17119  fmtQualifiedDumpable(attachinfo->parentIdx));
17120  appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
17121  fmtQualifiedDumpable(attachinfo->partitionIdx));
17122 
17123  /*
17124  * There is no point in creating a drop query as the drop is done by
17125  * index drop. (If you think to change this, see also
17126  * _printTocEntry().) Although this object doesn't really have
17127  * ownership as such, set the owner field anyway to ensure that the
17128  * command is run by the correct role at restore time.
17129  */
17130  ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
17131  ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
17132  .namespace = attachinfo->dobj.namespace->dobj.name,
17133  .owner = attachinfo->parentIdx->indextable->rolname,
17134  .description = "INDEX ATTACH",
17135  .section = SECTION_POST_DATA,
17136  .createStmt = q->data));
17137 
17138  destroyPQExpBuffer(q);
17139  }
17140 }
17141 
17142 /*
17143  * dumpStatisticsExt
17144  * write out to fout an extended statistics object
17145  */
17146 static void
17147 dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo)
17148 {
17149  DumpOptions *dopt = fout->dopt;
17150  PQExpBuffer q;
17151  PQExpBuffer delq;
17152  PQExpBuffer query;
17153  char *qstatsextname;
17154  PGresult *res;
17155  char *stxdef;
17156 
17157  /* Do nothing in data-only dump */
17158  if (dopt->dataOnly)
17159  return;
17160 
17161  q = createPQExpBuffer();
17162  delq = createPQExpBuffer();
17163  query = createPQExpBuffer();
17164 
17165  qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
17166 
17167  appendPQExpBuffer(query, "SELECT "
17168  "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
17169  statsextinfo->dobj.catId.oid);
17170 
17171  res = ExecuteSqlQueryForSingleRow(fout, query->data);
17172 
17173  stxdef = PQgetvalue(res, 0, 0);
17174 
17175  /* Result of pg_get_statisticsobjdef is complete except for semicolon */
17176  appendPQExpBuffer(q, "%s;\n", stxdef);
17177 
17178  /*
17179  * We only issue an ALTER STATISTICS statement if the stxstattarget entry
17180  * for this statistics object is not the default value.
17181  */
17182  if (statsextinfo->stattarget >= 0)
17183  {
17184  appendPQExpBuffer(q, "ALTER STATISTICS %s ",
17185  fmtQualifiedDumpable(statsextinfo));
17186  appendPQExpBuffer(q, "SET STATISTICS %d;\n",
17187  statsextinfo->stattarget);
17188  }
17189 
17190  appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
17191  fmtQualifiedDumpable(statsextinfo));
17192 
17193  if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17194  ArchiveEntry(fout, statsextinfo->dobj.catId,
17195  statsextinfo->dobj.dumpId,
17196  ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
17197  .namespace = statsextinfo->dobj.namespace->dobj.name,
17198  .owner = statsextinfo->rolname,
17199  .description = "STATISTICS",
17200  .section = SECTION_POST_DATA,
17201  .createStmt = q->data,
17202  .dropStmt = delq->data));
17203 
17204  /* Dump Statistics Comments */
17205  if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17206  dumpComment(fout, "STATISTICS", qstatsextname,
17207  statsextinfo->dobj.namespace->dobj.name,
17208  statsextinfo->rolname,
17209  statsextinfo->dobj.catId, 0,
17210  statsextinfo->dobj.dumpId);
17211 
17212  PQclear(res);
17213  destroyPQExpBuffer(q);
17214  destroyPQExpBuffer(delq);
17215  destroyPQExpBuffer(query);
17216  free(qstatsextname);
17217 }
17218 
17219 /*
17220  * dumpConstraint
17221  * write out to fout a user-defined constraint
17222  */
17223 static void
17224 dumpConstraint(Archive *fout, const ConstraintInfo *coninfo)
17225 {
17226  DumpOptions *dopt = fout->dopt;
17227  TableInfo *tbinfo = coninfo->contable;
17228  PQExpBuffer q;
17229  PQExpBuffer delq;
17230  char *tag = NULL;
17231  char *foreign;
17232 
17233  /* Do nothing in data-only dump */
17234  if (dopt->dataOnly)
17235  return;
17236 
17237  q = createPQExpBuffer();
17238  delq = createPQExpBuffer();
17239 
17240  foreign = tbinfo &&
17241  tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
17242 
17243  if (coninfo->contype == 'p' ||
17244  coninfo->contype == 'u' ||
17245  coninfo->contype == 'x')
17246  {
17247  /* Index-related constraint */
17248  IndxInfo *indxinfo;
17249  int k;
17250 
17251  indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
17252 
17253  if (indxinfo == NULL)
17254  pg_fatal("missing index for constraint \"%s\"",
17255  coninfo->dobj.name);
17256 
17257  if (dopt->binary_upgrade)
17259  indxinfo->dobj.catId.oid, true);
17260 
17261  appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s\n", foreign,
17262  fmtQualifiedDumpable(tbinfo));
17263  appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
17264  fmtId(coninfo->dobj.name));
17265 
17266  if (coninfo->condef)
17267  {
17268  /* pg_get_constraintdef should have provided everything */
17269  appendPQExpBuffer(q, "%s;\n", coninfo->condef);
17270  }
17271  else
17272  {
17274  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
17275 
17276  /*
17277  * PRIMARY KEY constraints should not be using NULLS NOT DISTINCT
17278  * indexes. Being able to create this was fixed, but we need to
17279  * make the index distinct in order to be able to restore the
17280  * dump.
17281  */
17282  if (indxinfo->indnullsnotdistinct && coninfo->contype != 'p')
17283  appendPQExpBufferStr(q, " NULLS NOT DISTINCT");
17284  appendPQExpBufferStr(q, " (");
17285  for (k = 0; k < indxinfo->indnkeyattrs; k++)
17286  {
17287  int indkey = (int) indxinfo->indkeys[k];
17288  const char *attname;
17289 
17290  if (indkey == InvalidAttrNumber)
17291  break;
17292  attname = getAttrName(indkey, tbinfo);
17293 
17294  appendPQExpBuffer(q, "%s%s",
17295  (k == 0) ? "" : ", ",
17296  fmtId(attname));
17297  }
17298  if (coninfo->conperiod)
17299  appendPQExpBufferStr(q, " WITHOUT OVERLAPS");
17300 
17301  if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
17302  appendPQExpBufferStr(q, ") INCLUDE (");
17303 
17304  for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
17305  {
17306  int indkey = (int) indxinfo->indkeys[k];
17307  const char *attname;
17308 
17309  if (indkey == InvalidAttrNumber)
17310  break;
17311  attname = getAttrName(indkey, tbinfo);
17312 
17313  appendPQExpBuffer(q, "%s%s",
17314  (k == indxinfo->indnkeyattrs) ? "" : ", ",
17315  fmtId(attname));
17316  }
17317 
17318  appendPQExpBufferChar(q, ')');
17319 
17320  if (nonemptyReloptions(indxinfo->indreloptions))
17321  {
17322  appendPQExpBufferStr(q, " WITH (");
17323  appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
17324  appendPQExpBufferChar(q, ')');
17325  }
17326 
17327  if (coninfo->condeferrable)
17328  {
17329  appendPQExpBufferStr(q, " DEFERRABLE");
17330  if (coninfo->condeferred)
17331  appendPQExpBufferStr(q, " INITIALLY DEFERRED");
17332  }
17333 
17334  appendPQExpBufferStr(q, ";\n");
17335  }
17336 
17337  /*
17338  * Append ALTER TABLE commands as needed to set properties that we
17339  * only have ALTER TABLE syntax for. Keep this in sync with the
17340  * similar code in dumpIndex!
17341  */
17342 
17343  /*
17344  * Drop any not-null constraints that were added to support the PK,
17345  * but leave them alone if they have a definition coming from their
17346  * parent.
17347  */
17348  if (coninfo->contype == 'p')
17349  for (int i = 0; i < tbinfo->numatts; i++)
17350  if (tbinfo->notnull_throwaway[i] &&
17351  !tbinfo->notnull_inh[i])
17352  appendPQExpBuffer(q, "\nALTER TABLE ONLY %s DROP CONSTRAINT %s;",
17353  fmtQualifiedDumpable(tbinfo),
17354  tbinfo->notnull_constrs[i]);
17355 
17356  /* If the index is clustered, we need to record that. */
17357  if (indxinfo->indisclustered)
17358  {
17359  appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
17360  fmtQualifiedDumpable(tbinfo));
17361  /* index name is not qualified in this syntax */
17362  appendPQExpBuffer(q, " ON %s;\n",
17363  fmtId(indxinfo->dobj.name));
17364  }
17365 
17366  /* If the index defines identity, we need to record that. */
17367  if (indxinfo->indisreplident)
17368  {
17369  appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
17370  fmtQualifiedDumpable(tbinfo));
17371  /* index name is not qualified in this syntax */
17372  appendPQExpBuffer(q, " INDEX %s;\n",
17373  fmtId(indxinfo->dobj.name));
17374  }
17375 
17376  /* Indexes can depend on extensions */
17377  append_depends_on_extension(fout, q, &indxinfo->dobj,
17378  "pg_catalog.pg_class", "INDEX",
17379  fmtQualifiedDumpable(indxinfo));
17380 
17381  appendPQExpBuffer(delq, "ALTER %sTABLE ONLY %s ", foreign,
17382  fmtQualifiedDumpable(tbinfo));
17383  appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
17384  fmtId(coninfo->dobj.name));
17385 
17386  tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
17387 
17388  if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17389  ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
17390  ARCHIVE_OPTS(.tag = tag,
17391  .namespace = tbinfo->dobj.namespace->dobj.name,
17392  .tablespace = indxinfo->tablespace,
17393  .owner = tbinfo->rolname,
17394  .description = "CONSTRAINT",
17395  .section = SECTION_POST_DATA,
17396  .createStmt = q->data,
17397  .dropStmt = delq->data));
17398  }
17399  else if (coninfo->contype == 'f')
17400  {
17401  char *only;
17402 
17403  /*
17404  * Foreign keys on partitioned tables are always declared as
17405  * inheriting to partitions; for all other cases, emit them as
17406  * applying ONLY directly to the named table, because that's how they
17407  * work for regular inherited tables.
17408  */
17409  only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
17410 
17411  /*
17412  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
17413  * current table data is not processed
17414  */
17415  appendPQExpBuffer(q, "ALTER %sTABLE %s%s\n", foreign,
17416  only, fmtQualifiedDumpable(tbinfo));
17417  appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
17418  fmtId(coninfo->dobj.name),
17419  coninfo->condef);
17420 
17421  appendPQExpBuffer(delq, "ALTER %sTABLE %s%s ", foreign,
17422  only, fmtQualifiedDumpable(tbinfo));
17423  appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
17424  fmtId(coninfo->dobj.name));
17425 
17426  tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
17427 
17428  if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17429  ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
17430  ARCHIVE_OPTS(.tag = tag,
17431  .namespace = tbinfo->dobj.namespace->dobj.name,
17432  .owner = tbinfo->rolname,
17433  .description = "FK CONSTRAINT",
17434  .section = SECTION_POST_DATA,
17435  .createStmt = q->data,
17436  .dropStmt = delq->data));
17437  }
17438  else if (coninfo->contype == 'c' && tbinfo)
17439  {
17440  /* CHECK constraint on a table */
17441 
17442  /* Ignore if not to be dumped separately, or if it was inherited */
17443  if (coninfo->separate && coninfo->conislocal)
17444  {
17445  /* not ONLY since we want it to propagate to children */
17446  appendPQExpBuffer(q, "ALTER %sTABLE %s\n", foreign,
17447  fmtQualifiedDumpable(tbinfo));
17448  appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
17449  fmtId(coninfo->dobj.name),
17450  coninfo->condef);
17451 
17452  appendPQExpBuffer(delq, "ALTER %sTABLE %s ", foreign,
17453  fmtQualifiedDumpable(tbinfo));
17454  appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
17455  fmtId(coninfo->dobj.name));
17456 
17457  tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
17458 
17459  if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17460  ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
17461  ARCHIVE_OPTS(.tag = tag,
17462  .namespace = tbinfo->dobj.namespace->dobj.name,
17463  .owner = tbinfo->rolname,
17464  .description = "CHECK CONSTRAINT",
17465  .section = SECTION_POST_DATA,
17466  .createStmt = q->data,
17467  .dropStmt = delq->data));
17468  }
17469  }
17470  else if (coninfo->contype == 'c' && tbinfo == NULL)
17471  {
17472  /* CHECK constraint on a domain */
17473  TypeInfo *tyinfo = coninfo->condomain;
17474 
17475  /* Ignore if not to be dumped separately */
17476  if (coninfo->separate)
17477  {
17478  appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
17479  fmtQualifiedDumpable(tyinfo));
17480  appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
17481  fmtId(coninfo->dobj.name),
17482  coninfo->condef);
17483 
17484  appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
17485  fmtQualifiedDumpable(tyinfo));
17486  appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
17487  fmtId(coninfo->dobj.name));
17488 
17489  tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
17490 
17491  if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17492  ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
17493  ARCHIVE_OPTS(.tag = tag,
17494  .namespace = tyinfo->dobj.namespace->dobj.name,
17495  .owner = tyinfo->rolname,
17496  .description = "CHECK CONSTRAINT",
17497  .section = SECTION_POST_DATA,
17498  .createStmt = q->data,
17499  .dropStmt = delq->data));
17500  }
17501  }
17502  else
17503  {
17504  pg_fatal("unrecognized constraint type: %c",
17505  coninfo->contype);
17506  }
17507 
17508  /* Dump Constraint Comments --- only works for table constraints */
17509  if (tbinfo && coninfo->separate &&
17510  coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17511  dumpTableConstraintComment(fout, coninfo);
17512 
17513  free(tag);
17514  destroyPQExpBuffer(q);
17515  destroyPQExpBuffer(delq);
17516 }
17517 
17518 /*
17519  * dumpTableConstraintComment --- dump a constraint's comment if any
17520  *
17521  * This is split out because we need the function in two different places
17522  * depending on whether the constraint is dumped as part of CREATE TABLE
17523  * or as a separate ALTER command.
17524  */
17525 static void
17527 {
17528  TableInfo *tbinfo = coninfo->contable;
17529  PQExpBuffer conprefix = createPQExpBuffer();
17530  char *qtabname;
17531 
17532  qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17533 
17534  appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
17535  fmtId(coninfo->dobj.name));
17536 
17537  if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17538  dumpComment(fout, conprefix->data, qtabname,
17539  tbinfo->dobj.namespace->dobj.name,
17540  tbinfo->rolname,
17541  coninfo->dobj.catId, 0,
17542  coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
17543 
17544  destroyPQExpBuffer(conprefix);
17545  free(qtabname);
17546 }
17547 
17548 /*
17549  * dumpSequence
17550  * write the declaration (not data) of one user-defined sequence
17551  */
17552 static void
17553 dumpSequence(Archive *fout, const TableInfo *tbinfo)
17554 {
17555  DumpOptions *dopt = fout->dopt;
17556  PGresult *res;
17557  char *startv,
17558  *incby,
17559  *maxv,
17560  *minv,
17561  *cache,
17562  *seqtype;
17563  bool cycled;
17564  bool is_ascending;
17565  int64 default_minv,
17566  default_maxv;
17567  char bufm[32],
17568  bufx[32];
17569  PQExpBuffer query = createPQExpBuffer();
17570  PQExpBuffer delqry = createPQExpBuffer();
17571  char *qseqname;
17572  TableInfo *owning_tab = NULL;
17573 
17574  qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
17575 
17576  if (fout->remoteVersion >= 100000)
17577  {
17578  appendPQExpBuffer(query,
17579  "SELECT format_type(seqtypid, NULL), "
17580  "seqstart, seqincrement, "
17581  "seqmax, seqmin, "
17582  "seqcache, seqcycle "
17583  "FROM pg_catalog.pg_sequence "
17584  "WHERE seqrelid = '%u'::oid",
17585  tbinfo->dobj.catId.oid);
17586  }
17587  else
17588  {
17589  /*
17590  * Before PostgreSQL 10, sequence metadata is in the sequence itself.
17591  *
17592  * Note: it might seem that 'bigint' potentially needs to be
17593  * schema-qualified, but actually that's a keyword.
17594  */
17595  appendPQExpBuffer(query,
17596  "SELECT 'bigint' AS sequence_type, "
17597  "start_value, increment_by, max_value, min_value, "
17598  "cache_value, is_cycled FROM %s",
17599  fmtQualifiedDumpable(tbinfo));
17600  }
17601 
17602  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17603 
17604  if (PQntuples(res) != 1)
17605  pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
17606  "query to get data of sequence \"%s\" returned %d rows (expected 1)",
17607  PQntuples(res)),
17608  tbinfo->dobj.name, PQntuples(res));
17609 
17610  seqtype = PQgetvalue(res, 0, 0);
17611  startv = PQgetvalue(res, 0, 1);
17612  incby = PQgetvalue(res, 0, 2);
17613  maxv = PQgetvalue(res, 0, 3);
17614  minv = PQgetvalue(res, 0, 4);
17615  cache = PQgetvalue(res, 0, 5);
17616  cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
17617 
17618  /* Calculate default limits for a sequence of this type */
17619  is_ascending = (incby[0] != '-');
17620  if (strcmp(seqtype, "smallint") == 0)
17621  {
17622  default_minv = is_ascending ? 1 : PG_INT16_MIN;
17623  default_maxv = is_ascending ? PG_INT16_MAX : -1;
17624  }
17625  else if (strcmp(seqtype, "integer") == 0)
17626  {
17627  default_minv = is_ascending ? 1 : PG_INT32_MIN;
17628  default_maxv = is_ascending ? PG_INT32_MAX : -1;
17629  }
17630  else if (strcmp(seqtype, "bigint") == 0)
17631  {
17632  default_minv = is_ascending ? 1 : PG_INT64_MIN;
17633  default_maxv = is_ascending ? PG_INT64_MAX : -1;
17634  }
17635  else
17636  {
17637  pg_fatal("unrecognized sequence type: %s", seqtype);
17638  default_minv = default_maxv = 0; /* keep compiler quiet */
17639  }
17640 
17641  /*
17642  * 64-bit strtol() isn't very portable, so convert the limits to strings
17643  * and compare that way.
17644  */
17645  snprintf(bufm, sizeof(bufm), INT64_FORMAT, default_minv);
17646  snprintf(bufx, sizeof(bufx), INT64_FORMAT, default_maxv);
17647 
17648  /* Don't print minv/maxv if they match the respective default limit */
17649  if (strcmp(minv, bufm) == 0)
17650  minv = NULL;
17651  if (strcmp(maxv, bufx) == 0)
17652  maxv = NULL;
17653 
17654  /*
17655  * Identity sequences are not to be dropped separately.
17656  */
17657  if (!tbinfo->is_identity_sequence)
17658  {
17659  appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
17660  fmtQualifiedDumpable(tbinfo));
17661  }
17662 
17663  resetPQExpBuffer(query);
17664 
17665  if (dopt->binary_upgrade)
17666  {
17668  tbinfo->dobj.catId.oid, false);
17669 
17670  /*
17671  * In older PG versions a sequence will have a pg_type entry, but v14
17672  * and up don't use that, so don't attempt to preserve the type OID.
17673  */
17674  }
17675 
17676  if (tbinfo->is_identity_sequence)
17677  {
17678  owning_tab = findTableByOid(tbinfo->owning_tab);
17679 
17680  appendPQExpBuffer(query,
17681  "ALTER TABLE %s ",
17682  fmtQualifiedDumpable(owning_tab));
17683  appendPQExpBuffer(query,
17684  "ALTER COLUMN %s ADD GENERATED ",
17685  fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
17686  if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
17687  appendPQExpBufferStr(query, "ALWAYS");
17688  else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
17689  appendPQExpBufferStr(query, "BY DEFAULT");
17690  appendPQExpBuffer(query, " AS IDENTITY (\n SEQUENCE NAME %s\n",
17691  fmtQualifiedDumpable(tbinfo));
17692  }
17693  else
17694  {
17695  appendPQExpBuffer(query,
17696  "CREATE %sSEQUENCE %s\n",
17697  tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
17698  "UNLOGGED " : "",
17699  fmtQualifiedDumpable(tbinfo));
17700 
17701  if (strcmp(seqtype, "bigint") != 0)
17702  appendPQExpBuffer(query, " AS %s\n", seqtype);
17703  }
17704 
17705  appendPQExpBuffer(query, " START WITH %s\n", startv);
17706 
17707  appendPQExpBuffer(query, " INCREMENT BY %s\n", incby);
17708 
17709  if (minv)
17710  appendPQExpBuffer(query, " MINVALUE %s\n", minv);
17711  else
17712  appendPQExpBufferStr(query, " NO MINVALUE\n");
17713 
17714  if (maxv)
17715  appendPQExpBuffer(query, " MAXVALUE %s\n", maxv);
17716  else
17717  appendPQExpBufferStr(query, " NO MAXVALUE\n");
17718 
17719  appendPQExpBuffer(query,
17720  " CACHE %s%s",
17721  cache, (cycled ? "\n CYCLE" : ""));
17722 
17723  if (tbinfo->is_identity_sequence)
17724  {
17725  appendPQExpBufferStr(query, "\n);\n");
17726  if (tbinfo->relpersistence != owning_tab->relpersistence)
17727  appendPQExpBuffer(query,
17728  "ALTER SEQUENCE %s SET %s;\n",
17729  fmtQualifiedDumpable(tbinfo),
17730  tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
17731  "UNLOGGED" : "LOGGED");
17732  }
17733  else
17734  appendPQExpBufferStr(query, ";\n");
17735 
17736  /* binary_upgrade: no need to clear TOAST table oid */
17737 
17738  if (dopt->binary_upgrade)
17739  binary_upgrade_extension_member(query, &tbinfo->dobj,
17740  "SEQUENCE", qseqname,
17741  tbinfo->dobj.namespace->dobj.name);
17742 
17743  if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17744  ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
17745  ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17746  .namespace = tbinfo->dobj.namespace->dobj.name,
17747  .owner = tbinfo->rolname,
17748  .description = "SEQUENCE",
17749  .section = SECTION_PRE_DATA,
17750  .createStmt = query->data,
17751  .dropStmt = delqry->data));
17752 
17753  /*
17754  * If the sequence is owned by a table column, emit the ALTER for it as a
17755  * separate TOC entry immediately following the sequence's own entry. It's
17756  * OK to do this rather than using full sorting logic, because the
17757  * dependency that tells us it's owned will have forced the table to be
17758  * created first. We can't just include the ALTER in the TOC entry
17759  * because it will fail if we haven't reassigned the sequence owner to
17760  * match the table's owner.
17761  *
17762  * We need not schema-qualify the table reference because both sequence
17763  * and table must be in the same schema.
17764  */
17765  if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
17766  {
17767  owning_tab = findTableByOid(tbinfo->owning_tab);
17768 
17769  if (owning_tab == NULL)
17770  pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
17771  tbinfo->owning_tab, tbinfo->dobj.catId.oid);
17772 
17773  if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
17774  {
17775  resetPQExpBuffer(query);
17776  appendPQExpBuffer(query, "ALTER SEQUENCE %s",
17777  fmtQualifiedDumpable(tbinfo));
17778  appendPQExpBuffer(query, " OWNED BY %s",
17779  fmtQualifiedDumpable(owning_tab));
17780  appendPQExpBuffer(query, ".%s;\n",
17781  fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
17782 
17783  if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17785  ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17786  .namespace = tbinfo->dobj.namespace->dobj.name,
17787  .owner = tbinfo->rolname,
17788  .description = "SEQUENCE OWNED BY",
17789  .section = SECTION_PRE_DATA,
17790  .createStmt = query->data,
17791  .deps = &(tbinfo->dobj.dumpId),
17792  .nDeps = 1));
17793  }
17794  }
17795 
17796  /* Dump Sequence Comments and Security Labels */
17797  if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17798  dumpComment(fout, "SEQUENCE", qseqname,
17799  tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17800  tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
17801 
17802  if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
17803  dumpSecLabel(fout, "SEQUENCE", qseqname,
17804  tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17805  tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
17806 
17807  PQclear(res);
17808 
17809  destroyPQExpBuffer(query);
17810  destroyPQExpBuffer(delqry);
17811  free(qseqname);
17812 }
17813 
17814 /*
17815  * dumpSequenceData
17816  * write the data of one user-defined sequence
17817  */
17818 static void
17820 {
17821  TableInfo *tbinfo = tdinfo->tdtable;
17822  PGresult *res;
17823  char *last;
17824  bool called;
17825  PQExpBuffer query = createPQExpBuffer();
17826 
17827  appendPQExpBuffer(query,
17828  "SELECT last_value, is_called FROM %s",
17829  fmtQualifiedDumpable(tbinfo));
17830 
17831  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17832 
17833  if (PQntuples(res) != 1)
17834  pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
17835  "query to get data of sequence \"%s\" returned %d rows (expected 1)",
17836  PQntuples(res)),
17837  tbinfo->dobj.name, PQntuples(res));
17838 
17839  last = PQgetvalue(res, 0, 0);
17840  called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
17841 
17842  resetPQExpBuffer(query);
17843  appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
17844  appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
17845  appendPQExpBuffer(query, ", %s, %s);\n",
17846  last, (called ? "true" : "false"));
17847 
17848  if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
17850  ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17851  .namespace = tbinfo->dobj.namespace->dobj.name,
17852  .owner = tbinfo->rolname,
17853  .description = "SEQUENCE SET",
17854  .section = SECTION_DATA,
17855  .createStmt = query->data,
17856  .deps = &(tbinfo->dobj.dumpId),
17857  .nDeps = 1));
17858 
17859  PQclear(res);
17860 
17861  destroyPQExpBuffer(query);
17862 }
17863 
17864 /*
17865  * dumpTrigger
17866  * write the declaration of one user-defined table trigger
17867  */
17868 static void
17869 dumpTrigger(Archive *fout, const TriggerInfo *tginfo)
17870 {
17871  DumpOptions *dopt = fout->dopt;
17872  TableInfo *tbinfo = tginfo->tgtable;
17873  PQExpBuffer query;
17874  PQExpBuffer delqry;
17875  PQExpBuffer trigprefix;
17876  PQExpBuffer trigidentity;
17877  char *qtabname;
17878  char *tag;
17879 
17880  /* Do nothing in data-only dump */
17881  if (dopt->dataOnly)
17882  return;
17883 
17884  query = createPQExpBuffer();
17885  delqry = createPQExpBuffer();
17886  trigprefix = createPQExpBuffer();
17887  trigidentity = createPQExpBuffer();
17888 
17889  qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17890 
17891  appendPQExpBuffer(trigidentity, "%s ", fmtId(tginfo->dobj.name));
17892  appendPQExpBuffer(trigidentity, "ON %s", fmtQualifiedDumpable(tbinfo));
17893 
17894  appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
17895  appendPQExpBuffer(delqry, "DROP TRIGGER %s;\n", trigidentity->data);
17896 
17897  /* Triggers can depend on extensions */
17898  append_depends_on_extension(fout, query, &tginfo->dobj,
17899  "pg_catalog.pg_trigger", "TRIGGER",
17900  trigidentity->data);
17901 
17902  if (tginfo->tgispartition)
17903  {
17904  Assert(tbinfo->ispartition);
17905 
17906  /*
17907  * Partition triggers only appear here because their 'tgenabled' flag
17908  * differs from its parent's. The trigger is created already, so
17909  * remove the CREATE and replace it with an ALTER. (Clear out the
17910  * DROP query too, so that pg_dump --create does not cause errors.)
17911  */
17912  resetPQExpBuffer(query);
17913  resetPQExpBuffer(delqry);
17914  appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
17915  tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
17916  fmtQualifiedDumpable(tbinfo));
17917  switch (tginfo->tgenabled)
17918  {
17919  case 'f':
17920  case 'D':
17921  appendPQExpBufferStr(query, "DISABLE");
17922  break;
17923  case 't':
17924  case 'O':
17925  appendPQExpBufferStr(query, "ENABLE");
17926  break;
17927  case 'R':
17928  appendPQExpBufferStr(query, "ENABLE REPLICA");
17929  break;
17930  case 'A':
17931  appendPQExpBufferStr(query, "ENABLE ALWAYS");
17932  break;
17933  }
17934  appendPQExpBuffer(query, " TRIGGER %s;\n",
17935  fmtId(tginfo->dobj.name));
17936  }
17937  else if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
17938  {
17939  appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
17940  tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
17941  fmtQualifiedDumpable(tbinfo));
17942  switch (tginfo->tgenabled)
17943  {
17944  case 'D':
17945  case 'f':
17946  appendPQExpBufferStr(query, "DISABLE");
17947  break;
17948  case 'A':
17949  appendPQExpBufferStr(query, "ENABLE ALWAYS");
17950  break;
17951  case 'R':
17952  appendPQExpBufferStr(query, "ENABLE REPLICA");
17953  break;
17954  default:
17955  appendPQExpBufferStr(query, "ENABLE");
17956  break;
17957  }
17958  appendPQExpBuffer(query, " TRIGGER %s;\n",
17959  fmtId(tginfo->dobj.name));
17960  }
17961 
17962  appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
17963  fmtId(tginfo->dobj.name));
17964 
17965  tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
17966 
17967  if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17968  ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
17969  ARCHIVE_OPTS(.tag = tag,
17970  .namespace = tbinfo->dobj.namespace->dobj.name,
17971  .owner = tbinfo->rolname,
17972  .description = "TRIGGER",
17973  .section = SECTION_POST_DATA,
17974  .createStmt = query->data,
17975  .dropStmt = delqry->data));
17976 
17977  if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17978  dumpComment(fout, trigprefix->data, qtabname,
17979  tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17980  tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
17981 
17982  free(tag);
17983  destroyPQExpBuffer(query);
17984  destroyPQExpBuffer(delqry);
17985  destroyPQExpBuffer(trigprefix);
17986  destroyPQExpBuffer(trigidentity);
17987  free(qtabname);
17988 }
17989 
17990 /*
17991  * dumpEventTrigger
17992  * write the declaration of one user-defined event trigger
17993  */
17994 static void
17996 {
17997  DumpOptions *dopt = fout->dopt;
17998  PQExpBuffer query;
17999  PQExpBuffer delqry;
18000  char *qevtname;
18001 
18002  /* Do nothing in data-only dump */
18003  if (dopt->dataOnly)
18004  return;
18005 
18006  query = createPQExpBuffer();
18007  delqry = createPQExpBuffer();
18008 
18009  qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
18010 
18011  appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
18012  appendPQExpBufferStr(query, qevtname);
18013  appendPQExpBufferStr(query, " ON ");
18014  appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
18015 
18016  if (strcmp("", evtinfo->evttags) != 0)
18017  {
18018  appendPQExpBufferStr(query, "\n WHEN TAG IN (");
18019  appendPQExpBufferStr(query, evtinfo->evttags);
18020  appendPQExpBufferChar(query, ')');
18021  }
18022 
18023  appendPQExpBufferStr(query, "\n EXECUTE FUNCTION ");
18024  appendPQExpBufferStr(query, evtinfo->evtfname);
18025  appendPQExpBufferStr(query, "();\n");
18026 
18027  if (evtinfo->evtenabled != 'O')
18028  {
18029  appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
18030  qevtname);
18031  switch (evtinfo->evtenabled)
18032  {
18033  case 'D':
18034  appendPQExpBufferStr(query, "DISABLE");
18035  break;
18036  case 'A':
18037  appendPQExpBufferStr(query, "ENABLE ALWAYS");
18038  break;
18039  case 'R':
18040  appendPQExpBufferStr(query, "ENABLE REPLICA");
18041  break;
18042  default:
18043  appendPQExpBufferStr(query, "ENABLE");
18044  break;
18045  }
18046  appendPQExpBufferStr(query, ";\n");
18047  }
18048 
18049  appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
18050  qevtname);
18051 
18052  if (dopt->binary_upgrade)
18053  binary_upgrade_extension_member(query, &evtinfo->dobj,
18054  "EVENT TRIGGER", qevtname, NULL);
18055 
18056  if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18057  ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
18058  ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
18059  .owner = evtinfo->evtowner,
18060  .description = "EVENT TRIGGER",
18061  .section = SECTION_POST_DATA,
18062  .createStmt = query->data,
18063  .dropStmt = delqry->data));
18064 
18065  if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
18066  dumpComment(fout, "EVENT TRIGGER", qevtname,
18067  NULL, evtinfo->evtowner,
18068  evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
18069 
18070  destroyPQExpBuffer(query);
18071  destroyPQExpBuffer(delqry);
18072  free(qevtname);
18073 }
18074 
18075 /*
18076  * dumpRule
18077  * Dump a rule
18078  */
18079 static void
18080 dumpRule(Archive *fout, const RuleInfo *rinfo)
18081 {
18082  DumpOptions *dopt = fout->dopt;
18083  TableInfo *tbinfo = rinfo->ruletable;
18084  bool is_view;
18085  PQExpBuffer query;
18086  PQExpBuffer cmd;
18087  PQExpBuffer delcmd;
18088  PQExpBuffer ruleprefix;
18089  char *qtabname;
18090  PGresult *res;
18091  char *tag;
18092 
18093  /* Do nothing in data-only dump */
18094  if (dopt->dataOnly)
18095  return;
18096 
18097  /*
18098  * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
18099  * we do not want to dump it as a separate object.
18100  */
18101  if (!rinfo->separate)
18102  return;
18103 
18104  /*
18105  * If it's an ON SELECT rule, we want to print it as a view definition,
18106  * instead of a rule.
18107  */
18108  is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
18109 
18110  query = createPQExpBuffer();
18111  cmd = createPQExpBuffer();
18112  delcmd = createPQExpBuffer();
18113  ruleprefix = createPQExpBuffer();
18114 
18115  qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
18116 
18117  if (is_view)
18118  {
18119  PQExpBuffer result;
18120 
18121  /*
18122  * We need OR REPLACE here because we'll be replacing a dummy view.
18123  * Otherwise this should look largely like the regular view dump code.
18124  */
18125  appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
18126  fmtQualifiedDumpable(tbinfo));
18127  if (nonemptyReloptions(tbinfo->reloptions))
18128  {
18129  appendPQExpBufferStr(cmd, " WITH (");
18130  appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
18131  appendPQExpBufferChar(cmd, ')');
18132  }
18133  result = createViewAsClause(fout, tbinfo);
18134  appendPQExpBuffer(cmd, " AS\n%s", result->data);
18135  destroyPQExpBuffer(result);
18136  if (tbinfo->checkoption != NULL)
18137  appendPQExpBuffer(cmd, "\n WITH %s CHECK OPTION",
18138  tbinfo->checkoption);
18139  appendPQExpBufferStr(cmd, ";\n");
18140  }
18141  else
18142  {
18143  /* In the rule case, just print pg_get_ruledef's result verbatim */
18144  appendPQExpBuffer(query,
18145  "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
18146  rinfo->dobj.catId.oid);
18147 
18148  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
18149 
18150  if (PQntuples(res) != 1)
18151  pg_fatal("query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
18152  rinfo->dobj.name, tbinfo->dobj.name);
18153 
18154  printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
18155 
18156  PQclear(res);
18157  }
18158 
18159  /*
18160  * Add the command to alter the rules replication firing semantics if it
18161  * differs from the default.
18162  */
18163  if (rinfo->ev_enabled != 'O')
18164  {
18165  appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
18166  switch (rinfo->ev_enabled)
18167  {
18168  case 'A':
18169  appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
18170  fmtId(rinfo->dobj.name));
18171  break;
18172  case 'R':
18173  appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
18174  fmtId(rinfo->dobj.name));
18175  break;
18176  case 'D':
18177  appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
18178  fmtId(rinfo->dobj.name));
18179  break;
18180  }
18181  }
18182 
18183  if (is_view)
18184  {
18185  /*
18186  * We can't DROP a view's ON SELECT rule. Instead, use CREATE OR
18187  * REPLACE VIEW to replace the rule with something with minimal
18188  * dependencies.
18189  */
18190  PQExpBuffer result;
18191 
18192  appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
18193  fmtQualifiedDumpable(tbinfo));
18194  result = createDummyViewAsClause(fout, tbinfo);
18195  appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
18196  destroyPQExpBuffer(result);
18197  }
18198  else
18199  {
18200  appendPQExpBuffer(delcmd, "DROP RULE %s ",
18201  fmtId(rinfo->dobj.name));
18202  appendPQExpBuffer(delcmd, "ON %s;\n",
18203  fmtQualifiedDumpable(tbinfo));
18204  }
18205 
18206  appendPQExpBuffer(ruleprefix, "RULE %s ON",
18207  fmtId(rinfo->dobj.name));
18208 
18209  tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
18210 
18211  if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
18212  ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
18213  ARCHIVE_OPTS(.tag = tag,
18214  .namespace = tbinfo->dobj.namespace->dobj.name,
18215  .owner = tbinfo->rolname,
18216  .description = "RULE",
18217  .section = SECTION_POST_DATA,
18218  .createStmt = cmd->data,
18219  .dropStmt = delcmd->data));
18220 
18221  /* Dump rule comments */
18222  if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
18223  dumpComment(fout, ruleprefix->data, qtabname,
18224  tbinfo->dobj.namespace->dobj.name,
18225  tbinfo->rolname,
18226  rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
18227 
18228  free(tag);
18229  destroyPQExpBuffer(query);
18230  destroyPQExpBuffer(cmd);
18231  destroyPQExpBuffer(delcmd);
18232  destroyPQExpBuffer(ruleprefix);
18233  free(qtabname);
18234 }
18235 
18236 /*
18237  * getExtensionMembership --- obtain extension membership data
18238  *
18239  * We need to identify objects that are extension members as soon as they're
18240  * loaded, so that we can correctly determine whether they need to be dumped.
18241  * Generally speaking, extension member objects will get marked as *not* to
18242  * be dumped, as they will be recreated by the single CREATE EXTENSION
18243  * command. However, in binary upgrade mode we still need to dump the members
18244  * individually.
18245  */
18246 void
18248  int numExtensions)
18249 {
18250  PQExpBuffer query;
18251  PGresult *res;
18252  int ntups,
18253  i;
18254  int i_classid,
18255  i_objid,
18256  i_refobjid;
18257  ExtensionInfo *ext;
18258 
18259  /* Nothing to do if no extensions */
18260  if (numExtensions == 0)
18261  return;
18262 
18263  query = createPQExpBuffer();
18264 
18265  /* refclassid constraint is redundant but may speed the search */
18266  appendPQExpBufferStr(query, "SELECT "
18267  "classid, objid, refobjid "
18268  "FROM pg_depend "
18269  "WHERE refclassid = 'pg_extension'::regclass "
18270  "AND deptype = 'e' "
18271  "ORDER BY 3");
18272 
18273  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
18274 
18275  ntups = PQntuples(res);
18276 
18277  i_classid = PQfnumber(res, "classid");
18278  i_objid = PQfnumber(res, "objid");
18279  i_refobjid = PQfnumber(res, "refobjid");
18280 
18281  /*
18282  * Since we ordered the SELECT by referenced ID, we can expect that
18283  * multiple entries for the same extension will appear together; this
18284  * saves on searches.
18285  */
18286  ext = NULL;
18287 
18288  for (i = 0; i < ntups; i++)
18289  {
18290  CatalogId objId;
18291  Oid extId;
18292 
18293  objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
18294  objId.oid = atooid(PQgetvalue(res, i, i_objid));
18295  extId = atooid(PQgetvalue(res, i, i_refobjid));
18296 
18297  if (ext == NULL ||
18298  ext->dobj.catId.oid != extId)
18299  ext = findExtensionByOid(extId);
18300 
18301  if (ext == NULL)
18302  {
18303  /* shouldn't happen */
18304  pg_log_warning("could not find referenced extension %u", extId);
18305  continue;
18306  }
18307 
18308  recordExtensionMembership(objId, ext);
18309  }
18310 
18311  PQclear(res);
18312 
18313  destroyPQExpBuffer(query);
18314 }
18315 
18316 /*
18317  * processExtensionTables --- deal with extension configuration tables
18318  *
18319  * There are two parts to this process:
18320  *
18321  * 1. Identify and create dump records for extension configuration tables.
18322  *
18323  * Extensions can mark tables as "configuration", which means that the user
18324  * is able and expected to modify those tables after the extension has been
18325  * loaded. For these tables, we dump out only the data- the structure is
18326  * expected to be handled at CREATE EXTENSION time, including any indexes or
18327  * foreign keys, which brings us to-
18328  *
18329  * 2. Record FK dependencies between configuration tables.
18330  *
18331  * Due to the FKs being created at CREATE EXTENSION time and therefore before
18332  * the data is loaded, we have to work out what the best order for reloading
18333  * the data is, to avoid FK violations when the tables are restored. This is
18334  * not perfect- we can't handle circular dependencies and if any exist they
18335  * will cause an invalid dump to be produced (though at least all of the data
18336  * is included for a user to manually restore). This is currently documented
18337  * but perhaps we can provide a better solution in the future.
18338  */
18339 void
18341  int numExtensions)
18342 {
18343  DumpOptions *dopt = fout->dopt;
18344  PQExpBuffer query;
18345  PGresult *res;
18346  int ntups,
18347  i;
18348  int i_conrelid,
18349  i_confrelid;
18350 
18351  /* Nothing to do if no extensions */
18352  if (numExtensions == 0)
18353  return;
18354 
18355  /*
18356  * Identify extension configuration tables and create TableDataInfo
18357  * objects for them, ensuring their data will be dumped even though the
18358  * tables themselves won't be.
18359  *
18360  * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
18361  * user data in a configuration table is treated like schema data. This
18362  * seems appropriate since system data in a config table would get
18363  * reloaded by CREATE EXTENSION. If the extension is not listed in the
18364  * list of extensions to be included, none of its data is dumped.
18365  */
18366  for (i = 0; i < numExtensions; i++)
18367  {
18368  ExtensionInfo *curext = &(extinfo[i]);
18369  char *extconfig = curext->extconfig;
18370  char *extcondition = curext->extcondition;
18371  char **extconfigarray = NULL;
18372  char **extconditionarray = NULL;
18373  int nconfigitems = 0;
18374  int nconditionitems = 0;
18375 
18376  /*
18377  * Check if this extension is listed as to include in the dump. If
18378  * not, any table data associated with it is discarded.
18379  */
18380  if (extension_include_oids.head != NULL &&
18382  curext->dobj.catId.oid))
18383  continue;
18384 
18385  /*
18386  * Check if this extension is listed as to exclude in the dump. If
18387  * yes, any table data associated with it is discarded.
18388  */
18389  if (extension_exclude_oids.head != NULL &&
18391  curext->dobj.catId.oid))
18392  continue;
18393 
18394  if (strlen(extconfig) != 0 || strlen(extcondition) != 0)
18395  {
18396  int j;
18397 
18398  if (!parsePGArray(extconfig, &extconfigarray, &nconfigitems))
18399  pg_fatal("could not parse %s array", "extconfig");
18400  if (!parsePGArray(extcondition, &extconditionarray, &nconditionitems))
18401  pg_fatal("could not parse %s array", "extcondition");
18402  if (nconfigitems != nconditionitems)
18403  pg_fatal("mismatched number of configurations and conditions for extension");
18404 
18405  for (j = 0; j < nconfigitems; j++)
18406  {
18407  TableInfo *configtbl;
18408  Oid configtbloid = atooid(extconfigarray[j]);
18409  bool dumpobj =
18411 
18412  configtbl = findTableByOid(configtbloid);
18413  if (configtbl == NULL)
18414  continue;
18415 
18416  /*
18417  * Tables of not-to-be-dumped extensions shouldn't be dumped
18418  * unless the table or its schema is explicitly included
18419  */
18420  if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
18421  {
18422  /* check table explicitly requested */
18423  if (table_include_oids.head != NULL &&
18425  configtbloid))
18426  dumpobj = true;
18427 
18428  /* check table's schema explicitly requested */
18429  if (configtbl->dobj.namespace->dobj.dump &
18431  dumpobj = true;
18432  }
18433 
18434  /* check table excluded by an exclusion switch */
18435  if (table_exclude_oids.head != NULL &&
18437  configtbloid))
18438  dumpobj = false;
18439 
18440  /* check schema excluded by an exclusion switch */
18442  configtbl->dobj.namespace->dobj.catId.oid))
18443  dumpobj = false;
18444 
18445  if (dumpobj)
18446  {
18447  makeTableDataInfo(dopt, configtbl);
18448  if (configtbl->dataObj != NULL)
18449  {
18450  if (strlen(extconditionarray[j]) > 0)
18451  configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
18452  }
18453  }
18454  }
18455  }
18456  if (extconfigarray)
18457  free(extconfigarray);
18458  if (extconditionarray)
18459  free(extconditionarray);
18460  }
18461 
18462  /*
18463  * Now that all the TableDataInfo objects have been created for all the
18464  * extensions, check their FK dependencies and register them to try and
18465  * dump the data out in an order that they can be restored in.
18466  *
18467  * Note that this is not a problem for user tables as their FKs are
18468  * recreated after the data has been loaded.
18469  */
18470 
18471  query = createPQExpBuffer();
18472 
18473  printfPQExpBuffer(query,
18474  "SELECT conrelid, confrelid "
18475  "FROM pg_constraint "
18476  "JOIN pg_depend ON (objid = confrelid) "
18477  "WHERE contype = 'f' "
18478  "AND refclassid = 'pg_extension'::regclass "
18479  "AND classid = 'pg_class'::regclass;");
18480 
18481  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
18482  ntups = PQntuples(res);
18483 
18484  i_conrelid = PQfnumber(res, "conrelid");
18485  i_confrelid = PQfnumber(res, "confrelid");
18486 
18487  /* Now get the dependencies and register them */
18488  for (i = 0; i < ntups; i++)
18489  {
18490  Oid conrelid,
18491  confrelid;
18492  TableInfo *reftable,
18493  *contable;
18494 
18495  conrelid = atooid(PQgetvalue(res, i, i_conrelid));
18496  confrelid = atooid(PQgetvalue(res, i, i_confrelid));
18497  contable = findTableByOid(conrelid);
18498  reftable = findTableByOid(confrelid);
18499 
18500  if (reftable == NULL ||
18501  reftable->dataObj == NULL ||
18502  contable == NULL ||
18503  contable->dataObj == NULL)
18504  continue;
18505 
18506  /*
18507  * Make referencing TABLE_DATA object depend on the referenced table's
18508  * TABLE_DATA object.
18509  */
18510  addObjectDependency(&contable->dataObj->dobj,
18511  reftable->dataObj->dobj.dumpId);
18512  }
18513  PQclear(res);
18514  destroyPQExpBuffer(query);
18515 }
18516 
18517 /*
18518  * getDependencies --- obtain available dependency data
18519  */
18520 static void
18522 {
18523  PQExpBuffer query;
18524  PGresult *res;
18525  int ntups,
18526  i;
18527  int i_classid,
18528  i_objid,
18529  i_refclassid,
18530  i_refobjid,
18531  i_deptype;
18532  DumpableObject *dobj,
18533  *refdobj;
18534 
18535  pg_log_info("reading dependency data");
18536 
18537  query = createPQExpBuffer();
18538 
18539  /*
18540  * Messy query to collect the dependency data we need. Note that we
18541  * ignore the sub-object column, so that dependencies of or on a column
18542  * look the same as dependencies of or on a whole table.
18543  *
18544  * PIN dependencies aren't interesting, and EXTENSION dependencies were
18545  * already processed by getExtensionMembership.
18546  */
18547  appendPQExpBufferStr(query, "SELECT "
18548  "classid, objid, refclassid, refobjid, deptype "
18549  "FROM pg_depend "
18550  "WHERE deptype != 'p' AND deptype != 'e'\n");
18551 
18552  /*
18553  * Since we don't treat pg_amop entries as separate DumpableObjects, we
18554  * have to translate their dependencies into dependencies of their parent
18555  * opfamily. Ignore internal dependencies though, as those will point to
18556  * their parent opclass, which we needn't consider here (and if we did,
18557  * it'd just result in circular dependencies). Also, "loose" opfamily
18558  * entries will have dependencies on their parent opfamily, which we
18559  * should drop since they'd likewise become useless self-dependencies.
18560  * (But be sure to keep deps on *other* opfamilies; see amopsortfamily.)
18561  */
18562  appendPQExpBufferStr(query, "UNION ALL\n"
18563  "SELECT 'pg_opfamily'::regclass AS classid, amopfamily AS objid, refclassid, refobjid, deptype "
18564  "FROM pg_depend d, pg_amop o "
18565  "WHERE deptype NOT IN ('p', 'e', 'i') AND "
18566  "classid = 'pg_amop'::regclass AND objid = o.oid "
18567  "AND NOT (refclassid = 'pg_opfamily'::regclass AND amopfamily = refobjid)\n");
18568 
18569  /* Likewise for pg_amproc entries */
18570  appendPQExpBufferStr(query, "UNION ALL\n"
18571  "SELECT 'pg_opfamily'::regclass AS classid, amprocfamily AS objid, refclassid, refobjid, deptype "
18572  "FROM pg_depend d, pg_amproc p "
18573  "WHERE deptype NOT IN ('p', 'e', 'i') AND "
18574  "classid = 'pg_amproc'::regclass AND objid = p.oid "
18575  "AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n");
18576 
18577  /* Sort the output for efficiency below */
18578  appendPQExpBufferStr(query, "ORDER BY 1,2");
18579 
18580  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
18581 
18582  ntups = PQntuples(res);
18583 
18584  i_classid = PQfnumber(res, "classid");
18585  i_objid = PQfnumber(res, "objid");
18586  i_refclassid = PQfnumber(res, "refclassid");
18587  i_refobjid = PQfnumber(res, "refobjid");
18588  i_deptype = PQfnumber(res, "deptype");
18589 
18590  /*
18591  * Since we ordered the SELECT by referencing ID, we can expect that
18592  * multiple entries for the same object will appear together; this saves
18593  * on searches.
18594  */
18595  dobj = NULL;
18596 
18597  for (i = 0; i < ntups; i++)
18598  {
18599  CatalogId objId;
18600  CatalogId refobjId;
18601  char deptype;
18602 
18603  objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
18604  objId.oid = atooid(PQgetvalue(res, i, i_objid));
18605  refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
18606  refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
18607  deptype = *(PQgetvalue(res, i, i_deptype));
18608 
18609  if (dobj == NULL ||
18610  dobj->catId.tableoid != objId.tableoid ||
18611  dobj->catId.oid != objId.oid)
18612  dobj = findObjectByCatalogId(objId);
18613 
18614  /*
18615  * Failure to find objects mentioned in pg_depend is not unexpected,
18616  * since for example we don't collect info about TOAST tables.
18617  */
18618  if (dobj == NULL)
18619  {
18620 #ifdef NOT_USED
18621  pg_log_warning("no referencing object %u %u",
18622  objId.tableoid, objId.oid);
18623 #endif
18624  continue;
18625  }
18626 
18627  refdobj = findObjectByCatalogId(refobjId);
18628 
18629  if (refdobj == NULL)
18630  {
18631 #ifdef NOT_USED
18632  pg_log_warning("no referenced object %u %u",
18633  refobjId.tableoid, refobjId.oid);
18634 #endif
18635  continue;
18636  }
18637 
18638  /*
18639  * For 'x' dependencies, mark the object for later; we still add the
18640  * normal dependency, for possible ordering purposes. Currently
18641  * pg_dump_sort.c knows to put extensions ahead of all object types
18642  * that could possibly depend on them, but this is safer.
18643  */
18644  if (deptype == 'x')
18645  dobj->depends_on_ext = true;
18646 
18647  /*
18648  * Ordinarily, table rowtypes have implicit dependencies on their
18649  * tables. However, for a composite type the implicit dependency goes
18650  * the other way in pg_depend; which is the right thing for DROP but
18651  * it doesn't produce the dependency ordering we need. So in that one
18652  * case, we reverse the direction of the dependency.
18653  */
18654  if (deptype == 'i' &&
18655  dobj->objType == DO_TABLE &&
18656  refdobj->objType == DO_TYPE)
18657  addObjectDependency(refdobj, dobj->dumpId);
18658  else
18659  /* normal case */
18660  addObjectDependency(dobj, refdobj->dumpId);
18661  }
18662 
18663  PQclear(res);
18664 
18665  destroyPQExpBuffer(query);
18666 }
18667 
18668 
18669 /*
18670  * createBoundaryObjects - create dummy DumpableObjects to represent
18671  * dump section boundaries.
18672  */
18673 static DumpableObject *
18675 {
18676  DumpableObject *dobjs;
18677 
18678  dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
18679 
18680  dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
18681  dobjs[0].catId = nilCatalogId;
18682  AssignDumpId(dobjs + 0);
18683  dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
18684 
18685  dobjs[1].objType = DO_POST_DATA_BOUNDARY;
18686  dobjs[1].catId = nilCatalogId;
18687  AssignDumpId(dobjs + 1);
18688  dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
18689 
18690  return dobjs;
18691 }
18692 
18693 /*
18694  * addBoundaryDependencies - add dependencies as needed to enforce the dump
18695  * section boundaries.
18696  */
18697 static void
18699  DumpableObject *boundaryObjs)
18700 {
18701  DumpableObject *preDataBound = boundaryObjs + 0;
18702  DumpableObject *postDataBound = boundaryObjs + 1;
18703  int i;
18704 
18705  for (i = 0; i < numObjs; i++)
18706  {
18707  DumpableObject *dobj = dobjs[i];
18708 
18709  /*
18710  * The classification of object types here must match the SECTION_xxx
18711  * values assigned during subsequent ArchiveEntry calls!
18712  */
18713  switch (dobj->objType)
18714  {
18715  case DO_NAMESPACE:
18716  case DO_EXTENSION:
18717  case DO_TYPE:
18718  case DO_SHELL_TYPE:
18719  case DO_FUNC:
18720  case DO_AGG:
18721  case DO_OPERATOR:
18722  case DO_ACCESS_METHOD:
18723  case DO_OPCLASS:
18724  case DO_OPFAMILY:
18725  case DO_COLLATION:
18726  case DO_CONVERSION:
18727  case DO_TABLE:
18728  case DO_TABLE_ATTACH:
18729  case DO_ATTRDEF:
18730  case DO_PROCLANG:
18731  case DO_CAST:
18732  case DO_DUMMY_TYPE:
18733  case DO_TSPARSER:
18734  case DO_TSDICT:
18735  case DO_TSTEMPLATE:
18736  case DO_TSCONFIG:
18737  case DO_FDW:
18738  case DO_FOREIGN_SERVER:
18739  case DO_TRANSFORM:
18740  /* Pre-data objects: must come before the pre-data boundary */
18741  addObjectDependency(preDataBound, dobj->dumpId);
18742  break;
18743  case DO_TABLE_DATA:
18744  case DO_SEQUENCE_SET:
18745  case DO_LARGE_OBJECT:
18746  case DO_LARGE_OBJECT_DATA:
18747  /* Data objects: must come between the boundaries */
18748  addObjectDependency(dobj, preDataBound->dumpId);
18749  addObjectDependency(postDataBound, dobj->dumpId);
18750  break;
18751  case DO_INDEX:
18752  case DO_INDEX_ATTACH:
18753  case DO_STATSEXT:
18754  case DO_REFRESH_MATVIEW:
18755  case DO_TRIGGER:
18756  case DO_EVENT_TRIGGER:
18757  case DO_DEFAULT_ACL:
18758  case DO_POLICY:
18759  case DO_PUBLICATION:
18760  case DO_PUBLICATION_REL:
18762  case DO_SUBSCRIPTION:
18763  case DO_SUBSCRIPTION_REL:
18764  /* Post-data objects: must come after the post-data boundary */
18765  addObjectDependency(dobj, postDataBound->dumpId);
18766  break;
18767  case DO_RULE:
18768  /* Rules are post-data, but only if dumped separately */
18769  if (((RuleInfo *) dobj)->separate)
18770  addObjectDependency(dobj, postDataBound->dumpId);
18771  break;
18772  case DO_CONSTRAINT:
18773  case DO_FK_CONSTRAINT:
18774  /* Constraints are post-data, but only if dumped separately */
18775  if (((ConstraintInfo *) dobj)->separate)
18776  addObjectDependency(dobj, postDataBound->dumpId);
18777  break;
18778  case DO_PRE_DATA_BOUNDARY:
18779  /* nothing to do */
18780  break;
18781  case DO_POST_DATA_BOUNDARY:
18782  /* must come after the pre-data boundary */
18783  addObjectDependency(dobj, preDataBound->dumpId);
18784  break;
18785  }
18786  }
18787 }
18788 
18789 
18790 /*
18791  * BuildArchiveDependencies - create dependency data for archive TOC entries
18792  *
18793  * The raw dependency data obtained by getDependencies() is not terribly
18794  * useful in an archive dump, because in many cases there are dependency
18795  * chains linking through objects that don't appear explicitly in the dump.
18796  * For example, a view will depend on its _RETURN rule while the _RETURN rule
18797  * will depend on other objects --- but the rule will not appear as a separate
18798  * object in the dump. We need to adjust the view's dependencies to include
18799  * whatever the rule depends on that is included in the dump.
18800  *
18801  * Just to make things more complicated, there are also "special" dependencies
18802  * such as the dependency of a TABLE DATA item on its TABLE, which we must
18803  * not rearrange because pg_restore knows that TABLE DATA only depends on
18804  * its table. In these cases we must leave the dependencies strictly as-is
18805  * even if they refer to not-to-be-dumped objects.
18806  *
18807  * To handle this, the convention is that "special" dependencies are created
18808  * during ArchiveEntry calls, and an archive TOC item that has any such
18809  * entries will not be touched here. Otherwise, we recursively search the
18810  * DumpableObject data structures to build the correct dependencies for each
18811  * archive TOC item.
18812  */
18813 static void
18815 {
18816  ArchiveHandle *AH = (ArchiveHandle *) fout;
18817  TocEntry *te;
18818 
18819  /* Scan all TOC entries in the archive */
18820  for (te = AH->toc->next; te != AH->toc; te = te->next)
18821  {
18822  DumpableObject *dobj;
18823  DumpId *dependencies;
18824  int nDeps;
18825  int allocDeps;
18826 
18827  /* No need to process entries that will not be dumped */
18828  if (te->reqs == 0)
18829  continue;
18830  /* Ignore entries that already have "special" dependencies */
18831  if (te->nDeps > 0)
18832  continue;
18833  /* Otherwise, look up the item's original DumpableObject, if any */
18834  dobj = findObjectByDumpId(te->dumpId);
18835  if (dobj == NULL)
18836  continue;
18837  /* No work if it has no dependencies */
18838  if (dobj->nDeps <= 0)
18839  continue;
18840  /* Set up work array */
18841  allocDeps = 64;
18842  dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
18843  nDeps = 0;
18844  /* Recursively find all dumpable dependencies */
18845  findDumpableDependencies(AH, dobj,
18846  &dependencies, &nDeps, &allocDeps);
18847  /* And save 'em ... */
18848  if (nDeps > 0)
18849  {
18850  dependencies = (DumpId *) pg_realloc(dependencies,
18851  nDeps * sizeof(DumpId));
18852  te->dependencies = dependencies;
18853  te->nDeps = nDeps;
18854  }
18855  else
18856  free(dependencies);
18857  }
18858 }
18859 
18860 /* Recursive search subroutine for BuildArchiveDependencies */
18861 static void
18863  DumpId **dependencies, int *nDeps, int *allocDeps)
18864 {
18865  int i;
18866 
18867  /*
18868  * Ignore section boundary objects: if we search through them, we'll
18869  * report lots of bogus dependencies.
18870  */
18871  if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
18872  dobj->objType == DO_POST_DATA_BOUNDARY)
18873  return;
18874 
18875  for (i = 0; i < dobj->nDeps; i++)
18876  {
18877  DumpId depid = dobj->dependencies[i];
18878 
18879  if (TocIDRequired(AH, depid) != 0)
18880  {
18881  /* Object will be dumped, so just reference it as a dependency */
18882  if (*nDeps >= *allocDeps)
18883  {
18884  *allocDeps *= 2;
18885  *dependencies = (DumpId *) pg_realloc(*dependencies,
18886  *allocDeps * sizeof(DumpId));
18887  }
18888  (*dependencies)[*nDeps] = depid;
18889  (*nDeps)++;
18890  }
18891  else
18892  {
18893  /*
18894  * Object will not be dumped, so recursively consider its deps. We
18895  * rely on the assumption that sortDumpableObjects already broke
18896  * any dependency loops, else we might recurse infinitely.
18897  */
18898  DumpableObject *otherdobj = findObjectByDumpId(depid);
18899 
18900  if (otherdobj)
18901  findDumpableDependencies(AH, otherdobj,
18902  dependencies, nDeps, allocDeps);
18903  }
18904  }
18905 }
18906 
18907 
18908 /*
18909  * getFormattedTypeName - retrieve a nicely-formatted type name for the
18910  * given type OID.
18911  *
18912  * This does not guarantee to schema-qualify the output, so it should not
18913  * be used to create the target object name for CREATE or ALTER commands.
18914  *
18915  * Note that the result is cached and must not be freed by the caller.
18916  */
18917 static const char *
18919 {
18920  TypeInfo *typeInfo;
18921  char *result;
18922  PQExpBuffer query;
18923  PGresult *res;
18924 
18925  if (oid == 0)
18926  {
18927  if ((opts & zeroAsStar) != 0)
18928  return "*";
18929  else if ((opts & zeroAsNone) != 0)
18930  return "NONE";
18931  }
18932 
18933  /* see if we have the result cached in the type's TypeInfo record */
18934  typeInfo = findTypeByOid(oid);
18935  if (typeInfo && typeInfo->ftypname)
18936  return typeInfo->ftypname;
18937 
18938  query = createPQExpBuffer();
18939  appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
18940  oid);
18941 
18942  res = ExecuteSqlQueryForSingleRow(fout, query->data);
18943 
18944  /* result of format_type is already quoted */
18945  result = pg_strdup(PQgetvalue(res, 0, 0));
18946 
18947  PQclear(res);
18948  destroyPQExpBuffer(query);
18949 
18950  /*
18951  * Cache the result for re-use in later requests, if possible. If we
18952  * don't have a TypeInfo for the type, the string will be leaked once the
18953  * caller is done with it ... but that case really should not happen, so
18954  * leaking if it does seems acceptable.
18955  */
18956  if (typeInfo)
18957  typeInfo->ftypname = result;
18958 
18959  return result;
18960 }
18961 
18962 /*
18963  * Return a column list clause for the given relation.
18964  *
18965  * Special case: if there are no undropped columns in the relation, return
18966  * "", not an invalid "()" column list.
18967  */
18968 static const char *
18970 {
18971  int numatts = ti->numatts;
18972  char **attnames = ti->attnames;
18973  bool *attisdropped = ti->attisdropped;
18974  char *attgenerated = ti->attgenerated;
18975  bool needComma;
18976  int i;
18977 
18978  appendPQExpBufferChar(buffer, '(');
18979  needComma = false;
18980  for (i = 0; i < numatts; i++)
18981  {
18982  if (attisdropped[i])
18983  continue;
18984  if (attgenerated[i])
18985  continue;
18986  if (needComma)
18987  appendPQExpBufferStr(buffer, ", ");
18988  appendPQExpBufferStr(buffer, fmtId(attnames[i]));
18989  needComma = true;
18990  }
18991 
18992  if (!needComma)
18993  return ""; /* no undropped columns */
18994 
18995  appendPQExpBufferChar(buffer, ')');
18996  return buffer->data;
18997 }
18998 
18999 /*
19000  * Check if a reloptions array is nonempty.
19001  */
19002 static bool
19003 nonemptyReloptions(const char *reloptions)
19004 {
19005  /* Don't want to print it if it's just "{}" */
19006  return (reloptions != NULL && strlen(reloptions) > 2);
19007 }
19008 
19009 /*
19010  * Format a reloptions array and append it to the given buffer.
19011  *
19012  * "prefix" is prepended to the option names; typically it's "" or "toast.".
19013  */
19014 static void
19015 appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
19016  const char *prefix, Archive *fout)
19017 {
19018  bool res;
19019 
19020  res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
19021  fout->std_strings);
19022  if (!res)
19023  pg_log_warning("could not parse %s array", "reloptions");
19024 }
19025 
19026 /*
19027  * read_dump_filters - retrieve object identifier patterns from file
19028  *
19029  * Parse the specified filter file for include and exclude patterns, and add
19030  * them to the relevant lists. If the filename is "-" then filters will be
19031  * read from STDIN rather than a file.
19032  */
19033 static void
19035 {
19036  FilterStateData fstate;
19037  char *objname;
19038  FilterCommandType comtype;
19039  FilterObjectType objtype;
19040 
19041  filter_init(&fstate, filename, exit_nicely);
19042 
19043  while (filter_read_item(&fstate, &objname, &comtype, &objtype))
19044  {
19045  if (comtype == FILTER_COMMAND_TYPE_INCLUDE)
19046  {
19047  switch (objtype)
19048  {
19050  break;
19057  pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
19058  "include",
19059  filter_object_type_name(objtype));
19060  exit_nicely(1);
19061  break; /* unreachable */
19062 
19065  break;
19068  break;
19071  dopt->include_everything = false;
19072  break;
19075  dopt->include_everything = false;
19076  break;
19079  objname);
19080  dopt->include_everything = false;
19081  break;
19082  }
19083  }
19084  else if (comtype == FILTER_COMMAND_TYPE_EXCLUDE)
19085  {
19086  switch (objtype)
19087  {
19089  break;
19095  pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
19096  "exclude",
19097  filter_object_type_name(objtype));
19098  exit_nicely(1);
19099  break;
19100 
19103  break;
19106  objname);
19107  break;
19110  objname);
19111  break;
19114  break;
19117  break;
19120  objname);
19121  break;
19122  }
19123  }
19124  else
19125  {
19126  Assert(comtype == FILTER_COMMAND_TYPE_NONE);
19127  Assert(objtype == FILTER_OBJECT_TYPE_NONE);
19128  }
19129 
19130  if (objname)
19131  free(objname);
19132  }
19133 
19134  filter_free(&fstate);
19135 }
Acl * acldefault(ObjectType objtype, Oid ownerId)
Definition: acl.c:786
#define InvalidAttrNumber
Definition: attnum.h:23
int lo_read(int fd, char *buf, int len)
Definition: be-fsstubs.c:154
void recordAdditionalCatalogID(CatalogId catId, DumpableObject *dobj)
Definition: common.c:710
void recordExtensionMembership(CatalogId catId, ExtensionInfo *ext)
Definition: common.c:1036
FuncInfo * findFuncByOid(Oid oid)
Definition: common.c:909
NamespaceInfo * findNamespaceByOid(Oid oid)
Definition: common.c:963
SubscriptionInfo * findSubscriptionByOid(Oid oid)
Definition: common.c:1017
ExtensionInfo * findOwningExtension(CatalogId catalogId)
Definition: common.c:1060
TableInfo * getSchemaData(Archive *fout, int *numTablesPtr)
Definition: common.c:99
DumpableObject * findObjectByCatalogId(CatalogId catalogId)
Definition: common.c:769
void addObjectDependency(DumpableObject *dobj, DumpId refId)
Definition: common.c:809
DumpableObject * findObjectByDumpId(DumpId dumpId)
Definition: common.c:756
void parseOidArray(const char *str, Oid *array, int arraysize)
Definition: common.c:1084
TableInfo * findTableByOid(Oid oid)
Definition: common.c:854
DumpId createDumpId(void)
Definition: common.c:736
ExtensionInfo * findExtensionByOid(Oid oid)
Definition: common.c:981
void AssignDumpId(DumpableObject *dobj)
Definition: common.c:648
void getDumpableObjects(DumpableObject ***objs, int *numObjs)
Definition: common.c:788
CollInfo * findCollationByOid(Oid oid)
Definition: common.c:945
TypeInfo * findTypeByOid(Oid oid)
Definition: common.c:890
OprInfo * findOprByOid(Oid oid)
Definition: common.c:927
PublicationInfo * findPublicationByOid(Oid oid)
Definition: common.c:999
void on_exit_close_archive(Archive *AHX)
Definition: parallel.c:328
void init_parallel_dump_utils(void)
Definition: parallel.c:236
#define PG_MAX_JOBS
Definition: parallel.h:48
uint32 BlockNumber
Definition: block.h:31
static void cleanup(void)
Definition: bootstrap.c:682
static const gbtree_vinfo tinfo
Definition: btree_bit.c:109
unsigned int uint32
Definition: c.h:506
#define PG_INT32_MAX
Definition: c.h:589
#define ngettext(s, p, n)
Definition: c.h:1181
#define INT64_FORMAT
Definition: c.h:548
#define Assert(condition)
Definition: c.h:858
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1214
#define PG_INT16_MIN
Definition: c.h:585
#define CppAsString2(x)
Definition: c.h:327
#define PG_INT64_MAX
Definition: c.h:592
#define PG_INT64_MIN
Definition: c.h:591
#define PG_INT32_MIN
Definition: c.h:588
#define PG_INT16_MAX
Definition: c.h:586
#define OidIsValid(objectId)
Definition: c.h:775
int nspid
void set_pglocale_pgservice(const char *argv0, const char *app)
Definition: exec.c:448
char * supports_compression(const pg_compress_specification compression_spec)
Definition: compress_io.c:88
bool parse_compress_algorithm(char *name, pg_compress_algorithm *algorithm)
Definition: compression.c:49
void parse_compress_specification(pg_compress_algorithm algorithm, char *specification, pg_compress_specification *result)
Definition: compression.c:107
char * validate_compress_specification(pg_compress_specification *spec)
Definition: compression.c:344
#define PG_COMPRESSION_OPTION_WORKERS
Definition: compression.h:29
pg_compress_algorithm
Definition: compression.h:22
@ PG_COMPRESSION_NONE
Definition: compression.h:23
void parse_compress_options(const char *option, char **algorithm, char **detail)
#define ALWAYS_SECURE_SEARCH_PATH_SQL
Definition: connect.h:25
PGconn * GetConnection(UserMapping *user, bool will_prep_stmt, PgFdwConnState **state)
Definition: connection.c:177
bool buildACLCommands(const char *name, const char *subname, const char *nspname, const char *type, const char *acls, const char *baseacls, const char *owner, const char *prefix, int remoteVersion, PQExpBuffer sql)
Definition: dumputils.c:64
void buildShSecLabelQuery(const char *catalog_name, Oid objectId, PQExpBuffer sql)
Definition: dumputils.c:637
void makeAlterConfigCommand(PGconn *conn, const char *configitem, const char *type, const char *name, const char *type2, const char *name2, PQExpBuffer buf)
Definition: dumputils.c:823
bool buildDefaultACLCommands(const char *type, const char *nspname, const char *acls, const char *acldefault, const char *owner, int remoteVersion, PQExpBuffer sql)
Definition: dumputils.c:326
bool variable_is_guc_list_quote(const char *name)
Definition: dumputils.c:689
void quoteAclUserName(PQExpBuffer output, const char *input)
Definition: dumputils.c:544
void emitShSecLabels(PGconn *conn, PGresult *res, PQExpBuffer buffer, const char *objtype, const char *objname)
Definition: dumputils.c:655
#define _(x)
Definition: elog.c:90
const char * PQparameterStatus(const PGconn *conn, const char *paramName)
Definition: fe-connect.c:7112
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:6993
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:7147
int PQclientEncoding(const PGconn *conn)
Definition: fe-connect.c:7235
int PQsetClientEncoding(PGconn *conn, const char *encoding)
Definition: fe-connect.c:7243
int PQgetlength(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3887
void PQfreemem(void *ptr)
Definition: fe-exec.c:4032
Oid PQftype(const PGresult *res, int field_num)
Definition: fe-exec.c:3719
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:3411
int PQntuples(const PGresult *res)
Definition: fe-exec.c:3481
char * PQfname(const PGresult *res, int field_num)
Definition: fe-exec.c:3567
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3876
int PQfnumber(const PGresult *res, const char *field_name)
Definition: fe-exec.c:3589
int PQgetisnull(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3901
int PQnfields(const PGresult *res)
Definition: fe-exec.c:3489
PGresult * PQgetResult(PGconn *conn)
Definition: fe-exec.c:2062
int PQgetCopyData(PGconn *conn, char **buffer, int async)
Definition: fe-exec.c:2816
int lo_close(PGconn *conn, int fd)
Definition: fe-lobj.c:96
int lo_open(PGconn *conn, Oid lobjId, int mode)
Definition: fe-lobj.c:57
void * pg_realloc(void *ptr, size_t size)
Definition: fe_memutils.c:65
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
void pg_free(void *ptr)
Definition: fe_memutils.c:105
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
DataDirSyncMethod
Definition: file_utils.h:28
@ DATA_DIR_SYNC_METHOD_FSYNC
Definition: file_utils.h:29
void filter_init(FilterStateData *fstate, const char *filename, exit_function f_exit)
Definition: filter.c:37
void filter_free(FilterStateData *fstate)
Definition: filter.c:61
bool filter_read_item(FilterStateData *fstate, char **objname, FilterCommandType *comtype, FilterObjectType *objtype)
Definition: filter.c:388
void pg_log_filter_error(FilterStateData *fstate, const char *fmt,...)
Definition: filter.c:155
const char * filter_object_type_name(FilterObjectType fot)
Definition: filter.c:83
FilterObjectType
Definition: filter.h:48
@ FILTER_OBJECT_TYPE_TABLE_DATA_AND_CHILDREN
Definition: filter.h:51
@ FILTER_OBJECT_TYPE_SCHEMA
Definition: filter.h:57
@ FILTER_OBJECT_TYPE_INDEX
Definition: filter.h:56
@ FILTER_OBJECT_TYPE_TRIGGER
Definition: filter.h:60
@ FILTER_OBJECT_TYPE_FOREIGN_DATA
Definition: filter.h:54
@ FILTER_OBJECT_TYPE_DATABASE
Definition: filter.h:52
@ FILTER_OBJECT_TYPE_FUNCTION
Definition: filter.h:55
@ FILTER_OBJECT_TYPE_TABLE_DATA
Definition: filter.h:50
@ FILTER_OBJECT_TYPE_NONE
Definition: filter.h:49
@ FILTER_OBJECT_TYPE_TABLE_AND_CHILDREN
Definition: filter.h:59
@ FILTER_OBJECT_TYPE_EXTENSION
Definition: filter.h:53
@ FILTER_OBJECT_TYPE_TABLE
Definition: filter.h:58
FilterCommandType
Definition: filter.h:38
@ FILTER_COMMAND_TYPE_NONE
Definition: filter.h:39
@ FILTER_COMMAND_TYPE_EXCLUDE
Definition: filter.h:41
@ FILTER_COMMAND_TYPE_INCLUDE
Definition: filter.h:40
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition: getopt_long.c:60
#define no_argument
Definition: getopt_long.h:24
#define required_argument
Definition: getopt_long.h:25
#define free(a)
Definition: header.h:65
#define comment
Definition: indent_codes.h:49
#define storage
Definition: indent_codes.h:68
long val
Definition: informix.c:670
static char * locale
Definition: initdb.c:140
static DataDirSyncMethod sync_method
Definition: initdb.c:170
int j
Definition: isn.c:74
int i
Definition: isn.c:73
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
static JitProviderCallbacks provider
Definition: jit.c:43
@ PGRES_COMMAND_OK
Definition: libpq-fe.h:100
@ PGRES_COPY_OUT
Definition: libpq-fe.h:106
@ PGRES_TUPLES_OK
Definition: libpq-fe.h:103
#define INV_READ
Definition: libpq-fs.h:22
void pg_logging_increase_verbosity(void)
Definition: logging.c:182
void pg_logging_init(const char *argv0)
Definition: logging.c:83
void pg_logging_set_level(enum pg_log_level new_level)
Definition: logging.c:173
#define pg_log_error(...)
Definition: logging.h:106
#define pg_log_error_hint(...)
Definition: logging.h:112
#define pg_log_info(...)
Definition: logging.h:124
@ PG_LOG_WARNING
Definition: logging.h:38
#define pg_log_error_detail(...)
Definition: logging.h:109
const char * progname
Definition: main.c:44
char * pstrdup(const char *in)
Definition: mcxt.c:1695
void * palloc(Size size)
Definition: mcxt.c:1316
bool option_parse_int(const char *optarg, const char *optname, int min_range, int max_range, int *result)
Definition: option_utils.c:50
bool parse_sync_method(const char *optarg, DataDirSyncMethod *sync_method)
Definition: option_utils.c:90
Oid oprid(Operator op)
Definition: parse_oper.c:238
static AmcheckOptions opts
Definition: pg_amcheck.c:111
NameData attname
Definition: pg_attribute.h:41
char attalign
Definition: pg_attribute.h:109
int16 attlen
Definition: pg_attribute.h:59
NameData rolname
Definition: pg_authid.h:34
void ConnectDatabase(Archive *AHX, const ConnParams *cparams, bool isReconnect)
Definition: pg_backup_db.c:110
@ SECTION_NONE
Definition: pg_backup.h:57
@ SECTION_POST_DATA
Definition: pg_backup.h:60
@ SECTION_PRE_DATA
Definition: pg_backup.h:58
@ SECTION_DATA
Definition: pg_backup.h:59
int DumpId
Definition: pg_backup.h:270
int EndLO(Archive *AHX, Oid oid)
void ProcessArchiveRestoreOptions(Archive *AHX)
#define InvalidDumpId
Definition: pg_backup.h:272
#define appendStringLiteralAH(buf, str, AH)
Definition: pg_backup.h:332
RestoreOptions * NewRestoreOptions(void)
int StartLO(Archive *AHX, Oid oid)
Archive * CreateArchive(const char *FileSpec, const ArchiveFormat fmt, const pg_compress_specification compression_spec, bool dosync, ArchiveMode mode, SetupWorkerPtrType setupDumpWorker, DataDirSyncMethod sync_method)
enum _archiveFormat ArchiveFormat
void CloseArchive(Archive *AHX)
@ archModeWrite
Definition: pg_backup.h:51
@ archModeAppend
Definition: pg_backup.h:50
@ PREPQUERY_DUMPFUNC
Definition: pg_backup.h:71
@ PREPQUERY_DUMPTABLEATTACH
Definition: pg_backup.h:74
@ PREPQUERY_DUMPBASETYPE
Definition: pg_backup.h:67
@ PREPQUERY_DUMPRANGETYPE
Definition: pg_backup.h:73
@ PREPQUERY_DUMPOPR
Definition: pg_backup.h:72
@ PREPQUERY_DUMPDOMAIN
Definition: pg_backup.h:69
@ NUM_PREP_QUERIES
Definition: pg_backup.h:77
@ PREPQUERY_DUMPCOMPOSITETYPE
Definition: pg_backup.h:68
@ PREPQUERY_DUMPAGG
Definition: pg_backup.h:66
@ PREPQUERY_GETCOLUMNACLS
Definition: pg_backup.h:75
@ PREPQUERY_GETDOMAINCONSTRAINTS
Definition: pg_backup.h:76
@ PREPQUERY_DUMPENUMTYPE
Definition: pg_backup.h:70
int archprintf(Archive *AH, const char *fmt,...) pg_attribute_printf(2
void SetArchiveOptions(Archive *AH, DumpOptions *dopt, RestoreOptions *ropt)
void RestoreArchive(Archive *AHX)
void archputs(const char *s, Archive *AH)
@ archUnknown
Definition: pg_backup.h:41
@ archTar
Definition: pg_backup.h:43
@ archCustom
Definition: pg_backup.h:42
@ archDirectory
Definition: pg_backup.h:45
@ archNull
Definition: pg_backup.h:44
void InitDumpOptions(DumpOptions *opts)
void WriteData(Archive *AHX, const void *data, size_t dLen)
int(* DataDumperPtr)(Archive *AH, const void *userArg)
Definition: pg_backup.h:278
int TocIDRequired(ArchiveHandle *AH, DumpId id)
TocEntry * ArchiveEntry(Archive *AHX, CatalogId catalogId, DumpId dumpId, ArchiveOpts *opts)
#define ARCHIVE_OPTS(...)
#define LOBBUFSIZE
void ExecuteSqlStatement(Archive *AHX, const char *query)
Definition: pg_backup_db.c:278
PGresult * ExecuteSqlQuery(Archive *AHX, const char *query, ExecStatusType status)
Definition: pg_backup_db.c:290
PGresult * ExecuteSqlQueryForSingleRow(Archive *fout, const char *query)
Definition: pg_backup_db.c:305
void set_dump_section(const char *arg, int *dumpSections)
void * arg
#define pg_fatal(...)
static char format
static char * label
static PgChecksumMode mode
Definition: pg_checksums.c:56
#define FUNC_MAX_ARGS
const void size_t len
char datlocprovider
Definition: pg_database.h:44
NameData datname
Definition: pg_database.h:35
int32 encoding
Definition: pg_database.h:41
bool datistemplate
Definition: pg_database.h:47
int32 datconnlimit
Definition: pg_database.h:59
static void expand_schema_name_patterns(Archive *fout, SimpleStringList *patterns, SimpleOidList *oids, bool strict_names)
Definition: pg_dump.c:1418
NamespaceInfo * getNamespaces(Archive *fout, int *numNamespaces)
Definition: pg_dump.c:5556
static const CatalogId nilCatalogId
Definition: pg_dump.c:142
static void dumpEncoding(Archive *AH)
Definition: pg_dump.c:3507
void getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:7722
static DumpId dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId, const char *type, const char *name, const char *subname, const char *nspname, const char *tag, const char *owner, const DumpableAcl *dacl)
Definition: pg_dump.c:15285
static SimpleStringList schema_include_patterns
Definition: pg_dump.c:118
static void dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo)
Definition: pg_dump.c:16877
static void selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
Definition: pg_dump.c:1970
static PQExpBuffer createDummyViewAsClause(Archive *fout, const TableInfo *tbinfo)
Definition: pg_dump.c:15929
static void dumpUserMappings(Archive *fout, const char *servername, const char *namespace, const char *owner, CatalogId catalogId, DumpId dumpId)
Definition: pg_dump.c:15102
static void dumpPublicationNamespace(Archive *fout, const PublicationSchemaInfo *pubsinfo)
Definition: pg_dump.c:4596
static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs, DumpableObject *boundaryObjs)
Definition: pg_dump.c:18698
void getPublicationNamespaces(Archive *fout)
Definition: pg_dump.c:4377
static void dumpSearchPath(Archive *AH)
Definition: pg_dump.c:3556
static int ncomments
Definition: pg_dump.c:154
static void selectDumpableTable(TableInfo *tbinfo, Archive *fout)
Definition: pg_dump.c:1839
static DumpableObject * createBoundaryObjects(void)
Definition: pg_dump.c:18674
static char * convertTSFunction(Archive *fout, Oid funcOid)
Definition: pg_dump.c:13275
static void dumpDatabase(Archive *fout)
Definition: pg_dump.c:2997
static SimpleStringList table_include_patterns
Definition: pg_dump.c:123
static void append_depends_on_extension(Archive *fout, PQExpBuffer create, const DumpableObject *dobj, const char *catalog, const char *keyword, const char *objname)
Definition: pg_dump.c:5220
static Oid get_next_possible_free_pg_type_oid(Archive *fout, PQExpBuffer upgrade_query)
Definition: pg_dump.c:5265
static void dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
Definition: pg_dump.c:10790
static bool forcePartitionRootLoad(const TableInfo *tbinfo)
Definition: pg_dump.c:2573
static void dumpCast(Archive *fout, const CastInfo *cast)
Definition: pg_dump.c:12751
static SimpleOidList schema_exclude_oids
Definition: pg_dump.c:121
static bool have_extra_float_digits
Definition: pg_dump.c:145
static void dumpIndex(Archive *fout, const IndxInfo *indxinfo)
Definition: pg_dump.c:16967
void getPartitioningInfo(Archive *fout)
Definition: pg_dump.c:7263
static void dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
Definition: pg_dump.c:11388
OidOptions
Definition: pg_dump.c:96
@ zeroIsError
Definition: pg_dump.c:97
@ zeroAsStar
Definition: pg_dump.c:98
@ zeroAsNone
Definition: pg_dump.c:99
DefaultACLInfo * getDefaultACLs(Archive *fout, int *numDefaultACLs)
Definition: pg_dump.c:9921
static SimpleOidList extension_include_oids
Definition: pg_dump.c:137
static void dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo)
Definition: pg_dump.c:14674
static void dumpAgg(Archive *fout, const AggInfo *agginfo)
Definition: pg_dump.c:14250
static int extra_float_digits
Definition: pg_dump.c:146
static void dumpTableComment(Archive *fout, const TableInfo *tbinfo, const char *reltypename)
Definition: pg_dump.c:10337
static SimpleStringList extension_include_patterns
Definition: pg_dump.c:136
static void selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
Definition: pg_dump.c:1753
static void dumpTrigger(Archive *fout, const TriggerInfo *tginfo)
Definition: pg_dump.c:17869
static void binary_upgrade_set_type_oids_by_rel(Archive *fout, PQExpBuffer upgrade_buffer, const TableInfo *tbinfo)
Definition: pg_dump.c:5381
static void dumpTable(Archive *fout, const TableInfo *tbinfo)
Definition: pg_dump.c:15740
static SimpleOidList extension_exclude_oids
Definition: pg_dump.c:140
static SimpleStringList table_exclude_patterns
Definition: pg_dump.c:126
static PQExpBuffer createViewAsClause(Archive *fout, const TableInfo *tbinfo)
Definition: pg_dump.c:15880
static void dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo)
Definition: pg_dump.c:17147
void getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:3892
static void dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
Definition: pg_dump.c:11166
static void binary_upgrade_set_pg_class_oids(Archive *fout, PQExpBuffer upgrade_buffer, Oid pg_class_oid, bool is_index)
Definition: pg_dump.c:5393
void getExtensionMembership(Archive *fout, ExtensionInfo extinfo[], int numExtensions)
Definition: pg_dump.c:18247
static void dumpComment(Archive *fout, const char *type, const char *name, const char *namespace, const char *owner, CatalogId catalogId, int subid, DumpId dumpId)
Definition: pg_dump.c:10321
static char * getFormattedOperatorName(const char *oproid)
Definition: pg_dump.c:13245
ForeignServerInfo * getForeignServers(Archive *fout, int *numForeignServers)
Definition: pg_dump.c:9827
static char * format_function_signature(Archive *fout, const FuncInfo *finfo, bool honor_quotes)
Definition: pg_dump.c:12306
static int nseclabels
Definition: pg_dump.c:158
static pg_compress_algorithm compression_algorithm
Definition: pg_dump.c:110
static void dumpStdStrings(Archive *AH)
Definition: pg_dump.c:3532
static void dumpConstraint(Archive *fout, const ConstraintInfo *coninfo)
Definition: pg_dump.c:17224
static void dumpType(Archive *fout, const TypeInfo *tyinfo)
Definition: pg_dump.c:10995
static void dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
Definition: pg_dump.c:16809
AccessMethodInfo * getAccessMethods(Archive *fout, int *numAccessMethods)
Definition: pg_dump.c:6147
FdwInfo * getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
Definition: pg_dump.c:9737
FuncInfo * getFuncs(Archive *fout, int *numFuncs)
Definition: pg_dump.c:6499
static void help(const char *progname)
Definition: pg_dump.c:1089
static void dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo)
Definition: pg_dump.c:13297
TSConfigInfo * getTSConfigurations(Archive *fout, int *numTSConfigs)
Definition: pg_dump.c:9672
int main(int argc, char **argv)
Definition: pg_dump.c:346
static void dumpOpr(Archive *fout, const OprInfo *oprinfo)
Definition: pg_dump.c:12985
static void selectDumpableStatisticsObject(StatsExtInfo *sobj, Archive *fout)
Definition: pg_dump.c:2088
static void selectDumpablePublicationObject(DumpableObject *dobj, Archive *fout)
Definition: pg_dump.c:2070
static void dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo)
Definition: pg_dump.c:17819
static void dumpFunc(Archive *fout, const FuncInfo *finfo)
Definition: pg_dump.c:12335
static void selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
Definition: pg_dump.c:1923
static void BuildArchiveDependencies(Archive *fout)
Definition: pg_dump.c:18814
ConvInfo * getConversions(Archive *fout, int *numConversions)
Definition: pg_dump.c:6079
void getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:7144
static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
Definition: pg_dump.c:2767
static const char * getAttrName(int attrnum, const TableInfo *tblInfo)
Definition: pg_dump.c:16938
static void dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo)
Definition: pg_dump.c:15002
static RoleNameItem * rolenames
Definition: pg_dump.c:149
static void collectRoleNames(Archive *fout)
Definition: pg_dump.c:10057
static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions, const char *prefix, Archive *fout)
Definition: pg_dump.c:19015
static void dumpTableData(Archive *fout, const TableDataInfo *tdinfo)
Definition: pg_dump.c:2601
static void prohibit_crossdb_refs(PGconn *conn, const char *dbname, const char *pattern)
Definition: pg_dump.c:1678
static bool dosync
Definition: pg_dump.c:103
static int dumpTableData_copy(Archive *fout, const void *dcontext)
Definition: pg_dump.c:2128
#define MAX_BLOBS_PER_ARCHIVE_ENTRY
Definition: pg_dump.c:171
static const char * getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
Definition: pg_dump.c:18918
static void getDependencies(Archive *fout)
Definition: pg_dump.c:18521
static void buildMatViewRefreshDependencies(Archive *fout)
Definition: pg_dump.c:2841
static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout, PQExpBuffer upgrade_buffer, Oid pg_type_oid, bool force_array_type, bool include_multirange_type)
Definition: pg_dump.c:5296
#define DUMP_DEFAULT_ROWS_PER_INSERT
Definition: pg_dump.c:164
void getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:4464
static const char * getRoleName(const char *roleoid_str)
Definition: pg_dump.c:10021
AggInfo * getAggregates(Archive *fout, int *numAggs)
Definition: pg_dump.c:6352
static void dumpShellType(Archive *fout, const ShellTypeInfo *stinfo)
Definition: pg_dump.c:12105
static void refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo)
Definition: pg_dump.c:2713
static int findComments(Oid classoid, Oid objoid, CommentItem **items)
Definition: pg_dump.c:10435
static SimpleStringList foreign_servers_include_patterns
Definition: pg_dump.c:133
static char * format_aggregate_signature(const AggInfo *agginfo, Archive *fout, bool honor_quotes)
Definition: pg_dump.c:14218
static void selectDumpableCast(CastInfo *cast, Archive *fout)
Definition: pg_dump.c:1945
static void dumpPublication(Archive *fout, const PublicationInfo *pubinfo)
Definition: pg_dump.c:4281
static char * get_language_name(Archive *fout, Oid langid)
Definition: pg_dump.c:8569
static void dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
Definition: pg_dump.c:4059
void getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:7323
static void setupDumpWorker(Archive *AH)
Definition: pg_dump.c:1351
static void addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx)
Definition: pg_dump.c:7887
static int nrolenames
Definition: pg_dump.c:150
static int findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items)
Definition: pg_dump.c:15575
static SimpleStringList table_include_patterns_and_children
Definition: pg_dump.c:124
static char * convertRegProcReference(const char *proc)
Definition: pg_dump.c:13204
static void getAdditionalACLs(Archive *fout)
Definition: pg_dump.c:10092
static bool is_superuser(Archive *fout)
Definition: pg_dump.c:4700
static void getTableDataFKConstraints(void)
Definition: pg_dump.c:2956
static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
Definition: pg_dump.c:2748
static SimpleOidList table_exclude_oids
Definition: pg_dump.c:128
TSDictInfo * getTSDictionaries(Archive *fout, int *numTSDicts)
Definition: pg_dump.c:9535
InhInfo * getInherits(Archive *fout, int *numInherits)
Definition: pg_dump.c:7207
OpfamilyInfo * getOpfamilies(Archive *fout, int *numOpfamilies)
Definition: pg_dump.c:6284
static void dumpDomain(Archive *fout, const TypeInfo *tyinfo)
Definition: pg_dump.c:11637
void getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
Definition: pg_dump.c:8683
static void collectComments(Archive *fout)
Definition: pg_dump.c:10512
static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
Definition: pg_dump.c:7910
static void dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo)
Definition: pg_dump.c:13646
static void dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
Definition: pg_dump.c:15196
void getSubscriptionTables(Archive *fout)
Definition: pg_dump.c:4918
static void selectDumpableObject(DumpableObject *dobj, Archive *fout)
Definition: pg_dump.c:2106
static void dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo)
Definition: pg_dump.c:14754
static void dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo)
Definition: pg_dump.c:17108
static void dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo)
Definition: pg_dump.c:5004
static char * format_function_arguments(const FuncInfo *finfo, const char *funcargs, bool is_agg)
Definition: pg_dump.c:12283
static int strict_names
Definition: pg_dump.c:108
static void dumpTransform(Archive *fout, const TransformInfo *transform)
Definition: pg_dump.c:12856
static void dumpLO(Archive *fout, const LoInfo *loinfo)
Definition: pg_dump.c:3756
static void dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo)
Definition: pg_dump.c:4639
static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer, const DumpableObject *dobj, const char *objtype, const char *objname, const char *objnamespace)
Definition: pg_dump.c:5509
static void dumpDumpableObject(Archive *fout, DumpableObject *dobj)
Definition: pg_dump.c:10597
static void getLOs(Archive *fout)
Definition: pg_dump.c:3618
static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf, const char *dbname, Oid dboid)
Definition: pg_dump.c:3463
static void setup_connection(Archive *AH, const char *dumpencoding, const char *dumpsnapshot, char *use_role)
Definition: pg_dump.c:1189
static void dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo)
Definition: pg_dump.c:17526
static void dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo)
Definition: pg_dump.c:11324
static void selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
Definition: pg_dump.c:2003
static const char * fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
Definition: pg_dump.c:18969
PublicationInfo * getPublications(Archive *fout, int *numPublications)
Definition: pg_dump.c:4177
static void expand_table_name_patterns(Archive *fout, SimpleStringList *patterns, SimpleOidList *oids, bool strict_names, bool with_child_tables)
Definition: pg_dump.c:1582
static void findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj, DumpId **dependencies, int *nDeps, int *allocDeps)
Definition: pg_dump.c:18862
static void dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
Definition: pg_dump.c:15969
static void dumpTSParser(Archive *fout, const TSParserInfo *prsinfo)
Definition: pg_dump.c:14610
static void expand_foreign_server_name_patterns(Archive *fout, SimpleStringList *patterns, SimpleOidList *oids)
Definition: pg_dump.c:1530
TSTemplateInfo * getTSTemplates(Archive *fout, int *numTSTemplates)
Definition: pg_dump.c:9607
static void dumpRule(Archive *fout, const RuleInfo *rinfo)
Definition: pg_dump.c:18080
static void dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
Definition: pg_dump.c:11810
ProcLangInfo * getProcLangs(Archive *fout, int *numProcLangs)
Definition: pg_dump.c:8386
static void dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
Definition: pg_dump.c:11026
static void dumpExtension(Archive *fout, const ExtensionInfo *extinfo)
Definition: pg_dump.c:10867
#define fmtQualifiedDumpable(obj)
Definition: pg_dump.c:176
TypeInfo * getTypes(Archive *fout, int *numTypes)
Definition: pg_dump.c:5767
static bool nonemptyReloptions(const char *reloptions)
Definition: pg_dump.c:19003
static SimpleStringList extension_exclude_patterns
Definition: pg_dump.c:139
static SimpleOidList table_include_oids
Definition: pg_dump.c:125
void getExtendedStatistics(Archive *fout)
Definition: pg_dump.c:7643
static NamespaceInfo * findNamespace(Oid nsoid)
Definition: pg_dump.c:5674
static char * get_synchronized_snapshot(Archive *fout)
Definition: pg_dump.c:1366
static int dumpLOs(Archive *fout, const void *arg)
Definition: pg_dump.c:3846
static void dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
Definition: pg_dump.c:5073
void processExtensionTables(Archive *fout, ExtensionInfo extinfo[], int numExtensions)
Definition: pg_dump.c:18340
static void dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo)
Definition: pg_dump.c:17995
static void dumpCommentExtended(Archive *fout, const char *type, const char *name, const char *namespace, const char *owner, CatalogId catalogId, int subid, DumpId dumpId, const char *initdb_comment)
Definition: pg_dump.c:10221
static SimpleStringList tabledata_exclude_patterns
Definition: pg_dump.c:129
OpclassInfo * getOpclasses(Archive *fout, int *numOpclasses)
Definition: pg_dump.c:6218
static void dumpConversion(Archive *fout, const ConvInfo *convinfo)
Definition: pg_dump.c:14122
static void dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo)
Definition: pg_dump.c:14932
CollInfo * getCollations(Archive *fout, int *numCollations)
Definition: pg_dump.c:6011
static void dumpProcLang(Archive *fout, const ProcLangInfo *plang)
Definition: pg_dump.c:12151
static void dumpSecLabel(Archive *fout, const char *type, const char *name, const char *namespace, const char *owner, CatalogId catalogId, int subid, DumpId dumpId)
Definition: pg_dump.c:15413
void getSubscriptions(Archive *fout)
Definition: pg_dump.c:4718
static void collectSecLabels(Archive *fout)
Definition: pg_dump.c:15654
static void selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
Definition: pg_dump.c:2031
static Oid g_last_builtin_oid
Definition: pg_dump.c:105
ExtensionInfo * getExtensions(Archive *fout, int *numExtensions)
Definition: pg_dump.c:5692
TSParserInfo * getTSParsers(Archive *fout, int *numTSParsers)
Definition: pg_dump.c:9455
TransformInfo * getTransforms(Archive *fout, int *numTransforms)
Definition: pg_dump.c:8592
void getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:8103
static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode)
Definition: pg_dump.c:1380
static void read_dump_filters(const char *filename, DumpOptions *dopt)
Definition: pg_dump.c:19034
static void dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo)
Definition: pg_dump.c:14812
OprInfo * getOperators(Archive *fout, int *numOprs)
Definition: pg_dump.c:5937
static SecLabelItem * seclabels
Definition: pg_dump.c:157
static SimpleStringList tabledata_exclude_patterns_and_children
Definition: pg_dump.c:130
static bool checkExtensionMembership(DumpableObject *dobj, Archive *fout)
Definition: pg_dump.c:1703
RuleInfo * getRules(Archive *fout, int *numRules)
Definition: pg_dump.c:8002
static CommentItem * comments
Definition: pg_dump.c:153
static int dumpTableData_insert(Archive *fout, const void *dcontext)
Definition: pg_dump.c:2287
static SimpleOidList tabledata_exclude_oids
Definition: pg_dump.c:131
EventTriggerInfo * getEventTriggers(Archive *fout, int *numEventTriggers)
Definition: pg_dump.c:8299
static SimpleStringList table_exclude_patterns_and_children
Definition: pg_dump.c:127
TableInfo * getTables(Archive *fout, int *numTables)
Definition: pg_dump.c:6698
static void dumpSequence(Archive *fout, const TableInfo *tbinfo)
Definition: pg_dump.c:17553
bool shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
Definition: pg_dump.c:9437
static TableInfo * getRootTableInfo(const TableInfo *tbinfo)
Definition: pg_dump.c:2548
static SimpleOidList foreign_servers_include_oids
Definition: pg_dump.c:134
static void dumpCollation(Archive *fout, const CollInfo *collinfo)
Definition: pg_dump.c:13865
static void dumpTableSecLabel(Archive *fout, const TableInfo *tbinfo, const char *reltypename)
Definition: pg_dump.c:15493
CastInfo * getCasts(Archive *fout, int *numCasts)
Definition: pg_dump.c:8476
static void dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo, PGresult *res)
Definition: pg_dump.c:12016
static void expand_extension_name_patterns(Archive *fout, SimpleStringList *patterns, SimpleOidList *oids, bool strict_names)
Definition: pg_dump.c:1477
static void selectDumpableType(TypeInfo *tyinfo, Archive *fout)
Definition: pg_dump.c:1878
static SimpleOidList schema_include_oids
Definition: pg_dump.c:119
static void dumpOpclass(Archive *fout, const OpclassInfo *opcinfo)
Definition: pg_dump.c:13365
static SimpleStringList schema_exclude_patterns
Definition: pg_dump.c:120
#define DUMP_COMPONENT_COMMENT
Definition: pg_dump.h:99
#define DUMP_COMPONENT_DATA
Definition: pg_dump.h:98
#define DUMP_COMPONENT_USERMAP
Definition: pg_dump.h:103
#define DUMP_COMPONENT_POLICY
Definition: pg_dump.h:102
#define DUMP_COMPONENT_SECLABEL
Definition: pg_dump.h:100
#define DUMP_COMPONENT_ALL
Definition: pg_dump.h:104
#define DUMP_COMPONENT_ACL
Definition: pg_dump.h:101
#define DUMP_COMPONENT_NONE
Definition: pg_dump.h:96
#define DUMP_COMPONENTS_REQUIRING_LOCK
Definition: pg_dump.h:128
void sortDumpableObjects(DumpableObject **objs, int numObjs, DumpId preBoundaryId, DumpId postBoundaryId)
Definition: pg_dump_sort.c:322
#define DUMP_COMPONENT_DEFINITION
Definition: pg_dump.h:97
@ DO_EVENT_TRIGGER
Definition: pg_dump.h:79
@ DO_REFRESH_MATVIEW
Definition: pg_dump.h:80
@ DO_POLICY
Definition: pg_dump.h:81
@ DO_CAST
Definition: pg_dump.h:63
@ DO_FOREIGN_SERVER
Definition: pg_dump.h:72
@ DO_PRE_DATA_BOUNDARY
Definition: pg_dump.h:77
@ DO_PROCLANG
Definition: pg_dump.h:62
@ DO_TYPE
Definition: pg_dump.h:42
@ DO_INDEX
Definition: pg_dump.h:55
@ DO_COLLATION
Definition: pg_dump.h:50
@ DO_LARGE_OBJECT
Definition: pg_dump.h:75
@ DO_TSCONFIG
Definition: pg_dump.h:70
@ DO_OPERATOR
Definition: pg_dump.h:46
@ DO_FK_CONSTRAINT
Definition: pg_dump.h:61
@ DO_CONSTRAINT
Definition: pg_dump.h:60
@ DO_SUBSCRIPTION
Definition: pg_dump.h:85
@ DO_DEFAULT_ACL
Definition: pg_dump.h:73
@ DO_FDW
Definition: pg_dump.h:71
@ DO_SUBSCRIPTION_REL
Definition: pg_dump.h:86
@ DO_SEQUENCE_SET
Definition: pg_dump.h:65
@ DO_ATTRDEF
Definition: pg_dump.h:54
@ DO_PUBLICATION_REL
Definition: pg_dump.h:83
@ DO_TABLE_ATTACH
Definition: pg_dump.h:53
@ DO_OPCLASS
Definition: pg_dump.h:48
@ DO_INDEX_ATTACH
Definition: pg_dump.h:56
@ DO_TSTEMPLATE
Definition: pg_dump.h:69
@ DO_STATSEXT
Definition: pg_dump.h:57
@ DO_FUNC
Definition: pg_dump.h:44
@ DO_POST_DATA_BOUNDARY
Definition: pg_dump.h:78
@ DO_LARGE_OBJECT_DATA
Definition: pg_dump.h:76
@ DO_OPFAMILY
Definition: pg_dump.h:49
@ DO_TRANSFORM
Definition: pg_dump.h:74
@ DO_ACCESS_METHOD
Definition: pg_dump.h:47
@ DO_PUBLICATION_TABLE_IN_SCHEMA
Definition: pg_dump.h:84
@ DO_CONVERSION
Definition: pg_dump.h:51
@ DO_TRIGGER
Definition: pg_dump.h:59
@ DO_RULE
Definition: pg_dump.h:58
@ DO_DUMMY_TYPE
Definition: pg_dump.h:66
@ DO_TSDICT
Definition: pg_dump.h:68
@ DO_TSPARSER
Definition: pg_dump.h:67
@ DO_EXTENSION
Definition: pg_dump.h:41
@ DO_TABLE_DATA
Definition: pg_dump.h:64
@ DO_PUBLICATION
Definition: pg_dump.h:82
@ DO_TABLE
Definition: pg_dump.h:52
@ DO_NAMESPACE
Definition: pg_dump.h:40
@ DO_AGG
Definition: pg_dump.h:45
@ DO_SHELL_TYPE
Definition: pg_dump.h:43
void sortDumpableObjectsByTypeName(DumpableObject **objs, int numObjs)
Definition: pg_dump_sort.c:189
#define exit_nicely(code)
Definition: pg_dumpall.c:124
static char * filename
Definition: pg_dumpall.c:119
PGDLLIMPORT int optind
Definition: getopt.c:50
PGDLLIMPORT char * optarg
Definition: getopt.c:52
#define LOGICALREP_ORIGIN_ANY
NameData subname
#define LOGICALREP_TWOPHASE_STATE_DISABLED
static char * buf
Definition: pg_test_fsync.c:73
char typalign
Definition: pg_type.h:176
#define pg_encoding_to_char
Definition: pg_wchar.h:630
char * tablespace
Definition: pgbench.c:216
#define pg_log_warning(...)
Definition: pgfnames.c:24
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
const char * get_progname(const char *argv0)
Definition: path.c:574
#define snprintf
Definition: port.h:238
#define printf(...)
Definition: port.h:244
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
#define atooid(x)
Definition: postgres_ext.h:42
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:235
PQExpBuffer createPQExpBuffer(void)
Definition: pqexpbuffer.c:72
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:90
void resetPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:146
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:265
void appendBinaryPQExpBuffer(PQExpBuffer str, const char *data, size_t datalen)
Definition: pqexpbuffer.c:397
void destroyPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:114
void appendPQExpBufferChar(PQExpBuffer str, char ch)
Definition: pqexpbuffer.c:378
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:367
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:129
char * c
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
Oid RelFileNumber
Definition: relpath.h:25
#define RelFileNumberIsValid(relnumber)
Definition: relpath.h:27
bool quote_all_identifiers
Definition: ruleutils.c:323
void simple_string_list_append(SimpleStringList *list, const char *val)
Definition: simple_list.c:63
bool simple_oid_list_member(SimpleOidList *list, Oid val)
Definition: simple_list.c:45
void simple_oid_list_append(SimpleOidList *list, Oid val)
Definition: simple_list.c:26
struct SimplePtrList SimplePtrList
char * dbname
Definition: streamutil.c:52
PGconn * conn
Definition: streamutil.c:55
void appendStringLiteralConn(PQExpBuffer buf, const char *str, PGconn *conn)
Definition: string_utils.c:293
void appendPGArray(PQExpBuffer buffer, const char *value)
Definition: string_utils.c:740
bool processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern, bool have_where, bool force_escape, const char *schemavar, const char *namevar, const char *altnamevar, const char *visibilityrule, PQExpBuffer dbnamebuf, int *dotcnt)
Definition: string_utils.c:891
const char * fmtId(const char *rawid)
Definition: string_utils.c:64
bool parsePGArray(const char *atext, char ***itemarray, int *nitems)
Definition: string_utils.c:657
bool appendReloptionsArray(PQExpBuffer buffer, const char *reloptions, const char *prefix, int encoding, bool std_strings)
Definition: string_utils.c:804
void appendStringLiteralDQ(PQExpBuffer buf, const char *str, const char *dqprefix)
Definition: string_utils.c:331
int minRemoteVersion
Definition: pg_backup.h:222
int remoteVersion
Definition: pg_backup.h:219
DumpOptions * dopt
Definition: pg_backup.h:214
bool * is_prepared
Definition: pg_backup.h:241
char * searchpath
Definition: pg_backup.h:233
bool isStandby
Definition: pg_backup.h:220
int maxRemoteVersion
Definition: pg_backup.h:223
bool std_strings
Definition: pg_backup.h:230
int numWorkers
Definition: pg_backup.h:225
int encoding
Definition: pg_backup.h:229
char * use_role
Definition: pg_backup.h:234
char * sync_snapshot_id
Definition: pg_backup.h:226
int verbose
Definition: pg_backup.h:217
Oid tableoid
Definition: pg_backup.h:266
Oid classoid
Definition: pg_dump.c:81
Oid objoid
Definition: pg_dump.c:82
int objsubid
Definition: pg_dump.c:83
const char * descr
Definition: pg_dump.c:80
const char * rolename
Definition: pg_dump.c:75
Oid roleoid
Definition: pg_dump.c:74
const char * provider
Definition: pg_dump.c:88
Oid classoid
Definition: pg_dump.c:90
int objsubid
Definition: pg_dump.c:92
const char * label
Definition: pg_dump.c:89
Oid objoid
Definition: pg_dump.c:91
SimpleOidListCell * head
Definition: simple_list.h:28
struct SimplePtrListCell * next
Definition: simple_list.h:48
SimplePtrListCell * head
Definition: simple_list.h:54
char val[FLEXIBLE_ARRAY_MEMBER]
Definition: simple_list.h:37
struct SimpleStringListCell * next
Definition: simple_list.h:34
SimpleStringListCell * head
Definition: simple_list.h:42
const char * rolname
Definition: pg_dump.h:626
bool puballtables
Definition: pg_dump.h:627
bool pubtruncate
Definition: pg_dump.h:631
DumpableObject dobj
Definition: pg_dump.h:625
NamespaceInfo * pubschema
Definition: pg_dump.h:656
DumpableObject dobj
Definition: pg_dump.h:654
PublicationInfo * publication
Definition: pg_dump.h:655
DumpableObject dobj
Definition: pg_dump.h:694
char * srsublsn
Definition: pg_dump.h:698
SubscriptionInfo * subinfo
Definition: pg_dump.h:695
TableInfo * tblinfo
Definition: pg_dump.h:696
char srsubstate
Definition: pg_dump.h:697
char * suboriginremotelsn
Definition: pg_dump.h:678
char * suborigin
Definition: pg_dump.h:677
char * subbinary
Definition: pg_dump.h:667
const char * rolname
Definition: pg_dump.h:665
char * subrunasowner
Definition: pg_dump.h:672
char * subsynccommit
Definition: pg_dump.h:675
char * subpublications
Definition: pg_dump.h:676
char * subtwophasestate
Definition: pg_dump.h:669
char * subfailover
Definition: pg_dump.h:679
char * subenabled
Definition: pg_dump.h:666
char * substream
Definition: pg_dump.h:668
char * subpasswordrequired
Definition: pg_dump.h:671
char * subslotname
Definition: pg_dump.h:674
char * subdisableonerr
Definition: pg_dump.h:670
char * subconninfo
Definition: pg_dump.h:673
DumpableObject dobj
Definition: pg_dump.h:664
char * amhandler
Definition: pg_dump.h:253
DumpableObject dobj
Definition: pg_dump.h:251
struct _tocEntry * toc
DumpableObject dobj
Definition: pg_dump.h:380
char * adef_expr
Definition: pg_dump.h:383
TableInfo * adtable
Definition: pg_dump.h:381
bool separate
Definition: pg_dump.h:384
char castmethod
Definition: pg_dump.h:505
Oid casttarget
Definition: pg_dump.h:502
char castcontext
Definition: pg_dump.h:504
DumpableObject dobj
Definition: pg_dump.h:500
Oid castsource
Definition: pg_dump.h:501
Oid castfunc
Definition: pg_dump.h:503
Oid cfgparser
Definition: pg_dump.h:553
DumpableObject dobj
Definition: pg_dump.h:551
const char * rolname
Definition: pg_dump.h:552
const char * rolname
Definition: pg_dump.h:271
DumpableObject dobj
Definition: pg_dump.h:270
char * pgport
Definition: pg_backup.h:85
char * pghost
Definition: pg_backup.h:86
trivalue promptPassword
Definition: pg_backup.h:88
char * username
Definition: pg_backup.h:87
char * dbname
Definition: pg_backup.h:84
TypeInfo * condomain
Definition: pg_dump.h:475
TableInfo * contable
Definition: pg_dump.h:474
bool condeferred
Definition: pg_dump.h:481
bool conperiod
Definition: pg_dump.h:482
bool conislocal
Definition: pg_dump.h:483
DumpableObject dobj
Definition: pg_dump.h:473
DumpId conindex
Definition: pg_dump.h:479
bool condeferrable
Definition: pg_dump.h:480
char * condef
Definition: pg_dump.h:477
DumpableObject dobj
Definition: pg_dump.h:276
const char * rolname
Definition: pg_dump.h:277
DumpableObject dobj
Definition: pg_dump.h:579
DumpableAcl dacl
Definition: pg_dump.h:580
const char * defaclrole
Definition: pg_dump.h:581
char defaclobjtype
Definition: pg_dump.h:582
char * dictinitoption
Definition: pg_dump.h:539
DumpableObject dobj
Definition: pg_dump.h:536
const char * rolname
Definition: pg_dump.h:537
Oid dicttemplate
Definition: pg_dump.h:538
bool dataOnly
Definition: pg_backup.h:170
int dump_inserts
Definition: pg_backup.h:174
int no_toast_compression
Definition: pg_backup.h:184
int column_inserts
Definition: pg_backup.h:178
bool dontOutputLOs
Definition: pg_backup.h:200
int use_setsessauth
Definition: pg_backup.h:190
int outputCreateDB
Definition: pg_backup.h:198
bool include_everything
Definition: pg_backup.h:195
int sequence_data
Definition: pg_backup.h:204
int disable_dollar_quoting
Definition: pg_backup.h:177
bool outputLOs
Definition: pg_backup.h:199
int no_comments
Definition: pg_backup.h:180
int serializable_deferrable
Definition: pg_backup.h:186
int outputNoTableAm
Definition: pg_backup.h:188
int enable_row_security
Definition: pg_backup.h:191
char * outputSuperuser
Definition: pg_backup.h:202
int dumpSections
Definition: pg_backup.h:171
int no_security_labels
Definition: pg_backup.h:181
int no_unlogged_table_data
Definition: pg_backup.h:185
int no_publications
Definition: pg_backup.h:182
ConnParams cparams
Definition: pg_backup.h:164
const char * lockWaitTimeout
Definition: pg_backup.h:173
int no_subscriptions
Definition: pg_backup.h:183
bool aclsSkip
Definition: pg_backup.h:172
int load_via_partition_root
Definition: pg_backup.h:192
int outputClean
Definition: pg_backup.h:197
int do_nothing
Definition: pg_backup.h:205
int outputNoTablespaces
Definition: pg_backup.h:189
int disable_triggers
Definition: pg_backup.h:187
int outputNoOwner
Definition: pg_backup.h:201
bool schemaOnly
Definition: pg_backup.h:169
int binary_upgrade
Definition: pg_backup.h:166
char privtype
Definition: pg_dump.h:159
char * acldefault
Definition: pg_dump.h:157
char * acl
Definition: pg_dump.h:156
char * initprivs
Definition: pg_dump.h:160
DumpableAcl dacl
Definition: pg_dump.h:167
DumpComponents dump
Definition: pg_dump.h:139
char * name
Definition: pg_dump.h:138
DumpId * dependencies
Definition: pg_dump.h:145
DumpId dumpId
Definition: pg_dump.h:137
bool ext_member
Definition: pg_dump.h:143
DumpComponents components
Definition: pg_dump.h:142
DumpableObjectType objType
Definition: pg_dump.h:135
CatalogId catId
Definition: pg_dump.h:136
DumpComponents dump_contains
Definition: pg_dump.h:141
bool depends_on_ext
Definition: pg_dump.h:144
char * evtevent
Definition: pg_dump.h:456
char * evtfname
Definition: pg_dump.h:459
char evtenabled
Definition: pg_dump.h:460
char * evtname
Definition: pg_dump.h:455
const char * evtowner
Definition: pg_dump.h:457
char * evttags
Definition: pg_dump.h:458
DumpableObject dobj
Definition: pg_dump.h:454
bool relocatable
Definition: pg_dump.h:182
char * extversion
Definition: pg_dump.h:184
DumpableObject dobj
Definition: pg_dump.h:181
char * extcondition
Definition: pg_dump.h:186
char * extconfig
Definition: pg_dump.h:185
char * fdwhandler
Definition: pg_dump.h:561
const char * rolname
Definition: pg_dump.h:560
char * fdwvalidator
Definition: pg_dump.h:562
char * fdwoptions
Definition: pg_dump.h:563
DumpableAcl dacl
Definition: pg_dump.h:559
DumpableObject dobj
Definition: pg_dump.h:558
DumpableAcl dacl
Definition: pg_dump.h:569
char * srvoptions
Definition: pg_dump.h:574
DumpableObject dobj
Definition: pg_dump.h:568
const char * rolname
Definition: pg_dump.h:570
char * srvversion
Definition: pg_dump.h:573
bool postponed_def
Definition: pg_dump.h:231
Oid lang
Definition: pg_dump.h:227
const char * rolname
Definition: pg_dump.h:226
Oid * argtypes
Definition: pg_dump.h:229
Oid prorettype
Definition: pg_dump.h:230
DumpableObject dobj
Definition: pg_dump.h:224
int nargs
Definition: pg_dump.h:228
DumpableAcl dacl
Definition: pg_dump.h:225
IndxInfo * partitionIdx
Definition: pg_dump.h:421
DumpableObject dobj
Definition: pg_dump.h:419
IndxInfo * parentIdx
Definition: pg_dump.h:420
bool indisreplident
Definition: pg_dump.h:408
int indnkeyattrs
Definition: pg_dump.h:403
char * indstatvals
Definition: pg_dump.h:402
char * indstatcols
Definition: pg_dump.h:401
int indnattrs
Definition: pg_dump.h:404
TableInfo * indextable
Definition: pg_dump.h:397
Oid parentidx
Definition: pg_dump.h:410
Oid * indkeys
Definition: pg_dump.h:405
char * indreloptions
Definition: pg_dump.h:400
DumpId indexconstraint
Definition: pg_dump.h:414
bool indisclustered
Definition: pg_dump.h:407
SimplePtrList partattaches
Definition: pg_dump.h:411
char * tablespace
Definition: pg_dump.h:399
bool indnullsnotdistinct
Definition: pg_dump.h:409
char * indexdef
Definition: pg_dump.h:398
DumpableObject dobj
Definition: pg_dump.h:396
Oid inhparent
Definition: pg_dump.h:521
Oid inhrelid
Definition: pg_dump.h:520
const char * rolname
Definition: pg_dump.h:597
DumpableObject dobj
Definition: pg_dump.h:595
DumpableAcl dacl
Definition: pg_dump.h:596
Oid looids[FLEXIBLE_ARRAY_MEMBER]
Definition: pg_dump.h:599
int numlos
Definition: pg_dump.h:598
DumpableObject dobj
Definition: pg_dump.h:172
DumpableAcl dacl
Definition: pg_dump.h:173
const char * rolname
Definition: pg_dump.h:176
DumpableObject dobj
Definition: pg_dump.h:258
const char * rolname
Definition: pg_dump.h:259
const char * rolname
Definition: pg_dump.h:265
DumpableObject dobj
Definition: pg_dump.h:264
DumpableObject dobj
Definition: pg_dump.h:243
char oprkind
Definition: pg_dump.h:245
Oid oprcode
Definition: pg_dump.h:246
const char * rolname
Definition: pg_dump.h:244
TableInfo * poltable
Definition: pg_dump.h:611
char * polqual
Definition: pg_dump.h:616
char polcmd
Definition: pg_dump.h:613
char * polroles
Definition: pg_dump.h:615
char * polwithcheck
Definition: pg_dump.h:617
DumpableObject dobj
Definition: pg_dump.h:610
bool polpermissive
Definition: pg_dump.h:614
char * polname
Definition: pg_dump.h:612
Oid lanvalidator
Definition: pg_dump.h:494
DumpableAcl dacl
Definition: pg_dump.h:490
DumpableObject dobj
Definition: pg_dump.h:489
Oid laninline
Definition: pg_dump.h:493
const char * lanowner
Definition: pg_dump.h:495
Oid lanplcallfoid
Definition: pg_dump.h:492
bool lanpltrusted
Definition: pg_dump.h:491
DumpableObject dobj
Definition: pg_dump.h:526
Oid prstoken
Definition: pg_dump.h:528
Oid prslextype
Definition: pg_dump.h:531
Oid prsheadline
Definition: pg_dump.h:530
Oid prsstart
Definition: pg_dump.h:527
Oid prsend
Definition: pg_dump.h:529
int include_everything
Definition: pg_backup.h:124
int suppressDumpWarnings
Definition: pg_backup.h:150
ConnParams cparams
Definition: pg_backup.h:144
pg_compress_specification compression_spec
Definition: pg_backup.h:148
int no_subscriptions
Definition: pg_backup.h:114
int disable_dollar_quoting
Definition: pg_backup.h:107
const char * filename
Definition: pg_backup.h:117
int no_security_labels
Definition: pg_backup.h:113
char * superuser
Definition: pg_backup.h:104
const char * lockWaitTimeout
Definition: pg_backup.h:123
int enable_row_security
Definition: pg_backup.h:157
int disable_triggers
Definition: pg_backup.h:100
DumpableObject dobj
Definition: pg_dump.h:434
bool separate
Definition: pg_dump.h:439
char ev_enabled
Definition: pg_dump.h:438
bool is_instead
Definition: pg_dump.h:437
TableInfo * ruletable
Definition: pg_dump.h:435
char ev_type
Definition: pg_dump.h:436
TypeInfo * baseType
Definition: pg_dump.h:219
DumpableObject dobj
Definition: pg_dump.h:217
TableInfo * stattable
Definition: pg_dump.h:428
int stattarget
Definition: pg_dump.h:429
const char * rolname
Definition: pg_dump.h:427
DumpableObject dobj
Definition: pg_dump.h:426
TableInfo * partitionTbl
Definition: pg_dump.h:375
DumpableObject dobj
Definition: pg_dump.h:373
TableInfo * parentTbl
Definition: pg_dump.h:374
TableInfo * tdtable
Definition: pg_dump.h:390
DumpableObject dobj
Definition: pg_dump.h:389
char * filtercond
Definition: pg_dump.h:391
char * attidentity
Definition: pg_dump.h:339
char * reltablespace
Definition: pg_dump.h:292
char ** notnull_constrs
Definition: pg_dump.h:349
int ncheck
Definition: pg_dump.h:308
bool ispartition
Definition: pg_dump.h:322
struct _indxInfo * indexes
Definition: pg_dump.h:365
bool * attislocal
Definition: pg_dump.h:343
DumpableObject dobj
Definition: pg_dump.h:285
bool is_identity_sequence
Definition: pg_dump.h:315
Oid reloftype
Definition: pg_dump.h:310
int numParents
Definition: pg_dump.h:325
bool interesting
Definition: pg_dump.h:319
char * toast_reloptions
Definition: pg_dump.h:295
struct _tableInfo ** parents
Definition: pg_dump.h:326
DumpableAcl dacl
Definition: pg_dump.h:286
bool relispopulated
Definition: pg_dump.h:290
char * attgenerated
Definition: pg_dump.h:340
int * attlen
Definition: pg_dump.h:341
Oid reltype
Definition: pg_dump.h:309
char ** attfdwoptions
Definition: pg_dump.h:347
bool hasoids
Definition: pg_dump.h:302
Oid toast_oid
Definition: pg_dump.h:305
Oid foreign_server
Definition: pg_dump.h:311
bool hasrules
Definition: pg_dump.h:297
struct _triggerInfo * triggers
Definition: pg_dump.h:368
bool * attisdropped
Definition: pg_dump.h:338
bool needs_override
Definition: pg_dump.h:358
struct _constraintInfo * checkexprs
Definition: pg_dump.h:357
int * attstattarget
Definition: pg_dump.h:335
uint32 frozenxid
Definition: pg_dump.h:303
char * typstorage
Definition: pg_dump.h:337
int owning_col
Definition: pg_dump.h:314
char * checkoption
Definition: pg_dump.h:294
int numatts
Definition: pg_dump.h:332
bool hastriggers
Definition: pg_dump.h:298
const char * rolname
Definition: pg_dump.h:287
struct _attrDefInfo ** attrdefs
Definition: pg_dump.h:356
char ** attoptions
Definition: pg_dump.h:344
bool * notnull_throwaway
Definition: pg_dump.h:354
char relreplident
Definition: pg_dump.h:291
int numTriggers
Definition: pg_dump.h:367
uint32 minmxid
Definition: pg_dump.h:304
Oid * attcollation
Definition: pg_dump.h:345
bool * notnull_noinh
Definition: pg_dump.h:353
char * attstorage
Definition: pg_dump.h:336
int toastpages
Definition: pg_dump.h:317
Oid owning_tab
Definition: pg_dump.h:313
struct _tableDataInfo * dataObj
Definition: pg_dump.h:366
char * amname
Definition: pg_dump.h:359
bool dummy_view
Definition: pg_dump.h:320
bool forcerowsec
Definition: pg_dump.h:301
bool hascolumnACLs
Definition: pg_dump.h:299
char ** atttypnames
Definition: pg_dump.h:334
char ** attmissingval
Definition: pg_dump.h:348
char relpersistence
Definition: pg_dump.h:289
char ** attnames
Definition: pg_dump.h:333
char relkind
Definition: pg_dump.h:288
bool hasindex
Definition: pg_dump.h:296
bool unsafe_partitions
Definition: pg_dump.h:323
char * reloptions
Definition: pg_dump.h:293
int numIndexes
Definition: pg_dump.h:364
int relpages
Definition: pg_dump.h:316
uint32 toast_frozenxid
Definition: pg_dump.h:306
uint32 toast_minmxid
Definition: pg_dump.h:307
char * attalign
Definition: pg_dump.h:342
char * attcompression
Definition: pg_dump.h:346
bool postponed_def
Definition: pg_dump.h:321
bool * notnull_inh
Definition: pg_dump.h:355
bool rowsec
Definition: pg_dump.h:300
Oid tmpllexize
Definition: pg_dump.h:546
Oid tmplinit
Definition: pg_dump.h:545
DumpableObject dobj
Definition: pg_dump.h:544
pgoff_t dataLength
struct _tocEntry * next
DumpId * dependencies
DumpableObject dobj
Definition: pg_dump.h:510
Oid trffromsql
Definition: pg_dump.h:513
TableInfo * tgtable
Definition: pg_dump.h:446
DumpableObject dobj
Definition: pg_dump.h:445
char tgenabled
Definition: pg_dump.h:447
char * tgdef
Definition: pg_dump.h:449
bool tgispartition
Definition: pg_dump.h:448
bool isMultirange
Definition: pg_dump.h:206
struct _constraintInfo * domChecks
Definition: pg_dump.h:212
DumpableAcl dacl
Definition: pg_dump.h:192
DumpableObject dobj
Definition: pg_dump.h:191
bool isDefined
Definition: pg_dump.h:207
char * ftypname
Definition: pg_dump.h:199
char typrelkind
Definition: pg_dump.h:203
Oid typelem
Definition: pg_dump.h:201
struct _shellTypeInfo * shellType
Definition: pg_dump.h:209
int nDomChecks
Definition: pg_dump.h:211
char typtype
Definition: pg_dump.h:204
const char * rolname
Definition: pg_dump.h:200
Oid typrelid
Definition: pg_dump.h:202
bool isArray
Definition: pg_dump.h:205
#define MinTransactionIdAttributeNumber
Definition: sysattr.h:22
#define MaxCommandIdAttributeNumber
Definition: sysattr.h:25
#define MaxTransactionIdAttributeNumber
Definition: sysattr.h:24
#define TableOidAttributeNumber
Definition: sysattr.h:26
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21
#define MinCommandIdAttributeNumber
Definition: sysattr.h:23
static StringInfo copybuf
Definition: tablesync.c:137
static ItemArray items
Definition: test_tidstore.c:49
static void * fn(void *arg)
Definition: thread-alloc.c:119
#define FirstNormalObjectId
Definition: transam.h:197
@ TRI_YES
Definition: vacuumlo.c:38
@ TRI_NO
Definition: vacuumlo.c:37
bool SplitGUCList(char *rawstring, char separator, List **namelist)
Definition: varlena.c:3705
const char * description
const char * type
const char * name
#define pgoff_t
Definition: win32_port.h:207
ArchiveMode
Definition: xlog.h:62