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/int.h"
59 #include "common/relpath.h"
60 #include "compress_io.h"
61 #include "dumputils.h"
62 #include "fe_utils/option_utils.h"
63 #include "fe_utils/string_utils.h"
64 #include "filter.h"
65 #include "getopt_long.h"
66 #include "libpq/libpq-fs.h"
67 #include "parallel.h"
68 #include "pg_backup_db.h"
69 #include "pg_backup_utils.h"
70 #include "pg_dump.h"
71 #include "storage/block.h"
72 
73 typedef struct
74 {
75  Oid roleoid; /* role's OID */
76  const char *rolename; /* role's name */
77 } RoleNameItem;
78 
79 typedef struct
80 {
81  const char *descr; /* comment for an object */
82  Oid classoid; /* object class (catalog OID) */
83  Oid objoid; /* object OID */
84  int objsubid; /* subobject (table column #) */
85 } CommentItem;
86 
87 typedef struct
88 {
89  const char *provider; /* label provider of this security label */
90  const char *label; /* security label for an object */
91  Oid classoid; /* object class (catalog OID) */
92  Oid objoid; /* object OID */
93  int objsubid; /* subobject (table column #) */
94 } SecLabelItem;
95 
96 typedef struct
97 {
98  Oid oid; /* object OID */
99  char relkind; /* object kind */
100  RelFileNumber relfilenumber; /* object filenode */
101  Oid toast_oid; /* toast table OID */
102  RelFileNumber toast_relfilenumber; /* toast table filenode */
103  Oid toast_index_oid; /* toast table index OID */
104  RelFileNumber toast_index_relfilenumber; /* toast table index filenode */
106 
107 typedef enum OidOptions
108 {
113 
114 /* global decls */
115 static bool dosync = true; /* Issue fsync() to make dump durable on disk. */
116 
117 static Oid g_last_builtin_oid; /* value of the last builtin oid */
118 
119 /* The specified names/patterns should to match at least one entity */
120 static int strict_names = 0;
121 
123 
124 /*
125  * Object inclusion/exclusion lists
126  *
127  * The string lists record the patterns given by command-line switches,
128  * which we then convert to lists of OIDs of matching objects.
129  */
131 static SimpleOidList schema_include_oids = {NULL, NULL};
133 static SimpleOidList schema_exclude_oids = {NULL, NULL};
134 
137 static SimpleOidList table_include_oids = {NULL, NULL};
140 static SimpleOidList table_exclude_oids = {NULL, NULL};
143 static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
144 
147 
149 static SimpleOidList extension_include_oids = {NULL, NULL};
150 
152 static SimpleOidList extension_exclude_oids = {NULL, NULL};
153 
154 static const CatalogId nilCatalogId = {0, 0};
155 
156 /* override for standard extra_float_digits setting */
157 static bool have_extra_float_digits = false;
159 
160 /* sorted table of role names */
161 static RoleNameItem *rolenames = NULL;
162 static int nrolenames = 0;
163 
164 /* sorted table of comments */
165 static CommentItem *comments = NULL;
166 static int ncomments = 0;
167 
168 /* sorted table of security labels */
169 static SecLabelItem *seclabels = NULL;
170 static int nseclabels = 0;
171 
172 /* sorted table of pg_class information for binary upgrade */
174 static int nbinaryUpgradeClassOids = 0;
175 
176 /*
177  * The default number of rows per INSERT when
178  * --inserts is specified without --rows-per-insert
179  */
180 #define DUMP_DEFAULT_ROWS_PER_INSERT 1
181 
182 /*
183  * Maximum number of large objects to group into a single ArchiveEntry.
184  * At some point we might want to make this user-controllable, but for now
185  * a hard-wired setting will suffice.
186  */
187 #define MAX_BLOBS_PER_ARCHIVE_ENTRY 1000
188 
189 /*
190  * Macro for producing quoted, schema-qualified name of a dumpable object.
191  */
192 #define fmtQualifiedDumpable(obj) \
193  fmtQualifiedId((obj)->dobj.namespace->dobj.name, \
194  (obj)->dobj.name)
195 
196 static void help(const char *progname);
197 static void setup_connection(Archive *AH,
198  const char *dumpencoding, const char *dumpsnapshot,
199  char *use_role);
201 static void expand_schema_name_patterns(Archive *fout,
202  SimpleStringList *patterns,
203  SimpleOidList *oids,
204  bool strict_names);
205 static void expand_extension_name_patterns(Archive *fout,
206  SimpleStringList *patterns,
207  SimpleOidList *oids,
208  bool strict_names);
210  SimpleStringList *patterns,
211  SimpleOidList *oids);
212 static void expand_table_name_patterns(Archive *fout,
213  SimpleStringList *patterns,
214  SimpleOidList *oids,
215  bool strict_names,
216  bool with_child_tables);
217 static void prohibit_crossdb_refs(PGconn *conn, const char *dbname,
218  const char *pattern);
219 
220 static NamespaceInfo *findNamespace(Oid nsoid);
221 static void dumpTableData(Archive *fout, const TableDataInfo *tdinfo);
222 static void refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo);
223 static const char *getRoleName(const char *roleoid_str);
224 static void collectRoleNames(Archive *fout);
225 static void getAdditionalACLs(Archive *fout);
226 static void dumpCommentExtended(Archive *fout, const char *type,
227  const char *name, const char *namespace,
228  const char *owner, CatalogId catalogId,
229  int subid, DumpId dumpId,
230  const char *initdb_comment);
231 static inline void dumpComment(Archive *fout, const char *type,
232  const char *name, const char *namespace,
233  const char *owner, CatalogId catalogId,
234  int subid, DumpId dumpId);
235 static int findComments(Oid classoid, Oid objoid, CommentItem **items);
236 static void collectComments(Archive *fout);
237 static void dumpSecLabel(Archive *fout, const char *type, const char *name,
238  const char *namespace, const char *owner,
239  CatalogId catalogId, int subid, DumpId dumpId);
240 static int findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items);
241 static void collectSecLabels(Archive *fout);
242 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
243 static void dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo);
244 static void dumpExtension(Archive *fout, const ExtensionInfo *extinfo);
245 static void dumpType(Archive *fout, const TypeInfo *tyinfo);
246 static void dumpBaseType(Archive *fout, const TypeInfo *tyinfo);
247 static void dumpEnumType(Archive *fout, const TypeInfo *tyinfo);
248 static void dumpRangeType(Archive *fout, const TypeInfo *tyinfo);
249 static void dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo);
250 static void dumpDomain(Archive *fout, const TypeInfo *tyinfo);
251 static void dumpCompositeType(Archive *fout, const TypeInfo *tyinfo);
252 static void dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo,
253  PGresult *res);
254 static void dumpShellType(Archive *fout, const ShellTypeInfo *stinfo);
255 static void dumpProcLang(Archive *fout, const ProcLangInfo *plang);
256 static void dumpFunc(Archive *fout, const FuncInfo *finfo);
257 static void dumpCast(Archive *fout, const CastInfo *cast);
258 static void dumpTransform(Archive *fout, const TransformInfo *transform);
259 static void dumpOpr(Archive *fout, const OprInfo *oprinfo);
260 static void dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo);
261 static void dumpOpclass(Archive *fout, const OpclassInfo *opcinfo);
262 static void dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo);
263 static void dumpCollation(Archive *fout, const CollInfo *collinfo);
264 static void dumpConversion(Archive *fout, const ConvInfo *convinfo);
265 static void dumpRule(Archive *fout, const RuleInfo *rinfo);
266 static void dumpAgg(Archive *fout, const AggInfo *agginfo);
267 static void dumpTrigger(Archive *fout, const TriggerInfo *tginfo);
268 static void dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo);
269 static void dumpTable(Archive *fout, const TableInfo *tbinfo);
270 static void dumpTableSchema(Archive *fout, const TableInfo *tbinfo);
271 static void dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo);
272 static void dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo);
273 static void dumpSequence(Archive *fout, const TableInfo *tbinfo);
274 static void dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo);
275 static void dumpIndex(Archive *fout, const IndxInfo *indxinfo);
276 static void dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo);
277 static void dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo);
278 static void dumpConstraint(Archive *fout, const ConstraintInfo *coninfo);
279 static void dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo);
280 static void dumpTSParser(Archive *fout, const TSParserInfo *prsinfo);
281 static void dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo);
282 static void dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo);
283 static void dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo);
284 static void dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo);
285 static void dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo);
286 static void dumpUserMappings(Archive *fout,
287  const char *servername, const char *namespace,
288  const char *owner, CatalogId catalogId, DumpId dumpId);
289 static void dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo);
290 
291 static DumpId dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
292  const char *type, const char *name, const char *subname,
293  const char *nspname, const char *tag, const char *owner,
294  const DumpableAcl *dacl);
295 
296 static void getDependencies(Archive *fout);
297 static void BuildArchiveDependencies(Archive *fout);
298 static void findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj,
299  DumpId **dependencies, int *nDeps, int *allocDeps);
300 
302 static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
303  DumpableObject *boundaryObjs);
304 
305 static void addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx);
306 static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
307 static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind);
308 static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo);
309 static void buildMatViewRefreshDependencies(Archive *fout);
310 static void getTableDataFKConstraints(void);
311 static char *format_function_arguments(const FuncInfo *finfo, const char *funcargs,
312  bool is_agg);
313 static char *format_function_signature(Archive *fout,
314  const FuncInfo *finfo, bool honor_quotes);
315 static char *convertRegProcReference(const char *proc);
316 static char *getFormattedOperatorName(const char *oproid);
317 static char *convertTSFunction(Archive *fout, Oid funcOid);
318 static const char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
319 static void getLOs(Archive *fout);
320 static void dumpLO(Archive *fout, const LoInfo *loinfo);
321 static int dumpLOs(Archive *fout, const void *arg);
322 static void dumpPolicy(Archive *fout, const PolicyInfo *polinfo);
323 static void dumpPublication(Archive *fout, const PublicationInfo *pubinfo);
324 static void dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo);
325 static void dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo);
326 static void dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo);
327 static void dumpDatabase(Archive *fout);
328 static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
329  const char *dbname, Oid dboid);
330 static void dumpEncoding(Archive *AH);
331 static void dumpStdStrings(Archive *AH);
332 static void dumpSearchPath(Archive *AH);
334  PQExpBuffer upgrade_buffer,
335  Oid pg_type_oid,
336  bool force_array_type,
337  bool include_multirange_type);
339  PQExpBuffer upgrade_buffer,
340  const TableInfo *tbinfo);
341 static void collectBinaryUpgradeClassOids(Archive *fout);
342 static void binary_upgrade_set_pg_class_oids(Archive *fout,
343  PQExpBuffer upgrade_buffer,
344  Oid pg_class_oid);
345 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
346  const DumpableObject *dobj,
347  const char *objtype,
348  const char *objname,
349  const char *objnamespace);
350 static const char *getAttrName(int attrnum, const TableInfo *tblInfo);
351 static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
352 static bool nonemptyReloptions(const char *reloptions);
353 static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
354  const char *prefix, Archive *fout);
355 static char *get_synchronized_snapshot(Archive *fout);
356 static void setupDumpWorker(Archive *AH);
357 static TableInfo *getRootTableInfo(const TableInfo *tbinfo);
358 static bool forcePartitionRootLoad(const TableInfo *tbinfo);
359 static void read_dump_filters(const char *filename, DumpOptions *dopt);
360 
361 
362 int
363 main(int argc, char **argv)
364 {
365  int c;
366  const char *filename = NULL;
367  const char *format = "p";
368  TableInfo *tblinfo;
369  int numTables;
370  DumpableObject **dobjs;
371  int numObjs;
372  DumpableObject *boundaryObjs;
373  int i;
374  int optindex;
375  RestoreOptions *ropt;
376  Archive *fout; /* the script file */
377  bool g_verbose = false;
378  const char *dumpencoding = NULL;
379  const char *dumpsnapshot = NULL;
380  char *use_role = NULL;
381  int numWorkers = 1;
382  int plainText = 0;
383  ArchiveFormat archiveFormat = archUnknown;
384  ArchiveMode archiveMode;
385  pg_compress_specification compression_spec = {0};
386  char *compression_detail = NULL;
387  char *compression_algorithm_str = "none";
388  char *error_detail = NULL;
389  bool user_compression_defined = false;
391 
392  static DumpOptions dopt;
393 
394  static struct option long_options[] = {
395  {"data-only", no_argument, NULL, 'a'},
396  {"blobs", no_argument, NULL, 'b'},
397  {"large-objects", no_argument, NULL, 'b'},
398  {"no-blobs", no_argument, NULL, 'B'},
399  {"no-large-objects", no_argument, NULL, 'B'},
400  {"clean", no_argument, NULL, 'c'},
401  {"create", no_argument, NULL, 'C'},
402  {"dbname", required_argument, NULL, 'd'},
403  {"extension", required_argument, NULL, 'e'},
404  {"file", required_argument, NULL, 'f'},
405  {"format", required_argument, NULL, 'F'},
406  {"host", required_argument, NULL, 'h'},
407  {"jobs", 1, NULL, 'j'},
408  {"no-reconnect", no_argument, NULL, 'R'},
409  {"no-owner", no_argument, NULL, 'O'},
410  {"port", required_argument, NULL, 'p'},
411  {"schema", required_argument, NULL, 'n'},
412  {"exclude-schema", required_argument, NULL, 'N'},
413  {"schema-only", no_argument, NULL, 's'},
414  {"superuser", required_argument, NULL, 'S'},
415  {"table", required_argument, NULL, 't'},
416  {"exclude-table", required_argument, NULL, 'T'},
417  {"no-password", no_argument, NULL, 'w'},
418  {"password", no_argument, NULL, 'W'},
419  {"username", required_argument, NULL, 'U'},
420  {"verbose", no_argument, NULL, 'v'},
421  {"no-privileges", no_argument, NULL, 'x'},
422  {"no-acl", no_argument, NULL, 'x'},
423  {"compress", required_argument, NULL, 'Z'},
424  {"encoding", required_argument, NULL, 'E'},
425  {"help", no_argument, NULL, '?'},
426  {"version", no_argument, NULL, 'V'},
427 
428  /*
429  * the following options don't have an equivalent short option letter
430  */
431  {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
432  {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
433  {"column-inserts", no_argument, &dopt.column_inserts, 1},
434  {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
435  {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
436  {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
437  {"exclude-table-data", required_argument, NULL, 4},
438  {"extra-float-digits", required_argument, NULL, 8},
439  {"if-exists", no_argument, &dopt.if_exists, 1},
440  {"inserts", no_argument, NULL, 9},
441  {"lock-wait-timeout", required_argument, NULL, 2},
442  {"no-table-access-method", no_argument, &dopt.outputNoTableAm, 1},
443  {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
444  {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
445  {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
446  {"role", required_argument, NULL, 3},
447  {"section", required_argument, NULL, 5},
448  {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
449  {"snapshot", required_argument, NULL, 6},
450  {"strict-names", no_argument, &strict_names, 1},
451  {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
452  {"no-comments", no_argument, &dopt.no_comments, 1},
453  {"no-publications", no_argument, &dopt.no_publications, 1},
454  {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
455  {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
456  {"no-toast-compression", no_argument, &dopt.no_toast_compression, 1},
457  {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
458  {"no-sync", no_argument, NULL, 7},
459  {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
460  {"rows-per-insert", required_argument, NULL, 10},
461  {"include-foreign-data", required_argument, NULL, 11},
462  {"table-and-children", required_argument, NULL, 12},
463  {"exclude-table-and-children", required_argument, NULL, 13},
464  {"exclude-table-data-and-children", required_argument, NULL, 14},
465  {"sync-method", required_argument, NULL, 15},
466  {"filter", required_argument, NULL, 16},
467  {"exclude-extension", required_argument, NULL, 17},
468 
469  {NULL, 0, NULL, 0}
470  };
471 
472  pg_logging_init(argv[0]);
474  set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
475 
476  /*
477  * Initialize what we need for parallel execution, especially for thread
478  * support on Windows.
479  */
481 
482  progname = get_progname(argv[0]);
483 
484  if (argc > 1)
485  {
486  if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
487  {
488  help(progname);
489  exit_nicely(0);
490  }
491  if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
492  {
493  puts("pg_dump (PostgreSQL) " PG_VERSION);
494  exit_nicely(0);
495  }
496  }
497 
498  InitDumpOptions(&dopt);
499 
500  while ((c = getopt_long(argc, argv, "abBcCd:e:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxZ:",
501  long_options, &optindex)) != -1)
502  {
503  switch (c)
504  {
505  case 'a': /* Dump data only */
506  dopt.dataOnly = true;
507  break;
508 
509  case 'b': /* Dump LOs */
510  dopt.outputLOs = true;
511  break;
512 
513  case 'B': /* Don't dump LOs */
514  dopt.dontOutputLOs = true;
515  break;
516 
517  case 'c': /* clean (i.e., drop) schema prior to create */
518  dopt.outputClean = 1;
519  break;
520 
521  case 'C': /* Create DB */
522  dopt.outputCreateDB = 1;
523  break;
524 
525  case 'd': /* database name */
526  dopt.cparams.dbname = pg_strdup(optarg);
527  break;
528 
529  case 'e': /* include extension(s) */
531  dopt.include_everything = false;
532  break;
533 
534  case 'E': /* Dump encoding */
535  dumpencoding = pg_strdup(optarg);
536  break;
537 
538  case 'f':
540  break;
541 
542  case 'F':
544  break;
545 
546  case 'h': /* server host */
547  dopt.cparams.pghost = pg_strdup(optarg);
548  break;
549 
550  case 'j': /* number of dump jobs */
551  if (!option_parse_int(optarg, "-j/--jobs", 1,
552  PG_MAX_JOBS,
553  &numWorkers))
554  exit_nicely(1);
555  break;
556 
557  case 'n': /* include schema(s) */
559  dopt.include_everything = false;
560  break;
561 
562  case 'N': /* exclude schema(s) */
564  break;
565 
566  case 'O': /* Don't reconnect to match owner */
567  dopt.outputNoOwner = 1;
568  break;
569 
570  case 'p': /* server port */
571  dopt.cparams.pgport = pg_strdup(optarg);
572  break;
573 
574  case 'R':
575  /* no-op, still accepted for backwards compatibility */
576  break;
577 
578  case 's': /* dump schema only */
579  dopt.schemaOnly = true;
580  break;
581 
582  case 'S': /* Username for superuser in plain text output */
584  break;
585 
586  case 't': /* include table(s) */
588  dopt.include_everything = false;
589  break;
590 
591  case 'T': /* exclude table(s) */
593  break;
594 
595  case 'U':
597  break;
598 
599  case 'v': /* verbose */
600  g_verbose = true;
602  break;
603 
604  case 'w':
606  break;
607 
608  case 'W':
610  break;
611 
612  case 'x': /* skip ACL dump */
613  dopt.aclsSkip = true;
614  break;
615 
616  case 'Z': /* Compression */
617  parse_compress_options(optarg, &compression_algorithm_str,
618  &compression_detail);
619  user_compression_defined = true;
620  break;
621 
622  case 0:
623  /* This covers the long options. */
624  break;
625 
626  case 2: /* lock-wait-timeout */
628  break;
629 
630  case 3: /* SET ROLE */
631  use_role = pg_strdup(optarg);
632  break;
633 
634  case 4: /* exclude table(s) data */
636  break;
637 
638  case 5: /* section */
640  break;
641 
642  case 6: /* snapshot */
643  dumpsnapshot = pg_strdup(optarg);
644  break;
645 
646  case 7: /* no-sync */
647  dosync = false;
648  break;
649 
650  case 8:
652  if (!option_parse_int(optarg, "--extra-float-digits", -15, 3,
654  exit_nicely(1);
655  break;
656 
657  case 9: /* inserts */
658 
659  /*
660  * dump_inserts also stores --rows-per-insert, careful not to
661  * overwrite that.
662  */
663  if (dopt.dump_inserts == 0)
665  break;
666 
667  case 10: /* rows per insert */
668  if (!option_parse_int(optarg, "--rows-per-insert", 1, INT_MAX,
669  &dopt.dump_inserts))
670  exit_nicely(1);
671  break;
672 
673  case 11: /* include foreign data */
675  optarg);
676  break;
677 
678  case 12: /* include table(s) and their children */
680  optarg);
681  dopt.include_everything = false;
682  break;
683 
684  case 13: /* exclude table(s) and their children */
686  optarg);
687  break;
688 
689  case 14: /* exclude data of table(s) and children */
691  optarg);
692  break;
693 
694  case 15:
696  exit_nicely(1);
697  break;
698 
699  case 16: /* read object filters from file */
700  read_dump_filters(optarg, &dopt);
701  break;
702 
703  case 17: /* exclude extension(s) */
705  optarg);
706  break;
707 
708  default:
709  /* getopt_long already emitted a complaint */
710  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
711  exit_nicely(1);
712  }
713  }
714 
715  /*
716  * Non-option argument specifies database name as long as it wasn't
717  * already specified with -d / --dbname
718  */
719  if (optind < argc && dopt.cparams.dbname == NULL)
720  dopt.cparams.dbname = argv[optind++];
721 
722  /* Complain if any arguments remain */
723  if (optind < argc)
724  {
725  pg_log_error("too many command-line arguments (first is \"%s\")",
726  argv[optind]);
727  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
728  exit_nicely(1);
729  }
730 
731  /* --column-inserts implies --inserts */
732  if (dopt.column_inserts && dopt.dump_inserts == 0)
734 
735  /*
736  * Binary upgrade mode implies dumping sequence data even in schema-only
737  * mode. This is not exposed as a separate option, but kept separate
738  * internally for clarity.
739  */
740  if (dopt.binary_upgrade)
741  dopt.sequence_data = 1;
742 
743  if (dopt.dataOnly && dopt.schemaOnly)
744  pg_fatal("options -s/--schema-only and -a/--data-only cannot be used together");
745 
747  pg_fatal("options -s/--schema-only and --include-foreign-data cannot be used together");
748 
749  if (numWorkers > 1 && foreign_servers_include_patterns.head != NULL)
750  pg_fatal("option --include-foreign-data is not supported with parallel backup");
751 
752  if (dopt.dataOnly && dopt.outputClean)
753  pg_fatal("options -c/--clean and -a/--data-only cannot be used together");
754 
755  if (dopt.if_exists && !dopt.outputClean)
756  pg_fatal("option --if-exists requires option -c/--clean");
757 
758  /*
759  * --inserts are already implied above if --column-inserts or
760  * --rows-per-insert were specified.
761  */
762  if (dopt.do_nothing && dopt.dump_inserts == 0)
763  pg_fatal("option --on-conflict-do-nothing requires option --inserts, --rows-per-insert, or --column-inserts");
764 
765  /* Identify archive format to emit */
766  archiveFormat = parseArchiveFormat(format, &archiveMode);
767 
768  /* archiveFormat specific setup */
769  if (archiveFormat == archNull)
770  plainText = 1;
771 
772  /*
773  * Custom and directory formats are compressed by default with gzip when
774  * available, not the others. If gzip is not available, no compression is
775  * done by default.
776  */
777  if ((archiveFormat == archCustom || archiveFormat == archDirectory) &&
778  !user_compression_defined)
779  {
780 #ifdef HAVE_LIBZ
781  compression_algorithm_str = "gzip";
782 #else
783  compression_algorithm_str = "none";
784 #endif
785  }
786 
787  /*
788  * Compression options
789  */
790  if (!parse_compress_algorithm(compression_algorithm_str,
792  pg_fatal("unrecognized compression algorithm: \"%s\"",
793  compression_algorithm_str);
794 
796  &compression_spec);
797  error_detail = validate_compress_specification(&compression_spec);
798  if (error_detail != NULL)
799  pg_fatal("invalid compression specification: %s",
800  error_detail);
801 
802  error_detail = supports_compression(compression_spec);
803  if (error_detail != NULL)
804  pg_fatal("%s", error_detail);
805 
806  /*
807  * Disable support for zstd workers for now - these are based on
808  * threading, and it's unclear how it interacts with parallel dumps on
809  * platforms where that relies on threads too (e.g. Windows).
810  */
811  if (compression_spec.options & PG_COMPRESSION_OPTION_WORKERS)
812  pg_log_warning("compression option \"%s\" is not currently supported by pg_dump",
813  "workers");
814 
815  /*
816  * If emitting an archive format, we always want to emit a DATABASE item,
817  * in case --create is specified at pg_restore time.
818  */
819  if (!plainText)
820  dopt.outputCreateDB = 1;
821 
822  /* Parallel backup only in the directory archive format so far */
823  if (archiveFormat != archDirectory && numWorkers > 1)
824  pg_fatal("parallel backup only supported by the directory format");
825 
826  /* Open the output file */
827  fout = CreateArchive(filename, archiveFormat, compression_spec,
828  dosync, archiveMode, setupDumpWorker, sync_method);
829 
830  /* Make dump options accessible right away */
831  SetArchiveOptions(fout, &dopt, NULL);
832 
833  /* Register the cleanup hook */
834  on_exit_close_archive(fout);
835 
836  /* Let the archiver know how noisy to be */
837  fout->verbose = g_verbose;
838 
839 
840  /*
841  * We allow the server to be back to 9.2, and up to any minor release of
842  * our own major version. (See also version check in pg_dumpall.c.)
843  */
844  fout->minRemoteVersion = 90200;
845  fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
846 
847  fout->numWorkers = numWorkers;
848 
849  /*
850  * Open the database using the Archiver, so it knows about it. Errors mean
851  * death.
852  */
853  ConnectDatabase(fout, &dopt.cparams, false);
854  setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
855 
856  /*
857  * On hot standbys, never try to dump unlogged table data, since it will
858  * just throw an error.
859  */
860  if (fout->isStandby)
861  dopt.no_unlogged_table_data = true;
862 
863  /*
864  * Find the last built-in OID, if needed (prior to 8.1)
865  *
866  * With 8.1 and above, we can just use FirstNormalObjectId - 1.
867  */
869 
870  pg_log_info("last built-in OID is %u", g_last_builtin_oid);
871 
872  /* Expand schema selection patterns into OID lists */
873  if (schema_include_patterns.head != NULL)
874  {
877  strict_names);
878  if (schema_include_oids.head == NULL)
879  pg_fatal("no matching schemas were found");
880  }
883  false);
884  /* non-matching exclusion patterns aren't an error */
885 
886  /* Expand table selection patterns into OID lists */
889  strict_names, false);
892  strict_names, true);
893  if ((table_include_patterns.head != NULL ||
895  table_include_oids.head == NULL)
896  pg_fatal("no matching tables were found");
897 
900  false, false);
903  false, true);
904 
907  false, false);
910  false, true);
911 
914 
915  /* non-matching exclusion patterns aren't an error */
916 
917  /* Expand extension selection patterns into OID lists */
918  if (extension_include_patterns.head != NULL)
919  {
922  strict_names);
923  if (extension_include_oids.head == NULL)
924  pg_fatal("no matching extensions were found");
925  }
928  false);
929  /* non-matching exclusion patterns aren't an error */
930 
931  /*
932  * Dumping LOs is the default for dumps where an inclusion switch is not
933  * used (an "include everything" dump). -B can be used to exclude LOs
934  * from those dumps. -b can be used to include LOs even when an inclusion
935  * switch is used.
936  *
937  * -s means "schema only" and LOs are data, not schema, so we never
938  * include LOs when -s is used.
939  */
940  if (dopt.include_everything && !dopt.schemaOnly && !dopt.dontOutputLOs)
941  dopt.outputLOs = true;
942 
943  /*
944  * Collect role names so we can map object owner OIDs to names.
945  */
946  collectRoleNames(fout);
947 
948  /*
949  * Now scan the database and create DumpableObject structs for all the
950  * objects we intend to dump.
951  */
952  tblinfo = getSchemaData(fout, &numTables);
953 
954  if (!dopt.schemaOnly)
955  {
956  getTableData(&dopt, tblinfo, numTables, 0);
958  if (dopt.dataOnly)
960  }
961 
962  if (dopt.schemaOnly && dopt.sequence_data)
963  getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
964 
965  /*
966  * In binary-upgrade mode, we do not have to worry about the actual LO
967  * data or the associated metadata that resides in the pg_largeobject and
968  * pg_largeobject_metadata tables, respectively.
969  *
970  * However, we do need to collect LO information as there may be comments
971  * or other information on LOs that we do need to dump out.
972  */
973  if (dopt.outputLOs || dopt.binary_upgrade)
974  getLOs(fout);
975 
976  /*
977  * Collect dependency data to assist in ordering the objects.
978  */
979  getDependencies(fout);
980 
981  /*
982  * Collect ACLs, comments, and security labels, if wanted.
983  */
984  if (!dopt.aclsSkip)
985  getAdditionalACLs(fout);
986  if (!dopt.no_comments)
987  collectComments(fout);
988  if (!dopt.no_security_labels)
989  collectSecLabels(fout);
990 
991  /* For binary upgrade mode, collect required pg_class information. */
992  if (dopt.binary_upgrade)
994 
995  /* Lastly, create dummy objects to represent the section boundaries */
996  boundaryObjs = createBoundaryObjects();
997 
998  /* Get pointers to all the known DumpableObjects */
999  getDumpableObjects(&dobjs, &numObjs);
1000 
1001  /*
1002  * Add dummy dependencies to enforce the dump section ordering.
1003  */
1004  addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
1005 
1006  /*
1007  * Sort the objects into a safe dump order (no forward references).
1008  *
1009  * We rely on dependency information to help us determine a safe order, so
1010  * the initial sort is mostly for cosmetic purposes: we sort by name to
1011  * ensure that logically identical schemas will dump identically.
1012  */
1013  sortDumpableObjectsByTypeName(dobjs, numObjs);
1014 
1015  sortDumpableObjects(dobjs, numObjs,
1016  boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
1017 
1018  /*
1019  * Create archive TOC entries for all the objects to be dumped, in a safe
1020  * order.
1021  */
1022 
1023  /*
1024  * First the special entries for ENCODING, STDSTRINGS, and SEARCHPATH.
1025  */
1026  dumpEncoding(fout);
1027  dumpStdStrings(fout);
1028  dumpSearchPath(fout);
1029 
1030  /* The database items are always next, unless we don't want them at all */
1031  if (dopt.outputCreateDB)
1032  dumpDatabase(fout);
1033 
1034  /* Now the rearrangeable objects. */
1035  for (i = 0; i < numObjs; i++)
1036  dumpDumpableObject(fout, dobjs[i]);
1037 
1038  /*
1039  * Set up options info to ensure we dump what we want.
1040  */
1041  ropt = NewRestoreOptions();
1042  ropt->filename = filename;
1043 
1044  /* if you change this list, see dumpOptionsFromRestoreOptions */
1045  ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
1046  ropt->cparams.pgport = dopt.cparams.pgport ? pg_strdup(dopt.cparams.pgport) : NULL;
1047  ropt->cparams.pghost = dopt.cparams.pghost ? pg_strdup(dopt.cparams.pghost) : NULL;
1048  ropt->cparams.username = dopt.cparams.username ? pg_strdup(dopt.cparams.username) : NULL;
1050  ropt->dropSchema = dopt.outputClean;
1051  ropt->dataOnly = dopt.dataOnly;
1052  ropt->schemaOnly = dopt.schemaOnly;
1053  ropt->if_exists = dopt.if_exists;
1054  ropt->column_inserts = dopt.column_inserts;
1055  ropt->dumpSections = dopt.dumpSections;
1056  ropt->aclsSkip = dopt.aclsSkip;
1057  ropt->superuser = dopt.outputSuperuser;
1058  ropt->createDB = dopt.outputCreateDB;
1059  ropt->noOwner = dopt.outputNoOwner;
1060  ropt->noTableAm = dopt.outputNoTableAm;
1061  ropt->noTablespace = dopt.outputNoTablespaces;
1062  ropt->disable_triggers = dopt.disable_triggers;
1063  ropt->use_setsessauth = dopt.use_setsessauth;
1065  ropt->dump_inserts = dopt.dump_inserts;
1066  ropt->no_comments = dopt.no_comments;
1067  ropt->no_publications = dopt.no_publications;
1069  ropt->no_subscriptions = dopt.no_subscriptions;
1070  ropt->lockWaitTimeout = dopt.lockWaitTimeout;
1073  ropt->sequence_data = dopt.sequence_data;
1074  ropt->binary_upgrade = dopt.binary_upgrade;
1075 
1076  ropt->compression_spec = compression_spec;
1077 
1078  ropt->suppressDumpWarnings = true; /* We've already shown them */
1079 
1080  SetArchiveOptions(fout, &dopt, ropt);
1081 
1082  /* Mark which entries should be output */
1084 
1085  /*
1086  * The archive's TOC entries are now marked as to which ones will actually
1087  * be output, so we can set up their dependency lists properly. This isn't
1088  * necessary for plain-text output, though.
1089  */
1090  if (!plainText)
1092 
1093  /*
1094  * And finally we can do the actual output.
1095  *
1096  * Note: for non-plain-text output formats, the output file is written
1097  * inside CloseArchive(). This is, um, bizarre; but not worth changing
1098  * right now.
1099  */
1100  if (plainText)
1101  RestoreArchive(fout);
1102 
1103  CloseArchive(fout);
1104 
1105  exit_nicely(0);
1106 }
1107 
1108 
1109 static void
1110 help(const char *progname)
1111 {
1112  printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
1113  printf(_("Usage:\n"));
1114  printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
1115 
1116  printf(_("\nGeneral options:\n"));
1117  printf(_(" -f, --file=FILENAME output file or directory name\n"));
1118  printf(_(" -F, --format=c|d|t|p output file format (custom, directory, tar,\n"
1119  " plain text (default))\n"));
1120  printf(_(" -j, --jobs=NUM use this many parallel jobs to dump\n"));
1121  printf(_(" -v, --verbose verbose mode\n"));
1122  printf(_(" -V, --version output version information, then exit\n"));
1123  printf(_(" -Z, --compress=METHOD[:DETAIL]\n"
1124  " compress as specified\n"));
1125  printf(_(" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
1126  printf(_(" --no-sync do not wait for changes to be written safely to disk\n"));
1127  printf(_(" --sync-method=METHOD set method for syncing files to disk\n"));
1128  printf(_(" -?, --help show this help, then exit\n"));
1129 
1130  printf(_("\nOptions controlling the output content:\n"));
1131  printf(_(" -a, --data-only dump only the data, not the schema\n"));
1132  printf(_(" -b, --large-objects include large objects in dump\n"));
1133  printf(_(" --blobs (same as --large-objects, deprecated)\n"));
1134  printf(_(" -B, --no-large-objects exclude large objects in dump\n"));
1135  printf(_(" --no-blobs (same as --no-large-objects, deprecated)\n"));
1136  printf(_(" -c, --clean clean (drop) database objects before recreating\n"));
1137  printf(_(" -C, --create include commands to create database in dump\n"));
1138  printf(_(" -e, --extension=PATTERN dump the specified extension(s) only\n"));
1139  printf(_(" -E, --encoding=ENCODING dump the data in encoding ENCODING\n"));
1140  printf(_(" -n, --schema=PATTERN dump the specified schema(s) only\n"));
1141  printf(_(" -N, --exclude-schema=PATTERN do NOT dump the specified schema(s)\n"));
1142  printf(_(" -O, --no-owner skip restoration of object ownership in\n"
1143  " plain-text format\n"));
1144  printf(_(" -s, --schema-only dump only the schema, no data\n"));
1145  printf(_(" -S, --superuser=NAME superuser user name to use in plain-text format\n"));
1146  printf(_(" -t, --table=PATTERN dump only the specified table(s)\n"));
1147  printf(_(" -T, --exclude-table=PATTERN do NOT dump the specified table(s)\n"));
1148  printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
1149  printf(_(" --binary-upgrade for use by upgrade utilities only\n"));
1150  printf(_(" --column-inserts dump data as INSERT commands with column names\n"));
1151  printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n"));
1152  printf(_(" --disable-triggers disable triggers during data-only restore\n"));
1153  printf(_(" --enable-row-security enable row security (dump only content user has\n"
1154  " access to)\n"));
1155  printf(_(" --exclude-extension=PATTERN do NOT dump the specified extension(s)\n"));
1156  printf(_(" --exclude-table-and-children=PATTERN\n"
1157  " do NOT dump the specified table(s), including\n"
1158  " child and partition tables\n"));
1159  printf(_(" --exclude-table-data=PATTERN do NOT dump data for the specified table(s)\n"));
1160  printf(_(" --exclude-table-data-and-children=PATTERN\n"
1161  " do NOT dump data for the specified table(s),\n"
1162  " including child and partition tables\n"));
1163  printf(_(" --extra-float-digits=NUM override default setting for extra_float_digits\n"));
1164  printf(_(" --filter=FILENAME include or exclude objects and data from dump\n"
1165  " based on expressions in FILENAME\n"));
1166  printf(_(" --if-exists use IF EXISTS when dropping objects\n"));
1167  printf(_(" --include-foreign-data=PATTERN\n"
1168  " include data of foreign tables on foreign\n"
1169  " servers matching PATTERN\n"));
1170  printf(_(" --inserts dump data as INSERT commands, rather than COPY\n"));
1171  printf(_(" --load-via-partition-root load partitions via the root table\n"));
1172  printf(_(" --no-comments do not dump comments\n"));
1173  printf(_(" --no-publications do not dump publications\n"));
1174  printf(_(" --no-security-labels do not dump security label assignments\n"));
1175  printf(_(" --no-subscriptions do not dump subscriptions\n"));
1176  printf(_(" --no-table-access-method do not dump table access methods\n"));
1177  printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
1178  printf(_(" --no-toast-compression do not dump TOAST compression methods\n"));
1179  printf(_(" --no-unlogged-table-data do not dump unlogged table data\n"));
1180  printf(_(" --on-conflict-do-nothing add ON CONFLICT DO NOTHING to INSERT commands\n"));
1181  printf(_(" --quote-all-identifiers quote all identifiers, even if not key words\n"));
1182  printf(_(" --rows-per-insert=NROWS number of rows per INSERT; implies --inserts\n"));
1183  printf(_(" --section=SECTION dump named section (pre-data, data, or post-data)\n"));
1184  printf(_(" --serializable-deferrable wait until the dump can run without anomalies\n"));
1185  printf(_(" --snapshot=SNAPSHOT use given snapshot for the dump\n"));
1186  printf(_(" --strict-names require table and/or schema include patterns to\n"
1187  " match at least one entity each\n"));
1188  printf(_(" --table-and-children=PATTERN dump only the specified table(s), including\n"
1189  " child and partition tables\n"));
1190  printf(_(" --use-set-session-authorization\n"
1191  " use SET SESSION AUTHORIZATION commands instead of\n"
1192  " ALTER OWNER commands to set ownership\n"));
1193 
1194  printf(_("\nConnection options:\n"));
1195  printf(_(" -d, --dbname=DBNAME database to dump\n"));
1196  printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
1197  printf(_(" -p, --port=PORT database server port number\n"));
1198  printf(_(" -U, --username=NAME connect as specified database user\n"));
1199  printf(_(" -w, --no-password never prompt for password\n"));
1200  printf(_(" -W, --password force password prompt (should happen automatically)\n"));
1201  printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
1202 
1203  printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
1204  "variable value is used.\n\n"));
1205  printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
1206  printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
1207 }
1208 
1209 static void
1210 setup_connection(Archive *AH, const char *dumpencoding,
1211  const char *dumpsnapshot, char *use_role)
1212 {
1213  DumpOptions *dopt = AH->dopt;
1214  PGconn *conn = GetConnection(AH);
1215  const char *std_strings;
1216 
1218 
1219  /*
1220  * Set the client encoding if requested.
1221  */
1222  if (dumpencoding)
1223  {
1224  if (PQsetClientEncoding(conn, dumpencoding) < 0)
1225  pg_fatal("invalid client encoding \"%s\" specified",
1226  dumpencoding);
1227  }
1228 
1229  /*
1230  * Get the active encoding and the standard_conforming_strings setting, so
1231  * we know how to escape strings.
1232  */
1234 
1235  std_strings = PQparameterStatus(conn, "standard_conforming_strings");
1236  AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
1237 
1238  /*
1239  * Set the role if requested. In a parallel dump worker, we'll be passed
1240  * use_role == NULL, but AH->use_role is already set (if user specified it
1241  * originally) and we should use that.
1242  */
1243  if (!use_role && AH->use_role)
1244  use_role = AH->use_role;
1245 
1246  /* Set the role if requested */
1247  if (use_role)
1248  {
1249  PQExpBuffer query = createPQExpBuffer();
1250 
1251  appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
1252  ExecuteSqlStatement(AH, query->data);
1253  destroyPQExpBuffer(query);
1254 
1255  /* save it for possible later use by parallel workers */
1256  if (!AH->use_role)
1257  AH->use_role = pg_strdup(use_role);
1258  }
1259 
1260  /* Set the datestyle to ISO to ensure the dump's portability */
1261  ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
1262 
1263  /* Likewise, avoid using sql_standard intervalstyle */
1264  ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
1265 
1266  /*
1267  * Use an explicitly specified extra_float_digits if it has been provided.
1268  * Otherwise, set extra_float_digits so that we can dump float data
1269  * exactly (given correctly implemented float I/O code, anyway).
1270  */
1272  {
1274 
1275  appendPQExpBuffer(q, "SET extra_float_digits TO %d",
1277  ExecuteSqlStatement(AH, q->data);
1278  destroyPQExpBuffer(q);
1279  }
1280  else
1281  ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
1282 
1283  /*
1284  * Disable synchronized scanning, to prevent unpredictable changes in row
1285  * ordering across a dump and reload.
1286  */
1287  ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
1288 
1289  /*
1290  * Disable timeouts if supported.
1291  */
1292  ExecuteSqlStatement(AH, "SET statement_timeout = 0");
1293  if (AH->remoteVersion >= 90300)
1294  ExecuteSqlStatement(AH, "SET lock_timeout = 0");
1295  if (AH->remoteVersion >= 90600)
1296  ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
1297  if (AH->remoteVersion >= 170000)
1298  ExecuteSqlStatement(AH, "SET transaction_timeout = 0");
1299 
1300  /*
1301  * Quote all identifiers, if requested.
1302  */
1304  ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1305 
1306  /*
1307  * Adjust row-security mode, if supported.
1308  */
1309  if (AH->remoteVersion >= 90500)
1310  {
1311  if (dopt->enable_row_security)
1312  ExecuteSqlStatement(AH, "SET row_security = on");
1313  else
1314  ExecuteSqlStatement(AH, "SET row_security = off");
1315  }
1316 
1317  /*
1318  * Initialize prepared-query state to "nothing prepared". We do this here
1319  * so that a parallel dump worker will have its own state.
1320  */
1321  AH->is_prepared = (bool *) pg_malloc0(NUM_PREP_QUERIES * sizeof(bool));
1322 
1323  /*
1324  * Start transaction-snapshot mode transaction to dump consistent data.
1325  */
1326  ExecuteSqlStatement(AH, "BEGIN");
1327 
1328  /*
1329  * To support the combination of serializable_deferrable with the jobs
1330  * option we use REPEATABLE READ for the worker connections that are
1331  * passed a snapshot. As long as the snapshot is acquired in a
1332  * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
1333  * REPEATABLE READ transaction provides the appropriate integrity
1334  * guarantees. This is a kluge, but safe for back-patching.
1335  */
1336  if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
1338  "SET TRANSACTION ISOLATION LEVEL "
1339  "SERIALIZABLE, READ ONLY, DEFERRABLE");
1340  else
1342  "SET TRANSACTION ISOLATION LEVEL "
1343  "REPEATABLE READ, READ ONLY");
1344 
1345  /*
1346  * If user specified a snapshot to use, select that. In a parallel dump
1347  * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
1348  * is already set (if the server can handle it) and we should use that.
1349  */
1350  if (dumpsnapshot)
1351  AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
1352 
1353  if (AH->sync_snapshot_id)
1354  {
1355  PQExpBuffer query = createPQExpBuffer();
1356 
1357  appendPQExpBufferStr(query, "SET TRANSACTION SNAPSHOT ");
1359  ExecuteSqlStatement(AH, query->data);
1360  destroyPQExpBuffer(query);
1361  }
1362  else if (AH->numWorkers > 1)
1363  {
1364  if (AH->isStandby && AH->remoteVersion < 100000)
1365  pg_fatal("parallel dumps from standby servers are not supported by this server version");
1367  }
1368 }
1369 
1370 /* Set up connection for a parallel worker process */
1371 static void
1373 {
1374  /*
1375  * We want to re-select all the same values the leader connection is
1376  * using. We'll have inherited directly-usable values in
1377  * AH->sync_snapshot_id and AH->use_role, but we need to translate the
1378  * inherited encoding value back to a string to pass to setup_connection.
1379  */
1380  setup_connection(AH,
1382  NULL,
1383  NULL);
1384 }
1385 
1386 static char *
1388 {
1389  char *query = "SELECT pg_catalog.pg_export_snapshot()";
1390  char *result;
1391  PGresult *res;
1392 
1393  res = ExecuteSqlQueryForSingleRow(fout, query);
1394  result = pg_strdup(PQgetvalue(res, 0, 0));
1395  PQclear(res);
1396 
1397  return result;
1398 }
1399 
1400 static ArchiveFormat
1402 {
1403  ArchiveFormat archiveFormat;
1404 
1405  *mode = archModeWrite;
1406 
1407  if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1408  {
1409  /* This is used by pg_dumpall, and is not documented */
1410  archiveFormat = archNull;
1411  *mode = archModeAppend;
1412  }
1413  else if (pg_strcasecmp(format, "c") == 0)
1414  archiveFormat = archCustom;
1415  else if (pg_strcasecmp(format, "custom") == 0)
1416  archiveFormat = archCustom;
1417  else if (pg_strcasecmp(format, "d") == 0)
1418  archiveFormat = archDirectory;
1419  else if (pg_strcasecmp(format, "directory") == 0)
1420  archiveFormat = archDirectory;
1421  else if (pg_strcasecmp(format, "p") == 0)
1422  archiveFormat = archNull;
1423  else if (pg_strcasecmp(format, "plain") == 0)
1424  archiveFormat = archNull;
1425  else if (pg_strcasecmp(format, "t") == 0)
1426  archiveFormat = archTar;
1427  else if (pg_strcasecmp(format, "tar") == 0)
1428  archiveFormat = archTar;
1429  else
1430  pg_fatal("invalid output format \"%s\" specified", format);
1431  return archiveFormat;
1432 }
1433 
1434 /*
1435  * Find the OIDs of all schemas matching the given list of patterns,
1436  * and append them to the given OID list.
1437  */
1438 static void
1440  SimpleStringList *patterns,
1441  SimpleOidList *oids,
1442  bool strict_names)
1443 {
1444  PQExpBuffer query;
1445  PGresult *res;
1446  SimpleStringListCell *cell;
1447  int i;
1448 
1449  if (patterns->head == NULL)
1450  return; /* nothing to do */
1451 
1452  query = createPQExpBuffer();
1453 
1454  /*
1455  * The loop below runs multiple SELECTs might sometimes result in
1456  * duplicate entries in the OID list, but we don't care.
1457  */
1458 
1459  for (cell = patterns->head; cell; cell = cell->next)
1460  {
1461  PQExpBufferData dbbuf;
1462  int dotcnt;
1463 
1464  appendPQExpBufferStr(query,
1465  "SELECT oid FROM pg_catalog.pg_namespace n\n");
1466  initPQExpBuffer(&dbbuf);
1467  processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1468  false, NULL, "n.nspname", NULL, NULL, &dbbuf,
1469  &dotcnt);
1470  if (dotcnt > 1)
1471  pg_fatal("improper qualified name (too many dotted names): %s",
1472  cell->val);
1473  else if (dotcnt == 1)
1474  prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
1475  termPQExpBuffer(&dbbuf);
1476 
1477  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1478  if (strict_names && PQntuples(res) == 0)
1479  pg_fatal("no matching schemas were found for pattern \"%s\"", cell->val);
1480 
1481  for (i = 0; i < PQntuples(res); i++)
1482  {
1484  }
1485 
1486  PQclear(res);
1487  resetPQExpBuffer(query);
1488  }
1489 
1490  destroyPQExpBuffer(query);
1491 }
1492 
1493 /*
1494  * Find the OIDs of all extensions matching the given list of patterns,
1495  * and append them to the given OID list.
1496  */
1497 static void
1499  SimpleStringList *patterns,
1500  SimpleOidList *oids,
1501  bool strict_names)
1502 {
1503  PQExpBuffer query;
1504  PGresult *res;
1505  SimpleStringListCell *cell;
1506  int i;
1507 
1508  if (patterns->head == NULL)
1509  return; /* nothing to do */
1510 
1511  query = createPQExpBuffer();
1512 
1513  /*
1514  * The loop below runs multiple SELECTs might sometimes result in
1515  * duplicate entries in the OID list, but we don't care.
1516  */
1517  for (cell = patterns->head; cell; cell = cell->next)
1518  {
1519  int dotcnt;
1520 
1521  appendPQExpBufferStr(query,
1522  "SELECT oid FROM pg_catalog.pg_extension e\n");
1523  processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1524  false, NULL, "e.extname", NULL, NULL, NULL,
1525  &dotcnt);
1526  if (dotcnt > 0)
1527  pg_fatal("improper qualified name (too many dotted names): %s",
1528  cell->val);
1529 
1530  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1531  if (strict_names && PQntuples(res) == 0)
1532  pg_fatal("no matching extensions were found for pattern \"%s\"", cell->val);
1533 
1534  for (i = 0; i < PQntuples(res); i++)
1535  {
1537  }
1538 
1539  PQclear(res);
1540  resetPQExpBuffer(query);
1541  }
1542 
1543  destroyPQExpBuffer(query);
1544 }
1545 
1546 /*
1547  * Find the OIDs of all foreign servers matching the given list of patterns,
1548  * and append them to the given OID list.
1549  */
1550 static void
1552  SimpleStringList *patterns,
1553  SimpleOidList *oids)
1554 {
1555  PQExpBuffer query;
1556  PGresult *res;
1557  SimpleStringListCell *cell;
1558  int i;
1559 
1560  if (patterns->head == NULL)
1561  return; /* nothing to do */
1562 
1563  query = createPQExpBuffer();
1564 
1565  /*
1566  * The loop below runs multiple SELECTs might sometimes result in
1567  * duplicate entries in the OID list, but we don't care.
1568  */
1569 
1570  for (cell = patterns->head; cell; cell = cell->next)
1571  {
1572  int dotcnt;
1573 
1574  appendPQExpBufferStr(query,
1575  "SELECT oid FROM pg_catalog.pg_foreign_server s\n");
1576  processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1577  false, NULL, "s.srvname", NULL, NULL, NULL,
1578  &dotcnt);
1579  if (dotcnt > 0)
1580  pg_fatal("improper qualified name (too many dotted names): %s",
1581  cell->val);
1582 
1583  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1584  if (PQntuples(res) == 0)
1585  pg_fatal("no matching foreign servers were found for pattern \"%s\"", cell->val);
1586 
1587  for (i = 0; i < PQntuples(res); i++)
1589 
1590  PQclear(res);
1591  resetPQExpBuffer(query);
1592  }
1593 
1594  destroyPQExpBuffer(query);
1595 }
1596 
1597 /*
1598  * Find the OIDs of all tables matching the given list of patterns,
1599  * and append them to the given OID list. See also expand_dbname_patterns()
1600  * in pg_dumpall.c
1601  */
1602 static void
1604  SimpleStringList *patterns, SimpleOidList *oids,
1605  bool strict_names, bool with_child_tables)
1606 {
1607  PQExpBuffer query;
1608  PGresult *res;
1609  SimpleStringListCell *cell;
1610  int i;
1611 
1612  if (patterns->head == NULL)
1613  return; /* nothing to do */
1614 
1615  query = createPQExpBuffer();
1616 
1617  /*
1618  * this might sometimes result in duplicate entries in the OID list, but
1619  * we don't care.
1620  */
1621 
1622  for (cell = patterns->head; cell; cell = cell->next)
1623  {
1624  PQExpBufferData dbbuf;
1625  int dotcnt;
1626 
1627  /*
1628  * Query must remain ABSOLUTELY devoid of unqualified names. This
1629  * would be unnecessary given a pg_table_is_visible() variant taking a
1630  * search_path argument.
1631  *
1632  * For with_child_tables, we start with the basic query's results and
1633  * recursively search the inheritance tree to add child tables.
1634  */
1635  if (with_child_tables)
1636  {
1637  appendPQExpBuffer(query, "WITH RECURSIVE partition_tree (relid) AS (\n");
1638  }
1639 
1640  appendPQExpBuffer(query,
1641  "SELECT c.oid"
1642  "\nFROM pg_catalog.pg_class c"
1643  "\n LEFT JOIN pg_catalog.pg_namespace n"
1644  "\n ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
1645  "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
1646  "\n (array['%c', '%c', '%c', '%c', '%c', '%c'])\n",
1647  RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1648  RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
1649  RELKIND_PARTITIONED_TABLE);
1650  initPQExpBuffer(&dbbuf);
1651  processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1652  false, "n.nspname", "c.relname", NULL,
1653  "pg_catalog.pg_table_is_visible(c.oid)", &dbbuf,
1654  &dotcnt);
1655  if (dotcnt > 2)
1656  pg_fatal("improper relation name (too many dotted names): %s",
1657  cell->val);
1658  else if (dotcnt == 2)
1659  prohibit_crossdb_refs(GetConnection(fout), dbbuf.data, cell->val);
1660  termPQExpBuffer(&dbbuf);
1661 
1662  if (with_child_tables)
1663  {
1664  appendPQExpBuffer(query, "UNION"
1665  "\nSELECT i.inhrelid"
1666  "\nFROM partition_tree p"
1667  "\n JOIN pg_catalog.pg_inherits i"
1668  "\n ON p.relid OPERATOR(pg_catalog.=) i.inhparent"
1669  "\n)"
1670  "\nSELECT relid FROM partition_tree");
1671  }
1672 
1673  ExecuteSqlStatement(fout, "RESET search_path");
1674  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1677  if (strict_names && PQntuples(res) == 0)
1678  pg_fatal("no matching tables were found for pattern \"%s\"", cell->val);
1679 
1680  for (i = 0; i < PQntuples(res); i++)
1681  {
1683  }
1684 
1685  PQclear(res);
1686  resetPQExpBuffer(query);
1687  }
1688 
1689  destroyPQExpBuffer(query);
1690 }
1691 
1692 /*
1693  * Verifies that the connected database name matches the given database name,
1694  * and if not, dies with an error about the given pattern.
1695  *
1696  * The 'dbname' argument should be a literal name parsed from 'pattern'.
1697  */
1698 static void
1699 prohibit_crossdb_refs(PGconn *conn, const char *dbname, const char *pattern)
1700 {
1701  const char *db;
1702 
1703  db = PQdb(conn);
1704  if (db == NULL)
1705  pg_fatal("You are currently not connected to a database.");
1706 
1707  if (strcmp(db, dbname) != 0)
1708  pg_fatal("cross-database references are not implemented: %s",
1709  pattern);
1710 }
1711 
1712 /*
1713  * checkExtensionMembership
1714  * Determine whether object is an extension member, and if so,
1715  * record an appropriate dependency and set the object's dump flag.
1716  *
1717  * It's important to call this for each object that could be an extension
1718  * member. Generally, we integrate this with determining the object's
1719  * to-be-dumped-ness, since extension membership overrides other rules for that.
1720  *
1721  * Returns true if object is an extension member, else false.
1722  */
1723 static bool
1725 {
1726  ExtensionInfo *ext = findOwningExtension(dobj->catId);
1727 
1728  if (ext == NULL)
1729  return false;
1730 
1731  dobj->ext_member = true;
1732 
1733  /* Record dependency so that getDependencies needn't deal with that */
1734  addObjectDependency(dobj, ext->dobj.dumpId);
1735 
1736  /*
1737  * In 9.6 and above, mark the member object to have any non-initial ACLs
1738  * dumped. (Any initial ACLs will be removed later, using data from
1739  * pg_init_privs, so that we'll dump only the delta from the extension's
1740  * initial setup.)
1741  *
1742  * Prior to 9.6, we do not include any extension member components.
1743  *
1744  * In binary upgrades, we still dump all components of the members
1745  * individually, since the idea is to exactly reproduce the database
1746  * contents rather than replace the extension contents with something
1747  * different.
1748  *
1749  * Note: it might be interesting someday to implement storage and delta
1750  * dumping of extension members' RLS policies and/or security labels.
1751  * However there is a pitfall for RLS policies: trying to dump them
1752  * requires getting a lock on their tables, and the calling user might not
1753  * have privileges for that. We need no lock to examine a table's ACLs,
1754  * so the current feature doesn't have a problem of that sort.
1755  */
1756  if (fout->dopt->binary_upgrade)
1757  dobj->dump = ext->dobj.dump;
1758  else
1759  {
1760  if (fout->remoteVersion < 90600)
1761  dobj->dump = DUMP_COMPONENT_NONE;
1762  else
1763  dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL);
1764  }
1765 
1766  return true;
1767 }
1768 
1769 /*
1770  * selectDumpableNamespace: policy-setting subroutine
1771  * Mark a namespace as to be dumped or not
1772  */
1773 static void
1775 {
1776  /*
1777  * DUMP_COMPONENT_DEFINITION typically implies a CREATE SCHEMA statement
1778  * and (for --clean) a DROP SCHEMA statement. (In the absence of
1779  * DUMP_COMPONENT_DEFINITION, this value is irrelevant.)
1780  */
1781  nsinfo->create = true;
1782 
1783  /*
1784  * If specific tables are being dumped, do not dump any complete
1785  * namespaces. If specific namespaces are being dumped, dump just those
1786  * namespaces. Otherwise, dump all non-system namespaces.
1787  */
1788  if (table_include_oids.head != NULL)
1789  nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1790  else if (schema_include_oids.head != NULL)
1791  nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
1793  nsinfo->dobj.catId.oid) ?
1795  else if (fout->remoteVersion >= 90600 &&
1796  strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
1797  {
1798  /*
1799  * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
1800  * they are interesting (and not the original ACLs which were set at
1801  * initdb time, see pg_init_privs).
1802  */
1803  nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1804  }
1805  else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1806  strcmp(nsinfo->dobj.name, "information_schema") == 0)
1807  {
1808  /* Other system schemas don't get dumped */
1809  nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1810  }
1811  else if (strcmp(nsinfo->dobj.name, "public") == 0)
1812  {
1813  /*
1814  * The public schema is a strange beast that sits in a sort of
1815  * no-mans-land between being a system object and a user object.
1816  * CREATE SCHEMA would fail, so its DUMP_COMPONENT_DEFINITION is just
1817  * a comment and an indication of ownership. If the owner is the
1818  * default, omit that superfluous DUMP_COMPONENT_DEFINITION. Before
1819  * v15, the default owner was BOOTSTRAP_SUPERUSERID.
1820  */
1821  nsinfo->create = false;
1822  nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
1823  if (nsinfo->nspowner == ROLE_PG_DATABASE_OWNER)
1824  nsinfo->dobj.dump &= ~DUMP_COMPONENT_DEFINITION;
1826 
1827  /*
1828  * Also, make like it has a comment even if it doesn't; this is so
1829  * that we'll emit a command to drop the comment, if appropriate.
1830  * (Without this, we'd not call dumpCommentExtended for it.)
1831  */
1833  }
1834  else
1835  nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
1836 
1837  /*
1838  * In any case, a namespace can be excluded by an exclusion switch
1839  */
1840  if (nsinfo->dobj.dump_contains &&
1842  nsinfo->dobj.catId.oid))
1843  nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1844 
1845  /*
1846  * If the schema belongs to an extension, allow extension membership to
1847  * override the dump decision for the schema itself. However, this does
1848  * not change dump_contains, so this won't change what we do with objects
1849  * within the schema. (If they belong to the extension, they'll get
1850  * suppressed by it, otherwise not.)
1851  */
1852  (void) checkExtensionMembership(&nsinfo->dobj, fout);
1853 }
1854 
1855 /*
1856  * selectDumpableTable: policy-setting subroutine
1857  * Mark a table as to be dumped or not
1858  */
1859 static void
1861 {
1862  if (checkExtensionMembership(&tbinfo->dobj, fout))
1863  return; /* extension membership overrides all else */
1864 
1865  /*
1866  * If specific tables are being dumped, dump just those tables; else, dump
1867  * according to the parent namespace's dump flag.
1868  */
1869  if (table_include_oids.head != NULL)
1871  tbinfo->dobj.catId.oid) ?
1873  else
1874  tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
1875 
1876  /*
1877  * In any case, a table can be excluded by an exclusion switch
1878  */
1879  if (tbinfo->dobj.dump &&
1881  tbinfo->dobj.catId.oid))
1882  tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
1883 }
1884 
1885 /*
1886  * selectDumpableType: policy-setting subroutine
1887  * Mark a type as to be dumped or not
1888  *
1889  * If it's a table's rowtype or an autogenerated array type, we also apply a
1890  * special type code to facilitate sorting into the desired order. (We don't
1891  * want to consider those to be ordinary types because that would bring tables
1892  * up into the datatype part of the dump order.) We still set the object's
1893  * dump flag; that's not going to cause the dummy type to be dumped, but we
1894  * need it so that casts involving such types will be dumped correctly -- see
1895  * dumpCast. This means the flag should be set the same as for the underlying
1896  * object (the table or base type).
1897  */
1898 static void
1900 {
1901  /* skip complex types, except for standalone composite types */
1902  if (OidIsValid(tyinfo->typrelid) &&
1903  tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1904  {
1905  TableInfo *tytable = findTableByOid(tyinfo->typrelid);
1906 
1907  tyinfo->dobj.objType = DO_DUMMY_TYPE;
1908  if (tytable != NULL)
1909  tyinfo->dobj.dump = tytable->dobj.dump;
1910  else
1911  tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
1912  return;
1913  }
1914 
1915  /* skip auto-generated array and multirange types */
1916  if (tyinfo->isArray || tyinfo->isMultirange)
1917  {
1918  tyinfo->dobj.objType = DO_DUMMY_TYPE;
1919 
1920  /*
1921  * Fall through to set the dump flag; we assume that the subsequent
1922  * rules will do the same thing as they would for the array's base
1923  * type or multirange's range type. (We cannot reliably look up the
1924  * base type here, since getTypes may not have processed it yet.)
1925  */
1926  }
1927 
1928  if (checkExtensionMembership(&tyinfo->dobj, fout))
1929  return; /* extension membership overrides all else */
1930 
1931  /* Dump based on if the contents of the namespace are being dumped */
1932  tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
1933 }
1934 
1935 /*
1936  * selectDumpableDefaultACL: policy-setting subroutine
1937  * Mark a default ACL as to be dumped or not
1938  *
1939  * For per-schema default ACLs, dump if the schema is to be dumped.
1940  * Otherwise dump if we are dumping "everything". Note that dataOnly
1941  * and aclsSkip are checked separately.
1942  */
1943 static void
1945 {
1946  /* Default ACLs can't be extension members */
1947 
1948  if (dinfo->dobj.namespace)
1949  /* default ACLs are considered part of the namespace */
1950  dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
1951  else
1952  dinfo->dobj.dump = dopt->include_everything ?
1954 }
1955 
1956 /*
1957  * selectDumpableCast: policy-setting subroutine
1958  * Mark a cast as to be dumped or not
1959  *
1960  * Casts do not belong to any particular namespace (since they haven't got
1961  * names), nor do they have identifiable owners. To distinguish user-defined
1962  * casts from built-in ones, we must resort to checking whether the cast's
1963  * OID is in the range reserved for initdb.
1964  */
1965 static void
1967 {
1968  if (checkExtensionMembership(&cast->dobj, fout))
1969  return; /* extension membership overrides all else */
1970 
1971  /*
1972  * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
1973  * support ACLs currently.
1974  */
1975  if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1976  cast->dobj.dump = DUMP_COMPONENT_NONE;
1977  else
1978  cast->dobj.dump = fout->dopt->include_everything ?
1980 }
1981 
1982 /*
1983  * selectDumpableProcLang: policy-setting subroutine
1984  * Mark a procedural language as to be dumped or not
1985  *
1986  * Procedural languages do not belong to any particular namespace. To
1987  * identify built-in languages, we must resort to checking whether the
1988  * language's OID is in the range reserved for initdb.
1989  */
1990 static void
1992 {
1993  if (checkExtensionMembership(&plang->dobj, fout))
1994  return; /* extension membership overrides all else */
1995 
1996  /*
1997  * Only include procedural languages when we are dumping everything.
1998  *
1999  * For from-initdb procedural languages, only include ACLs, as we do for
2000  * the pg_catalog namespace. We need this because procedural languages do
2001  * not live in any namespace.
2002  */
2003  if (!fout->dopt->include_everything)
2004  plang->dobj.dump = DUMP_COMPONENT_NONE;
2005  else
2006  {
2007  if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
2008  plang->dobj.dump = fout->remoteVersion < 90600 ?
2010  else
2011  plang->dobj.dump = DUMP_COMPONENT_ALL;
2012  }
2013 }
2014 
2015 /*
2016  * selectDumpableAccessMethod: policy-setting subroutine
2017  * Mark an access method as to be dumped or not
2018  *
2019  * Access methods do not belong to any particular namespace. To identify
2020  * built-in access methods, we must resort to checking whether the
2021  * method's OID is in the range reserved for initdb.
2022  */
2023 static void
2025 {
2026  if (checkExtensionMembership(&method->dobj, fout))
2027  return; /* extension membership overrides all else */
2028 
2029  /*
2030  * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
2031  * they do not support ACLs currently.
2032  */
2033  if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
2034  method->dobj.dump = DUMP_COMPONENT_NONE;
2035  else
2036  method->dobj.dump = fout->dopt->include_everything ?
2038 }
2039 
2040 /*
2041  * selectDumpableExtension: policy-setting subroutine
2042  * Mark an extension as to be dumped or not
2043  *
2044  * Built-in extensions should be skipped except for checking ACLs, since we
2045  * assume those will already be installed in the target database. We identify
2046  * such extensions by their having OIDs in the range reserved for initdb.
2047  * We dump all user-added extensions by default. No extensions are dumped
2048  * if include_everything is false (i.e., a --schema or --table switch was
2049  * given), except if --extension specifies a list of extensions to dump.
2050  */
2051 static void
2053 {
2054  /*
2055  * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
2056  * change permissions on their member objects, if they wish to, and have
2057  * those changes preserved.
2058  */
2059  if (extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
2060  extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
2061  else
2062  {
2063  /* check if there is a list of extensions to dump */
2064  if (extension_include_oids.head != NULL)
2065  extinfo->dobj.dump = extinfo->dobj.dump_contains =
2067  extinfo->dobj.catId.oid) ?
2069  else
2070  extinfo->dobj.dump = extinfo->dobj.dump_contains =
2071  dopt->include_everything ?
2073 
2074  /* check that the extension is not explicitly excluded */
2075  if (extinfo->dobj.dump &&
2077  extinfo->dobj.catId.oid))
2078  extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_NONE;
2079  }
2080 }
2081 
2082 /*
2083  * selectDumpablePublicationObject: policy-setting subroutine
2084  * Mark a publication object as to be dumped or not
2085  *
2086  * A publication can have schemas and tables which have schemas, but those are
2087  * ignored in decision making, because publications are only dumped when we are
2088  * dumping everything.
2089  */
2090 static void
2092 {
2093  if (checkExtensionMembership(dobj, fout))
2094  return; /* extension membership overrides all else */
2095 
2096  dobj->dump = fout->dopt->include_everything ?
2098 }
2099 
2100 /*
2101  * selectDumpableStatisticsObject: policy-setting subroutine
2102  * Mark an extended statistics object as to be dumped or not
2103  *
2104  * We dump an extended statistics object if the schema it's in and the table
2105  * it's for are being dumped. (This'll need more thought if statistics
2106  * objects ever support cross-table stats.)
2107  */
2108 static void
2110 {
2111  if (checkExtensionMembership(&sobj->dobj, fout))
2112  return; /* extension membership overrides all else */
2113 
2114  sobj->dobj.dump = sobj->dobj.namespace->dobj.dump_contains;
2115  if (sobj->stattable == NULL ||
2117  sobj->dobj.dump = DUMP_COMPONENT_NONE;
2118 }
2119 
2120 /*
2121  * selectDumpableObject: policy-setting subroutine
2122  * Mark a generic dumpable object as to be dumped or not
2123  *
2124  * Use this only for object types without a special-case routine above.
2125  */
2126 static void
2128 {
2129  if (checkExtensionMembership(dobj, fout))
2130  return; /* extension membership overrides all else */
2131 
2132  /*
2133  * Default policy is to dump if parent namespace is dumpable, or for
2134  * non-namespace-associated items, dump if we're dumping "everything".
2135  */
2136  if (dobj->namespace)
2137  dobj->dump = dobj->namespace->dobj.dump_contains;
2138  else
2139  dobj->dump = fout->dopt->include_everything ?
2141 }
2142 
2143 /*
2144  * Dump a table's contents for loading using the COPY command
2145  * - this routine is called by the Archiver when it wants the table
2146  * to be dumped.
2147  */
2148 static int
2149 dumpTableData_copy(Archive *fout, const void *dcontext)
2150 {
2151  TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
2152  TableInfo *tbinfo = tdinfo->tdtable;
2153  const char *classname = tbinfo->dobj.name;
2155 
2156  /*
2157  * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
2158  * which uses it already.
2159  */
2160  PQExpBuffer clistBuf = createPQExpBuffer();
2161  PGconn *conn = GetConnection(fout);
2162  PGresult *res;
2163  int ret;
2164  char *copybuf;
2165  const char *column_list;
2166 
2167  pg_log_info("dumping contents of table \"%s.%s\"",
2168  tbinfo->dobj.namespace->dobj.name, classname);
2169 
2170  /*
2171  * Specify the column list explicitly so that we have no possibility of
2172  * retrieving data in the wrong column order. (The default column
2173  * ordering of COPY will not be what we want in certain corner cases
2174  * involving ADD COLUMN and inheritance.)
2175  */
2176  column_list = fmtCopyColumnList(tbinfo, clistBuf);
2177 
2178  /*
2179  * Use COPY (SELECT ...) TO when dumping a foreign table's data, and when
2180  * a filter condition was specified. For other cases a simple COPY
2181  * suffices.
2182  */
2183  if (tdinfo->filtercond || tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2184  {
2185  appendPQExpBufferStr(q, "COPY (SELECT ");
2186  /* klugery to get rid of parens in column list */
2187  if (strlen(column_list) > 2)
2188  {
2189  appendPQExpBufferStr(q, column_list + 1);
2190  q->data[q->len - 1] = ' ';
2191  }
2192  else
2193  appendPQExpBufferStr(q, "* ");
2194 
2195  appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
2196  fmtQualifiedDumpable(tbinfo),
2197  tdinfo->filtercond ? tdinfo->filtercond : "");
2198  }
2199  else
2200  {
2201  appendPQExpBuffer(q, "COPY %s %s TO stdout;",
2202  fmtQualifiedDumpable(tbinfo),
2203  column_list);
2204  }
2205  res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
2206  PQclear(res);
2207  destroyPQExpBuffer(clistBuf);
2208 
2209  for (;;)
2210  {
2211  ret = PQgetCopyData(conn, &copybuf, 0);
2212 
2213  if (ret < 0)
2214  break; /* done or error */
2215 
2216  if (copybuf)
2217  {
2218  WriteData(fout, copybuf, ret);
2219  PQfreemem(copybuf);
2220  }
2221 
2222  /* ----------
2223  * THROTTLE:
2224  *
2225  * There was considerable discussion in late July, 2000 regarding
2226  * slowing down pg_dump when backing up large tables. Users with both
2227  * slow & fast (multi-processor) machines experienced performance
2228  * degradation when doing a backup.
2229  *
2230  * Initial attempts based on sleeping for a number of ms for each ms
2231  * of work were deemed too complex, then a simple 'sleep in each loop'
2232  * implementation was suggested. The latter failed because the loop
2233  * was too tight. Finally, the following was implemented:
2234  *
2235  * If throttle is non-zero, then
2236  * See how long since the last sleep.
2237  * Work out how long to sleep (based on ratio).
2238  * If sleep is more than 100ms, then
2239  * sleep
2240  * reset timer
2241  * EndIf
2242  * EndIf
2243  *
2244  * where the throttle value was the number of ms to sleep per ms of
2245  * work. The calculation was done in each loop.
2246  *
2247  * Most of the hard work is done in the backend, and this solution
2248  * still did not work particularly well: on slow machines, the ratio
2249  * was 50:1, and on medium paced machines, 1:1, and on fast
2250  * multi-processor machines, it had little or no effect, for reasons
2251  * that were unclear.
2252  *
2253  * Further discussion ensued, and the proposal was dropped.
2254  *
2255  * For those people who want this feature, it can be implemented using
2256  * gettimeofday in each loop, calculating the time since last sleep,
2257  * multiplying that by the sleep ratio, then if the result is more
2258  * than a preset 'minimum sleep time' (say 100ms), call the 'select'
2259  * function to sleep for a subsecond period ie.
2260  *
2261  * select(0, NULL, NULL, NULL, &tvi);
2262  *
2263  * This will return after the interval specified in the structure tvi.
2264  * Finally, call gettimeofday again to save the 'last sleep time'.
2265  * ----------
2266  */
2267  }
2268  archprintf(fout, "\\.\n\n\n");
2269 
2270  if (ret == -2)
2271  {
2272  /* copy data transfer failed */
2273  pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
2274  pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
2275  pg_log_error_detail("Command was: %s", q->data);
2276  exit_nicely(1);
2277  }
2278 
2279  /* Check command status and return to normal libpq state */
2280  res = PQgetResult(conn);
2282  {
2283  pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
2284  pg_log_error_detail("Error message from server: %s", PQerrorMessage(conn));
2285  pg_log_error_detail("Command was: %s", q->data);
2286  exit_nicely(1);
2287  }
2288  PQclear(res);
2289 
2290  /* Do this to ensure we've pumped libpq back to idle state */
2291  if (PQgetResult(conn) != NULL)
2292  pg_log_warning("unexpected extra results during COPY of table \"%s\"",
2293  classname);
2294 
2295  destroyPQExpBuffer(q);
2296  return 1;
2297 }
2298 
2299 /*
2300  * Dump table data using INSERT commands.
2301  *
2302  * Caution: when we restore from an archive file direct to database, the
2303  * INSERT commands emitted by this function have to be parsed by
2304  * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
2305  * E'' strings, or dollar-quoted strings. So don't emit anything like that.
2306  */
2307 static int
2308 dumpTableData_insert(Archive *fout, const void *dcontext)
2309 {
2310  TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
2311  TableInfo *tbinfo = tdinfo->tdtable;
2312  DumpOptions *dopt = fout->dopt;
2314  PQExpBuffer insertStmt = NULL;
2315  char *attgenerated;
2316  PGresult *res;
2317  int nfields,
2318  i;
2319  int rows_per_statement = dopt->dump_inserts;
2320  int rows_this_statement = 0;
2321 
2322  /*
2323  * If we're going to emit INSERTs with column names, the most efficient
2324  * way to deal with generated columns is to exclude them entirely. For
2325  * INSERTs without column names, we have to emit DEFAULT rather than the
2326  * actual column value --- but we can save a few cycles by fetching nulls
2327  * rather than the uninteresting-to-us value.
2328  */
2329  attgenerated = (char *) pg_malloc(tbinfo->numatts * sizeof(char));
2330  appendPQExpBufferStr(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT ");
2331  nfields = 0;
2332  for (i = 0; i < tbinfo->numatts; i++)
2333  {
2334  if (tbinfo->attisdropped[i])
2335  continue;
2336  if (tbinfo->attgenerated[i] && dopt->column_inserts)
2337  continue;
2338  if (nfields > 0)
2339  appendPQExpBufferStr(q, ", ");
2340  if (tbinfo->attgenerated[i])
2341  appendPQExpBufferStr(q, "NULL");
2342  else
2343  appendPQExpBufferStr(q, fmtId(tbinfo->attnames[i]));
2344  attgenerated[nfields] = tbinfo->attgenerated[i];
2345  nfields++;
2346  }
2347  /* Servers before 9.4 will complain about zero-column SELECT */
2348  if (nfields == 0)
2349  appendPQExpBufferStr(q, "NULL");
2350  appendPQExpBuffer(q, " FROM ONLY %s",
2351  fmtQualifiedDumpable(tbinfo));
2352  if (tdinfo->filtercond)
2353  appendPQExpBuffer(q, " %s", tdinfo->filtercond);
2354 
2355  ExecuteSqlStatement(fout, q->data);
2356 
2357  while (1)
2358  {
2359  res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
2360  PGRES_TUPLES_OK);
2361 
2362  /* cross-check field count, allowing for dummy NULL if any */
2363  if (nfields != PQnfields(res) &&
2364  !(nfields == 0 && PQnfields(res) == 1))
2365  pg_fatal("wrong number of fields retrieved from table \"%s\"",
2366  tbinfo->dobj.name);
2367 
2368  /*
2369  * First time through, we build as much of the INSERT statement as
2370  * possible in "insertStmt", which we can then just print for each
2371  * statement. If the table happens to have zero dumpable columns then
2372  * this will be a complete statement, otherwise it will end in
2373  * "VALUES" and be ready to have the row's column values printed.
2374  */
2375  if (insertStmt == NULL)
2376  {
2377  TableInfo *targettab;
2378 
2379  insertStmt = createPQExpBuffer();
2380 
2381  /*
2382  * When load-via-partition-root is set or forced, get the root
2383  * table name for the partition table, so that we can reload data
2384  * through the root table.
2385  */
2386  if (tbinfo->ispartition &&
2387  (dopt->load_via_partition_root ||
2388  forcePartitionRootLoad(tbinfo)))
2389  targettab = getRootTableInfo(tbinfo);
2390  else
2391  targettab = tbinfo;
2392 
2393  appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
2394  fmtQualifiedDumpable(targettab));
2395 
2396  /* corner case for zero-column table */
2397  if (nfields == 0)
2398  {
2399  appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
2400  }
2401  else
2402  {
2403  /* append the list of column names if required */
2404  if (dopt->column_inserts)
2405  {
2406  appendPQExpBufferChar(insertStmt, '(');
2407  for (int field = 0; field < nfields; field++)
2408  {
2409  if (field > 0)
2410  appendPQExpBufferStr(insertStmt, ", ");
2411  appendPQExpBufferStr(insertStmt,
2412  fmtId(PQfname(res, field)));
2413  }
2414  appendPQExpBufferStr(insertStmt, ") ");
2415  }
2416 
2417  if (tbinfo->needs_override)
2418  appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
2419 
2420  appendPQExpBufferStr(insertStmt, "VALUES");
2421  }
2422  }
2423 
2424  for (int tuple = 0; tuple < PQntuples(res); tuple++)
2425  {
2426  /* Write the INSERT if not in the middle of a multi-row INSERT. */
2427  if (rows_this_statement == 0)
2428  archputs(insertStmt->data, fout);
2429 
2430  /*
2431  * If it is zero-column table then we've already written the
2432  * complete statement, which will mean we've disobeyed
2433  * --rows-per-insert when it's set greater than 1. We do support
2434  * a way to make this multi-row with: SELECT UNION ALL SELECT
2435  * UNION ALL ... but that's non-standard so we should avoid it
2436  * given that using INSERTs is mostly only ever needed for
2437  * cross-database exports.
2438  */
2439  if (nfields == 0)
2440  continue;
2441 
2442  /* Emit a row heading */
2443  if (rows_per_statement == 1)
2444  archputs(" (", fout);
2445  else if (rows_this_statement > 0)
2446  archputs(",\n\t(", fout);
2447  else
2448  archputs("\n\t(", fout);
2449 
2450  for (int field = 0; field < nfields; field++)
2451  {
2452  if (field > 0)
2453  archputs(", ", fout);
2454  if (attgenerated[field])
2455  {
2456  archputs("DEFAULT", fout);
2457  continue;
2458  }
2459  if (PQgetisnull(res, tuple, field))
2460  {
2461  archputs("NULL", fout);
2462  continue;
2463  }
2464 
2465  /* XXX This code is partially duplicated in ruleutils.c */
2466  switch (PQftype(res, field))
2467  {
2468  case INT2OID:
2469  case INT4OID:
2470  case INT8OID:
2471  case OIDOID:
2472  case FLOAT4OID:
2473  case FLOAT8OID:
2474  case NUMERICOID:
2475  {
2476  /*
2477  * These types are printed without quotes unless
2478  * they contain values that aren't accepted by the
2479  * scanner unquoted (e.g., 'NaN'). Note that
2480  * strtod() and friends might accept NaN, so we
2481  * can't use that to test.
2482  *
2483  * In reality we only need to defend against
2484  * infinity and NaN, so we need not get too crazy
2485  * about pattern matching here.
2486  */
2487  const char *s = PQgetvalue(res, tuple, field);
2488 
2489  if (strspn(s, "0123456789 +-eE.") == strlen(s))
2490  archputs(s, fout);
2491  else
2492  archprintf(fout, "'%s'", s);
2493  }
2494  break;
2495 
2496  case BITOID:
2497  case VARBITOID:
2498  archprintf(fout, "B'%s'",
2499  PQgetvalue(res, tuple, field));
2500  break;
2501 
2502  case BOOLOID:
2503  if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
2504  archputs("true", fout);
2505  else
2506  archputs("false", fout);
2507  break;
2508 
2509  default:
2510  /* All other types are printed as string literals. */
2511  resetPQExpBuffer(q);
2513  PQgetvalue(res, tuple, field),
2514  fout);
2515  archputs(q->data, fout);
2516  break;
2517  }
2518  }
2519 
2520  /* Terminate the row ... */
2521  archputs(")", fout);
2522 
2523  /* ... and the statement, if the target no. of rows is reached */
2524  if (++rows_this_statement >= rows_per_statement)
2525  {
2526  if (dopt->do_nothing)
2527  archputs(" ON CONFLICT DO NOTHING;\n", fout);
2528  else
2529  archputs(";\n", fout);
2530  /* Reset the row counter */
2531  rows_this_statement = 0;
2532  }
2533  }
2534 
2535  if (PQntuples(res) <= 0)
2536  {
2537  PQclear(res);
2538  break;
2539  }
2540  PQclear(res);
2541  }
2542 
2543  /* Terminate any statements that didn't make the row count. */
2544  if (rows_this_statement > 0)
2545  {
2546  if (dopt->do_nothing)
2547  archputs(" ON CONFLICT DO NOTHING;\n", fout);
2548  else
2549  archputs(";\n", fout);
2550  }
2551 
2552  archputs("\n\n", fout);
2553 
2554  ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
2555 
2556  destroyPQExpBuffer(q);
2557  if (insertStmt != NULL)
2558  destroyPQExpBuffer(insertStmt);
2559  free(attgenerated);
2560 
2561  return 1;
2562 }
2563 
2564 /*
2565  * getRootTableInfo:
2566  * get the root TableInfo for the given partition table.
2567  */
2568 static TableInfo *
2570 {
2571  TableInfo *parentTbinfo;
2572 
2573  Assert(tbinfo->ispartition);
2574  Assert(tbinfo->numParents == 1);
2575 
2576  parentTbinfo = tbinfo->parents[0];
2577  while (parentTbinfo->ispartition)
2578  {
2579  Assert(parentTbinfo->numParents == 1);
2580  parentTbinfo = parentTbinfo->parents[0];
2581  }
2582 
2583  return parentTbinfo;
2584 }
2585 
2586 /*
2587  * forcePartitionRootLoad
2588  * Check if we must force load_via_partition_root for this partition.
2589  *
2590  * This is required if any level of ancestral partitioned table has an
2591  * unsafe partitioning scheme.
2592  */
2593 static bool
2595 {
2596  TableInfo *parentTbinfo;
2597 
2598  Assert(tbinfo->ispartition);
2599  Assert(tbinfo->numParents == 1);
2600 
2601  parentTbinfo = tbinfo->parents[0];
2602  if (parentTbinfo->unsafe_partitions)
2603  return true;
2604  while (parentTbinfo->ispartition)
2605  {
2606  Assert(parentTbinfo->numParents == 1);
2607  parentTbinfo = parentTbinfo->parents[0];
2608  if (parentTbinfo->unsafe_partitions)
2609  return true;
2610  }
2611 
2612  return false;
2613 }
2614 
2615 /*
2616  * dumpTableData -
2617  * dump the contents of a single table
2618  *
2619  * Actually, this just makes an ArchiveEntry for the table contents.
2620  */
2621 static void
2622 dumpTableData(Archive *fout, const TableDataInfo *tdinfo)
2623 {
2624  DumpOptions *dopt = fout->dopt;
2625  TableInfo *tbinfo = tdinfo->tdtable;
2626  PQExpBuffer copyBuf = createPQExpBuffer();
2627  PQExpBuffer clistBuf = createPQExpBuffer();
2628  DataDumperPtr dumpFn;
2629  char *tdDefn = NULL;
2630  char *copyStmt;
2631  const char *copyFrom;
2632 
2633  /* We had better have loaded per-column details about this table */
2634  Assert(tbinfo->interesting);
2635 
2636  /*
2637  * When load-via-partition-root is set or forced, get the root table name
2638  * for the partition table, so that we can reload data through the root
2639  * table. Then construct a comment to be inserted into the TOC entry's
2640  * defn field, so that such cases can be identified reliably.
2641  */
2642  if (tbinfo->ispartition &&
2643  (dopt->load_via_partition_root ||
2644  forcePartitionRootLoad(tbinfo)))
2645  {
2646  TableInfo *parentTbinfo;
2647 
2648  parentTbinfo = getRootTableInfo(tbinfo);
2649  copyFrom = fmtQualifiedDumpable(parentTbinfo);
2650  printfPQExpBuffer(copyBuf, "-- load via partition root %s",
2651  copyFrom);
2652  tdDefn = pg_strdup(copyBuf->data);
2653  }
2654  else
2655  copyFrom = fmtQualifiedDumpable(tbinfo);
2656 
2657  if (dopt->dump_inserts == 0)
2658  {
2659  /* Dump/restore using COPY */
2660  dumpFn = dumpTableData_copy;
2661  /* must use 2 steps here 'cause fmtId is nonreentrant */
2662  printfPQExpBuffer(copyBuf, "COPY %s ",
2663  copyFrom);
2664  appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
2665  fmtCopyColumnList(tbinfo, clistBuf));
2666  copyStmt = copyBuf->data;
2667  }
2668  else
2669  {
2670  /* Restore using INSERT */
2671  dumpFn = dumpTableData_insert;
2672  copyStmt = NULL;
2673  }
2674 
2675  /*
2676  * Note: although the TableDataInfo is a full DumpableObject, we treat its
2677  * dependency on its table as "special" and pass it to ArchiveEntry now.
2678  * See comments for BuildArchiveDependencies.
2679  */
2680  if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2681  {
2682  TocEntry *te;
2683 
2684  te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
2685  ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
2686  .namespace = tbinfo->dobj.namespace->dobj.name,
2687  .owner = tbinfo->rolname,
2688  .description = "TABLE DATA",
2689  .section = SECTION_DATA,
2690  .createStmt = tdDefn,
2691  .copyStmt = copyStmt,
2692  .deps = &(tbinfo->dobj.dumpId),
2693  .nDeps = 1,
2694  .dumpFn = dumpFn,
2695  .dumpArg = tdinfo));
2696 
2697  /*
2698  * Set the TocEntry's dataLength in case we are doing a parallel dump
2699  * and want to order dump jobs by table size. We choose to measure
2700  * dataLength in table pages (including TOAST pages) during dump, so
2701  * no scaling is needed.
2702  *
2703  * However, relpages is declared as "integer" in pg_class, and hence
2704  * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
2705  * Cast so that we get the right interpretation of table sizes
2706  * exceeding INT_MAX pages.
2707  */
2708  te->dataLength = (BlockNumber) tbinfo->relpages;
2709  te->dataLength += (BlockNumber) tbinfo->toastpages;
2710 
2711  /*
2712  * If pgoff_t is only 32 bits wide, the above refinement is useless,
2713  * and instead we'd better worry about integer overflow. Clamp to
2714  * INT_MAX if the correct result exceeds that.
2715  */
2716  if (sizeof(te->dataLength) == 4 &&
2717  (tbinfo->relpages < 0 || tbinfo->toastpages < 0 ||
2718  te->dataLength < 0))
2719  te->dataLength = INT_MAX;
2720  }
2721 
2722  destroyPQExpBuffer(copyBuf);
2723  destroyPQExpBuffer(clistBuf);
2724 }
2725 
2726 /*
2727  * refreshMatViewData -
2728  * load or refresh the contents of a single materialized view
2729  *
2730  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
2731  * statement.
2732  */
2733 static void
2735 {
2736  TableInfo *tbinfo = tdinfo->tdtable;
2737  PQExpBuffer q;
2738 
2739  /* If the materialized view is not flagged as populated, skip this. */
2740  if (!tbinfo->relispopulated)
2741  return;
2742 
2743  q = createPQExpBuffer();
2744 
2745  appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
2746  fmtQualifiedDumpable(tbinfo));
2747 
2748  if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2749  ArchiveEntry(fout,
2750  tdinfo->dobj.catId, /* catalog ID */
2751  tdinfo->dobj.dumpId, /* dump ID */
2752  ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
2753  .namespace = tbinfo->dobj.namespace->dobj.name,
2754  .owner = tbinfo->rolname,
2755  .description = "MATERIALIZED VIEW DATA",
2756  .section = SECTION_POST_DATA,
2757  .createStmt = q->data,
2758  .deps = tdinfo->dobj.dependencies,
2759  .nDeps = tdinfo->dobj.nDeps));
2760 
2761  destroyPQExpBuffer(q);
2762 }
2763 
2764 /*
2765  * getTableData -
2766  * set up dumpable objects representing the contents of tables
2767  */
2768 static void
2769 getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
2770 {
2771  int i;
2772 
2773  for (i = 0; i < numTables; i++)
2774  {
2775  if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
2776  (!relkind || tblinfo[i].relkind == relkind))
2777  makeTableDataInfo(dopt, &(tblinfo[i]));
2778  }
2779 }
2780 
2781 /*
2782  * Make a dumpable object for the data of this specific table
2783  *
2784  * Note: we make a TableDataInfo if and only if we are going to dump the
2785  * table data; the "dump" field in such objects isn't very interesting.
2786  */
2787 static void
2789 {
2790  TableDataInfo *tdinfo;
2791 
2792  /*
2793  * Nothing to do if we already decided to dump the table. This will
2794  * happen for "config" tables.
2795  */
2796  if (tbinfo->dataObj != NULL)
2797  return;
2798 
2799  /* Skip VIEWs (no data to dump) */
2800  if (tbinfo->relkind == RELKIND_VIEW)
2801  return;
2802  /* Skip FOREIGN TABLEs (no data to dump) unless requested explicitly */
2803  if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
2806  tbinfo->foreign_server)))
2807  return;
2808  /* Skip partitioned tables (data in partitions) */
2809  if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
2810  return;
2811 
2812  /* Don't dump data in unlogged tables, if so requested */
2813  if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
2814  dopt->no_unlogged_table_data)
2815  return;
2816 
2817  /* Check that the data is not explicitly excluded */
2819  tbinfo->dobj.catId.oid))
2820  return;
2821 
2822  /* OK, let's dump it */
2823  tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
2824 
2825  if (tbinfo->relkind == RELKIND_MATVIEW)
2826  tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
2827  else if (tbinfo->relkind == RELKIND_SEQUENCE)
2828  tdinfo->dobj.objType = DO_SEQUENCE_SET;
2829  else
2830  tdinfo->dobj.objType = DO_TABLE_DATA;
2831 
2832  /*
2833  * Note: use tableoid 0 so that this object won't be mistaken for
2834  * something that pg_depend entries apply to.
2835  */
2836  tdinfo->dobj.catId.tableoid = 0;
2837  tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
2838  AssignDumpId(&tdinfo->dobj);
2839  tdinfo->dobj.name = tbinfo->dobj.name;
2840  tdinfo->dobj.namespace = tbinfo->dobj.namespace;
2841  tdinfo->tdtable = tbinfo;
2842  tdinfo->filtercond = NULL; /* might get set later */
2843  addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
2844 
2845  /* A TableDataInfo contains data, of course */
2846  tdinfo->dobj.components |= DUMP_COMPONENT_DATA;
2847 
2848  tbinfo->dataObj = tdinfo;
2849 
2850  /* Make sure that we'll collect per-column info for this table. */
2851  tbinfo->interesting = true;
2852 }
2853 
2854 /*
2855  * The refresh for a materialized view must be dependent on the refresh for
2856  * any materialized view that this one is dependent on.
2857  *
2858  * This must be called after all the objects are created, but before they are
2859  * sorted.
2860  */
2861 static void
2863 {
2864  PQExpBuffer query;
2865  PGresult *res;
2866  int ntups,
2867  i;
2868  int i_classid,
2869  i_objid,
2870  i_refobjid;
2871 
2872  /* No Mat Views before 9.3. */
2873  if (fout->remoteVersion < 90300)
2874  return;
2875 
2876  query = createPQExpBuffer();
2877 
2878  appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
2879  "( "
2880  "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
2881  "FROM pg_depend d1 "
2882  "JOIN pg_class c1 ON c1.oid = d1.objid "
2883  "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
2884  " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
2885  "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
2886  "AND d2.objid = r1.oid "
2887  "AND d2.refobjid <> d1.objid "
2888  "JOIN pg_class c2 ON c2.oid = d2.refobjid "
2889  "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2890  CppAsString2(RELKIND_VIEW) ") "
2891  "WHERE d1.classid = 'pg_class'::regclass "
2892  "UNION "
2893  "SELECT w.objid, d3.refobjid, c3.relkind "
2894  "FROM w "
2895  "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
2896  "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
2897  "AND d3.objid = r3.oid "
2898  "AND d3.refobjid <> w.refobjid "
2899  "JOIN pg_class c3 ON c3.oid = d3.refobjid "
2900  "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2901  CppAsString2(RELKIND_VIEW) ") "
2902  ") "
2903  "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
2904  "FROM w "
2905  "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
2906 
2907  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2908 
2909  ntups = PQntuples(res);
2910 
2911  i_classid = PQfnumber(res, "classid");
2912  i_objid = PQfnumber(res, "objid");
2913  i_refobjid = PQfnumber(res, "refobjid");
2914 
2915  for (i = 0; i < ntups; i++)
2916  {
2917  CatalogId objId;
2918  CatalogId refobjId;
2919  DumpableObject *dobj;
2920  DumpableObject *refdobj;
2921  TableInfo *tbinfo;
2922  TableInfo *reftbinfo;
2923 
2924  objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
2925  objId.oid = atooid(PQgetvalue(res, i, i_objid));
2926  refobjId.tableoid = objId.tableoid;
2927  refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
2928 
2929  dobj = findObjectByCatalogId(objId);
2930  if (dobj == NULL)
2931  continue;
2932 
2933  Assert(dobj->objType == DO_TABLE);
2934  tbinfo = (TableInfo *) dobj;
2935  Assert(tbinfo->relkind == RELKIND_MATVIEW);
2936  dobj = (DumpableObject *) tbinfo->dataObj;
2937  if (dobj == NULL)
2938  continue;
2939  Assert(dobj->objType == DO_REFRESH_MATVIEW);
2940 
2941  refdobj = findObjectByCatalogId(refobjId);
2942  if (refdobj == NULL)
2943  continue;
2944 
2945  Assert(refdobj->objType == DO_TABLE);
2946  reftbinfo = (TableInfo *) refdobj;
2947  Assert(reftbinfo->relkind == RELKIND_MATVIEW);
2948  refdobj = (DumpableObject *) reftbinfo->dataObj;
2949  if (refdobj == NULL)
2950  continue;
2951  Assert(refdobj->objType == DO_REFRESH_MATVIEW);
2952 
2953  addObjectDependency(dobj, refdobj->dumpId);
2954 
2955  if (!reftbinfo->relispopulated)
2956  tbinfo->relispopulated = false;
2957  }
2958 
2959  PQclear(res);
2960 
2961  destroyPQExpBuffer(query);
2962 }
2963 
2964 /*
2965  * getTableDataFKConstraints -
2966  * add dump-order dependencies reflecting foreign key constraints
2967  *
2968  * This code is executed only in a data-only dump --- in schema+data dumps
2969  * we handle foreign key issues by not creating the FK constraints until
2970  * after the data is loaded. In a data-only dump, however, we want to
2971  * order the table data objects in such a way that a table's referenced
2972  * tables are restored first. (In the presence of circular references or
2973  * self-references this may be impossible; we'll detect and complain about
2974  * that during the dependency sorting step.)
2975  */
2976 static void
2978 {
2979  DumpableObject **dobjs;
2980  int numObjs;
2981  int i;
2982 
2983  /* Search through all the dumpable objects for FK constraints */
2984  getDumpableObjects(&dobjs, &numObjs);
2985  for (i = 0; i < numObjs; i++)
2986  {
2987  if (dobjs[i]->objType == DO_FK_CONSTRAINT)
2988  {
2989  ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
2990  TableInfo *ftable;
2991 
2992  /* Not interesting unless both tables are to be dumped */
2993  if (cinfo->contable == NULL ||
2994  cinfo->contable->dataObj == NULL)
2995  continue;
2996  ftable = findTableByOid(cinfo->confrelid);
2997  if (ftable == NULL ||
2998  ftable->dataObj == NULL)
2999  continue;
3000 
3001  /*
3002  * Okay, make referencing table's TABLE_DATA object depend on the
3003  * referenced table's TABLE_DATA object.
3004  */
3006  ftable->dataObj->dobj.dumpId);
3007  }
3008  }
3009  free(dobjs);
3010 }
3011 
3012 
3013 /*
3014  * dumpDatabase:
3015  * dump the database definition
3016  */
3017 static void
3019 {
3020  DumpOptions *dopt = fout->dopt;
3021  PQExpBuffer dbQry = createPQExpBuffer();
3022  PQExpBuffer delQry = createPQExpBuffer();
3023  PQExpBuffer creaQry = createPQExpBuffer();
3024  PQExpBuffer labelq = createPQExpBuffer();
3025  PGconn *conn = GetConnection(fout);
3026  PGresult *res;
3027  int i_tableoid,
3028  i_oid,
3029  i_datname,
3030  i_datdba,
3031  i_encoding,
3032  i_datlocprovider,
3033  i_collate,
3034  i_ctype,
3035  i_datlocale,
3036  i_daticurules,
3037  i_frozenxid,
3038  i_minmxid,
3039  i_datacl,
3040  i_acldefault,
3041  i_datistemplate,
3042  i_datconnlimit,
3043  i_datcollversion,
3044  i_tablespace;
3045  CatalogId dbCatId;
3046  DumpId dbDumpId;
3047  DumpableAcl dbdacl;
3048  const char *datname,
3049  *dba,
3050  *encoding,
3051  *datlocprovider,
3052  *collate,
3053  *ctype,
3054  *locale,
3055  *icurules,
3056  *datistemplate,
3057  *datconnlimit,
3058  *tablespace;
3059  uint32 frozenxid,
3060  minmxid;
3061  char *qdatname;
3062 
3063  pg_log_info("saving database definition");
3064 
3065  /*
3066  * Fetch the database-level properties for this database.
3067  */
3068  appendPQExpBufferStr(dbQry, "SELECT tableoid, oid, datname, "
3069  "datdba, "
3070  "pg_encoding_to_char(encoding) AS encoding, "
3071  "datcollate, datctype, datfrozenxid, "
3072  "datacl, acldefault('d', datdba) AS acldefault, "
3073  "datistemplate, datconnlimit, ");
3074  if (fout->remoteVersion >= 90300)
3075  appendPQExpBufferStr(dbQry, "datminmxid, ");
3076  else
3077  appendPQExpBufferStr(dbQry, "0 AS datminmxid, ");
3078  if (fout->remoteVersion >= 170000)
3079  appendPQExpBufferStr(dbQry, "datlocprovider, datlocale, datcollversion, ");
3080  else if (fout->remoteVersion >= 150000)
3081  appendPQExpBufferStr(dbQry, "datlocprovider, daticulocale AS datlocale, datcollversion, ");
3082  else
3083  appendPQExpBufferStr(dbQry, "'c' AS datlocprovider, NULL AS datlocale, NULL AS datcollversion, ");
3084  if (fout->remoteVersion >= 160000)
3085  appendPQExpBufferStr(dbQry, "daticurules, ");
3086  else
3087  appendPQExpBufferStr(dbQry, "NULL AS daticurules, ");
3088  appendPQExpBufferStr(dbQry,
3089  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
3090  "shobj_description(oid, 'pg_database') AS description "
3091  "FROM pg_database "
3092  "WHERE datname = current_database()");
3093 
3094  res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
3095 
3096  i_tableoid = PQfnumber(res, "tableoid");
3097  i_oid = PQfnumber(res, "oid");
3098  i_datname = PQfnumber(res, "datname");
3099  i_datdba = PQfnumber(res, "datdba");
3100  i_encoding = PQfnumber(res, "encoding");
3101  i_datlocprovider = PQfnumber(res, "datlocprovider");
3102  i_collate = PQfnumber(res, "datcollate");
3103  i_ctype = PQfnumber(res, "datctype");
3104  i_datlocale = PQfnumber(res, "datlocale");
3105  i_daticurules = PQfnumber(res, "daticurules");
3106  i_frozenxid = PQfnumber(res, "datfrozenxid");
3107  i_minmxid = PQfnumber(res, "datminmxid");
3108  i_datacl = PQfnumber(res, "datacl");
3109  i_acldefault = PQfnumber(res, "acldefault");
3110  i_datistemplate = PQfnumber(res, "datistemplate");
3111  i_datconnlimit = PQfnumber(res, "datconnlimit");
3112  i_datcollversion = PQfnumber(res, "datcollversion");
3113  i_tablespace = PQfnumber(res, "tablespace");
3114 
3115  dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
3116  dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
3117  datname = PQgetvalue(res, 0, i_datname);
3118  dba = getRoleName(PQgetvalue(res, 0, i_datdba));
3119  encoding = PQgetvalue(res, 0, i_encoding);
3120  datlocprovider = PQgetvalue(res, 0, i_datlocprovider);
3121  collate = PQgetvalue(res, 0, i_collate);
3122  ctype = PQgetvalue(res, 0, i_ctype);
3123  if (!PQgetisnull(res, 0, i_datlocale))
3124  locale = PQgetvalue(res, 0, i_datlocale);
3125  else
3126  locale = NULL;
3127  if (!PQgetisnull(res, 0, i_daticurules))
3128  icurules = PQgetvalue(res, 0, i_daticurules);
3129  else
3130  icurules = NULL;
3131  frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
3132  minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
3133  dbdacl.acl = PQgetvalue(res, 0, i_datacl);
3134  dbdacl.acldefault = PQgetvalue(res, 0, i_acldefault);
3135  datistemplate = PQgetvalue(res, 0, i_datistemplate);
3136  datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
3137  tablespace = PQgetvalue(res, 0, i_tablespace);
3138 
3139  qdatname = pg_strdup(fmtId(datname));
3140 
3141  /*
3142  * Prepare the CREATE DATABASE command. We must specify OID (if we want
3143  * to preserve that), as well as the encoding, locale, and tablespace
3144  * since those can't be altered later. Other DB properties are left to
3145  * the DATABASE PROPERTIES entry, so that they can be applied after
3146  * reconnecting to the target DB.
3147  *
3148  * For binary upgrade, we use the FILE_COPY strategy because testing has
3149  * shown it to be faster. When the server is in binary upgrade mode, it
3150  * will also skip the checkpoints this strategy ordinarily performs.
3151  */
3152  if (dopt->binary_upgrade)
3153  {
3154  appendPQExpBuffer(creaQry,
3155  "CREATE DATABASE %s WITH TEMPLATE = template0 "
3156  "OID = %u STRATEGY = FILE_COPY",
3157  qdatname, dbCatId.oid);
3158  }
3159  else
3160  {
3161  appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
3162  qdatname);
3163  }
3164  if (strlen(encoding) > 0)
3165  {
3166  appendPQExpBufferStr(creaQry, " ENCODING = ");
3167  appendStringLiteralAH(creaQry, encoding, fout);
3168  }
3169 
3170  appendPQExpBufferStr(creaQry, " LOCALE_PROVIDER = ");
3171  if (datlocprovider[0] == 'b')
3172  appendPQExpBufferStr(creaQry, "builtin");
3173  else if (datlocprovider[0] == 'c')
3174  appendPQExpBufferStr(creaQry, "libc");
3175  else if (datlocprovider[0] == 'i')
3176  appendPQExpBufferStr(creaQry, "icu");
3177  else
3178  pg_fatal("unrecognized locale provider: %s",
3179  datlocprovider);
3180 
3181  if (strlen(collate) > 0 && strcmp(collate, ctype) == 0)
3182  {
3183  appendPQExpBufferStr(creaQry, " LOCALE = ");
3184  appendStringLiteralAH(creaQry, collate, fout);
3185  }
3186  else
3187  {
3188  if (strlen(collate) > 0)
3189  {
3190  appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
3191  appendStringLiteralAH(creaQry, collate, fout);
3192  }
3193  if (strlen(ctype) > 0)
3194  {
3195  appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
3196  appendStringLiteralAH(creaQry, ctype, fout);
3197  }
3198  }
3199  if (locale)
3200  {
3201  if (datlocprovider[0] == 'b')
3202  appendPQExpBufferStr(creaQry, " BUILTIN_LOCALE = ");
3203  else
3204  appendPQExpBufferStr(creaQry, " ICU_LOCALE = ");
3205 
3206  appendStringLiteralAH(creaQry, locale, fout);
3207  }
3208 
3209  if (icurules)
3210  {
3211  appendPQExpBufferStr(creaQry, " ICU_RULES = ");
3212  appendStringLiteralAH(creaQry, icurules, fout);
3213  }
3214 
3215  /*
3216  * For binary upgrade, carry over the collation version. For normal
3217  * dump/restore, omit the version, so that it is computed upon restore.
3218  */
3219  if (dopt->binary_upgrade)
3220  {
3221  if (!PQgetisnull(res, 0, i_datcollversion))
3222  {
3223  appendPQExpBufferStr(creaQry, " COLLATION_VERSION = ");
3224  appendStringLiteralAH(creaQry,
3225  PQgetvalue(res, 0, i_datcollversion),
3226  fout);
3227  }
3228  }
3229 
3230  /*
3231  * Note: looking at dopt->outputNoTablespaces here is completely the wrong
3232  * thing; the decision whether to specify a tablespace should be left till
3233  * pg_restore, so that pg_restore --no-tablespaces applies. Ideally we'd
3234  * label the DATABASE entry with the tablespace and let the normal
3235  * tablespace selection logic work ... but CREATE DATABASE doesn't pay
3236  * attention to default_tablespace, so that won't work.
3237  */
3238  if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
3239  !dopt->outputNoTablespaces)
3240  appendPQExpBuffer(creaQry, " TABLESPACE = %s",
3241  fmtId(tablespace));
3242  appendPQExpBufferStr(creaQry, ";\n");
3243 
3244  appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
3245  qdatname);
3246 
3247  dbDumpId = createDumpId();
3248 
3249  ArchiveEntry(fout,
3250  dbCatId, /* catalog ID */
3251  dbDumpId, /* dump ID */
3252  ARCHIVE_OPTS(.tag = datname,
3253  .owner = dba,
3254  .description = "DATABASE",
3255  .section = SECTION_PRE_DATA,
3256  .createStmt = creaQry->data,
3257  .dropStmt = delQry->data));
3258 
3259  /* Compute correct tag for archive entry */
3260  appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
3261 
3262  /* Dump DB comment if any */
3263  {
3264  /*
3265  * 8.2 and up keep comments on shared objects in a shared table, so we
3266  * cannot use the dumpComment() code used for other database objects.
3267  * Be careful that the ArchiveEntry parameters match that function.
3268  */
3269  char *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
3270 
3271  if (comment && *comment && !dopt->no_comments)
3272  {
3273  resetPQExpBuffer(dbQry);
3274 
3275  /*
3276  * Generates warning when loaded into a differently-named
3277  * database.
3278  */
3279  appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
3280  appendStringLiteralAH(dbQry, comment, fout);
3281  appendPQExpBufferStr(dbQry, ";\n");
3282 
3284  ARCHIVE_OPTS(.tag = labelq->data,
3285  .owner = dba,
3286  .description = "COMMENT",
3287  .section = SECTION_NONE,
3288  .createStmt = dbQry->data,
3289  .deps = &dbDumpId,
3290  .nDeps = 1));
3291  }
3292  }
3293 
3294  /* Dump DB security label, if enabled */
3295  if (!dopt->no_security_labels)
3296  {
3297  PGresult *shres;
3298  PQExpBuffer seclabelQry;
3299 
3300  seclabelQry = createPQExpBuffer();
3301 
3302  buildShSecLabelQuery("pg_database", dbCatId.oid, seclabelQry);
3303  shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
3304  resetPQExpBuffer(seclabelQry);
3305  emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
3306  if (seclabelQry->len > 0)
3308  ARCHIVE_OPTS(.tag = labelq->data,
3309  .owner = dba,
3310  .description = "SECURITY LABEL",
3311  .section = SECTION_NONE,
3312  .createStmt = seclabelQry->data,
3313  .deps = &dbDumpId,
3314  .nDeps = 1));
3315  destroyPQExpBuffer(seclabelQry);
3316  PQclear(shres);
3317  }
3318 
3319  /*
3320  * Dump ACL if any. Note that we do not support initial privileges
3321  * (pg_init_privs) on databases.
3322  */
3323  dbdacl.privtype = 0;
3324  dbdacl.initprivs = NULL;
3325 
3326  dumpACL(fout, dbDumpId, InvalidDumpId, "DATABASE",
3327  qdatname, NULL, NULL,
3328  NULL, dba, &dbdacl);
3329 
3330  /*
3331  * Now construct a DATABASE PROPERTIES archive entry to restore any
3332  * non-default database-level properties. (The reason this must be
3333  * separate is that we cannot put any additional commands into the TOC
3334  * entry that has CREATE DATABASE. pg_restore would execute such a group
3335  * in an implicit transaction block, and the backend won't allow CREATE
3336  * DATABASE in that context.)
3337  */
3338  resetPQExpBuffer(creaQry);
3339  resetPQExpBuffer(delQry);
3340 
3341  if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
3342  appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
3343  qdatname, datconnlimit);
3344 
3345  if (strcmp(datistemplate, "t") == 0)
3346  {
3347  appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
3348  qdatname);
3349 
3350  /*
3351  * The backend won't accept DROP DATABASE on a template database. We
3352  * can deal with that by removing the template marking before the DROP
3353  * gets issued. We'd prefer to use ALTER DATABASE IF EXISTS here, but
3354  * since no such command is currently supported, fake it with a direct
3355  * UPDATE on pg_database.
3356  */
3357  appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
3358  "SET datistemplate = false WHERE datname = ");
3359  appendStringLiteralAH(delQry, datname, fout);
3360  appendPQExpBufferStr(delQry, ";\n");
3361  }
3362 
3363  /*
3364  * We do not restore pg_database.dathasloginevt because it is set
3365  * automatically on login event trigger creation.
3366  */
3367 
3368  /* Add database-specific SET options */
3369  dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
3370 
3371  /*
3372  * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
3373  * entry, too, for lack of a better place.
3374  */
3375  if (dopt->binary_upgrade)
3376  {
3377  appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
3378  appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
3379  "SET datfrozenxid = '%u', datminmxid = '%u'\n"
3380  "WHERE datname = ",
3381  frozenxid, minmxid);
3382  appendStringLiteralAH(creaQry, datname, fout);
3383  appendPQExpBufferStr(creaQry, ";\n");
3384  }
3385 
3386  if (creaQry->len > 0)
3388  ARCHIVE_OPTS(.tag = datname,
3389  .owner = dba,
3390  .description = "DATABASE PROPERTIES",
3391  .section = SECTION_PRE_DATA,
3392  .createStmt = creaQry->data,
3393  .dropStmt = delQry->data,
3394  .deps = &dbDumpId));
3395 
3396  /*
3397  * pg_largeobject comes from the old system intact, so set its
3398  * relfrozenxids, relminmxids and relfilenode.
3399  */
3400  if (dopt->binary_upgrade)
3401  {
3402  PGresult *lo_res;
3403  PQExpBuffer loFrozenQry = createPQExpBuffer();
3404  PQExpBuffer loOutQry = createPQExpBuffer();
3405  PQExpBuffer loHorizonQry = createPQExpBuffer();
3406  int ii_relfrozenxid,
3407  ii_relfilenode,
3408  ii_oid,
3409  ii_relminmxid;
3410 
3411  /*
3412  * pg_largeobject
3413  */
3414  if (fout->remoteVersion >= 90300)
3415  appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid, relfilenode, oid\n"
3416  "FROM pg_catalog.pg_class\n"
3417  "WHERE oid IN (%u, %u);\n",
3418  LargeObjectRelationId, LargeObjectLOidPNIndexId);
3419  else
3420  appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid, relfilenode, oid\n"
3421  "FROM pg_catalog.pg_class\n"
3422  "WHERE oid IN (%u, %u);\n",
3423  LargeObjectRelationId, LargeObjectLOidPNIndexId);
3424 
3425  lo_res = ExecuteSqlQuery(fout, loFrozenQry->data, PGRES_TUPLES_OK);
3426 
3427  ii_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
3428  ii_relminmxid = PQfnumber(lo_res, "relminmxid");
3429  ii_relfilenode = PQfnumber(lo_res, "relfilenode");
3430  ii_oid = PQfnumber(lo_res, "oid");
3431 
3432  appendPQExpBufferStr(loHorizonQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
3433  appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, preserve pg_largeobject and index relfilenodes\n");
3434  for (int i = 0; i < PQntuples(lo_res); ++i)
3435  {
3436  Oid oid;
3437  RelFileNumber relfilenumber;
3438 
3439  appendPQExpBuffer(loHorizonQry, "UPDATE pg_catalog.pg_class\n"
3440  "SET relfrozenxid = '%u', relminmxid = '%u'\n"
3441  "WHERE oid = %u;\n",
3442  atooid(PQgetvalue(lo_res, i, ii_relfrozenxid)),
3443  atooid(PQgetvalue(lo_res, i, ii_relminmxid)),
3444  atooid(PQgetvalue(lo_res, i, ii_oid)));
3445 
3446  oid = atooid(PQgetvalue(lo_res, i, ii_oid));
3447  relfilenumber = atooid(PQgetvalue(lo_res, i, ii_relfilenode));
3448 
3449  if (oid == LargeObjectRelationId)
3450  appendPQExpBuffer(loOutQry,
3451  "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
3452  relfilenumber);
3453  else if (oid == LargeObjectLOidPNIndexId)
3454  appendPQExpBuffer(loOutQry,
3455  "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
3456  relfilenumber);
3457  }
3458 
3459  appendPQExpBufferStr(loOutQry,
3460  "TRUNCATE pg_catalog.pg_largeobject;\n");
3461  appendPQExpBufferStr(loOutQry, loHorizonQry->data);
3462 
3464  ARCHIVE_OPTS(.tag = "pg_largeobject",
3465  .description = "pg_largeobject",
3466  .section = SECTION_PRE_DATA,
3467  .createStmt = loOutQry->data));
3468 
3469  PQclear(lo_res);
3470 
3471  destroyPQExpBuffer(loFrozenQry);
3472  destroyPQExpBuffer(loHorizonQry);
3473  destroyPQExpBuffer(loOutQry);
3474  }
3475 
3476  PQclear(res);
3477 
3478  free(qdatname);
3479  destroyPQExpBuffer(dbQry);
3480  destroyPQExpBuffer(delQry);
3481  destroyPQExpBuffer(creaQry);
3482  destroyPQExpBuffer(labelq);
3483 }
3484 
3485 /*
3486  * Collect any database-specific or role-and-database-specific SET options
3487  * for this database, and append them to outbuf.
3488  */
3489 static void
3491  const char *dbname, Oid dboid)
3492 {
3493  PGconn *conn = GetConnection(AH);
3495  PGresult *res;
3496 
3497  /* First collect database-specific options */
3498  printfPQExpBuffer(buf, "SELECT unnest(setconfig) FROM pg_db_role_setting "
3499  "WHERE setrole = 0 AND setdatabase = '%u'::oid",
3500  dboid);
3501 
3502  res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3503 
3504  for (int i = 0; i < PQntuples(res); i++)
3506  "DATABASE", dbname, NULL, NULL,
3507  outbuf);
3508 
3509  PQclear(res);
3510 
3511  /* Now look for role-and-database-specific options */
3512  printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
3513  "FROM pg_db_role_setting s, pg_roles r "
3514  "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
3515  dboid);
3516 
3517  res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3518 
3519  for (int i = 0; i < PQntuples(res); i++)
3521  "ROLE", PQgetvalue(res, i, 0),
3522  "DATABASE", dbname,
3523  outbuf);
3524 
3525  PQclear(res);
3526 
3528 }
3529 
3530 /*
3531  * dumpEncoding: put the correct encoding into the archive
3532  */
3533 static void
3535 {
3536  const char *encname = pg_encoding_to_char(AH->encoding);
3538 
3539  pg_log_info("saving encoding = %s", encname);
3540 
3541  appendPQExpBufferStr(qry, "SET client_encoding = ");
3542  appendStringLiteralAH(qry, encname, AH);
3543  appendPQExpBufferStr(qry, ";\n");
3544 
3546  ARCHIVE_OPTS(.tag = "ENCODING",
3547  .description = "ENCODING",
3548  .section = SECTION_PRE_DATA,
3549  .createStmt = qry->data));
3550 
3551  destroyPQExpBuffer(qry);
3552 }
3553 
3554 
3555 /*
3556  * dumpStdStrings: put the correct escape string behavior into the archive
3557  */
3558 static void
3560 {
3561  const char *stdstrings = AH->std_strings ? "on" : "off";
3563 
3564  pg_log_info("saving \"standard_conforming_strings = %s\"",
3565  stdstrings);
3566 
3567  appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
3568  stdstrings);
3569 
3571  ARCHIVE_OPTS(.tag = "STDSTRINGS",
3572  .description = "STDSTRINGS",
3573  .section = SECTION_PRE_DATA,
3574  .createStmt = qry->data));
3575 
3576  destroyPQExpBuffer(qry);
3577 }
3578 
3579 /*
3580  * dumpSearchPath: record the active search_path in the archive
3581  */
3582 static void
3584 {
3586  PQExpBuffer path = createPQExpBuffer();
3587  PGresult *res;
3588  char **schemanames = NULL;
3589  int nschemanames = 0;
3590  int i;
3591 
3592  /*
3593  * We use the result of current_schemas(), not the search_path GUC,
3594  * because that might contain wildcards such as "$user", which won't
3595  * necessarily have the same value during restore. Also, this way avoids
3596  * listing schemas that may appear in search_path but not actually exist,
3597  * which seems like a prudent exclusion.
3598  */
3600  "SELECT pg_catalog.current_schemas(false)");
3601 
3602  if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
3603  pg_fatal("could not parse result of current_schemas()");
3604 
3605  /*
3606  * We use set_config(), not a simple "SET search_path" command, because
3607  * the latter has less-clean behavior if the search path is empty. While
3608  * that's likely to get fixed at some point, it seems like a good idea to
3609  * be as backwards-compatible as possible in what we put into archives.
3610  */
3611  for (i = 0; i < nschemanames; i++)
3612  {
3613  if (i > 0)
3614  appendPQExpBufferStr(path, ", ");
3615  appendPQExpBufferStr(path, fmtId(schemanames[i]));
3616  }
3617 
3618  appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
3619  appendStringLiteralAH(qry, path->data, AH);
3620  appendPQExpBufferStr(qry, ", false);\n");
3621 
3622  pg_log_info("saving \"search_path = %s\"", path->data);
3623 
3625  ARCHIVE_OPTS(.tag = "SEARCHPATH",
3626  .description = "SEARCHPATH",
3627  .section = SECTION_PRE_DATA,
3628  .createStmt = qry->data));
3629 
3630  /* Also save it in AH->searchpath, in case we're doing plain text dump */
3631  AH->searchpath = pg_strdup(qry->data);
3632 
3633  free(schemanames);
3634  PQclear(res);
3635  destroyPQExpBuffer(qry);
3636  destroyPQExpBuffer(path);
3637 }
3638 
3639 
3640 /*
3641  * getLOs:
3642  * Collect schema-level data about large objects
3643  */
3644 static void
3646 {
3647  DumpOptions *dopt = fout->dopt;
3648  PQExpBuffer loQry = createPQExpBuffer();
3649  PGresult *res;
3650  int ntups;
3651  int i;
3652  int n;
3653  int i_oid;
3654  int i_lomowner;
3655  int i_lomacl;
3656  int i_acldefault;
3657 
3658  pg_log_info("reading large objects");
3659 
3660  /*
3661  * Fetch LO OIDs and owner/ACL data. Order the data so that all the blobs
3662  * with the same owner/ACL appear together.
3663  */
3664  appendPQExpBufferStr(loQry,
3665  "SELECT oid, lomowner, lomacl, "
3666  "acldefault('L', lomowner) AS acldefault "
3667  "FROM pg_largeobject_metadata "
3668  "ORDER BY lomowner, lomacl::pg_catalog.text, oid");
3669 
3670  res = ExecuteSqlQuery(fout, loQry->data, PGRES_TUPLES_OK);
3671 
3672  i_oid = PQfnumber(res, "oid");
3673  i_lomowner = PQfnumber(res, "lomowner");
3674  i_lomacl = PQfnumber(res, "lomacl");
3675  i_acldefault = PQfnumber(res, "acldefault");
3676 
3677  ntups = PQntuples(res);
3678 
3679  /*
3680  * Group the blobs into suitably-sized groups that have the same owner and
3681  * ACL setting, and build a metadata and a data DumpableObject for each
3682  * group. (If we supported initprivs for blobs, we'd have to insist that
3683  * groups also share initprivs settings, since the DumpableObject only has
3684  * room for one.) i is the index of the first tuple in the current group,
3685  * and n is the number of tuples we include in the group.
3686  */
3687  for (i = 0; i < ntups; i += n)
3688  {
3689  Oid thisoid = atooid(PQgetvalue(res, i, i_oid));
3690  char *thisowner = PQgetvalue(res, i, i_lomowner);
3691  char *thisacl = PQgetvalue(res, i, i_lomacl);
3692  LoInfo *loinfo;
3693  DumpableObject *lodata;
3694  char namebuf[64];
3695 
3696  /* Scan to find first tuple not to be included in group */
3697  n = 1;
3698  while (n < MAX_BLOBS_PER_ARCHIVE_ENTRY && i + n < ntups)
3699  {
3700  if (strcmp(thisowner, PQgetvalue(res, i + n, i_lomowner)) != 0 ||
3701  strcmp(thisacl, PQgetvalue(res, i + n, i_lomacl)) != 0)
3702  break;
3703  n++;
3704  }
3705 
3706  /* Build the metadata DumpableObject */
3707  loinfo = (LoInfo *) pg_malloc(offsetof(LoInfo, looids) + n * sizeof(Oid));
3708 
3709  loinfo->dobj.objType = DO_LARGE_OBJECT;
3710  loinfo->dobj.catId.tableoid = LargeObjectRelationId;
3711  loinfo->dobj.catId.oid = thisoid;
3712  AssignDumpId(&loinfo->dobj);
3713 
3714  if (n > 1)
3715  snprintf(namebuf, sizeof(namebuf), "%u..%u", thisoid,
3716  atooid(PQgetvalue(res, i + n - 1, i_oid)));
3717  else
3718  snprintf(namebuf, sizeof(namebuf), "%u", thisoid);
3719  loinfo->dobj.name = pg_strdup(namebuf);
3720  loinfo->dacl.acl = pg_strdup(thisacl);
3721  loinfo->dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
3722  loinfo->dacl.privtype = 0;
3723  loinfo->dacl.initprivs = NULL;
3724  loinfo->rolname = getRoleName(thisowner);
3725  loinfo->numlos = n;
3726  loinfo->looids[0] = thisoid;
3727  /* Collect OIDs of the remaining blobs in this group */
3728  for (int k = 1; k < n; k++)
3729  {
3730  CatalogId extraID;
3731 
3732  loinfo->looids[k] = atooid(PQgetvalue(res, i + k, i_oid));
3733 
3734  /* Make sure we can look up loinfo by any of the blobs' OIDs */
3735  extraID.tableoid = LargeObjectRelationId;
3736  extraID.oid = loinfo->looids[k];
3737  recordAdditionalCatalogID(extraID, &loinfo->dobj);
3738  }
3739 
3740  /* LOs have data */
3741  loinfo->dobj.components |= DUMP_COMPONENT_DATA;
3742 
3743  /* Mark whether LO group has a non-empty ACL */
3744  if (!PQgetisnull(res, i, i_lomacl))
3745  loinfo->dobj.components |= DUMP_COMPONENT_ACL;
3746 
3747  /*
3748  * In binary-upgrade mode for LOs, we do *not* dump out the LO data,
3749  * as it will be copied by pg_upgrade, which simply copies the
3750  * pg_largeobject table. We *do* however dump out anything but the
3751  * data, as pg_upgrade copies just pg_largeobject, but not
3752  * pg_largeobject_metadata, after the dump is restored.
3753  */
3754  if (dopt->binary_upgrade)
3755  loinfo->dobj.dump &= ~DUMP_COMPONENT_DATA;
3756 
3757  /*
3758  * Create a "BLOBS" data item for the group, too. This is just a
3759  * placeholder for sorting; it carries no data now.
3760  */
3761  lodata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
3762  lodata->objType = DO_LARGE_OBJECT_DATA;
3763  lodata->catId = nilCatalogId;
3764  AssignDumpId(lodata);
3765  lodata->name = pg_strdup(namebuf);
3766  lodata->components |= DUMP_COMPONENT_DATA;
3767  /* Set up explicit dependency from data to metadata */
3768  lodata->dependencies = (DumpId *) pg_malloc(sizeof(DumpId));
3769  lodata->dependencies[0] = loinfo->dobj.dumpId;
3770  lodata->nDeps = lodata->allocDeps = 1;
3771  }
3772 
3773  PQclear(res);
3774  destroyPQExpBuffer(loQry);
3775 }
3776 
3777 /*
3778  * dumpLO
3779  *
3780  * dump the definition (metadata) of the given large object group
3781  */
3782 static void
3783 dumpLO(Archive *fout, const LoInfo *loinfo)
3784 {
3785  PQExpBuffer cquery = createPQExpBuffer();
3786 
3787  /*
3788  * The "definition" is just a newline-separated list of OIDs. We need to
3789  * put something into the dropStmt too, but it can just be a comment.
3790  */
3791  for (int i = 0; i < loinfo->numlos; i++)
3792  appendPQExpBuffer(cquery, "%u\n", loinfo->looids[i]);
3793 
3794  if (loinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
3795  ArchiveEntry(fout, loinfo->dobj.catId, loinfo->dobj.dumpId,
3796  ARCHIVE_OPTS(.tag = loinfo->dobj.name,
3797  .owner = loinfo->rolname,
3798  .description = "BLOB METADATA",
3799  .section = SECTION_DATA,
3800  .createStmt = cquery->data,
3801  .dropStmt = "-- dummy"));
3802 
3803  /*
3804  * Dump per-blob comments and seclabels if any. We assume these are rare
3805  * enough that it's okay to generate retail TOC entries for them.
3806  */
3807  if (loinfo->dobj.dump & (DUMP_COMPONENT_COMMENT |
3809  {
3810  for (int i = 0; i < loinfo->numlos; i++)
3811  {
3812  CatalogId catId;
3813  char namebuf[32];
3814 
3815  /* Build identifying info for this blob */
3816  catId.tableoid = loinfo->dobj.catId.tableoid;
3817  catId.oid = loinfo->looids[i];
3818  snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[i]);
3819 
3820  if (loinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3821  dumpComment(fout, "LARGE OBJECT", namebuf,
3822  NULL, loinfo->rolname,
3823  catId, 0, loinfo->dobj.dumpId);
3824 
3825  if (loinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3826  dumpSecLabel(fout, "LARGE OBJECT", namebuf,
3827  NULL, loinfo->rolname,
3828  catId, 0, loinfo->dobj.dumpId);
3829  }
3830  }
3831 
3832  /*
3833  * Dump the ACLs if any (remember that all blobs in the group will have
3834  * the same ACL). If there's just one blob, dump a simple ACL entry; if
3835  * there's more, make a "LARGE OBJECTS" entry that really contains only
3836  * the ACL for the first blob. _printTocEntry() will be cued by the tag
3837  * string to emit a mutated version for each blob.
3838  */
3839  if (loinfo->dobj.dump & DUMP_COMPONENT_ACL)
3840  {
3841  char namebuf[32];
3842 
3843  /* Build identifying info for the first blob */
3844  snprintf(namebuf, sizeof(namebuf), "%u", loinfo->looids[0]);
3845 
3846  if (loinfo->numlos > 1)
3847  {
3848  char tagbuf[64];
3849 
3850  snprintf(tagbuf, sizeof(tagbuf), "LARGE OBJECTS %u..%u",
3851  loinfo->looids[0], loinfo->looids[loinfo->numlos - 1]);
3852 
3853  dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
3854  "LARGE OBJECT", namebuf, NULL, NULL,
3855  tagbuf, loinfo->rolname, &loinfo->dacl);
3856  }
3857  else
3858  {
3859  dumpACL(fout, loinfo->dobj.dumpId, InvalidDumpId,
3860  "LARGE OBJECT", namebuf, NULL, NULL,
3861  NULL, loinfo->rolname, &loinfo->dacl);
3862  }
3863  }
3864 
3865  destroyPQExpBuffer(cquery);
3866 }
3867 
3868 /*
3869  * dumpLOs:
3870  * dump the data contents of the large objects in the given group
3871  */
3872 static int
3873 dumpLOs(Archive *fout, const void *arg)
3874 {
3875  const LoInfo *loinfo = (const LoInfo *) arg;
3876  PGconn *conn = GetConnection(fout);
3877  char buf[LOBBUFSIZE];
3878 
3879  pg_log_info("saving large objects \"%s\"", loinfo->dobj.name);
3880 
3881  for (int i = 0; i < loinfo->numlos; i++)
3882  {
3883  Oid loOid = loinfo->looids[i];
3884  int loFd;
3885  int cnt;
3886 
3887  /* Open the LO */
3888  loFd = lo_open(conn, loOid, INV_READ);
3889  if (loFd == -1)
3890  pg_fatal("could not open large object %u: %s",
3891  loOid, PQerrorMessage(conn));
3892 
3893  StartLO(fout, loOid);
3894 
3895  /* Now read it in chunks, sending data to archive */
3896  do
3897  {
3898  cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
3899  if (cnt < 0)
3900  pg_fatal("error reading large object %u: %s",
3901  loOid, PQerrorMessage(conn));
3902 
3903  WriteData(fout, buf, cnt);
3904  } while (cnt > 0);
3905 
3906  lo_close(conn, loFd);
3907 
3908  EndLO(fout, loOid);
3909  }
3910 
3911  return 1;
3912 }
3913 
3914 /*
3915  * getPolicies
3916  * get information about all RLS policies on dumpable tables.
3917  */
3918 void
3919 getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
3920 {
3921  PQExpBuffer query;
3922  PQExpBuffer tbloids;
3923  PGresult *res;
3924  PolicyInfo *polinfo;
3925  int i_oid;
3926  int i_tableoid;
3927  int i_polrelid;
3928  int i_polname;
3929  int i_polcmd;
3930  int i_polpermissive;
3931  int i_polroles;
3932  int i_polqual;
3933  int i_polwithcheck;
3934  int i,
3935  j,
3936  ntups;
3937 
3938  /* No policies before 9.5 */
3939  if (fout->remoteVersion < 90500)
3940  return;
3941 
3942  query = createPQExpBuffer();
3943  tbloids = createPQExpBuffer();
3944 
3945  /*
3946  * Identify tables of interest, and check which ones have RLS enabled.
3947  */
3948  appendPQExpBufferChar(tbloids, '{');
3949  for (i = 0; i < numTables; i++)
3950  {
3951  TableInfo *tbinfo = &tblinfo[i];
3952 
3953  /* Ignore row security on tables not to be dumped */
3954  if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
3955  continue;
3956 
3957  /* It can't have RLS or policies if it's not a table */
3958  if (tbinfo->relkind != RELKIND_RELATION &&
3959  tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
3960  continue;
3961 
3962  /* Add it to the list of table OIDs to be probed below */
3963  if (tbloids->len > 1) /* do we have more than the '{'? */
3964  appendPQExpBufferChar(tbloids, ',');
3965  appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
3966 
3967  /* Is RLS enabled? (That's separate from whether it has policies) */
3968  if (tbinfo->rowsec)
3969  {
3971 
3972  /*
3973  * We represent RLS being enabled on a table by creating a
3974  * PolicyInfo object with null polname.
3975  *
3976  * Note: use tableoid 0 so that this object won't be mistaken for
3977  * something that pg_depend entries apply to.
3978  */
3979  polinfo = pg_malloc(sizeof(PolicyInfo));
3980  polinfo->dobj.objType = DO_POLICY;
3981  polinfo->dobj.catId.tableoid = 0;
3982  polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
3983  AssignDumpId(&polinfo->dobj);
3984  polinfo->dobj.namespace = tbinfo->dobj.namespace;
3985  polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
3986  polinfo->poltable = tbinfo;
3987  polinfo->polname = NULL;
3988  polinfo->polcmd = '\0';
3989  polinfo->polpermissive = 0;
3990  polinfo->polroles = NULL;
3991  polinfo->polqual = NULL;
3992  polinfo->polwithcheck = NULL;
3993  }
3994  }
3995  appendPQExpBufferChar(tbloids, '}');
3996 
3997  /*
3998  * Now, read all RLS policies belonging to the tables of interest, and
3999  * create PolicyInfo objects for them. (Note that we must filter the
4000  * results server-side not locally, because we dare not apply pg_get_expr
4001  * to tables we don't have lock on.)
4002  */
4003  pg_log_info("reading row-level security policies");
4004 
4005  printfPQExpBuffer(query,
4006  "SELECT pol.oid, pol.tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
4007  if (fout->remoteVersion >= 100000)
4008  appendPQExpBufferStr(query, "pol.polpermissive, ");
4009  else
4010  appendPQExpBufferStr(query, "'t' as polpermissive, ");
4011  appendPQExpBuffer(query,
4012  "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
4013  " 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, "
4014  "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
4015  "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
4016  "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
4017  "JOIN pg_catalog.pg_policy pol ON (src.tbloid = pol.polrelid)",
4018  tbloids->data);
4019 
4020  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4021 
4022  ntups = PQntuples(res);
4023  if (ntups > 0)
4024  {
4025  i_oid = PQfnumber(res, "oid");
4026  i_tableoid = PQfnumber(res, "tableoid");
4027  i_polrelid = PQfnumber(res, "polrelid");
4028  i_polname = PQfnumber(res, "polname");
4029  i_polcmd = PQfnumber(res, "polcmd");
4030  i_polpermissive = PQfnumber(res, "polpermissive");
4031  i_polroles = PQfnumber(res, "polroles");
4032  i_polqual = PQfnumber(res, "polqual");
4033  i_polwithcheck = PQfnumber(res, "polwithcheck");
4034 
4035  polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
4036 
4037  for (j = 0; j < ntups; j++)
4038  {
4039  Oid polrelid = atooid(PQgetvalue(res, j, i_polrelid));
4040  TableInfo *tbinfo = findTableByOid(polrelid);
4041 
4043 
4044  polinfo[j].dobj.objType = DO_POLICY;
4045  polinfo[j].dobj.catId.tableoid =
4046  atooid(PQgetvalue(res, j, i_tableoid));
4047  polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
4048  AssignDumpId(&polinfo[j].dobj);
4049  polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4050  polinfo[j].poltable = tbinfo;
4051  polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
4052  polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
4053 
4054  polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
4055  polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
4056 
4057  if (PQgetisnull(res, j, i_polroles))
4058  polinfo[j].polroles = NULL;
4059  else
4060  polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
4061 
4062  if (PQgetisnull(res, j, i_polqual))
4063  polinfo[j].polqual = NULL;
4064  else
4065  polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
4066 
4067  if (PQgetisnull(res, j, i_polwithcheck))
4068  polinfo[j].polwithcheck = NULL;
4069  else
4070  polinfo[j].polwithcheck
4071  = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
4072  }
4073  }
4074 
4075  PQclear(res);
4076 
4077  destroyPQExpBuffer(query);
4078  destroyPQExpBuffer(tbloids);
4079 }
4080 
4081 /*
4082  * dumpPolicy
4083  * dump the definition of the given policy
4084  */
4085 static void
4086 dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
4087 {
4088  DumpOptions *dopt = fout->dopt;
4089  TableInfo *tbinfo = polinfo->poltable;
4090  PQExpBuffer query;
4091  PQExpBuffer delqry;
4092  PQExpBuffer polprefix;
4093  char *qtabname;
4094  const char *cmd;
4095  char *tag;
4096 
4097  /* Do nothing in data-only dump */
4098  if (dopt->dataOnly)
4099  return;
4100 
4101  /*
4102  * If polname is NULL, then this record is just indicating that ROW LEVEL
4103  * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
4104  * ROW LEVEL SECURITY.
4105  */
4106  if (polinfo->polname == NULL)
4107  {
4108  query = createPQExpBuffer();
4109 
4110  appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
4111  fmtQualifiedDumpable(tbinfo));
4112 
4113  /*
4114  * We must emit the ROW SECURITY object's dependency on its table
4115  * explicitly, because it will not match anything in pg_depend (unlike
4116  * the case for other PolicyInfo objects).
4117  */
4118  if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4119  ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
4120  ARCHIVE_OPTS(.tag = polinfo->dobj.name,
4121  .namespace = polinfo->dobj.namespace->dobj.name,
4122  .owner = tbinfo->rolname,
4123  .description = "ROW SECURITY",
4124  .section = SECTION_POST_DATA,
4125  .createStmt = query->data,
4126  .deps = &(tbinfo->dobj.dumpId),
4127  .nDeps = 1));
4128 
4129  destroyPQExpBuffer(query);
4130  return;
4131  }
4132 
4133  if (polinfo->polcmd == '*')
4134  cmd = "";
4135  else if (polinfo->polcmd == 'r')
4136  cmd = " FOR SELECT";
4137  else if (polinfo->polcmd == 'a')
4138  cmd = " FOR INSERT";
4139  else if (polinfo->polcmd == 'w')
4140  cmd = " FOR UPDATE";
4141  else if (polinfo->polcmd == 'd')
4142  cmd = " FOR DELETE";
4143  else
4144  pg_fatal("unexpected policy command type: %c",
4145  polinfo->polcmd);
4146 
4147  query = createPQExpBuffer();
4148  delqry = createPQExpBuffer();
4149  polprefix = createPQExpBuffer();
4150 
4151  qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
4152 
4153  appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
4154 
4155  appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
4156  !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
4157 
4158  if (polinfo->polroles != NULL)
4159  appendPQExpBuffer(query, " TO %s", polinfo->polroles);
4160 
4161  if (polinfo->polqual != NULL)
4162  appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
4163 
4164  if (polinfo->polwithcheck != NULL)
4165  appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
4166 
4167  appendPQExpBufferStr(query, ";\n");
4168 
4169  appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
4170  appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
4171 
4172  appendPQExpBuffer(polprefix, "POLICY %s ON",
4173  fmtId(polinfo->polname));
4174 
4175  tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
4176 
4177  if (polinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4178  ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
4179  ARCHIVE_OPTS(.tag = tag,
4180  .namespace = polinfo->dobj.namespace->dobj.name,
4181  .owner = tbinfo->rolname,
4182  .description = "POLICY",
4183  .section = SECTION_POST_DATA,
4184  .createStmt = query->data,
4185  .dropStmt = delqry->data));
4186 
4187  if (polinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4188  dumpComment(fout, polprefix->data, qtabname,
4189  tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
4190  polinfo->dobj.catId, 0, polinfo->dobj.dumpId);
4191 
4192  free(tag);
4193  destroyPQExpBuffer(query);
4194  destroyPQExpBuffer(delqry);
4195  destroyPQExpBuffer(polprefix);
4196  free(qtabname);
4197 }
4198 
4199 /*
4200  * getPublications
4201  * get information about publications
4202  */
4203 void
4205 {
4206  DumpOptions *dopt = fout->dopt;
4207  PQExpBuffer query;
4208  PGresult *res;
4209  PublicationInfo *pubinfo;
4210  int i_tableoid;
4211  int i_oid;
4212  int i_pubname;
4213  int i_pubowner;
4214  int i_puballtables;
4215  int i_pubinsert;
4216  int i_pubupdate;
4217  int i_pubdelete;
4218  int i_pubtruncate;
4219  int i_pubviaroot;
4220  int i,
4221  ntups;
4222 
4223  if (dopt->no_publications || fout->remoteVersion < 100000)
4224  return;
4225 
4226  query = createPQExpBuffer();
4227 
4228  resetPQExpBuffer(query);
4229 
4230  /* Get the publications. */
4231  if (fout->remoteVersion >= 130000)
4232  appendPQExpBufferStr(query,
4233  "SELECT p.tableoid, p.oid, p.pubname, "
4234  "p.pubowner, "
4235  "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, p.pubtruncate, p.pubviaroot "
4236  "FROM pg_publication p");
4237  else if (fout->remoteVersion >= 110000)
4238  appendPQExpBufferStr(query,
4239  "SELECT p.tableoid, p.oid, p.pubname, "
4240  "p.pubowner, "
4241  "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, p.pubtruncate, false AS pubviaroot "
4242  "FROM pg_publication p");
4243  else
4244  appendPQExpBufferStr(query,
4245  "SELECT p.tableoid, p.oid, p.pubname, "
4246  "p.pubowner, "
4247  "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, false AS pubtruncate, false AS pubviaroot "
4248  "FROM pg_publication p");
4249 
4250  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4251 
4252  ntups = PQntuples(res);
4253 
4254  i_tableoid = PQfnumber(res, "tableoid");
4255  i_oid = PQfnumber(res, "oid");
4256  i_pubname = PQfnumber(res, "pubname");
4257  i_pubowner = PQfnumber(res, "pubowner");
4258  i_puballtables = PQfnumber(res, "puballtables");
4259  i_pubinsert = PQfnumber(res, "pubinsert");
4260  i_pubupdate = PQfnumber(res, "pubupdate");
4261  i_pubdelete = PQfnumber(res, "pubdelete");
4262  i_pubtruncate = PQfnumber(res, "pubtruncate");
4263  i_pubviaroot = PQfnumber(res, "pubviaroot");
4264 
4265  pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
4266 
4267  for (i = 0; i < ntups; i++)
4268  {
4269  pubinfo[i].dobj.objType = DO_PUBLICATION;
4270  pubinfo[i].dobj.catId.tableoid =
4271  atooid(PQgetvalue(res, i, i_tableoid));
4272  pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4273  AssignDumpId(&pubinfo[i].dobj);
4274  pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
4275  pubinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_pubowner));
4276  pubinfo[i].puballtables =
4277  (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
4278  pubinfo[i].pubinsert =
4279  (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
4280  pubinfo[i].pubupdate =
4281  (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
4282  pubinfo[i].pubdelete =
4283  (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
4284  pubinfo[i].pubtruncate =
4285  (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
4286  pubinfo[i].pubviaroot =
4287  (strcmp(PQgetvalue(res, i, i_pubviaroot), "t") == 0);
4288 
4289  /* Decide whether we want to dump it */
4290  selectDumpableObject(&(pubinfo[i].dobj), fout);
4291  }
4292  PQclear(res);
4293 
4294  destroyPQExpBuffer(query);
4295 }
4296 
4297 /*
4298  * dumpPublication
4299  * dump the definition of the given publication
4300  */
4301 static void
4303 {
4304  DumpOptions *dopt = fout->dopt;
4305  PQExpBuffer delq;
4306  PQExpBuffer query;
4307  char *qpubname;
4308  bool first = true;
4309 
4310  /* Do nothing in data-only dump */
4311  if (dopt->dataOnly)
4312  return;
4313 
4314  delq = createPQExpBuffer();
4315  query = createPQExpBuffer();
4316 
4317  qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
4318 
4319  appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
4320  qpubname);
4321 
4322  appendPQExpBuffer(query, "CREATE PUBLICATION %s",
4323  qpubname);
4324 
4325  if (pubinfo->puballtables)
4326  appendPQExpBufferStr(query, " FOR ALL TABLES");
4327 
4328  appendPQExpBufferStr(query, " WITH (publish = '");
4329  if (pubinfo->pubinsert)
4330  {
4331  appendPQExpBufferStr(query, "insert");
4332  first = false;
4333  }
4334 
4335  if (pubinfo->pubupdate)
4336  {
4337  if (!first)
4338  appendPQExpBufferStr(query, ", ");
4339 
4340  appendPQExpBufferStr(query, "update");
4341  first = false;
4342  }
4343 
4344  if (pubinfo->pubdelete)
4345  {
4346  if (!first)
4347  appendPQExpBufferStr(query, ", ");
4348 
4349  appendPQExpBufferStr(query, "delete");
4350  first = false;
4351  }
4352 
4353  if (pubinfo->pubtruncate)
4354  {
4355  if (!first)
4356  appendPQExpBufferStr(query, ", ");
4357 
4358  appendPQExpBufferStr(query, "truncate");
4359  first = false;
4360  }
4361 
4362  appendPQExpBufferChar(query, '\'');
4363 
4364  if (pubinfo->pubviaroot)
4365  appendPQExpBufferStr(query, ", publish_via_partition_root = true");
4366 
4367  appendPQExpBufferStr(query, ");\n");
4368 
4369  if (pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4370  ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
4371  ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
4372  .owner = pubinfo->rolname,
4373  .description = "PUBLICATION",
4374  .section = SECTION_POST_DATA,
4375  .createStmt = query->data,
4376  .dropStmt = delq->data));
4377 
4378  if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4379  dumpComment(fout, "PUBLICATION", qpubname,
4380  NULL, pubinfo->rolname,
4381  pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
4382 
4383  if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
4384  dumpSecLabel(fout, "PUBLICATION", qpubname,
4385  NULL, pubinfo->rolname,
4386  pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
4387 
4388  destroyPQExpBuffer(delq);
4389  destroyPQExpBuffer(query);
4390  free(qpubname);
4391 }
4392 
4393 /*
4394  * getPublicationNamespaces
4395  * get information about publication membership for dumpable schemas.
4396  */
4397 void
4399 {
4400  PQExpBuffer query;
4401  PGresult *res;
4402  PublicationSchemaInfo *pubsinfo;
4403  DumpOptions *dopt = fout->dopt;
4404  int i_tableoid;
4405  int i_oid;
4406  int i_pnpubid;
4407  int i_pnnspid;
4408  int i,
4409  j,
4410  ntups;
4411 
4412  if (dopt->no_publications || fout->remoteVersion < 150000)
4413  return;
4414 
4415  query = createPQExpBuffer();
4416 
4417  /* Collect all publication membership info. */
4418  appendPQExpBufferStr(query,
4419  "SELECT tableoid, oid, pnpubid, pnnspid "
4420  "FROM pg_catalog.pg_publication_namespace");
4421  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4422 
4423  ntups = PQntuples(res);
4424 
4425  i_tableoid = PQfnumber(res, "tableoid");
4426  i_oid = PQfnumber(res, "oid");
4427  i_pnpubid = PQfnumber(res, "pnpubid");
4428  i_pnnspid = PQfnumber(res, "pnnspid");
4429 
4430  /* this allocation may be more than we need */
4431  pubsinfo = pg_malloc(ntups * sizeof(PublicationSchemaInfo));
4432  j = 0;
4433 
4434  for (i = 0; i < ntups; i++)
4435  {
4436  Oid pnpubid = atooid(PQgetvalue(res, i, i_pnpubid));
4437  Oid pnnspid = atooid(PQgetvalue(res, i, i_pnnspid));
4438  PublicationInfo *pubinfo;
4439  NamespaceInfo *nspinfo;
4440 
4441  /*
4442  * Ignore any entries for which we aren't interested in either the
4443  * publication or the rel.
4444  */
4445  pubinfo = findPublicationByOid(pnpubid);
4446  if (pubinfo == NULL)
4447  continue;
4448  nspinfo = findNamespaceByOid(pnnspid);
4449  if (nspinfo == NULL)
4450  continue;
4451 
4452  /*
4453  * We always dump publication namespaces unless the corresponding
4454  * namespace is excluded from the dump.
4455  */
4456  if (nspinfo->dobj.dump == DUMP_COMPONENT_NONE)
4457  continue;
4458 
4459  /* OK, make a DumpableObject for this relationship */
4461  pubsinfo[j].dobj.catId.tableoid =
4462  atooid(PQgetvalue(res, i, i_tableoid));
4463  pubsinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4464  AssignDumpId(&pubsinfo[j].dobj);
4465  pubsinfo[j].dobj.namespace = nspinfo->dobj.namespace;
4466  pubsinfo[j].dobj.name = nspinfo->dobj.name;
4467  pubsinfo[j].publication = pubinfo;
4468  pubsinfo[j].pubschema = nspinfo;
4469 
4470  /* Decide whether we want to dump it */
4471  selectDumpablePublicationObject(&(pubsinfo[j].dobj), fout);
4472 
4473  j++;
4474  }
4475 
4476  PQclear(res);
4477  destroyPQExpBuffer(query);
4478 }
4479 
4480 /*
4481  * getPublicationTables
4482  * get information about publication membership for dumpable tables.
4483  */
4484 void
4485 getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
4486 {
4487  PQExpBuffer query;
4488  PGresult *res;
4489  PublicationRelInfo *pubrinfo;
4490  DumpOptions *dopt = fout->dopt;
4491  int i_tableoid;
4492  int i_oid;
4493  int i_prpubid;
4494  int i_prrelid;
4495  int i_prrelqual;
4496  int i_prattrs;
4497  int i,
4498  j,
4499  ntups;
4500 
4501  if (dopt->no_publications || fout->remoteVersion < 100000)
4502  return;
4503 
4504  query = createPQExpBuffer();
4505 
4506  /* Collect all publication membership info. */
4507  if (fout->remoteVersion >= 150000)
4508  appendPQExpBufferStr(query,
4509  "SELECT tableoid, oid, prpubid, prrelid, "
4510  "pg_catalog.pg_get_expr(prqual, prrelid) AS prrelqual, "
4511  "(CASE\n"
4512  " WHEN pr.prattrs IS NOT NULL THEN\n"
4513  " (SELECT array_agg(attname)\n"
4514  " FROM\n"
4515  " pg_catalog.generate_series(0, pg_catalog.array_upper(pr.prattrs::pg_catalog.int2[], 1)) s,\n"
4516  " pg_catalog.pg_attribute\n"
4517  " WHERE attrelid = pr.prrelid AND attnum = prattrs[s])\n"
4518  " ELSE NULL END) prattrs "
4519  "FROM pg_catalog.pg_publication_rel pr");
4520  else
4521  appendPQExpBufferStr(query,
4522  "SELECT tableoid, oid, prpubid, prrelid, "
4523  "NULL AS prrelqual, NULL AS prattrs "
4524  "FROM pg_catalog.pg_publication_rel");
4525  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4526 
4527  ntups = PQntuples(res);
4528 
4529  i_tableoid = PQfnumber(res, "tableoid");
4530  i_oid = PQfnumber(res, "oid");
4531  i_prpubid = PQfnumber(res, "prpubid");
4532  i_prrelid = PQfnumber(res, "prrelid");
4533  i_prrelqual = PQfnumber(res, "prrelqual");
4534  i_prattrs = PQfnumber(res, "prattrs");
4535 
4536  /* this allocation may be more than we need */
4537  pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
4538  j = 0;
4539 
4540  for (i = 0; i < ntups; i++)
4541  {
4542  Oid prpubid = atooid(PQgetvalue(res, i, i_prpubid));
4543  Oid prrelid = atooid(PQgetvalue(res, i, i_prrelid));
4544  PublicationInfo *pubinfo;
4545  TableInfo *tbinfo;
4546 
4547  /*
4548  * Ignore any entries for which we aren't interested in either the
4549  * publication or the rel.
4550  */
4551  pubinfo = findPublicationByOid(prpubid);
4552  if (pubinfo == NULL)
4553  continue;
4554  tbinfo = findTableByOid(prrelid);
4555  if (tbinfo == NULL)
4556  continue;
4557 
4558  /*
4559  * Ignore publication membership of tables whose definitions are not
4560  * to be dumped.
4561  */
4562  if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
4563  continue;
4564 
4565  /* OK, make a DumpableObject for this relationship */
4566  pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
4567  pubrinfo[j].dobj.catId.tableoid =
4568  atooid(PQgetvalue(res, i, i_tableoid));
4569  pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4570  AssignDumpId(&pubrinfo[j].dobj);
4571  pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4572  pubrinfo[j].dobj.name = tbinfo->dobj.name;
4573  pubrinfo[j].publication = pubinfo;
4574  pubrinfo[j].pubtable = tbinfo;
4575  if (PQgetisnull(res, i, i_prrelqual))
4576  pubrinfo[j].pubrelqual = NULL;
4577  else
4578  pubrinfo[j].pubrelqual = pg_strdup(PQgetvalue(res, i, i_prrelqual));
4579 
4580  if (!PQgetisnull(res, i, i_prattrs))
4581  {
4582  char **attnames;
4583  int nattnames;
4584  PQExpBuffer attribs;
4585 
4586  if (!parsePGArray(PQgetvalue(res, i, i_prattrs),
4587  &attnames, &nattnames))
4588  pg_fatal("could not parse %s array", "prattrs");
4589  attribs = createPQExpBuffer();
4590  for (int k = 0; k < nattnames; k++)
4591  {
4592  if (k > 0)
4593  appendPQExpBufferStr(attribs, ", ");
4594 
4595  appendPQExpBufferStr(attribs, fmtId(attnames[k]));
4596  }
4597  pubrinfo[j].pubrattrs = attribs->data;
4598  }
4599  else
4600  pubrinfo[j].pubrattrs = NULL;
4601 
4602  /* Decide whether we want to dump it */
4603  selectDumpablePublicationObject(&(pubrinfo[j].dobj), fout);
4604 
4605  j++;
4606  }
4607 
4608  PQclear(res);
4609  destroyPQExpBuffer(query);
4610 }
4611 
4612 /*
4613  * dumpPublicationNamespace
4614  * dump the definition of the given publication schema mapping.
4615  */
4616 static void
4618 {
4619  DumpOptions *dopt = fout->dopt;
4620  NamespaceInfo *schemainfo = pubsinfo->pubschema;
4621  PublicationInfo *pubinfo = pubsinfo->publication;
4622  PQExpBuffer query;
4623  char *tag;
4624 
4625  /* Do nothing in data-only dump */
4626  if (dopt->dataOnly)
4627  return;
4628 
4629  tag = psprintf("%s %s", pubinfo->dobj.name, schemainfo->dobj.name);
4630 
4631  query = createPQExpBuffer();
4632 
4633  appendPQExpBuffer(query, "ALTER PUBLICATION %s ", fmtId(pubinfo->dobj.name));
4634  appendPQExpBuffer(query, "ADD TABLES IN SCHEMA %s;\n", fmtId(schemainfo->dobj.name));
4635 
4636  /*
4637  * There is no point in creating drop query as the drop is done by schema
4638  * drop.
4639  */
4640  if (pubsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4641  ArchiveEntry(fout, pubsinfo->dobj.catId, pubsinfo->dobj.dumpId,
4642  ARCHIVE_OPTS(.tag = tag,
4643  .namespace = schemainfo->dobj.name,
4644  .owner = pubinfo->rolname,
4645  .description = "PUBLICATION TABLES IN SCHEMA",
4646  .section = SECTION_POST_DATA,
4647  .createStmt = query->data));
4648 
4649  /* These objects can't currently have comments or seclabels */
4650 
4651  free(tag);
4652  destroyPQExpBuffer(query);
4653 }
4654 
4655 /*
4656  * dumpPublicationTable
4657  * dump the definition of the given publication table mapping
4658  */
4659 static void
4661 {
4662  DumpOptions *dopt = fout->dopt;
4663  PublicationInfo *pubinfo = pubrinfo->publication;
4664  TableInfo *tbinfo = pubrinfo->pubtable;
4665  PQExpBuffer query;
4666  char *tag;
4667 
4668  /* Do nothing in data-only dump */
4669  if (dopt->dataOnly)
4670  return;
4671 
4672  tag = psprintf("%s %s", pubinfo->dobj.name, tbinfo->dobj.name);
4673 
4674  query = createPQExpBuffer();
4675 
4676  appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
4677  fmtId(pubinfo->dobj.name));
4678  appendPQExpBuffer(query, " %s",
4679  fmtQualifiedDumpable(tbinfo));
4680 
4681  if (pubrinfo->pubrattrs)
4682  appendPQExpBuffer(query, " (%s)", pubrinfo->pubrattrs);
4683 
4684  if (pubrinfo->pubrelqual)
4685  {
4686  /*
4687  * It's necessary to add parentheses around the expression because
4688  * pg_get_expr won't supply the parentheses for things like WHERE
4689  * TRUE.
4690  */
4691  appendPQExpBuffer(query, " WHERE (%s)", pubrinfo->pubrelqual);
4692  }
4693  appendPQExpBufferStr(query, ";\n");
4694 
4695  /*
4696  * There is no point in creating a drop query as the drop is done by table
4697  * drop. (If you think to change this, see also _printTocEntry().)
4698  * Although this object doesn't really have ownership as such, set the
4699  * owner field anyway to ensure that the command is run by the correct
4700  * role at restore time.
4701  */
4702  if (pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
4703  ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
4704  ARCHIVE_OPTS(.tag = tag,
4705  .namespace = tbinfo->dobj.namespace->dobj.name,
4706  .owner = pubinfo->rolname,
4707  .description = "PUBLICATION TABLE",
4708  .section = SECTION_POST_DATA,
4709  .createStmt = query->data));
4710 
4711  /* These objects can't currently have comments or seclabels */
4712 
4713  free(tag);
4714  destroyPQExpBuffer(query);
4715 }
4716 
4717 /*
4718  * Is the currently connected user a superuser?
4719  */
4720 static bool
4722 {
4723  ArchiveHandle *AH = (ArchiveHandle *) fout;
4724  const char *val;
4725 
4726  val = PQparameterStatus(AH->connection, "is_superuser");
4727 
4728  if (val && strcmp(val, "on") == 0)
4729  return true;
4730 
4731  return false;
4732 }
4733 
4734 /*
4735  * getSubscriptions
4736  * get information about subscriptions
4737  */
4738 void
4740 {
4741  DumpOptions *dopt = fout->dopt;
4742  PQExpBuffer query;
4743  PGresult *res;
4744  SubscriptionInfo *subinfo;
4745  int i_tableoid;
4746  int i_oid;
4747  int i_subname;
4748  int i_subowner;
4749  int i_subbinary;
4750  int i_substream;
4751  int i_subtwophasestate;
4752  int i_subdisableonerr;
4753  int i_subpasswordrequired;
4754  int i_subrunasowner;
4755  int i_subconninfo;
4756  int i_subslotname;
4757  int i_subsynccommit;
4758  int i_subpublications;
4759  int i_suborigin;
4760  int i_suboriginremotelsn;
4761  int i_subenabled;
4762  int i_subfailover;
4763  int i,
4764  ntups;
4765 
4766  if (dopt->no_subscriptions || fout->remoteVersion < 100000)
4767  return;
4768 
4769  if (!is_superuser(fout))
4770  {
4771  int n;
4772 
4773  res = ExecuteSqlQuery(fout,
4774  "SELECT count(*) FROM pg_subscription "
4775  "WHERE subdbid = (SELECT oid FROM pg_database"
4776  " WHERE datname = current_database())",
4777  PGRES_TUPLES_OK);
4778  n = atoi(PQgetvalue(res, 0, 0));
4779  if (n > 0)
4780  pg_log_warning("subscriptions not dumped because current user is not a superuser");
4781  PQclear(res);
4782  return;
4783  }
4784 
4785  query = createPQExpBuffer();
4786 
4787  /* Get the subscriptions in current database. */
4788  appendPQExpBufferStr(query,
4789  "SELECT s.tableoid, s.oid, s.subname,\n"
4790  " s.subowner,\n"
4791  " s.subconninfo, s.subslotname, s.subsynccommit,\n"
4792  " s.subpublications,\n");
4793 
4794  if (fout->remoteVersion >= 140000)
4795  appendPQExpBufferStr(query, " s.subbinary,\n");
4796  else
4797  appendPQExpBufferStr(query, " false AS subbinary,\n");
4798 
4799  if (fout->remoteVersion >= 140000)
4800  appendPQExpBufferStr(query, " s.substream,\n");
4801  else
4802  appendPQExpBufferStr(query, " 'f' AS substream,\n");
4803 
4804  if (fout->remoteVersion >= 150000)
4805  appendPQExpBufferStr(query,
4806  " s.subtwophasestate,\n"
4807  " s.subdisableonerr,\n");
4808  else
4809  appendPQExpBuffer(query,
4810  " '%c' AS subtwophasestate,\n"
4811  " false AS subdisableonerr,\n",
4813 
4814  if (fout->remoteVersion >= 160000)
4815  appendPQExpBufferStr(query,
4816  " s.subpasswordrequired,\n"
4817  " s.subrunasowner,\n"
4818  " s.suborigin,\n");
4819  else
4820  appendPQExpBuffer(query,
4821  " 't' AS subpasswordrequired,\n"
4822  " 't' AS subrunasowner,\n"
4823  " '%s' AS suborigin,\n",
4825 
4826  if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
4827  appendPQExpBufferStr(query, " o.remote_lsn AS suboriginremotelsn,\n"
4828  " s.subenabled,\n");
4829  else
4830  appendPQExpBufferStr(query, " NULL AS suboriginremotelsn,\n"
4831  " false AS subenabled,\n");
4832 
4833  if (fout->remoteVersion >= 170000)
4834  appendPQExpBufferStr(query,
4835  " s.subfailover\n");
4836  else
4837  appendPQExpBuffer(query,
4838  " false AS subfailover\n");
4839 
4840  appendPQExpBufferStr(query,
4841  "FROM pg_subscription s\n");
4842 
4843  if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
4844  appendPQExpBufferStr(query,
4845  "LEFT JOIN pg_catalog.pg_replication_origin_status o \n"
4846  " ON o.external_id = 'pg_' || s.oid::text \n");
4847 
4848  appendPQExpBufferStr(query,
4849  "WHERE s.subdbid = (SELECT oid FROM pg_database\n"
4850  " WHERE datname = current_database())");
4851 
4852  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4853 
4854  ntups = PQntuples(res);
4855 
4856  /*
4857  * Get subscription fields. We don't include subskiplsn in the dump as
4858  * after restoring the dump this value may no longer be relevant.
4859  */
4860  i_tableoid = PQfnumber(res, "tableoid");
4861  i_oid = PQfnumber(res, "oid");
4862  i_subname = PQfnumber(res, "subname");
4863  i_subowner = PQfnumber(res, "subowner");
4864  i_subbinary = PQfnumber(res, "subbinary");
4865  i_substream = PQfnumber(res, "substream");
4866  i_subtwophasestate = PQfnumber(res, "subtwophasestate");
4867  i_subdisableonerr = PQfnumber(res, "subdisableonerr");
4868  i_subpasswordrequired = PQfnumber(res, "subpasswordrequired");
4869  i_subrunasowner = PQfnumber(res, "subrunasowner");
4870  i_subconninfo = PQfnumber(res, "subconninfo");
4871  i_subslotname = PQfnumber(res, "subslotname");
4872  i_subsynccommit = PQfnumber(res, "subsynccommit");
4873  i_subpublications = PQfnumber(res, "subpublications");
4874  i_suborigin = PQfnumber(res, "suborigin");
4875  i_suboriginremotelsn = PQfnumber(res, "suboriginremotelsn");
4876  i_subenabled = PQfnumber(res, "subenabled");
4877  i_subfailover = PQfnumber(res, "subfailover");
4878 
4879  subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
4880 
4881  for (i = 0; i < ntups; i++)
4882  {
4883  subinfo[i].dobj.objType = DO_SUBSCRIPTION;
4884  subinfo[i].dobj.catId.tableoid =
4885  atooid(PQgetvalue(res, i, i_tableoid));
4886  subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4887  AssignDumpId(&subinfo[i].dobj);
4888  subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
4889  subinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_subowner));
4890 
4891  subinfo[i].subbinary =
4892  pg_strdup(PQgetvalue(res, i, i_subbinary));
4893  subinfo[i].substream =
4894  pg_strdup(PQgetvalue(res, i, i_substream));
4895  subinfo[i].subtwophasestate =
4896  pg_strdup(PQgetvalue(res, i, i_subtwophasestate));
4897  subinfo[i].subdisableonerr =
4898  pg_strdup(PQgetvalue(res, i, i_subdisableonerr));
4899  subinfo[i].subpasswordrequired =
4900  pg_strdup(PQgetvalue(res, i, i_subpasswordrequired));
4901  subinfo[i].subrunasowner =
4902  pg_strdup(PQgetvalue(res, i, i_subrunasowner));
4903  subinfo[i].subconninfo =
4904  pg_strdup(PQgetvalue(res, i, i_subconninfo));
4905  if (PQgetisnull(res, i, i_subslotname))
4906  subinfo[i].subslotname = NULL;
4907  else
4908  subinfo[i].subslotname =
4909  pg_strdup(PQgetvalue(res, i, i_subslotname));
4910  subinfo[i].subsynccommit =
4911  pg_strdup(PQgetvalue(res, i, i_subsynccommit));
4912  subinfo[i].subpublications =
4913  pg_strdup(PQgetvalue(res, i, i_subpublications));
4914  subinfo[i].suborigin = pg_strdup(PQgetvalue(res, i, i_suborigin));
4915  if (PQgetisnull(res, i, i_suboriginremotelsn))
4916  subinfo[i].suboriginremotelsn = NULL;
4917  else
4918  subinfo[i].suboriginremotelsn =
4919  pg_strdup(PQgetvalue(res, i, i_suboriginremotelsn));
4920  subinfo[i].subenabled =
4921  pg_strdup(PQgetvalue(res, i, i_subenabled));
4922  subinfo[i].subfailover =
4923  pg_strdup(PQgetvalue(res, i, i_subfailover));
4924 
4925  /* Decide whether we want to dump it */
4926  selectDumpableObject(&(subinfo[i].dobj), fout);
4927  }
4928  PQclear(res);
4929 
4930  destroyPQExpBuffer(query);
4931 }
4932 
4933 /*
4934  * getSubscriptionTables
4935  * Get information about subscription membership for dumpable tables. This
4936  * will be used only in binary-upgrade mode for PG17 or later versions.
4937  */
4938 void
4940 {
4941  DumpOptions *dopt = fout->dopt;
4942  SubscriptionInfo *subinfo = NULL;
4943  SubRelInfo *subrinfo;
4944  PGresult *res;
4945  int i_srsubid;
4946  int i_srrelid;
4947  int i_srsubstate;
4948  int i_srsublsn;
4949  int ntups;
4950  Oid last_srsubid = InvalidOid;
4951 
4952  if (dopt->no_subscriptions || !dopt->binary_upgrade ||
4953  fout->remoteVersion < 170000)
4954  return;
4955 
4956  res = ExecuteSqlQuery(fout,
4957  "SELECT srsubid, srrelid, srsubstate, srsublsn "
4958  "FROM pg_catalog.pg_subscription_rel "
4959  "ORDER BY srsubid",
4960  PGRES_TUPLES_OK);
4961  ntups = PQntuples(res);
4962  if (ntups == 0)
4963  goto cleanup;
4964 
4965  /* Get pg_subscription_rel attributes */
4966  i_srsubid = PQfnumber(res, "srsubid");
4967  i_srrelid = PQfnumber(res, "srrelid");
4968  i_srsubstate = PQfnumber(res, "srsubstate");
4969  i_srsublsn = PQfnumber(res, "srsublsn");
4970 
4971  subrinfo = pg_malloc(ntups * sizeof(SubRelInfo));
4972  for (int i = 0; i < ntups; i++)
4973  {
4974  Oid cur_srsubid = atooid(PQgetvalue(res, i, i_srsubid));
4975  Oid relid = atooid(PQgetvalue(res, i, i_srrelid));
4976  TableInfo *tblinfo;
4977 
4978  /*
4979  * If we switched to a new subscription, check if the subscription
4980  * exists.
4981  */
4982  if (cur_srsubid != last_srsubid)
4983  {
4984  subinfo = findSubscriptionByOid(cur_srsubid);
4985  if (subinfo == NULL)
4986  pg_fatal("subscription with OID %u does not exist", cur_srsubid);
4987 
4988  last_srsubid = cur_srsubid;
4989  }
4990 
4991  tblinfo = findTableByOid(relid);
4992  if (tblinfo == NULL)
4993  pg_fatal("failed sanity check, table with OID %u not found",
4994  relid);
4995 
4996  /* OK, make a DumpableObject for this relationship */
4997  subrinfo[i].dobj.objType = DO_SUBSCRIPTION_REL;
4998  subrinfo[i].dobj.catId.tableoid = relid;
4999  subrinfo[i].dobj.catId.oid = cur_srsubid;
5000  AssignDumpId(&subrinfo[i].dobj);
5001  subrinfo[i].dobj.name = pg_strdup(subinfo->dobj.name);
5002  subrinfo[i].tblinfo = tblinfo;
5003  subrinfo[i].srsubstate = PQgetvalue(res, i, i_srsubstate)[0];
5004  if (PQgetisnull(res, i, i_srsublsn))
5005  subrinfo[i].srsublsn = NULL;
5006  else
5007  subrinfo[i].srsublsn = pg_strdup(PQgetvalue(res, i, i_srsublsn));
5008 
5009  subrinfo[i].subinfo = subinfo;
5010 
5011  /* Decide whether we want to dump it */
5012  selectDumpableObject(&(subrinfo[i].dobj), fout);
5013  }
5014 
5015 cleanup:
5016  PQclear(res);
5017 }
5018 
5019 /*
5020  * dumpSubscriptionTable
5021  * Dump the definition of the given subscription table mapping. This will be
5022  * used only in binary-upgrade mode for PG17 or later versions.
5023  */
5024 static void
5026 {
5027  DumpOptions *dopt = fout->dopt;
5028  SubscriptionInfo *subinfo = subrinfo->subinfo;
5029  PQExpBuffer query;
5030  char *tag;
5031 
5032  /* Do nothing in data-only dump */
5033  if (dopt->dataOnly)
5034  return;
5035 
5036  Assert(fout->dopt->binary_upgrade && fout->remoteVersion >= 170000);
5037 
5038  tag = psprintf("%s %s", subinfo->dobj.name, subrinfo->dobj.name);
5039 
5040  query = createPQExpBuffer();
5041 
5042  if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5043  {
5044  /*
5045  * binary_upgrade_add_sub_rel_state will add the subscription relation
5046  * to pg_subscription_rel table. This will be used only in
5047  * binary-upgrade mode.
5048  */
5049  appendPQExpBufferStr(query,
5050  "\n-- For binary upgrade, must preserve the subscriber table.\n");
5051  appendPQExpBufferStr(query,
5052  "SELECT pg_catalog.binary_upgrade_add_sub_rel_state(");
5053  appendStringLiteralAH(query, subrinfo->dobj.name, fout);
5054  appendPQExpBuffer(query,
5055  ", %u, '%c'",
5056  subrinfo->tblinfo->dobj.catId.oid,
5057  subrinfo->srsubstate);
5058 
5059  if (subrinfo->srsublsn && subrinfo->srsublsn[0] != '\0')
5060  appendPQExpBuffer(query, ", '%s'", subrinfo->srsublsn);
5061  else
5062  appendPQExpBuffer(query, ", NULL");
5063 
5064  appendPQExpBufferStr(query, ");\n");
5065  }
5066 
5067  /*
5068  * There is no point in creating a drop query as the drop is done by table
5069  * drop. (If you think to change this, see also _printTocEntry().)
5070  * Although this object doesn't really have ownership as such, set the
5071  * owner field anyway to ensure that the command is run by the correct
5072  * role at restore time.
5073  */
5074  if (subrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5075  ArchiveEntry(fout, subrinfo->dobj.catId, subrinfo->dobj.dumpId,
5076  ARCHIVE_OPTS(.tag = tag,
5077  .namespace = subrinfo->tblinfo->dobj.namespace->dobj.name,
5078  .owner = subinfo->rolname,
5079  .description = "SUBSCRIPTION TABLE",
5080  .section = SECTION_POST_DATA,
5081  .createStmt = query->data));
5082 
5083  /* These objects can't currently have comments or seclabels */
5084 
5085  free(tag);
5086  destroyPQExpBuffer(query);
5087 }
5088 
5089 /*
5090  * dumpSubscription
5091  * dump the definition of the given subscription
5092  */
5093 static void
5095 {
5096  DumpOptions *dopt = fout->dopt;
5097  PQExpBuffer delq;
5098  PQExpBuffer query;
5099  PQExpBuffer publications;
5100  char *qsubname;
5101  char **pubnames = NULL;
5102  int npubnames = 0;
5103  int i;
5104  char two_phase_disabled[] = {LOGICALREP_TWOPHASE_STATE_DISABLED, '\0'};
5105 
5106  /* Do nothing in data-only dump */
5107  if (dopt->dataOnly)
5108  return;
5109 
5110  delq = createPQExpBuffer();
5111  query = createPQExpBuffer();
5112 
5113  qsubname = pg_strdup(fmtId(subinfo->dobj.name));
5114 
5115  appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
5116  qsubname);
5117 
5118  appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
5119  qsubname);
5120  appendStringLiteralAH(query, subinfo->subconninfo, fout);
5121 
5122  /* Build list of quoted publications and append them to query. */
5123  if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
5124  pg_fatal("could not parse %s array", "subpublications");
5125 
5126  publications = createPQExpBuffer();
5127  for (i = 0; i < npubnames; i++)
5128  {
5129  if (i > 0)
5130  appendPQExpBufferStr(publications, ", ");
5131 
5132  appendPQExpBufferStr(publications, fmtId(pubnames[i]));
5133  }
5134 
5135  appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
5136  if (subinfo->subslotname)
5137  appendStringLiteralAH(query, subinfo->subslotname, fout);
5138  else
5139  appendPQExpBufferStr(query, "NONE");
5140 
5141  if (strcmp(subinfo->subbinary, "t") == 0)
5142  appendPQExpBufferStr(query, ", binary = true");
5143 
5144  if (strcmp(subinfo->substream, "t") == 0)
5145  appendPQExpBufferStr(query, ", streaming = on");
5146  else if (strcmp(subinfo->substream, "p") == 0)
5147  appendPQExpBufferStr(query, ", streaming = parallel");
5148 
5149  if (strcmp(subinfo->subtwophasestate, two_phase_disabled) != 0)
5150  appendPQExpBufferStr(query, ", two_phase = on");
5151 
5152  if (strcmp(subinfo->subdisableonerr, "t") == 0)
5153  appendPQExpBufferStr(query, ", disable_on_error = true");
5154 
5155  if (strcmp(subinfo->subpasswordrequired, "t") != 0)
5156  appendPQExpBuffer(query, ", password_required = false");
5157 
5158  if (strcmp(subinfo->subrunasowner, "t") == 0)
5159  appendPQExpBufferStr(query, ", run_as_owner = true");
5160 
5161  if (strcmp(subinfo->subfailover, "t") == 0)
5162  appendPQExpBufferStr(query, ", failover = true");
5163 
5164  if (strcmp(subinfo->subsynccommit, "off") != 0)
5165  appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
5166 
5167  if (pg_strcasecmp(subinfo->suborigin, LOGICALREP_ORIGIN_ANY) != 0)
5168  appendPQExpBuffer(query, ", origin = %s", subinfo->suborigin);
5169 
5170  appendPQExpBufferStr(query, ");\n");
5171 
5172  /*
5173  * In binary-upgrade mode, we allow the replication to continue after the
5174  * upgrade.
5175  */
5176  if (dopt->binary_upgrade && fout->remoteVersion >= 170000)
5177  {
5178  if (subinfo->suboriginremotelsn)
5179  {
5180  /*
5181  * Preserve the remote_lsn for the subscriber's replication
5182  * origin. This value is required to start the replication from
5183  * the position before the upgrade. This value will be stale if
5184  * the publisher gets upgraded before the subscriber node.
5185  * However, this shouldn't be a problem as the upgrade of the
5186  * publisher ensures that all the transactions were replicated
5187  * before upgrading it.
5188  */
5189  appendPQExpBufferStr(query,
5190  "\n-- For binary upgrade, must preserve the remote_lsn for the subscriber's replication origin.\n");
5191  appendPQExpBufferStr(query,
5192  "SELECT pg_catalog.binary_upgrade_replorigin_advance(");
5193  appendStringLiteralAH(query, subinfo->dobj.name, fout);
5194  appendPQExpBuffer(query, ", '%s');\n", subinfo->suboriginremotelsn);
5195  }
5196 
5197  if (strcmp(subinfo->subenabled, "t") == 0)
5198  {
5199  /*
5200  * Enable the subscription to allow the replication to continue
5201  * after the upgrade.
5202  */
5203  appendPQExpBufferStr(query,
5204  "\n-- For binary upgrade, must preserve the subscriber's running state.\n");
5205  appendPQExpBuffer(query, "ALTER SUBSCRIPTION %s ENABLE;\n", qsubname);
5206  }
5207  }
5208 
5209  if (subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
5210  ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
5211  ARCHIVE_OPTS(.tag = subinfo->dobj.name,
5212  .owner = subinfo->rolname,
5213  .description = "SUBSCRIPTION",
5214  .section = SECTION_POST_DATA,
5215  .createStmt = query->data,
5216  .dropStmt = delq->data));
5217 
5218  if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
5219  dumpComment(fout, "SUBSCRIPTION", qsubname,
5220  NULL, subinfo->rolname,
5221  subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
5222 
5223  if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
5224  dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
5225  NULL, subinfo->rolname,
5226  subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
5227 
5228  destroyPQExpBuffer(publications);
5229  free(pubnames);
5230 
5231  destroyPQExpBuffer(delq);
5232  destroyPQExpBuffer(query);
5233  free(qsubname);
5234 }
5235 
5236 /*
5237  * Given a "create query", append as many ALTER ... DEPENDS ON EXTENSION as
5238  * the object needs.
5239  */
5240 static void
5242  PQExpBuffer create,
5243  const DumpableObject *dobj,
5244  const char *catalog,
5245  const char *keyword,
5246  const char *objname)
5247 {
5248  if (dobj->depends_on_ext)
5249  {
5250  char *nm;
5251  PGresult *res;
5252  PQExpBuffer query;
5253  int ntups;
5254  int i_extname;
5255  int i;
5256 
5257  /* dodge fmtId() non-reentrancy */
5258  nm = pg_strdup(objname);
5259 
5260  query = createPQExpBuffer();
5261  appendPQExpBuffer(query,
5262  "SELECT e.extname "
5263  "FROM pg_catalog.pg_depend d, pg_catalog.pg_extension e "
5264  "WHERE d.refobjid = e.oid AND classid = '%s'::pg_catalog.regclass "
5265  "AND objid = '%u'::pg_catalog.oid AND deptype = 'x' "
5266  "AND refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass",
5267  catalog,
5268  dobj->catId.oid);
5269  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5270  ntups = PQntuples(res);
5271  i_extname = PQfnumber(res, "extname");
5272  for (i = 0; i < ntups; i++)
5273  {
5274  appendPQExpBuffer(create, "\nALTER %s %s DEPENDS ON EXTENSION %s;",
5275  keyword, nm,
5276  fmtId(PQgetvalue(res, i, i_extname)));
5277  }
5278 
5279  PQclear(res);
5280  destroyPQExpBuffer(query);
5281  pg_free(nm);
5282  }
5283 }
5284 
5285 static Oid
5287 {
5288  /*
5289  * If the old version didn't assign an array type, but the new version
5290  * does, we must select an unused type OID to assign. This currently only
5291  * happens for domains, when upgrading pre-v11 to v11 and up.
5292  *
5293  * Note: local state here is kind of ugly, but we must have some, since we
5294  * mustn't choose the same unused OID more than once.
5295  */
5296  static Oid next_possible_free_oid = FirstNormalObjectId;
5297  PGresult *res;
5298  bool is_dup;
5299 
5300  do
5301  {
5302  ++next_possible_free_oid;
5303  printfPQExpBuffer(upgrade_query,
5304  "SELECT EXISTS(SELECT 1 "
5305  "FROM pg_catalog.pg_type "
5306  "WHERE oid = '%u'::pg_catalog.oid);",
5307  next_possible_free_oid);
5308  res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
5309  is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
5310  PQclear(res);
5311  } while (is_dup);
5312 
5313  return next_possible_free_oid;
5314 }
5315 
5316 static void
5318  PQExpBuffer upgrade_buffer,
5319  Oid pg_type_oid,
5320  bool force_array_type,
5321  bool include_multirange_type)
5322 {
5323  PQExpBuffer upgrade_query = createPQExpBuffer();
5324  PGresult *res;
5325  Oid pg_type_array_oid;
5326  Oid pg_type_multirange_oid;
5327  Oid pg_type_multirange_array_oid;
5328 
5329  appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
5330  appendPQExpBuffer(upgrade_buffer,
5331  "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5332  pg_type_oid);
5333 
5334  appendPQExpBuffer(upgrade_query,
5335  "SELECT typarray "
5336  "FROM pg_catalog.pg_type "
5337  "WHERE oid = '%u'::pg_catalog.oid;",
5338  pg_type_oid);
5339 
5340  res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
5341 
5342  pg_type_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
5343 
5344  PQclear(res);
5345 
5346  if (!OidIsValid(pg_type_array_oid) && force_array_type)
5347  pg_type_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
5348 
5349  if (OidIsValid(pg_type_array_oid))
5350  {
5351  appendPQExpBufferStr(upgrade_buffer,
5352  "\n-- For binary upgrade, must preserve pg_type array oid\n");
5353  appendPQExpBuffer(upgrade_buffer,
5354  "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5355  pg_type_array_oid);
5356  }
5357 
5358  /*
5359  * Pre-set the multirange type oid and its own array type oid.
5360  */
5361  if (include_multirange_type)
5362  {
5363  if (fout->remoteVersion >= 140000)
5364  {
5365  printfPQExpBuffer(upgrade_query,
5366  "SELECT t.oid, t.typarray "
5367  "FROM pg_catalog.pg_type t "
5368  "JOIN pg_catalog.pg_range r "
5369  "ON t.oid = r.rngmultitypid "
5370  "WHERE r.rngtypid = '%u'::pg_catalog.oid;",
5371  pg_type_oid);
5372 
5373  res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
5374 
5375  pg_type_multirange_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
5376  pg_type_multirange_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
5377 
5378  PQclear(res);
5379  }
5380  else
5381  {
5382  pg_type_multirange_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
5383  pg_type_multirange_array_oid = get_next_possible_free_pg_type_oid(fout, upgrade_query);
5384  }
5385 
5386  appendPQExpBufferStr(upgrade_buffer,
5387  "\n-- For binary upgrade, must preserve multirange pg_type oid\n");
5388  appendPQExpBuffer(upgrade_buffer,
5389  "SELECT pg_catalog.binary_upgrade_set_next_multirange_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5390  pg_type_multirange_oid);
5391  appendPQExpBufferStr(upgrade_buffer,
5392  "\n-- For binary upgrade, must preserve multirange pg_type array oid\n");
5393  appendPQExpBuffer(upgrade_buffer,
5394  "SELECT pg_catalog.binary_upgrade_set_next_multirange_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
5395  pg_type_multirange_array_oid);
5396  }
5397 
5398  destroyPQExpBuffer(upgrade_query);
5399 }
5400 
5401 static void
5403  PQExpBuffer upgrade_buffer,
5404  const TableInfo *tbinfo)
5405 {
5406  Oid pg_type_oid = tbinfo->reltype;
5407 
5408  if (OidIsValid(pg_type_oid))
5409  binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
5410  pg_type_oid, false, false);
5411 }
5412 
5413 /*
5414  * bsearch() comparator for BinaryUpgradeClassOidItem
5415  */
5416 static int
5417 BinaryUpgradeClassOidItemCmp(const void *p1, const void *p2)
5418 {
5421 
5422  return pg_cmp_u32(v1.oid, v2.oid);
5423 }
5424 
5425 /*
5426  * collectBinaryUpgradeClassOids
5427  *
5428  * Construct a table of pg_class information required for
5429  * binary_upgrade_set_pg_class_oids(). The table is sorted by OID for speed in
5430  * lookup.
5431  */
5432 static void
5434 {
5435  PGresult *res;
5436  const char *query;
5437 
5438  query = "SELECT c.oid, c.relkind, c.relfilenode, c.reltoastrelid, "
5439  "ct.relfilenode, i.indexrelid, cti.relfilenode "
5440  "FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_index i "
5441  "ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
5442  "LEFT JOIN pg_catalog.pg_class ct ON (c.reltoastrelid = ct.oid) "
5443  "LEFT JOIN pg_catalog.pg_class AS cti ON (i.indexrelid = cti.oid) "
5444  "ORDER BY c.oid;";
5445 
5446  res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
5447 
5451 
5452  for (int i = 0; i < nbinaryUpgradeClassOids; i++)
5453  {
5461  }
5462 
5463  PQclear(res);
5464 }
5465 
5466 static void
5468  PQExpBuffer upgrade_buffer, Oid pg_class_oid)
5469 {
5472 
5474 
5475  /*
5476  * Preserve the OID and relfilenumber of the table, table's index, table's
5477  * toast table and toast table's index if any.
5478  *
5479  * One complexity is that the current table definition might not require
5480  * the creation of a TOAST table, but the old database might have a TOAST
5481  * table that was created earlier, before some wide columns were dropped.
5482  * By setting the TOAST oid we force creation of the TOAST heap and index
5483  * by the new backend, so we can copy the files during binary upgrade
5484  * without worrying about this case.
5485  */
5486  key.oid = pg_class_oid;
5488  sizeof(BinaryUpgradeClassOidItem),
5490 
5491  appendPQExpBufferStr(upgrade_buffer,
5492  "\n-- For binary upgrade, must preserve pg_class oids and relfilenodes\n");
5493 
5494  if (entry->relkind != RELKIND_INDEX &&
5495  entry->relkind != RELKIND_PARTITIONED_INDEX)
5496  {
5497  appendPQExpBuffer(upgrade_buffer,
5498  "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
5499  pg_class_oid);
5500 
5501  /*
5502  * Not every relation has storage. Also, in a pre-v12 database,
5503  * partitioned tables have a relfilenumber, which should not be
5504  * preserved when upgrading.
5505  */
5506  if (RelFileNumberIsValid(entry->relfilenumber) &&
5507  entry->relkind != RELKIND_PARTITIONED_TABLE)
5508  appendPQExpBuffer(upgrade_buffer,
5509  "SELECT pg_catalog.binary_upgrade_set_next_heap_relfilenode('%u'::pg_catalog.oid);\n",
5510  entry->relfilenumber);
5511 
5512  /*
5513  * In a pre-v12 database, partitioned tables might be marked as having
5514  * toast tables, but we should ignore them if so.
5515  */
5516  if (OidIsValid(entry->toast_oid) &&
5517  entry->relkind != RELKIND_PARTITIONED_TABLE)
5518  {
5519  appendPQExpBuffer(upgrade_buffer,
5520  "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
5521  entry->toast_oid);
5522  appendPQExpBuffer(upgrade_buffer,
5523  "SELECT pg_catalog.binary_upgrade_set_next_toast_relfilenode('%u'::pg_catalog.oid);\n",
5524  entry->toast_relfilenumber);
5525 
5526  /* every toast table has an index */
5527  appendPQExpBuffer(upgrade_buffer,
5528  "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
5529  entry->toast_index_oid);
5530  appendPQExpBuffer(upgrade_buffer,
5531  "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
5532  entry->toast_index_relfilenumber);
5533  }
5534  }
5535  else
5536  {
5537  /* Preserve the OID and relfilenumber of the index */
5538  appendPQExpBuffer(upgrade_buffer,
5539  "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
5540  pg_class_oid);
5541  appendPQExpBuffer(upgrade_buffer,
5542  "SELECT pg_catalog.binary_upgrade_set_next_index_relfilenode('%u'::pg_catalog.oid);\n",
5543  entry->relfilenumber);
5544  }
5545 
5546  appendPQExpBufferChar(upgrade_buffer, '\n');
5547 }
5548 
5549 /*
5550  * If the DumpableObject is a member of an extension, add a suitable
5551  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
5552  *
5553  * For somewhat historical reasons, objname should already be quoted,
5554  * but not objnamespace (if any).
5555  */
5556 static void
5558  const DumpableObject *dobj,
5559  const char *objtype,
5560  const char *objname,
5561  const char *objnamespace)
5562 {
5563  DumpableObject *extobj = NULL;
5564  int i;
5565 
5566  if (!dobj->ext_member)
5567  return;
5568 
5569  /*
5570  * Find the parent extension. We could avoid this search if we wanted to
5571  * add a link field to DumpableObject, but the space costs of that would
5572  * be considerable. We assume that member objects could only have a
5573  * direct dependency on their own extension, not any others.
5574  */
5575  for (i = 0; i < dobj->nDeps; i++)
5576  {
5577  extobj = findObjectByDumpId(dobj->dependencies[i]);
5578  if (extobj && extobj->objType == DO_EXTENSION)
5579  break;
5580  extobj = NULL;
5581  }
5582  if (extobj == NULL)
5583  pg_fatal("could not find parent extension for %s %s",
5584  objtype, objname);
5585 
5586  appendPQExpBufferStr(upgrade_buffer,
5587  "\n-- For binary upgrade, handle extension membership the hard way\n");
5588  appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
5589  fmtId(extobj->name),
5590  objtype);
5591  if (objnamespace && *objnamespace)
5592  appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
5593  appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
5594 }
5595 
5596 /*
5597  * getNamespaces:
5598  * get information about all namespaces in the system catalogs
5599  */
5600 void
5602 {
5603  PGresult *res;
5604  int ntups;
5605  int i;
5606  PQExpBuffer query;
5607  NamespaceInfo *nsinfo;
5608  int i_tableoid;
5609  int i_oid;
5610  int i_nspname;
5611  int i_nspowner;
5612  int i_nspacl;
5613  int i_acldefault;
5614 
5615  query = createPQExpBuffer();
5616 
5617  /*
5618  * we fetch all namespaces including system ones, so that every object we
5619  * read in can be linked to a containing namespace.
5620  */
5621  appendPQExpBufferStr(query, "SELECT n.tableoid, n.oid, n.nspname, "
5622  "n.nspowner, "
5623  "n.nspacl, "
5624  "acldefault('n', n.nspowner) AS acldefault "
5625  "FROM pg_namespace n");
5626 
5627  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5628 
5629  ntups = PQntuples(res);
5630 
5631  nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
5632 
5633  i_tableoid = PQfnumber(res, "tableoid");
5634  i_oid = PQfnumber(res, "oid");
5635  i_nspname = PQfnumber(res, "nspname");
5636  i_nspowner = PQfnumber(res, "nspowner");
5637  i_nspacl = PQfnumber(res, "nspacl");
5638  i_acldefault = PQfnumber(res, "acldefault");
5639 
5640  for (i = 0; i < ntups; i++)
5641  {
5642  const char *nspowner;
5643 
5644  nsinfo[i].dobj.objType = DO_NAMESPACE;
5645  nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5646  nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5647  AssignDumpId(&nsinfo[i].dobj);
5648  nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
5649  nsinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_nspacl));
5650  nsinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
5651  nsinfo[i].dacl.privtype = 0;
5652  nsinfo[i].dacl.initprivs = NULL;
5653  nspowner = PQgetvalue(res, i, i_nspowner);
5654  nsinfo[i].nspowner = atooid(nspowner);
5655  nsinfo[i].rolname = getRoleName(nspowner);
5656 
5657  /* Decide whether to dump this namespace */
5658  selectDumpableNamespace(&nsinfo[i], fout);
5659 
5660  /* Mark whether namespace has an ACL */
5661  if (!PQgetisnull(res, i, i_nspacl))
5662  nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
5663 
5664  /*
5665  * We ignore any pg_init_privs.initprivs entry for the public schema
5666  * and assume a predetermined default, for several reasons. First,
5667  * dropping and recreating the schema removes its pg_init_privs entry,
5668  * but an empty destination database starts with this ACL nonetheless.
5669  * Second, we support dump/reload of public schema ownership changes.
5670  * ALTER SCHEMA OWNER filters nspacl through aclnewowner(), but
5671  * initprivs continues to reflect the initial owner. Hence,
5672  * synthesize the value that nspacl will have after the restore's
5673  * ALTER SCHEMA OWNER. Third, this makes the destination database
5674  * match the source's ACL, even if the latter was an initdb-default
5675  * ACL, which changed in v15. An upgrade pulls in changes to most
5676  * system object ACLs that the DBA had not customized. We've made the
5677  * public schema depart from that, because changing its ACL so easily
5678  * breaks applications.
5679  */
5680  if (strcmp(nsinfo[i].dobj.name, "public") == 0)
5681  {
5682  PQExpBuffer aclarray = createPQExpBuffer();
5683  PQExpBuffer aclitem = createPQExpBuffer();
5684 
5685  /* Standard ACL as of v15 is {owner=UC/owner,=U/owner} */
5686  appendPQExpBufferChar(aclarray, '{');
5687  quoteAclUserName(aclitem, nsinfo[i].rolname);
5688  appendPQExpBufferStr(aclitem, "=UC/");
5689  quoteAclUserName(aclitem, nsinfo[i].rolname);
5690  appendPGArray(aclarray, aclitem->data);
5691  resetPQExpBuffer(aclitem);
5692  appendPQExpBufferStr(aclitem, "=U/");
5693  quoteAclUserName(aclitem, nsinfo[i].rolname);
5694  appendPGArray(aclarray, aclitem->data);
5695  appendPQExpBufferChar(aclarray, '}');
5696 
5697  nsinfo[i].dacl.privtype = 'i';
5698  nsinfo[i].dacl.initprivs = pstrdup(aclarray->data);
5699  nsinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
5700 
5701  destroyPQExpBuffer(aclarray);
5702  destroyPQExpBuffer(aclitem);
5703  }
5704  }
5705 
5706  PQclear(res);
5707  destroyPQExpBuffer(query);
5708 }
5709 
5710 /*
5711  * findNamespace:
5712  * given a namespace OID, look up the info read by getNamespaces
5713  */
5714 static NamespaceInfo *
5716 {
5717  NamespaceInfo *nsinfo;
5718 
5719  nsinfo = findNamespaceByOid(nsoid);
5720  if (nsinfo == NULL)
5721  pg_fatal("schema with OID %u does not exist", nsoid);
5722  return nsinfo;
5723 }
5724 
5725 /*
5726  * getExtensions:
5727  * read all extensions in the system catalogs and return them in the
5728  * ExtensionInfo* structure
5729  *
5730  * numExtensions is set to the number of extensions read in
5731  */
5732 ExtensionInfo *
5733 getExtensions(Archive *fout, int *numExtensions)
5734 {
5735  DumpOptions *dopt = fout->dopt;
5736  PGresult *res;
5737  int ntups;
5738  int i;
5739  PQExpBuffer query;
5740  ExtensionInfo *extinfo;
5741  int i_tableoid;
5742  int i_oid;
5743  int i_extname;
5744  int i_nspname;
5745  int i_extrelocatable;
5746  int i_extversion;
5747  int i_extconfig;
5748  int i_extcondition;
5749 
5750  query = createPQExpBuffer();
5751 
5752  appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
5753  "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
5754  "FROM pg_extension x "
5755  "JOIN pg_namespace n ON n.oid = x.extnamespace");
5756 
5757  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5758 
5759  ntups = PQntuples(res);
5760 
5761  extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
5762 
5763  i_tableoid = PQfnumber(res, "tableoid");
5764  i_oid = PQfnumber(res, "oid");
5765  i_extname = PQfnumber(res, "extname");
5766  i_nspname = PQfnumber(res, "nspname");
5767  i_extrelocatable = PQfnumber(res, "extrelocatable");
5768  i_extversion = PQfnumber(res, "extversion");
5769  i_extconfig = PQfnumber(res, "extconfig");
5770  i_extcondition = PQfnumber(res, "extcondition");
5771 
5772  for (i = 0; i < ntups; i++)
5773  {
5774  extinfo[i].dobj.objType = DO_EXTENSION;
5775  extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5776  extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5777  AssignDumpId(&extinfo[i].dobj);
5778  extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
5779  extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
5780  extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
5781  extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
5782  extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
5783  extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
5784 
5785  /* Decide whether we want to dump it */
5786  selectDumpableExtension(&(extinfo[i]), dopt);
5787  }
5788 
5789  PQclear(res);
5790  destroyPQExpBuffer(query);
5791 
5792  *numExtensions = ntups;
5793 
5794  return extinfo;
5795 }
5796 
5797 /*
5798  * getTypes:
5799  * get information about all types in the system catalogs
5800  *
5801  * NB: this must run after getFuncs() because we assume we can do
5802  * findFuncByOid().
5803  */
5804 void
5806 {
5807  PGresult *res;
5808  int ntups;
5809  int i;
5810  PQExpBuffer query = createPQExpBuffer();
5811  TypeInfo *tyinfo;
5812  ShellTypeInfo *stinfo;
5813  int i_tableoid;
5814  int i_oid;
5815  int i_typname;
5816  int i_typnamespace;
5817  int i_typacl;
5818  int i_acldefault;
5819  int i_typowner;
5820  int i_typelem;
5821  int i_typrelid;
5822  int i_typrelkind;
5823  int i_typtype;
5824  int i_typisdefined;
5825  int i_isarray;
5826 
5827  /*
5828  * we include even the built-in types because those may be used as array
5829  * elements by user-defined types
5830  *
5831  * we filter out the built-in types when we dump out the types
5832  *
5833  * same approach for undefined (shell) types and array types
5834  *
5835  * Note: as of 8.3 we can reliably detect whether a type is an
5836  * auto-generated array type by checking the element type's typarray.
5837  * (Before that the test is capable of generating false positives.) We
5838  * still check for name beginning with '_', though, so as to avoid the
5839  * cost of the subselect probe for all standard types. This would have to
5840  * be revisited if the backend ever allows renaming of array types.
5841  */
5842  appendPQExpBufferStr(query, "SELECT tableoid, oid, typname, "
5843  "typnamespace, typacl, "
5844  "acldefault('T', typowner) AS acldefault, "
5845  "typowner, "
5846  "typelem, typrelid, "
5847  "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
5848  "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
5849  "typtype, typisdefined, "
5850  "typname[0] = '_' AND typelem != 0 AND "
5851  "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
5852  "FROM pg_type");
5853 
5854  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5855 
5856  ntups = PQntuples(res);
5857 
5858  tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
5859 
5860  i_tableoid = PQfnumber(res, "tableoid");
5861  i_oid = PQfnumber(res, "oid");
5862  i_typname = PQfnumber(res, "typname");
5863  i_typnamespace = PQfnumber(res, "typnamespace");
5864  i_typacl = PQfnumber(res, "typacl");
5865  i_acldefault = PQfnumber(res, "acldefault");
5866  i_typowner = PQfnumber(res, "typowner");
5867  i_typelem = PQfnumber(res, "typelem");
5868  i_typrelid = PQfnumber(res, "typrelid");
5869  i_typrelkind = PQfnumber(res, "typrelkind");
5870  i_typtype = PQfnumber(res, "typtype");
5871  i_typisdefined = PQfnumber(res, "typisdefined");
5872  i_isarray = PQfnumber(res, "isarray");
5873 
5874  for (i = 0; i < ntups; i++)
5875  {
5876  tyinfo[i].dobj.objType = DO_TYPE;
5877  tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5878  tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5879  AssignDumpId(&tyinfo[i].dobj);
5880  tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
5881  tyinfo[i].dobj.namespace =
5882  findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)));
5883  tyinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_typacl));
5884  tyinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
5885  tyinfo[i].dacl.privtype = 0;
5886  tyinfo[i].dacl.initprivs = NULL;
5887  tyinfo[i].ftypname = NULL; /* may get filled later */
5888  tyinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_typowner));
5889  tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
5890  tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
5891  tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
5892  tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
5893  tyinfo[i].shellType = NULL;
5894 
5895  if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
5896  tyinfo[i].isDefined = true;
5897  else
5898  tyinfo[i].isDefined = false;
5899 
5900  if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
5901  tyinfo[i].isArray = true;
5902  else
5903  tyinfo[i].isArray = false;
5904 
5905  if (tyinfo[i].typtype == TYPTYPE_MULTIRANGE)
5906  tyinfo[i].isMultirange = true;
5907  else
5908  tyinfo[i].isMultirange = false;
5909 
5910  /* Decide whether we want to dump it */
5911  selectDumpableType(&tyinfo[i], fout);
5912 
5913  /* Mark whether type has an ACL */
5914  if (!PQgetisnull(res, i, i_typacl))
5915  tyinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
5916 
5917  /*
5918  * If it's a domain, fetch info about its constraints, if any
5919  */
5920  tyinfo[i].nDomChecks = 0;
5921  tyinfo[i].domChecks = NULL;
5922  if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
5923  tyinfo[i].typtype == TYPTYPE_DOMAIN)
5924  getDomainConstraints(fout, &(tyinfo[i]));
5925 
5926  /*
5927  * If it's a base type, make a DumpableObject representing a shell
5928  * definition of the type. We will need to dump that ahead of the I/O
5929  * functions for the type. Similarly, range types need a shell
5930  * definition in case they have a canonicalize function.
5931  *
5932  * Note: the shell type doesn't have a catId. You might think it
5933  * should copy the base type's catId, but then it might capture the
5934  * pg_depend entries for the type, which we don't want.
5935  */
5936  if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
5937  (tyinfo[i].typtype == TYPTYPE_BASE ||
5938  tyinfo[i].typtype == TYPTYPE_RANGE))
5939  {
5940  stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
5941  stinfo->dobj.objType = DO_SHELL_TYPE;
5942  stinfo->dobj.catId = nilCatalogId;
5943  AssignDumpId(&stinfo->dobj);
5944  stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
5945  stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
5946  stinfo->baseType = &(tyinfo[i]);
5947  tyinfo[i].shellType = stinfo;
5948 
5949  /*
5950  * Initially mark the shell type as not to be dumped. We'll only
5951  * dump it if the I/O or canonicalize functions need to be dumped;
5952  * this is taken care of while sorting dependencies.
5953  */
5954  stinfo->dobj.dump = DUMP_COMPONENT_NONE;
5955  }
5956  }
5957 
5958  PQclear(res);
5959 
5960  destroyPQExpBuffer(query);
5961 }
5962 
5963 /*
5964  * getOperators:
5965  * get information about all operators in the system catalogs
5966  */
5967 void
5969 {
5970  PGresult *res;
5971  int ntups;
5972  int i;
5973  PQExpBuffer query = createPQExpBuffer();
5974  OprInfo *oprinfo;
5975  int i_tableoid;
5976  int i_oid;
5977  int i_oprname;
5978  int i_oprnamespace;
5979  int i_oprowner;
5980  int i_oprkind;
5981  int i_oprcode;
5982 
5983  /*
5984  * find all operators, including builtin operators; we filter out
5985  * system-defined operators at dump-out time.
5986  */
5987 
5988  appendPQExpBufferStr(query, "SELECT tableoid, oid, oprname, "
5989  "oprnamespace, "
5990  "oprowner, "
5991  "oprkind, "
5992  "oprcode::oid AS oprcode "
5993  "FROM pg_operator");
5994 
5995  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5996 
5997  ntups = PQntuples(res);
5998 
5999  oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
6000 
6001  i_tableoid = PQfnumber(res, "tableoid");
6002  i_oid = PQfnumber(res, "oid");
6003  i_oprname = PQfnumber(res, "oprname");
6004  i_oprnamespace = PQfnumber(res, "oprnamespace");
6005  i_oprowner = PQfnumber(res, "oprowner");
6006  i_oprkind = PQfnumber(res, "oprkind");
6007  i_oprcode = PQfnumber(res, "oprcode");
6008 
6009  for (i = 0; i < ntups; i++)
6010  {
6011  oprinfo[i].dobj.objType = DO_OPERATOR;
6012  oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6013  oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6014  AssignDumpId(&oprinfo[i].dobj);
6015  oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
6016  oprinfo[i].dobj.namespace =
6017  findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)));
6018  oprinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_oprowner));
6019  oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
6020  oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
6021 
6022  /* Decide whether we want to dump it */
6023  selectDumpableObject(&(oprinfo[i].dobj), fout);
6024  }
6025 
6026  PQclear(res);
6027 
6028  destroyPQExpBuffer(query);
6029 }
6030 
6031 /*
6032  * getCollations:
6033  * get information about all collations in the system catalogs
6034  */
6035 void
6037 {
6038  PGresult *res;
6039  int ntups;
6040  int i;
6041  PQExpBuffer query;
6042  CollInfo *collinfo;
6043  int i_tableoid;
6044  int i_oid;
6045  int i_collname;
6046  int i_collnamespace;
6047  int i_collowner;
6048 
6049  query = createPQExpBuffer();
6050 
6051  /*
6052  * find all collations, including builtin collations; we filter out
6053  * system-defined collations at dump-out time.
6054  */
6055 
6056  appendPQExpBufferStr(query, "SELECT tableoid, oid, collname, "
6057  "collnamespace, "
6058  "collowner "
6059  "FROM pg_collation");
6060 
6061  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6062 
6063  ntups = PQntuples(res);
6064 
6065  collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
6066 
6067  i_tableoid = PQfnumber(res, "tableoid");
6068  i_oid = PQfnumber(res, "oid");
6069  i_collname = PQfnumber(res, "collname");
6070  i_collnamespace = PQfnumber(res, "collnamespace");
6071  i_collowner = PQfnumber(res, "collowner");
6072 
6073  for (i = 0; i < ntups; i++)
6074  {
6075  collinfo[i].dobj.objType = DO_COLLATION;
6076  collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6077  collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6078  AssignDumpId(&collinfo[i].dobj);
6079  collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
6080  collinfo[i].dobj.namespace =
6081  findNamespace(atooid(PQgetvalue(res, i, i_collnamespace)));
6082  collinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_collowner));
6083 
6084  /* Decide whether we want to dump it */
6085  selectDumpableObject(&(collinfo[i].dobj), fout);
6086  }
6087 
6088  PQclear(res);
6089 
6090  destroyPQExpBuffer(query);
6091 }
6092 
6093 /*
6094  * getConversions:
6095  * get information about all conversions in the system catalogs
6096  */
6097 void
6099 {
6100  PGresult *res;
6101  int ntups;
6102  int i;
6103  PQExpBuffer query;
6104  ConvInfo *convinfo;
6105  int i_tableoid;
6106  int i_oid;
6107  int i_conname;
6108  int i_connamespace;
6109  int i_conowner;
6110 
6111  query = createPQExpBuffer();
6112 
6113  /*
6114  * find all conversions, including builtin conversions; we filter out
6115  * system-defined conversions at dump-out time.
6116  */
6117 
6118  appendPQExpBufferStr(query, "SELECT tableoid, oid, conname, "
6119  "connamespace, "
6120  "conowner "
6121  "FROM pg_conversion");
6122 
6123  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6124 
6125  ntups = PQntuples(res);
6126 
6127  convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
6128 
6129  i_tableoid = PQfnumber(res, "tableoid");
6130  i_oid = PQfnumber(res, "oid");
6131  i_conname = PQfnumber(res, "conname");
6132  i_connamespace = PQfnumber(res, "connamespace");
6133  i_conowner = PQfnumber(res, "conowner");
6134 
6135  for (i = 0; i < ntups; i++)
6136  {
6137  convinfo[i].dobj.objType = DO_CONVERSION;
6138  convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6139  convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6140  AssignDumpId(&convinfo[i].dobj);
6141  convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
6142  convinfo[i].dobj.namespace =
6143  findNamespace(atooid(PQgetvalue(res, i, i_connamespace)));
6144  convinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_conowner));
6145 
6146  /* Decide whether we want to dump it */
6147  selectDumpableObject(&(convinfo[i].dobj), fout);
6148  }
6149 
6150  PQclear(res);
6151 
6152  destroyPQExpBuffer(query);
6153 }
6154 
6155 /*
6156  * getAccessMethods:
6157  * get information about all user-defined access methods
6158  */
6159 void
6161 {
6162  PGresult *res;
6163  int ntups;
6164  int i;
6165  PQExpBuffer query;
6166  AccessMethodInfo *aminfo;
6167  int i_tableoid;
6168  int i_oid;
6169  int i_amname;
6170  int i_amhandler;
6171  int i_amtype;
6172 
6173  /* Before 9.6, there are no user-defined access methods */
6174  if (fout->remoteVersion < 90600)
6175  return;
6176 
6177  query = createPQExpBuffer();
6178 
6179  /* Select all access methods from pg_am table */
6180  appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, amtype, "
6181  "amhandler::pg_catalog.regproc AS amhandler "
6182  "FROM pg_am");
6183 
6184  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6185 
6186  ntups = PQntuples(res);
6187 
6188  aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
6189 
6190  i_tableoid = PQfnumber(res, "tableoid");
6191  i_oid = PQfnumber(res, "oid");
6192  i_amname = PQfnumber(res, "amname");
6193  i_amhandler = PQfnumber(res, "amhandler");
6194  i_amtype = PQfnumber(res, "amtype");
6195 
6196  for (i = 0; i < ntups; i++)
6197  {
6198  aminfo[i].dobj.objType = DO_ACCESS_METHOD;
6199  aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6200  aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6201  AssignDumpId(&aminfo[i].dobj);
6202  aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
6203  aminfo[i].dobj.namespace = NULL;
6204  aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
6205  aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
6206 
6207  /* Decide whether we want to dump it */
6208  selectDumpableAccessMethod(&(aminfo[i]), fout);
6209  }
6210 
6211  PQclear(res);
6212 
6213  destroyPQExpBuffer(query);
6214 }
6215 
6216 
6217 /*
6218  * getOpclasses:
6219  * get information about all opclasses in the system catalogs
6220  */
6221 void
6223 {
6224  PGresult *res;
6225  int ntups;
6226  int i;
6227  PQExpBuffer query = createPQExpBuffer();
6228  OpclassInfo *opcinfo;
6229  int i_tableoid;
6230  int i_oid;
6231  int i_opcname;
6232  int i_opcnamespace;
6233  int i_opcowner;
6234 
6235  /*
6236  * find all opclasses, including builtin opclasses; we filter out
6237  * system-defined opclasses at dump-out time.
6238  */
6239 
6240  appendPQExpBufferStr(query, "SELECT tableoid, oid, opcname, "
6241  "opcnamespace, "
6242  "opcowner "
6243  "FROM pg_opclass");
6244 
6245  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6246 
6247  ntups = PQntuples(res);
6248 
6249  opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
6250 
6251  i_tableoid = PQfnumber(res, "tableoid");
6252  i_oid = PQfnumber(res, "oid");
6253  i_opcname = PQfnumber(res, "opcname");
6254  i_opcnamespace = PQfnumber(res, "opcnamespace");
6255  i_opcowner = PQfnumber(res, "opcowner");
6256 
6257  for (i = 0; i < ntups; i++)
6258  {
6259  opcinfo[i].dobj.objType = DO_OPCLASS;
6260  opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6261  opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6262  AssignDumpId(&opcinfo[i].dobj);
6263  opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
6264  opcinfo[i].dobj.namespace =
6265  findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)));
6266  opcinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opcowner));
6267 
6268  /* Decide whether we want to dump it */
6269  selectDumpableObject(&(opcinfo[i].dobj), fout);
6270  }
6271 
6272  PQclear(res);
6273 
6274  destroyPQExpBuffer(query);
6275 }
6276 
6277 /*
6278  * getOpfamilies:
6279  * get information about all opfamilies in the system catalogs
6280  */
6281 void
6283 {
6284  PGresult *res;
6285  int ntups;
6286  int i;
6287  PQExpBuffer query;
6288  OpfamilyInfo *opfinfo;
6289  int i_tableoid;
6290  int i_oid;
6291  int i_opfname;
6292  int i_opfnamespace;
6293  int i_opfowner;
6294 
6295  query = createPQExpBuffer();
6296 
6297  /*
6298  * find all opfamilies, including builtin opfamilies; we filter out
6299  * system-defined opfamilies at dump-out time.
6300  */
6301 
6302  appendPQExpBufferStr(query, "SELECT tableoid, oid, opfname, "
6303  "opfnamespace, "
6304  "opfowner "
6305  "FROM pg_opfamily");
6306 
6307  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6308 
6309  ntups = PQntuples(res);
6310 
6311  opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
6312 
6313  i_tableoid = PQfnumber(res, "tableoid");
6314  i_oid = PQfnumber(res, "oid");
6315  i_opfname = PQfnumber(res, "opfname");
6316  i_opfnamespace = PQfnumber(res, "opfnamespace");
6317  i_opfowner = PQfnumber(res, "opfowner");
6318 
6319  for (i = 0; i < ntups; i++)
6320  {
6321  opfinfo[i].dobj.objType = DO_OPFAMILY;
6322  opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6323  opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6324  AssignDumpId(&opfinfo[i].dobj);
6325  opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
6326  opfinfo[i].dobj.namespace =
6327  findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)));
6328  opfinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_opfowner));
6329 
6330  /* Decide whether we want to dump it */
6331  selectDumpableObject(&(opfinfo[i].dobj), fout);
6332  }
6333 
6334  PQclear(res);
6335 
6336  destroyPQExpBuffer(query);
6337 }
6338 
6339 /*
6340  * getAggregates:
6341  * get information about all user-defined aggregates in the system catalogs
6342  */
6343 void
6345 {
6346  DumpOptions *dopt = fout->dopt;
6347  PGresult *res;
6348  int ntups;
6349  int i;
6350  PQExpBuffer query = createPQExpBuffer();
6351  AggInfo *agginfo;
6352  int i_tableoid;
6353  int i_oid;
6354  int i_aggname;
6355  int i_aggnamespace;
6356  int i_pronargs;
6357  int i_proargtypes;
6358  int i_proowner;
6359  int i_aggacl;
6360  int i_acldefault;
6361 
6362  /*
6363  * Find all interesting aggregates. See comment in getFuncs() for the
6364  * rationale behind the filtering logic.
6365  */
6366  if (fout->remoteVersion >= 90600)
6367  {
6368  const char *agg_check;
6369 
6370  agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
6371  : "p.proisagg");
6372 
6373  appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
6374  "p.proname AS aggname, "
6375  "p.pronamespace AS aggnamespace, "
6376  "p.pronargs, p.proargtypes, "
6377  "p.proowner, "
6378  "p.proacl AS aggacl, "
6379  "acldefault('f', p.proowner) AS acldefault "
6380  "FROM pg_proc p "
6381  "LEFT JOIN pg_init_privs pip ON "
6382  "(p.oid = pip.objoid "
6383  "AND pip.classoid = 'pg_proc'::regclass "
6384  "AND pip.objsubid = 0) "
6385  "WHERE %s AND ("
6386  "p.pronamespace != "
6387  "(SELECT oid FROM pg_namespace "
6388  "WHERE nspname = 'pg_catalog') OR "
6389  "p.proacl IS DISTINCT FROM pip.initprivs",
6390  agg_check);
6391  if (dopt->binary_upgrade)
6392  appendPQExpBufferStr(query,
6393  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6394  "classid = 'pg_proc'::regclass AND "
6395  "objid = p.oid AND "
6396  "refclassid = 'pg_extension'::regclass AND "
6397  "deptype = 'e')");
6398  appendPQExpBufferChar(query, ')');
6399  }
6400  else
6401  {
6402  appendPQExpBufferStr(query, "SELECT tableoid, oid, proname AS aggname, "
6403  "pronamespace AS aggnamespace, "
6404  "pronargs, proargtypes, "
6405  "proowner, "
6406  "proacl AS aggacl, "
6407  "acldefault('f', proowner) AS acldefault "
6408  "FROM pg_proc p "
6409  "WHERE proisagg AND ("
6410  "pronamespace != "
6411  "(SELECT oid FROM pg_namespace "
6412  "WHERE nspname = 'pg_catalog')");
6413  if (dopt->binary_upgrade)
6414  appendPQExpBufferStr(query,
6415  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6416  "classid = 'pg_proc'::regclass AND "
6417  "objid = p.oid AND "
6418  "refclassid = 'pg_extension'::regclass AND "
6419  "deptype = 'e')");
6420  appendPQExpBufferChar(query, ')');
6421  }
6422 
6423  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6424 
6425  ntups = PQntuples(res);
6426 
6427  agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
6428 
6429  i_tableoid = PQfnumber(res, "tableoid");
6430  i_oid = PQfnumber(res, "oid");
6431  i_aggname = PQfnumber(res, "aggname");
6432  i_aggnamespace = PQfnumber(res, "aggnamespace");
6433  i_pronargs = PQfnumber(res, "pronargs");
6434  i_proargtypes = PQfnumber(res, "proargtypes");
6435  i_proowner = PQfnumber(res, "proowner");
6436  i_aggacl = PQfnumber(res, "aggacl");
6437  i_acldefault = PQfnumber(res, "acldefault");
6438 
6439  for (i = 0; i < ntups; i++)
6440  {
6441  agginfo[i].aggfn.dobj.objType = DO_AGG;
6442  agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6443  agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6444  AssignDumpId(&agginfo[i].aggfn.dobj);
6445  agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
6446  agginfo[i].aggfn.dobj.namespace =
6447  findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)));
6448  agginfo[i].aggfn.dacl.acl = pg_strdup(PQgetvalue(res, i, i_aggacl));
6449  agginfo[i].aggfn.dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6450  agginfo[i].aggfn.dacl.privtype = 0;
6451  agginfo[i].aggfn.dacl.initprivs = NULL;
6452  agginfo[i].aggfn.rolname = getRoleName(PQgetvalue(res, i, i_proowner));
6453  agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
6454  agginfo[i].aggfn.prorettype = InvalidOid; /* not saved */
6455  agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
6456  if (agginfo[i].aggfn.nargs == 0)
6457  agginfo[i].aggfn.argtypes = NULL;
6458  else
6459  {
6460  agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
6461  parseOidArray(PQgetvalue(res, i, i_proargtypes),
6462  agginfo[i].aggfn.argtypes,
6463  agginfo[i].aggfn.nargs);
6464  }
6465  agginfo[i].aggfn.postponed_def = false; /* might get set during sort */
6466 
6467  /* Decide whether we want to dump it */
6468  selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
6469 
6470  /* Mark whether aggregate has an ACL */
6471  if (!PQgetisnull(res, i, i_aggacl))
6472  agginfo[i].aggfn.dobj.components |= DUMP_COMPONENT_ACL;
6473  }
6474 
6475  PQclear(res);
6476 
6477  destroyPQExpBuffer(query);
6478 }
6479 
6480 /*
6481  * getFuncs:
6482  * get information about all user-defined functions in the system catalogs
6483  */
6484 void
6486 {
6487  DumpOptions *dopt = fout->dopt;
6488  PGresult *res;
6489  int ntups;
6490  int i;
6491  PQExpBuffer query = createPQExpBuffer();
6492  FuncInfo *finfo;
6493  int i_tableoid;
6494  int i_oid;
6495  int i_proname;
6496  int i_pronamespace;
6497  int i_proowner;
6498  int i_prolang;
6499  int i_pronargs;
6500  int i_proargtypes;
6501  int i_prorettype;
6502  int i_proacl;
6503  int i_acldefault;
6504 
6505  /*
6506  * Find all interesting functions. This is a bit complicated:
6507  *
6508  * 1. Always exclude aggregates; those are handled elsewhere.
6509  *
6510  * 2. Always exclude functions that are internally dependent on something
6511  * else, since presumably those will be created as a result of creating
6512  * the something else. This currently acts only to suppress constructor
6513  * functions for range types. Note this is OK only because the
6514  * constructors don't have any dependencies the range type doesn't have;
6515  * otherwise we might not get creation ordering correct.
6516  *
6517  * 3. Otherwise, we normally exclude functions in pg_catalog. However, if
6518  * they're members of extensions and we are in binary-upgrade mode then
6519  * include them, since we want to dump extension members individually in
6520  * that mode. Also, if they are used by casts or transforms then we need
6521  * to gather the information about them, though they won't be dumped if
6522  * they are built-in. Also, in 9.6 and up, include functions in
6523  * pg_catalog if they have an ACL different from what's shown in
6524  * pg_init_privs (so we have to join to pg_init_privs; annoying).
6525  */
6526  if (fout->remoteVersion >= 90600)
6527  {
6528  const char *not_agg_check;
6529 
6530  not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
6531  : "NOT p.proisagg");
6532 
6533  appendPQExpBuffer(query,
6534  "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
6535  "p.pronargs, p.proargtypes, p.prorettype, "
6536  "p.proacl, "
6537  "acldefault('f', p.proowner) AS acldefault, "
6538  "p.pronamespace, "
6539  "p.proowner "
6540  "FROM pg_proc p "
6541  "LEFT JOIN pg_init_privs pip ON "
6542  "(p.oid = pip.objoid "
6543  "AND pip.classoid = 'pg_proc'::regclass "
6544  "AND pip.objsubid = 0) "
6545  "WHERE %s"
6546  "\n AND NOT EXISTS (SELECT 1 FROM pg_depend "
6547  "WHERE classid = 'pg_proc'::regclass AND "
6548  "objid = p.oid AND deptype = 'i')"
6549  "\n AND ("
6550  "\n pronamespace != "
6551  "(SELECT oid FROM pg_namespace "
6552  "WHERE nspname = 'pg_catalog')"
6553  "\n OR EXISTS (SELECT 1 FROM pg_cast"
6554  "\n WHERE pg_cast.oid > %u "
6555  "\n AND p.oid = pg_cast.castfunc)"
6556  "\n OR EXISTS (SELECT 1 FROM pg_transform"
6557  "\n WHERE pg_transform.oid > %u AND "
6558  "\n (p.oid = pg_transform.trffromsql"
6559  "\n OR p.oid = pg_transform.trftosql))",
6560  not_agg_check,
6563  if (dopt->binary_upgrade)
6564  appendPQExpBufferStr(query,
6565  "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6566  "classid = 'pg_proc'::regclass AND "
6567  "objid = p.oid AND "
6568  "refclassid = 'pg_extension'::regclass AND "
6569  "deptype = 'e')");
6570  appendPQExpBufferStr(query,
6571  "\n OR p.proacl IS DISTINCT FROM pip.initprivs");
6572  appendPQExpBufferChar(query, ')');
6573  }
6574  else
6575  {
6576  appendPQExpBuffer(query,
6577  "SELECT tableoid, oid, proname, prolang, "
6578  "pronargs, proargtypes, prorettype, proacl, "
6579  "acldefault('f', proowner) AS acldefault, "
6580  "pronamespace, "
6581  "proowner "
6582  "FROM pg_proc p "
6583  "WHERE NOT proisagg"
6584  "\n AND NOT EXISTS (SELECT 1 FROM pg_depend "
6585  "WHERE classid = 'pg_proc'::regclass AND "
6586  "objid = p.oid AND deptype = 'i')"
6587  "\n AND ("
6588  "\n pronamespace != "
6589  "(SELECT oid FROM pg_namespace "
6590  "WHERE nspname = 'pg_catalog')"
6591  "\n OR EXISTS (SELECT 1 FROM pg_cast"
6592  "\n WHERE pg_cast.oid > '%u'::oid"
6593  "\n AND p.oid = pg_cast.castfunc)",
6595 
6596  if (fout->remoteVersion >= 90500)
6597  appendPQExpBuffer(query,
6598  "\n OR EXISTS (SELECT 1 FROM pg_transform"
6599  "\n WHERE pg_transform.oid > '%u'::oid"
6600  "\n AND (p.oid = pg_transform.trffromsql"
6601  "\n OR p.oid = pg_transform.trftosql))",
6603 
6604  if (dopt->binary_upgrade)
6605  appendPQExpBufferStr(query,
6606  "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE "
6607  "classid = 'pg_proc'::regclass AND "
6608  "objid = p.oid AND "
6609  "refclassid = 'pg_extension'::regclass AND "
6610  "deptype = 'e')");
6611  appendPQExpBufferChar(query, ')');
6612  }
6613 
6614  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6615 
6616  ntups = PQntuples(res);
6617 
6618  finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
6619 
6620  i_tableoid = PQfnumber(res, "tableoid");
6621  i_oid = PQfnumber(res, "oid");
6622  i_proname = PQfnumber(res, "proname");
6623  i_pronamespace = PQfnumber(res, "pronamespace");
6624  i_proowner = PQfnumber(res, "proowner");
6625  i_prolang = PQfnumber(res, "prolang");
6626  i_pronargs = PQfnumber(res, "pronargs");
6627  i_proargtypes = PQfnumber(res, "proargtypes");
6628  i_prorettype = PQfnumber(res, "prorettype");
6629  i_proacl = PQfnumber(res, "proacl");
6630  i_acldefault = PQfnumber(res, "acldefault");
6631 
6632  for (i = 0; i < ntups; i++)
6633  {
6634  finfo[i].dobj.objType = DO_FUNC;
6635  finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6636  finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6637  AssignDumpId(&finfo[i].dobj);
6638  finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
6639  finfo[i].dobj.namespace =
6640  findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)));
6641  finfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_proacl));
6642  finfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6643  finfo[i].dacl.privtype = 0;
6644  finfo[i].dacl.initprivs = NULL;
6645  finfo[i].rolname = getRoleName(PQgetvalue(res, i, i_proowner));
6646  finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
6647  finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
6648  finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
6649  if (finfo[i].nargs == 0)
6650  finfo[i].argtypes = NULL;
6651  else
6652  {
6653  finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
6654  parseOidArray(PQgetvalue(res, i, i_proargtypes),
6655  finfo[i].argtypes, finfo[i].nargs);
6656  }
6657  finfo[i].postponed_def = false; /* might get set during sort */
6658 
6659  /* Decide whether we want to dump it */
6660  selectDumpableObject(&(finfo[i].dobj), fout);
6661 
6662  /* Mark whether function has an ACL */
6663  if (!PQgetisnull(res, i, i_proacl))
6664  finfo[i].dobj.components |= DUMP_COMPONENT_ACL;
6665  }
6666 
6667  PQclear(res);
6668 
6669  destroyPQExpBuffer(query);
6670 }
6671 
6672 /*
6673  * getTables
6674  * read all the tables (no indexes) in the system catalogs,
6675  * and return them as an array of TableInfo structures
6676  *
6677  * *numTables is set to the number of tables read in
6678  */
6679 TableInfo *
6680 getTables(Archive *fout, int *numTables)
6681 {
6682  DumpOptions *dopt = fout->dopt;
6683  PGresult *res;
6684  int ntups;
6685  int i;
6686  PQExpBuffer query = createPQExpBuffer();
6687  TableInfo *tblinfo;
6688  int i_reltableoid;
6689  int i_reloid;
6690  int i_relname;
6691  int i_relnamespace;
6692  int i_relkind;
6693  int i_reltype;
6694  int i_relowner;
6695  int i_relchecks;
6696  int i_relhasindex;
6697  int i_relhasrules;
6698  int i_relpages;
6699  int i_toastpages;
6700  int i_owning_tab;
6701  int i_owning_col;
6702  int i_reltablespace;
6703  int i_relhasoids;
6704  int i_relhastriggers;
6705  int i_relpersistence;
6706  int i_relispopulated;
6707  int i_relreplident;
6708  int i_relrowsec;
6709  int i_relforcerowsec;
6710  int i_relfrozenxid;
6711  int i_toastfrozenxid;
6712  int i_toastoid;
6713  int i_relminmxid;
6714  int i_toastminmxid;
6715  int i_reloptions;
6716  int i_checkoption;
6717  int i_toastreloptions;
6718  int i_reloftype;
6719  int i_foreignserver;
6720  int i_amname;
6721  int i_is_identity_sequence;
6722  int i_relacl;
6723  int i_acldefault;
6724  int i_ispartition;
6725 
6726  /*
6727  * Find all the tables and table-like objects.
6728  *
6729  * We must fetch all tables in this phase because otherwise we cannot
6730  * correctly identify inherited columns, owned sequences, etc.
6731  *
6732  * We include system catalogs, so that we can work if a user table is
6733  * defined to inherit from a system catalog (pretty weird, but...)
6734  *
6735  * Note: in this phase we should collect only a minimal amount of
6736  * information about each table, basically just enough to decide if it is
6737  * interesting. In particular, since we do not yet have lock on any user
6738  * table, we MUST NOT invoke any server-side data collection functions
6739  * (for instance, pg_get_partkeydef()). Those are likely to fail or give
6740  * wrong answers if any concurrent DDL is happening.
6741  */
6742 
6743  appendPQExpBufferStr(query,
6744  "SELECT c.tableoid, c.oid, c.relname, "
6745  "c.relnamespace, c.relkind, c.reltype, "
6746  "c.relowner, "
6747  "c.relchecks, "
6748  "c.relhasindex, c.relhasrules, c.relpages, "
6749  "c.relhastriggers, "
6750  "c.relpersistence, "
6751  "c.reloftype, "
6752  "c.relacl, "
6753  "acldefault(CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
6754  " THEN 's'::\"char\" ELSE 'r'::\"char\" END, c.relowner) AS acldefault, "
6755  "CASE WHEN c.relkind = " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN "
6756  "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
6757  "ELSE 0 END AS foreignserver, "
6758  "c.relfrozenxid, tc.relfrozenxid AS tfrozenxid, "
6759  "tc.oid AS toid, "
6760  "tc.relpages AS toastpages, "
6761  "tc.reloptions AS toast_reloptions, "
6762  "d.refobjid AS owning_tab, "
6763  "d.refobjsubid AS owning_col, "
6764  "tsp.spcname AS reltablespace, ");
6765 
6766  if (fout->remoteVersion >= 120000)
6767  appendPQExpBufferStr(query,
6768  "false AS relhasoids, ");
6769  else
6770  appendPQExpBufferStr(query,
6771  "c.relhasoids, ");
6772 
6773  if (fout->remoteVersion >= 90300)
6774  appendPQExpBufferStr(query,
6775  "c.relispopulated, ");
6776  else
6777  appendPQExpBufferStr(query,
6778  "'t' as relispopulated, ");
6779 
6780  if (fout->remoteVersion >= 90400)
6781  appendPQExpBufferStr(query,
6782  "c.relreplident, ");
6783  else
6784  appendPQExpBufferStr(query,
6785  "'d' AS relreplident, ");
6786 
6787  if (fout->remoteVersion >= 90500)
6788  appendPQExpBufferStr(query,
6789  "c.relrowsecurity, c.relforcerowsecurity, ");
6790  else
6791  appendPQExpBufferStr(query,
6792  "false AS relrowsecurity, "
6793  "false AS relforcerowsecurity, ");
6794 
6795  if (fout->remoteVersion >= 90300)
6796  appendPQExpBufferStr(query,
6797  "c.relminmxid, tc.relminmxid AS tminmxid, ");
6798  else
6799  appendPQExpBufferStr(query,
6800  "0 AS relminmxid, 0 AS tminmxid, ");
6801 
6802  if (fout->remoteVersion >= 90300)
6803  appendPQExpBufferStr(query,
6804  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6805  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6806  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, ");
6807  else
6808  appendPQExpBufferStr(query,
6809  "c.reloptions, NULL AS checkoption, ");
6810 
6811  if (fout->remoteVersion >= 90600)
6812  appendPQExpBufferStr(query,
6813  "am.amname, ");
6814  else
6815  appendPQExpBufferStr(query,
6816  "NULL AS amname, ");
6817 
6818  if (fout->remoteVersion >= 90600)
6819  appendPQExpBufferStr(query,
6820  "(d.deptype = 'i') IS TRUE AS is_identity_sequence, ");
6821  else
6822  appendPQExpBufferStr(query,
6823  "false AS is_identity_sequence, ");
6824 
6825  if (fout->remoteVersion >= 100000)
6826  appendPQExpBufferStr(query,
6827  "c.relispartition AS ispartition ");
6828  else
6829  appendPQExpBufferStr(query,
6830  "false AS ispartition ");
6831 
6832  /*
6833  * Left join to pg_depend to pick up dependency info linking sequences to
6834  * their owning column, if any (note this dependency is AUTO except for
6835  * identity sequences, where it's INTERNAL). Also join to pg_tablespace to
6836  * collect the spcname.
6837  */
6838  appendPQExpBufferStr(query,
6839  "\nFROM pg_class c\n"
6840  "LEFT JOIN pg_depend d ON "
6841  "(c.relkind = " CppAsString2(RELKIND_SEQUENCE) " AND "
6842  "d.classid = 'pg_class'::regclass AND d.objid = c.oid AND "
6843  "d.objsubid = 0 AND "
6844  "d.refclassid = 'pg_class'::regclass AND d.deptype IN ('a', 'i'))\n"
6845  "LEFT JOIN pg_tablespace tsp ON (tsp.oid = c.reltablespace)\n");
6846 
6847  /*
6848  * In 9.6 and up, left join to pg_am to pick up the amname.
6849  */
6850  if (fout->remoteVersion >= 90600)
6851  appendPQExpBufferStr(query,
6852  "LEFT JOIN pg_am am ON (c.relam = am.oid)\n");
6853 
6854  /*
6855  * We purposefully ignore toast OIDs for partitioned tables; the reason is
6856  * that versions 10 and 11 have them, but later versions do not, so
6857  * emitting them causes the upgrade to fail.
6858  */
6859  appendPQExpBufferStr(query,
6860  "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid"
6861  " AND tc.relkind = " CppAsString2(RELKIND_TOASTVALUE)
6862  " AND c.relkind <> " CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
6863 
6864  /*
6865  * Restrict to interesting relkinds (in particular, not indexes). Not all
6866  * relkinds are possible in older servers, but it's not worth the trouble
6867  * to emit a version-dependent list.
6868  *
6869  * Composite-type table entries won't be dumped as such, but we have to
6870  * make a DumpableObject for them so that we can track dependencies of the
6871  * composite type (pg_depend entries for columns of the composite type
6872  * link to the pg_class entry not the pg_type entry).
6873  */
6874  appendPQExpBufferStr(query,
6875  "WHERE c.relkind IN ("
6876  CppAsString2(RELKIND_RELATION) ", "
6877  CppAsString2(RELKIND_SEQUENCE) ", "
6878  CppAsString2(RELKIND_VIEW) ", "
6879  CppAsString2(RELKIND_COMPOSITE_TYPE) ", "
6880  CppAsString2(RELKIND_MATVIEW) ", "
6881  CppAsString2(RELKIND_FOREIGN_TABLE) ", "
6882  CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n"
6883  "ORDER BY c.oid");
6884 
6885  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6886 
6887  ntups = PQntuples(res);
6888 
6889  *numTables = ntups;
6890 
6891  /*
6892  * Extract data from result and lock dumpable tables. We do the locking
6893  * before anything else, to minimize the window wherein a table could
6894  * disappear under us.
6895  *
6896  * Note that we have to save info about all tables here, even when dumping
6897  * only one, because we don't yet know which tables might be inheritance
6898  * ancestors of the target table.
6899  */
6900  tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
6901 
6902  i_reltableoid = PQfnumber(res, "tableoid");
6903  i_reloid = PQfnumber(res, "oid");
6904  i_relname = PQfnumber(res, "relname");
6905  i_relnamespace = PQfnumber(res, "relnamespace");
6906  i_relkind = PQfnumber(res, "relkind");
6907  i_reltype = PQfnumber(res, "reltype");
6908  i_relowner = PQfnumber(res, "relowner");
6909  i_relchecks = PQfnumber(res, "relchecks");
6910  i_relhasindex = PQfnumber(res, "relhasindex");
6911  i_relhasrules = PQfnumber(res, "relhasrules");
6912  i_relpages = PQfnumber(res, "relpages");
6913  i_toastpages = PQfnumber(res, "toastpages");
6914  i_owning_tab = PQfnumber(res, "owning_tab");
6915  i_owning_col = PQfnumber(res, "owning_col");
6916  i_reltablespace = PQfnumber(res, "reltablespace");
6917  i_relhasoids = PQfnumber(res, "relhasoids");
6918  i_relhastriggers = PQfnumber(res, "relhastriggers");
6919  i_relpersistence = PQfnumber(res, "relpersistence");
6920  i_relispopulated = PQfnumber(res, "relispopulated");
6921  i_relreplident = PQfnumber(res, "relreplident");
6922  i_relrowsec = PQfnumber(res, "relrowsecurity");
6923  i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
6924  i_relfrozenxid = PQfnumber(res, "relfrozenxid");
6925  i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
6926  i_toastoid = PQfnumber(res, "toid");
6927  i_relminmxid = PQfnumber(res, "relminmxid");
6928  i_toastminmxid = PQfnumber(res, "tminmxid");
6929  i_reloptions = PQfnumber(res, "reloptions");
6930  i_checkoption = PQfnumber(res, "checkoption");
6931  i_toastreloptions = PQfnumber(res, "toast_reloptions");
6932  i_reloftype = PQfnumber(res, "reloftype");
6933  i_foreignserver = PQfnumber(res, "foreignserver");
6934  i_amname = PQfnumber(res, "amname");
6935  i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
6936  i_relacl = PQfnumber(res, "relacl");
6937  i_acldefault = PQfnumber(res, "acldefault");
6938  i_ispartition = PQfnumber(res, "ispartition");
6939 
6940  if (dopt->lockWaitTimeout)
6941  {
6942  /*
6943  * Arrange to fail instead of waiting forever for a table lock.
6944  *
6945  * NB: this coding assumes that the only queries issued within the
6946  * following loop are LOCK TABLEs; else the timeout may be undesirably
6947  * applied to other things too.
6948  */
6949  resetPQExpBuffer(query);
6950  appendPQExpBufferStr(query, "SET statement_timeout = ");
6952  ExecuteSqlStatement(fout, query->data);
6953  }
6954 
6955  resetPQExpBuffer(query);
6956 
6957  for (i = 0; i < ntups; i++)
6958  {
6959  tblinfo[i].dobj.objType = DO_TABLE;
6960  tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
6961  tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
6962  AssignDumpId(&tblinfo[i].dobj);
6963  tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
6964  tblinfo[i].dobj.namespace =
6965  findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)));
6966  tblinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_relacl));
6967  tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
6968  tblinfo[i].dacl.privtype = 0;
6969  tblinfo[i].dacl.initprivs = NULL;
6970  tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
6971  tblinfo[i].reltype = atooid(PQgetvalue(res, i, i_reltype));
6972  tblinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_relowner));
6973  tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
6974  tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
6975  tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
6976  tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
6977  if (PQgetisnull(res, i, i_toastpages))
6978  tblinfo[i].toastpages = 0;
6979  else
6980  tblinfo[i].toastpages = atoi(PQgetvalue(res, i, i_toastpages));
6981  if (PQgetisnull(res, i, i_owning_tab))
6982  {
6983  tblinfo[i].owning_tab = InvalidOid;
6984  tblinfo[i].owning_col = 0;
6985  }
6986  else
6987  {
6988  tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
6989  tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
6990  }
6991  tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
6992  tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
6993  tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
6994  tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
6995  tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
6996  tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
6997  tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
6998  tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
6999  tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
7000  tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
7001  tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
7002  tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
7003  tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
7004  tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
7005  if (PQgetisnull(res, i, i_checkoption))
7006  tblinfo[i].checkoption = NULL;
7007  else
7008  tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
7009  tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
7010  tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype));
7011  tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver));
7012  if (PQgetisnull(res, i, i_amname))
7013  tblinfo[i].amname = NULL;
7014  else
7015  tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
7016  tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
7017  tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
7018 
7019  /* other fields were zeroed above */
7020 
7021  /*
7022  * Decide whether we want to dump this table.
7023  */
7024  if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
7025  tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
7026  else
7027  selectDumpableTable(&tblinfo[i], fout);
7028 
7029  /*
7030  * Now, consider the table "interesting" if we need to dump its
7031  * definition or its data. Later on, we'll skip a lot of data
7032  * collection for uninteresting tables.
7033  *
7034  * Note: the "interesting" flag will also be set by flagInhTables for
7035  * parents of interesting tables, so that we collect necessary
7036  * inheritance info even when the parents are not themselves being
7037  * dumped. This is the main reason why we need an "interesting" flag
7038  * that's separate from the components-to-dump bitmask.
7039  */
7040  tblinfo[i].interesting = (tblinfo[i].dobj.dump &
7042  DUMP_COMPONENT_DATA)) != 0;
7043 
7044  tblinfo[i].dummy_view = false; /* might get set during sort */
7045  tblinfo[i].postponed_def = false; /* might get set during sort */
7046 
7047  /* Tables have data */
7048  tblinfo[i].dobj.components |= DUMP_COMPONENT_DATA;
7049 
7050  /* Mark whether table has an ACL */
7051  if (!PQgetisnull(res, i, i_relacl))
7052  tblinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
7053  tblinfo[i].hascolumnACLs = false; /* may get set later */
7054 
7055  /*
7056  * Read-lock target tables to make sure they aren't DROPPED or altered
7057  * in schema before we get around to dumping them.
7058  *
7059  * Note that we don't explicitly lock parents of the target tables; we
7060  * assume our lock on the child is enough to prevent schema
7061  * alterations to parent tables.
7062  *
7063  * NOTE: it'd be kinda nice to lock other relations too, not only
7064  * plain or partitioned tables, but the backend doesn't presently
7065  * allow that.
7066  *
7067  * We only need to lock the table for certain components; see
7068  * pg_dump.h
7069  */
7070  if ((tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK) &&
7071  (tblinfo[i].relkind == RELKIND_RELATION ||
7072  tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE))
7073  {
7074  /*
7075  * Tables are locked in batches. When dumping from a remote
7076  * server this can save a significant amount of time by reducing
7077  * the number of round trips.
7078  */
7079  if (query->len == 0)
7080  appendPQExpBuffer(query, "LOCK TABLE %s",
7081  fmtQualifiedDumpable(&tblinfo[i]));
7082  else
7083  {
7084  appendPQExpBuffer(query, ", %s",
7085  fmtQualifiedDumpable(&tblinfo[i]));
7086 
7087  /* Arbitrarily end a batch when query length reaches 100K. */
7088  if (query->len >= 100000)
7089  {
7090  /* Lock another batch of tables. */
7091  appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
7092  ExecuteSqlStatement(fout, query->data);
7093  resetPQExpBuffer(query);
7094  }
7095  }
7096  }
7097  }
7098 
7099  if (query->len != 0)
7100  {
7101  /* Lock the tables in the last batch. */
7102  appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
7103  ExecuteSqlStatement(fout, query->data);
7104  }
7105 
7106  if (dopt->lockWaitTimeout)
7107  {
7108  ExecuteSqlStatement(fout, "SET statement_timeout = 0");
7109  }
7110 
7111  PQclear(res);
7112 
7113  destroyPQExpBuffer(query);
7114 
7115  return tblinfo;
7116 }
7117 
7118 /*
7119  * getOwnedSeqs
7120  * identify owned sequences and mark them as dumpable if owning table is
7121  *
7122  * We used to do this in getTables(), but it's better to do it after the
7123  * index used by findTableByOid() has been set up.
7124  */
7125 void
7126 getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
7127 {
7128  int i;
7129 
7130  /*
7131  * Force sequences that are "owned" by table columns to be dumped whenever
7132  * their owning table is being dumped.
7133  */
7134  for (i = 0; i < numTables; i++)
7135  {
7136  TableInfo *seqinfo = &tblinfo[i];
7137  TableInfo *owning_tab;
7138 
7139  if (!OidIsValid(seqinfo->owning_tab))
7140  continue; /* not an owned sequence */
7141 
7142  owning_tab = findTableByOid(seqinfo->owning_tab);
7143  if (owning_tab == NULL)
7144  pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
7145  seqinfo->owning_tab, seqinfo->dobj.catId.oid);
7146 
7147  /*
7148  * Only dump identity sequences if we're going to dump the table that
7149  * it belongs to.
7150  */
7151  if (owning_tab->dobj.dump == DUMP_COMPONENT_NONE &&
7152  seqinfo->is_identity_sequence)
7153  {
7154  seqinfo->dobj.dump = DUMP_COMPONENT_NONE;
7155  continue;
7156  }
7157 
7158  /*
7159  * Otherwise we need to dump the components that are being dumped for
7160  * the table and any components which the sequence is explicitly
7161  * marked with.
7162  *
7163  * We can't simply use the set of components which are being dumped
7164  * for the table as the table might be in an extension (and only the
7165  * non-extension components, eg: ACLs if changed, security labels, and
7166  * policies, are being dumped) while the sequence is not (and
7167  * therefore the definition and other components should also be
7168  * dumped).
7169  *
7170  * If the sequence is part of the extension then it should be properly
7171  * marked by checkExtensionMembership() and this will be a no-op as
7172  * the table will be equivalently marked.
7173  */
7174  seqinfo->dobj.dump = seqinfo->dobj.dump | owning_tab->dobj.dump;
7175 
7176  if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
7177  seqinfo->interesting = true;
7178  }
7179 }
7180 
7181 /*
7182  * getInherits
7183  * read all the inheritance information
7184  * from the system catalogs return them in the InhInfo* structure
7185  *
7186  * numInherits is set to the number of pairs read in
7187  */
7188 InhInfo *
7189 getInherits(Archive *fout, int *numInherits)
7190 {
7191  PGresult *res;
7192  int ntups;
7193  int i;
7194  PQExpBuffer query = createPQExpBuffer();
7195  InhInfo *inhinfo;
7196 
7197  int i_inhrelid;
7198  int i_inhparent;
7199 
7200  /* find all the inheritance information */
7201  appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
7202 
7203  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7204 
7205  ntups = PQntuples(res);
7206 
7207  *numInherits = ntups;
7208 
7209  inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
7210 
7211  i_inhrelid = PQfnumber(res, "inhrelid");
7212  i_inhparent = PQfnumber(res, "inhparent");
7213 
7214  for (i = 0; i < ntups; i++)
7215  {
7216  inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
7217  inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
7218  }
7219 
7220  PQclear(res);
7221 
7222  destroyPQExpBuffer(query);
7223 
7224  return inhinfo;
7225 }
7226 
7227 /*
7228  * getPartitioningInfo
7229  * get information about partitioning
7230  *
7231  * For the most part, we only collect partitioning info about tables we
7232  * intend to dump. However, this function has to consider all partitioned
7233  * tables in the database, because we need to know about parents of partitions
7234  * we are going to dump even if the parents themselves won't be dumped.
7235  *
7236  * Specifically, what we need to know is whether each partitioned table
7237  * has an "unsafe" partitioning scheme that requires us to force
7238  * load-via-partition-root mode for its children. Currently the only case
7239  * for which we force that is hash partitioning on enum columns, since the
7240  * hash codes depend on enum value OIDs which won't be replicated across
7241  * dump-and-reload. There are other cases in which load-via-partition-root
7242  * might be necessary, but we expect users to cope with them.
7243  */
7244 void
7246 {
7247  PQExpBuffer query;
7248  PGresult *res;
7249  int ntups;
7250 
7251  /* hash partitioning didn't exist before v11 */
7252  if (fout->remoteVersion < 110000)
7253  return;
7254  /* needn't bother if schema-only dump */
7255  if (fout->dopt->schemaOnly)
7256  return;
7257 
7258  query = createPQExpBuffer();
7259 
7260  /*
7261  * Unsafe partitioning schemes are exactly those for which hash enum_ops
7262  * appears among the partition opclasses. We needn't check partstrat.
7263  *
7264  * Note that this query may well retrieve info about tables we aren't
7265  * going to dump and hence have no lock on. That's okay since we need not
7266  * invoke any unsafe server-side functions.
7267  */
7268  appendPQExpBufferStr(query,
7269  "SELECT partrelid FROM pg_partitioned_table WHERE\n"
7270  "(SELECT c.oid FROM pg_opclass c JOIN pg_am a "
7271  "ON c.opcmethod = a.oid\n"
7272  "WHERE opcname = 'enum_ops' "
7273  "AND opcnamespace = 'pg_catalog'::regnamespace "
7274  "AND amname = 'hash') = ANY(partclass)");
7275 
7276  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7277 
7278  ntups = PQntuples(res);
7279 
7280  for (int i = 0; i < ntups; i++)
7281  {
7282  Oid tabrelid = atooid(PQgetvalue(res, i, 0));
7283  TableInfo *tbinfo;
7284 
7285  tbinfo = findTableByOid(tabrelid);
7286  if (tbinfo == NULL)
7287  pg_fatal("failed sanity check, table OID %u appearing in pg_partitioned_table not found",
7288  tabrelid);
7289  tbinfo->unsafe_partitions = true;
7290  }
7291 
7292  PQclear(res);
7293 
7294  destroyPQExpBuffer(query);
7295 }
7296 
7297 /*
7298  * getIndexes
7299  * get information about every index on a dumpable table
7300  *
7301  * Note: index data is not returned directly to the caller, but it
7302  * does get entered into the DumpableObject tables.
7303  */
7304 void
7305 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
7306 {
7307  PQExpBuffer query = createPQExpBuffer();
7308  PQExpBuffer tbloids = createPQExpBuffer();
7309  PGresult *res;
7310  int ntups;
7311  int curtblindx;
7312  IndxInfo *indxinfo;
7313  int i_tableoid,
7314  i_oid,
7315  i_indrelid,
7316  i_indexname,
7317  i_parentidx,
7318  i_indexdef,
7319  i_indnkeyatts,
7320  i_indnatts,
7321  i_indkey,
7322  i_indisclustered,
7323  i_indisreplident,
7324  i_indnullsnotdistinct,
7325  i_contype,
7326  i_conname,
7327  i_condeferrable,
7328  i_condeferred,
7329  i_contableoid,
7330  i_conoid,
7331  i_condef,
7332  i_tablespace,
7333  i_indreloptions,
7334  i_indstatcols,
7335  i_indstatvals;
7336 
7337  /*
7338  * We want to perform just one query against pg_index. However, we
7339  * mustn't try to select every row of the catalog and then sort it out on
7340  * the client side, because some of the server-side functions we need
7341  * would be unsafe to apply to tables we don't have lock on. Hence, we
7342  * build an array of the OIDs of tables we care about (and now have lock
7343  * on!), and use a WHERE clause to constrain which rows are selected.
7344  */
7345  appendPQExpBufferChar(tbloids, '{');
7346  for (int i = 0; i < numTables; i++)
7347  {
7348  TableInfo *tbinfo = &tblinfo[i];
7349 
7350  if (!tbinfo->hasindex)
7351  continue;
7352 
7353  /*
7354  * We can ignore indexes of uninteresting tables.
7355  */
7356  if (!tbinfo->interesting)
7357  continue;
7358 
7359  /* OK, we need info for this table */
7360  if (tbloids->len > 1) /* do we have more than the '{'? */
7361  appendPQExpBufferChar(tbloids, ',');
7362  appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
7363  }
7364  appendPQExpBufferChar(tbloids, '}');
7365 
7366  appendPQExpBufferStr(query,
7367  "SELECT t.tableoid, t.oid, i.indrelid, "
7368  "t.relname AS indexname, "
7369  "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
7370  "i.indkey, i.indisclustered, "
7371  "c.contype, c.conname, "
7372  "c.condeferrable, c.condeferred, "
7373  "c.tableoid AS contableoid, "
7374  "c.oid AS conoid, "
7375  "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
7376  "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
7377  "t.reloptions AS indreloptions, ");
7378 
7379 
7380  if (fout->remoteVersion >= 90400)
7381  appendPQExpBufferStr(query,
7382  "i.indisreplident, ");
7383  else
7384  appendPQExpBufferStr(query,
7385  "false AS indisreplident, ");
7386 
7387  if (fout->remoteVersion >= 110000)
7388  appendPQExpBufferStr(query,
7389  "inh.inhparent AS parentidx, "
7390  "i.indnkeyatts AS indnkeyatts, "
7391  "i.indnatts AS indnatts, "
7392  "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
7393  " FROM pg_catalog.pg_attribute "
7394  " WHERE attrelid = i.indexrelid AND "
7395  " attstattarget >= 0) AS indstatcols, "
7396  "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
7397  " FROM pg_catalog.pg_attribute "
7398  " WHERE attrelid = i.indexrelid AND "
7399  " attstattarget >= 0) AS indstatvals, ");
7400  else
7401  appendPQExpBufferStr(query,
7402  "0 AS parentidx, "
7403  "i.indnatts AS indnkeyatts, "
7404  "i.indnatts AS indnatts, "
7405  "'' AS indstatcols, "
7406  "'' AS indstatvals, ");
7407 
7408  if (fout->remoteVersion >= 150000)
7409  appendPQExpBufferStr(query,
7410  "i.indnullsnotdistinct ");
7411  else
7412  appendPQExpBufferStr(query,
7413  "false AS indnullsnotdistinct ");
7414 
7415  /*
7416  * The point of the messy-looking outer join is to find a constraint that
7417  * is related by an internal dependency link to the index. If we find one,
7418  * create a CONSTRAINT entry linked to the INDEX entry. We assume an
7419  * index won't have more than one internal dependency.
7420  *
7421  * Note: the check on conrelid is redundant, but useful because that
7422  * column is indexed while conindid is not.
7423  */
7424  if (fout->remoteVersion >= 110000)
7425  {
7426  appendPQExpBuffer(query,
7427  "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
7428  "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
7429  "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
7430  "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
7431  "LEFT JOIN pg_catalog.pg_constraint c "
7432  "ON (i.indrelid = c.conrelid AND "
7433  "i.indexrelid = c.conindid AND "
7434  "c.contype IN ('p','u','x')) "
7435  "LEFT JOIN pg_catalog.pg_inherits inh "
7436  "ON (inh.inhrelid = indexrelid) "
7437  "WHERE (i.indisvalid OR t2.relkind = 'p') "
7438  "AND i.indisready "
7439  "ORDER BY i.indrelid, indexname",
7440  tbloids->data);
7441  }
7442  else
7443  {
7444  /*
7445  * the test on indisready is necessary in 9.2, and harmless in
7446  * earlier/later versions
7447  */
7448  appendPQExpBuffer(query,
7449  "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
7450  "JOIN pg_catalog.pg_index i ON (src.tbloid = i.indrelid) "
7451  "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
7452  "LEFT JOIN pg_catalog.pg_constraint c "
7453  "ON (i.indrelid = c.conrelid AND "
7454  "i.indexrelid = c.conindid AND "
7455  "c.contype IN ('p','u','x')) "
7456  "WHERE i.indisvalid AND i.indisready "
7457  "ORDER BY i.indrelid, indexname",
7458  tbloids->data);
7459  }
7460 
7461  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7462 
7463  ntups = PQntuples(res);
7464 
7465  i_tableoid = PQfnumber(res, "tableoid");
7466  i_oid = PQfnumber(res, "oid");
7467  i_indrelid = PQfnumber(res, "indrelid");
7468  i_indexname = PQfnumber(res, "indexname");
7469  i_parentidx = PQfnumber(res, "parentidx");
7470  i_indexdef = PQfnumber(res, "indexdef");
7471  i_indnkeyatts = PQfnumber(res, "indnkeyatts");
7472  i_indnatts = PQfnumber(res, "indnatts");
7473  i_indkey = PQfnumber(res, "indkey");
7474  i_indisclustered = PQfnumber(res, "indisclustered");
7475  i_indisreplident = PQfnumber(res, "indisreplident");
7476  i_indnullsnotdistinct = PQfnumber(res, "indnullsnotdistinct");
7477  i_contype = PQfnumber(res, "contype");
7478  i_conname = PQfnumber(res, "conname");
7479  i_condeferrable = PQfnumber(res, "condeferrable");
7480  i_condeferred = PQfnumber(res, "condeferred");
7481  i_contableoid = PQfnumber(res, "contableoid");
7482  i_conoid = PQfnumber(res, "conoid");
7483  i_condef = PQfnumber(res, "condef");
7484  i_tablespace = PQfnumber(res, "tablespace");
7485  i_indreloptions = PQfnumber(res, "indreloptions");
7486  i_indstatcols = PQfnumber(res, "indstatcols");
7487  i_indstatvals = PQfnumber(res, "indstatvals");
7488 
7489  indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
7490 
7491  /*
7492  * Outer loop iterates once per table, not once per row. Incrementing of
7493  * j is handled by the inner loop.
7494  */
7495  curtblindx = -1;
7496  for (int j = 0; j < ntups;)
7497  {
7498  Oid indrelid = atooid(PQgetvalue(res, j, i_indrelid));
7499  TableInfo *tbinfo = NULL;
7500  int numinds;
7501 
7502  /* Count rows for this table */
7503  for (numinds = 1; numinds < ntups - j; numinds++)
7504  if (atooid(PQgetvalue(res, j + numinds, i_indrelid)) != indrelid)
7505  break;
7506 
7507  /*
7508  * Locate the associated TableInfo; we rely on tblinfo[] being in OID
7509  * order.
7510  */
7511  while (++curtblindx < numTables)
7512  {
7513  tbinfo = &tblinfo[curtblindx];
7514  if (tbinfo->dobj.catId.oid == indrelid)
7515  break;
7516  }
7517  if (curtblindx >= numTables)
7518  pg_fatal("unrecognized table OID %u", indrelid);
7519  /* cross-check that we only got requested tables */
7520  if (!tbinfo->hasindex ||
7521  !tbinfo->interesting)
7522  pg_fatal("unexpected index data for table \"%s\"",
7523  tbinfo->dobj.name);
7524 
7525  /* Save data for this table */
7526  tbinfo->indexes = indxinfo + j;
7527  tbinfo->numIndexes = numinds;
7528 
7529  for (int c = 0; c < numinds; c++, j++)
7530  {
7531  char contype;
7532 
7533  indxinfo[j].dobj.objType = DO_INDEX;
7534  indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
7535  indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7536  AssignDumpId(&indxinfo[j].dobj);
7537  indxinfo[j].dobj.dump = tbinfo->dobj.dump;
7538  indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
7539  indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7540  indxinfo[j].indextable = tbinfo;
7541  indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
7542  indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
7543  indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
7544  indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
7545  indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
7546  indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
7547  indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
7548  indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
7549  parseOidArray(PQgetvalue(res, j, i_indkey),
7550  indxinfo[j].indkeys, indxinfo[j].indnattrs);
7551  indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
7552  indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
7553  indxinfo[j].indnullsnotdistinct = (PQgetvalue(res, j, i_indnullsnotdistinct)[0] == 't');
7554  indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
7555  indxinfo[j].partattaches = (SimplePtrList)
7556  {
7557  NULL, NULL
7558  };
7559  contype = *(PQgetvalue(res, j, i_contype));
7560 
7561  if (contype == 'p' || contype == 'u' || contype == 'x')
7562  {
7563  /*
7564  * If we found a constraint matching the index, create an
7565  * entry for it.
7566  */
7567  ConstraintInfo *constrinfo;
7568 
7569  constrinfo = (ConstraintInfo *) pg_malloc(sizeof(ConstraintInfo));
7570  constrinfo->dobj.objType = DO_CONSTRAINT;
7571  constrinfo->dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7572  constrinfo->dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7573  AssignDumpId(&constrinfo->dobj);
7574  constrinfo->dobj.dump = tbinfo->dobj.dump;
7575  constrinfo->dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7576  constrinfo->dobj.namespace = tbinfo->dobj.namespace;
7577  constrinfo->contable = tbinfo;
7578  constrinfo->condomain = NULL;
7579  constrinfo->contype = contype;
7580  if (contype == 'x')
7581  constrinfo->condef = pg_strdup(PQgetvalue(res, j, i_condef));
7582  else
7583  constrinfo->condef = NULL;
7584  constrinfo->confrelid = InvalidOid;
7585  constrinfo->conindex = indxinfo[j].dobj.dumpId;
7586  constrinfo->condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
7587  constrinfo->condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
7588  constrinfo->conislocal = true;
7589  constrinfo->separate = true;
7590 
7591  indxinfo[j].indexconstraint = constrinfo->dobj.dumpId;
7592  }
7593  else
7594  {
7595  /* Plain secondary index */
7596  indxinfo[j].indexconstraint = 0;
7597  }
7598  }
7599  }
7600 
7601  PQclear(res);
7602 
7603  destroyPQExpBuffer(query);
7604  destroyPQExpBuffer(tbloids);
7605 }
7606 
7607 /*
7608  * getExtendedStatistics
7609  * get information about extended-statistics objects.
7610  *
7611  * Note: extended statistics data is not returned directly to the caller, but
7612  * it does get entered into the DumpableObject tables.
7613  */
7614 void
7616 {
7617  PQExpBuffer query;
7618  PGresult *res;
7619  StatsExtInfo *statsextinfo;
7620  int ntups;
7621  int i_tableoid;
7622  int i_oid;
7623  int i_stxname;
7624  int i_stxnamespace;
7625  int i_stxowner;
7626  int i_stxrelid;
7627  int i_stattarget;
7628  int i;
7629 
7630  /* Extended statistics were new in v10 */
7631  if (fout->remoteVersion < 100000)
7632  return;
7633 
7634  query = createPQExpBuffer();
7635 
7636  if (fout->remoteVersion < 130000)
7637  appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
7638  "stxnamespace, stxowner, stxrelid, NULL AS stxstattarget "
7639  "FROM pg_catalog.pg_statistic_ext");
7640  else
7641  appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
7642  "stxnamespace, stxowner, stxrelid, stxstattarget "
7643  "FROM pg_catalog.pg_statistic_ext");
7644 
7645  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7646 
7647  ntups = PQntuples(res);
7648 
7649  i_tableoid = PQfnumber(res, "tableoid");
7650  i_oid = PQfnumber(res, "oid");
7651  i_stxname = PQfnumber(res, "stxname");
7652  i_stxnamespace = PQfnumber(res, "stxnamespace");
7653  i_stxowner = PQfnumber(res, "stxowner");
7654  i_stxrelid = PQfnumber(res, "stxrelid");
7655  i_stattarget = PQfnumber(res, "stxstattarget");
7656 
7657  statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
7658 
7659  for (i = 0; i < ntups; i++)
7660  {
7661  statsextinfo[i].dobj.objType = DO_STATSEXT;
7662  statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7663  statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7664  AssignDumpId(&statsextinfo[i].dobj);
7665  statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
7666  statsextinfo[i].dobj.namespace =
7667  findNamespace(atooid(PQgetvalue(res, i, i_stxnamespace)));
7668  statsextinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_stxowner));
7669  statsextinfo[i].stattable =
7670  findTableByOid(atooid(PQgetvalue(res, i, i_stxrelid)));
7671  if (PQgetisnull(res, i, i_stattarget))
7672  statsextinfo[i].stattarget = -1;
7673  else
7674  statsextinfo[i].stattarget = atoi(PQgetvalue(res, i, i_stattarget));
7675 
7676  /* Decide whether we want to dump it */
7677  selectDumpableStatisticsObject(&(statsextinfo[i]), fout);
7678  }
7679 
7680  PQclear(res);
7681  destroyPQExpBuffer(query);
7682 }
7683 
7684 /*
7685  * getConstraints
7686  *
7687  * Get info about constraints on dumpable tables.
7688  *
7689  * Currently handles foreign keys only.
7690  * Unique and primary key constraints are handled with indexes,
7691  * while check constraints are processed in getTableAttrs().
7692  */
7693 void
7694 getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
7695 {
7696  PQExpBuffer query = createPQExpBuffer();
7697  PQExpBuffer tbloids = createPQExpBuffer();
7698  PGresult *res;
7699  int ntups;
7700  int curtblindx;
7701  TableInfo *tbinfo = NULL;
7702  ConstraintInfo *constrinfo;
7703  int i_contableoid,
7704  i_conoid,
7705  i_conrelid,
7706  i_conname,
7707  i_confrelid,
7708  i_conindid,
7709  i_condef;
7710 
7711  /*
7712  * We want to perform just one query against pg_constraint. However, we
7713  * mustn't try to select every row of the catalog and then sort it out on
7714  * the client side, because some of the server-side functions we need
7715  * would be unsafe to apply to tables we don't have lock on. Hence, we
7716  * build an array of the OIDs of tables we care about (and now have lock
7717  * on!), and use a WHERE clause to constrain which rows are selected.
7718  */
7719  appendPQExpBufferChar(tbloids, '{');
7720  for (int i = 0; i < numTables; i++)
7721  {
7722  TableInfo *tinfo = &tblinfo[i];
7723 
7724  /*
7725  * For partitioned tables, foreign keys have no triggers so they must
7726  * be included anyway in case some foreign keys are defined.
7727  */
7728  if ((!tinfo->hastriggers &&
7729  tinfo->relkind != RELKIND_PARTITIONED_TABLE) ||
7730  !(tinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7731  continue;
7732 
7733  /* OK, we need info for this table */
7734  if (tbloids->len > 1) /* do we have more than the '{'? */
7735  appendPQExpBufferChar(tbloids, ',');
7736  appendPQExpBuffer(tbloids, "%u", tinfo->dobj.catId.oid);
7737  }
7738  appendPQExpBufferChar(tbloids, '}');
7739 
7740  appendPQExpBufferStr(query,
7741  "SELECT c.tableoid, c.oid, "
7742  "conrelid, conname, confrelid, ");
7743  if (fout->remoteVersion >= 110000)
7744  appendPQExpBufferStr(query, "conindid, ");
7745  else
7746  appendPQExpBufferStr(query, "0 AS conindid, ");
7747  appendPQExpBuffer(query,
7748  "pg_catalog.pg_get_constraintdef(c.oid) AS condef\n"
7749  "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
7750  "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
7751  "WHERE contype = 'f' ",
7752  tbloids->data);
7753  if (fout->remoteVersion >= 110000)
7754  appendPQExpBufferStr(query,
7755  "AND conparentid = 0 ");
7756  appendPQExpBufferStr(query,
7757  "ORDER BY conrelid, conname");
7758 
7759  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7760 
7761  ntups = PQntuples(res);
7762 
7763  i_contableoid = PQfnumber(res, "tableoid");
7764  i_conoid = PQfnumber(res, "oid");
7765  i_conrelid = PQfnumber(res, "conrelid");
7766  i_conname = PQfnumber(res, "conname");
7767  i_confrelid = PQfnumber(res, "confrelid");
7768  i_conindid = PQfnumber(res, "conindid");
7769  i_condef = PQfnumber(res, "condef");
7770 
7771  constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7772 
7773  curtblindx = -1;
7774  for (int j = 0; j < ntups; j++)
7775  {
7776  Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
7777  TableInfo *reftable;
7778 
7779  /*
7780  * Locate the associated TableInfo; we rely on tblinfo[] being in OID
7781  * order.
7782  */
7783  if (tbinfo == NULL || tbinfo->dobj.catId.oid != conrelid)
7784  {
7785  while (++curtblindx < numTables)
7786  {
7787  tbinfo = &tblinfo[curtblindx];
7788  if (tbinfo->dobj.catId.oid == conrelid)
7789  break;
7790  }
7791  if (curtblindx >= numTables)
7792  pg_fatal("unrecognized table OID %u", conrelid);
7793  }
7794 
7795  constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
7796  constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7797  constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7798  AssignDumpId(&constrinfo[j].dobj);
7799  constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7800  constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7801  constrinfo[j].contable = tbinfo;
7802  constrinfo[j].condomain = NULL;
7803  constrinfo[j].contype = 'f';
7804  constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
7805  constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
7806  constrinfo[j].conindex = 0;
7807  constrinfo[j].condeferrable = false;
7808  constrinfo[j].condeferred = false;
7809  constrinfo[j].conislocal = true;
7810  constrinfo[j].separate = true;
7811 
7812  /*
7813  * Restoring an FK that points to a partitioned table requires that
7814  * all partition indexes have been attached beforehand. Ensure that
7815  * happens by making the constraint depend on each index partition
7816  * attach object.
7817  */
7818  reftable = findTableByOid(constrinfo[j].confrelid);
7819  if (reftable && reftable->relkind == RELKIND_PARTITIONED_TABLE)
7820  {
7821  Oid indexOid = atooid(PQgetvalue(res, j, i_conindid));
7822 
7823  if (indexOid != InvalidOid)
7824  {
7825  for (int k = 0; k < reftable->numIndexes; k++)
7826  {
7827  IndxInfo *refidx;
7828 
7829  /* not our index? */
7830  if (reftable->indexes[k].dobj.catId.oid != indexOid)
7831  continue;
7832 
7833  refidx = &reftable->indexes[k];
7834  addConstrChildIdxDeps(&constrinfo[j].dobj, refidx);
7835  break;
7836  }
7837  }
7838  }
7839  }
7840 
7841  PQclear(res);
7842 
7843  destroyPQExpBuffer(query);
7844  destroyPQExpBuffer(tbloids);
7845 }
7846 
7847 /*
7848  * addConstrChildIdxDeps
7849  *
7850  * Recursive subroutine for getConstraints
7851  *
7852  * Given an object representing a foreign key constraint and an index on the
7853  * partitioned table it references, mark the constraint object as dependent
7854  * on the DO_INDEX_ATTACH object of each index partition, recursively
7855  * drilling down to their partitions if any. This ensures that the FK is not
7856  * restored until the index is fully marked valid.
7857  */
7858 static void
7860 {
7861  SimplePtrListCell *cell;
7862 
7863  Assert(dobj->objType == DO_FK_CONSTRAINT);
7864 
7865  for (cell = refidx->partattaches.head; cell; cell = cell->next)
7866  {
7867  IndexAttachInfo *attach = (IndexAttachInfo *) cell->ptr;
7868 
7869  addObjectDependency(dobj, attach->dobj.dumpId);
7870 
7871  if (attach->partitionIdx->partattaches.head != NULL)
7872  addConstrChildIdxDeps(dobj, attach->partitionIdx);
7873  }
7874 }
7875 
7876 /*
7877  * getDomainConstraints
7878  *
7879  * Get info about constraints on a domain.
7880  */
7881 static void
7883 {
7884  int i;
7885  ConstraintInfo *constrinfo;
7886  PQExpBuffer query = createPQExpBuffer();
7887  PGresult *res;
7888  int i_tableoid,
7889  i_oid,
7890  i_conname,
7891  i_consrc;
7892  int ntups;
7893 
7895  {
7896  /* Set up query for constraint-specific details */
7897  appendPQExpBufferStr(query,
7898  "PREPARE getDomainConstraints(pg_catalog.oid) AS\n"
7899  "SELECT tableoid, oid, conname, "
7900  "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7901  "convalidated "
7902  "FROM pg_catalog.pg_constraint "
7903  "WHERE contypid = $1 AND contype = 'c' "
7904  "ORDER BY conname");
7905 
7906  ExecuteSqlStatement(fout, query->data);
7907 
7909  }
7910 
7911  printfPQExpBuffer(query,
7912  "EXECUTE getDomainConstraints('%u')",
7913  tyinfo->dobj.catId.oid);
7914 
7915  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7916 
7917  ntups = PQntuples(res);
7918 
7919  i_tableoid = PQfnumber(res, "tableoid");
7920  i_oid = PQfnumber(res, "oid");
7921  i_conname = PQfnumber(res, "conname");
7922  i_consrc = PQfnumber(res, "consrc");
7923 
7924  constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7925 
7926  tyinfo->nDomChecks = ntups;
7927  tyinfo->domChecks = constrinfo;
7928 
7929  for (i = 0; i < ntups; i++)
7930  {
7931  bool validated = PQgetvalue(res, i, 4)[0] == 't';
7932 
7933  constrinfo[i].dobj.objType = DO_CONSTRAINT;
7934  constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7935  constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7936  AssignDumpId(&constrinfo[i].dobj);
7937  constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
7938  constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
7939  constrinfo[i].contable = NULL;
7940  constrinfo[i].condomain = tyinfo;
7941  constrinfo[i].contype = 'c';
7942  constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
7943  constrinfo[i].confrelid = InvalidOid;
7944  constrinfo[i].conindex = 0;
7945  constrinfo[i].condeferrable = false;
7946  constrinfo[i].condeferred = false;
7947  constrinfo[i].conislocal = true;
7948 
7949  constrinfo[i].separate = !validated;
7950 
7951  /*
7952  * Make the domain depend on the constraint, ensuring it won't be
7953  * output till any constraint dependencies are OK. If the constraint
7954  * has not been validated, it's going to be dumped after the domain
7955  * anyway, so this doesn't matter.
7956  */
7957  if (validated)
7958  addObjectDependency(&tyinfo->dobj,
7959  constrinfo[i].dobj.dumpId);
7960  }
7961 
7962  PQclear(res);
7963 
7964  destroyPQExpBuffer(query);
7965 }
7966 
7967 /*
7968  * getRules
7969  * get basic information about every rule in the system
7970  */
7971 void
7973 {
7974  PGresult *res;
7975  int ntups;
7976  int i;
7977  PQExpBuffer query = createPQExpBuffer();
7978  RuleInfo *ruleinfo;
7979  int i_tableoid;
7980  int i_oid;
7981  int i_rulename;
7982  int i_ruletable;
7983  int i_ev_type;
7984  int i_is_instead;
7985  int i_ev_enabled;
7986 
7987  appendPQExpBufferStr(query, "SELECT "
7988  "tableoid, oid, rulename, "
7989  "ev_class AS ruletable, ev_type, is_instead, "
7990  "ev_enabled "
7991  "FROM pg_rewrite "
7992  "ORDER BY oid");
7993 
7994  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7995 
7996  ntups = PQntuples(res);
7997 
7998  ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
7999 
8000  i_tableoid = PQfnumber(res, "tableoid");
8001  i_oid = PQfnumber(res, "oid");
8002  i_rulename = PQfnumber(res, "rulename");
8003  i_ruletable = PQfnumber(res, "ruletable");
8004  i_ev_type = PQfnumber(res, "ev_type");
8005  i_is_instead = PQfnumber(res, "is_instead");
8006  i_ev_enabled = PQfnumber(res, "ev_enabled");
8007 
8008  for (i = 0; i < ntups; i++)
8009  {
8010  Oid ruletableoid;
8011 
8012  ruleinfo[i].dobj.objType = DO_RULE;
8013  ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8014  ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8015  AssignDumpId(&ruleinfo[i].dobj);
8016  ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
8017  ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
8018  ruleinfo[i].ruletable = findTableByOid(ruletableoid);
8019  if (ruleinfo[i].ruletable == NULL)
8020  pg_fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
8021  ruletableoid, ruleinfo[i].dobj.catId.oid);
8022  ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
8023  ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
8024  ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
8025  ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
8026  ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
8027  if (ruleinfo[i].ruletable)
8028  {
8029  /*
8030  * If the table is a view or materialized view, force its ON
8031  * SELECT rule to be sorted before the view itself --- this
8032  * ensures that any dependencies for the rule affect the table's
8033  * positioning. Other rules are forced to appear after their
8034  * table.
8035  */
8036  if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
8037  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
8038  ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
8039  {
8040  addObjectDependency(&ruleinfo[i].ruletable->dobj,
8041  ruleinfo[i].dobj.dumpId);
8042  /* We'll merge the rule into CREATE VIEW, if possible */
8043  ruleinfo[i].separate = false;
8044  }
8045  else
8046  {
8047  addObjectDependency(&ruleinfo[i].dobj,
8048  ruleinfo[i].ruletable->dobj.dumpId);
8049  ruleinfo[i].separate = true;
8050  }
8051  }
8052  else
8053  ruleinfo[i].separate = true;
8054  }
8055 
8056  PQclear(res);
8057 
8058  destroyPQExpBuffer(query);
8059 }
8060 
8061 /*
8062  * getTriggers
8063  * get information about every trigger on a dumpable table
8064  *
8065  * Note: trigger data is not returned directly to the caller, but it
8066  * does get entered into the DumpableObject tables.
8067  */
8068 void
8069 getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
8070 {
8071  PQExpBuffer query = createPQExpBuffer();
8072  PQExpBuffer tbloids = createPQExpBuffer();
8073  PGresult *res;
8074  int ntups;
8075  int curtblindx;
8076  TriggerInfo *tginfo;
8077  int i_tableoid,
8078  i_oid,
8079  i_tgrelid,
8080  i_tgname,
8081  i_tgenabled,
8082  i_tgispartition,
8083  i_tgdef;
8084 
8085  /*
8086  * We want to perform just one query against pg_trigger. However, we
8087  * mustn't try to select every row of the catalog and then sort it out on
8088  * the client side, because some of the server-side functions we need
8089  * would be unsafe to apply to tables we don't have lock on. Hence, we
8090  * build an array of the OIDs of tables we care about (and now have lock
8091  * on!), and use a WHERE clause to constrain which rows are selected.
8092  */
8093  appendPQExpBufferChar(tbloids, '{');
8094  for (int i = 0; i < numTables; i++)
8095  {
8096  TableInfo *tbinfo = &tblinfo[i];
8097 
8098  if (!tbinfo->hastriggers ||
8099  !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
8100  continue;
8101 
8102  /* OK, we need info for this table */
8103  if (tbloids->len > 1) /* do we have more than the '{'? */
8104  appendPQExpBufferChar(tbloids, ',');
8105  appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
8106  }
8107  appendPQExpBufferChar(tbloids, '}');
8108 
8109  if (fout->remoteVersion >= 150000)
8110  {
8111  /*
8112  * NB: think not to use pretty=true in pg_get_triggerdef. It could
8113  * result in non-forward-compatible dumps of WHEN clauses due to
8114  * under-parenthesization.
8115  *
8116  * NB: We need to see partition triggers in case the tgenabled flag
8117  * has been changed from the parent.
8118  */
8119  appendPQExpBuffer(query,
8120  "SELECT t.tgrelid, t.tgname, "
8121  "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8122  "t.tgenabled, t.tableoid, t.oid, "
8123  "t.tgparentid <> 0 AS tgispartition\n"
8124  "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8125  "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8126  "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
8127  "WHERE ((NOT t.tgisinternal AND t.tgparentid = 0) "
8128  "OR t.tgenabled != u.tgenabled) "
8129  "ORDER BY t.tgrelid, t.tgname",
8130  tbloids->data);
8131  }
8132  else if (fout->remoteVersion >= 130000)
8133  {
8134  /*
8135  * NB: think not to use pretty=true in pg_get_triggerdef. It could
8136  * result in non-forward-compatible dumps of WHEN clauses due to
8137  * under-parenthesization.
8138  *
8139  * NB: We need to see tgisinternal triggers in partitions, in case the
8140  * tgenabled flag has been changed from the parent.
8141  */
8142  appendPQExpBuffer(query,
8143  "SELECT t.tgrelid, t.tgname, "
8144  "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8145  "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition\n"
8146  "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8147  "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8148  "LEFT JOIN pg_catalog.pg_trigger u ON (u.oid = t.tgparentid) "
8149  "WHERE (NOT t.tgisinternal OR t.tgenabled != u.tgenabled) "
8150  "ORDER BY t.tgrelid, t.tgname",
8151  tbloids->data);
8152  }
8153  else if (fout->remoteVersion >= 110000)
8154  {
8155  /*
8156  * NB: We need to see tgisinternal triggers in partitions, in case the
8157  * tgenabled flag has been changed from the parent. No tgparentid in
8158  * version 11-12, so we have to match them via pg_depend.
8159  *
8160  * See above about pretty=true in pg_get_triggerdef.
8161  */
8162  appendPQExpBuffer(query,
8163  "SELECT t.tgrelid, t.tgname, "
8164  "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8165  "t.tgenabled, t.tableoid, t.oid, t.tgisinternal as tgispartition "
8166  "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8167  "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8168  "LEFT JOIN pg_catalog.pg_depend AS d ON "
8169  " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
8170  " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
8171  " d.objid = t.oid "
8172  "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "
8173  "WHERE (NOT t.tgisinternal OR t.tgenabled != pt.tgenabled) "
8174  "ORDER BY t.tgrelid, t.tgname",
8175  tbloids->data);
8176  }
8177  else
8178  {
8179  /* See above about pretty=true in pg_get_triggerdef */
8180  appendPQExpBuffer(query,
8181  "SELECT t.tgrelid, t.tgname, "
8182  "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
8183  "t.tgenabled, false as tgispartition, "
8184  "t.tableoid, t.oid "
8185  "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8186  "JOIN pg_catalog.pg_trigger t ON (src.tbloid = t.tgrelid) "
8187  "WHERE NOT tgisinternal "
8188  "ORDER BY t.tgrelid, t.tgname",
8189  tbloids->data);
8190  }
8191 
8192  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8193 
8194  ntups = PQntuples(res);
8195 
8196  i_tableoid = PQfnumber(res, "tableoid");
8197  i_oid = PQfnumber(res, "oid");
8198  i_tgrelid = PQfnumber(res, "tgrelid");
8199  i_tgname = PQfnumber(res, "tgname");
8200  i_tgenabled = PQfnumber(res, "tgenabled");
8201  i_tgispartition = PQfnumber(res, "tgispartition");
8202  i_tgdef = PQfnumber(res, "tgdef");
8203 
8204  tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
8205 
8206  /*
8207  * Outer loop iterates once per table, not once per row. Incrementing of
8208  * j is handled by the inner loop.
8209  */
8210  curtblindx = -1;
8211  for (int j = 0; j < ntups;)
8212  {
8213  Oid tgrelid = atooid(PQgetvalue(res, j, i_tgrelid));
8214  TableInfo *tbinfo = NULL;
8215  int numtrigs;
8216 
8217  /* Count rows for this table */
8218  for (numtrigs = 1; numtrigs < ntups - j; numtrigs++)
8219  if (atooid(PQgetvalue(res, j + numtrigs, i_tgrelid)) != tgrelid)
8220  break;
8221 
8222  /*
8223  * Locate the associated TableInfo; we rely on tblinfo[] being in OID
8224  * order.
8225  */
8226  while (++curtblindx < numTables)
8227  {
8228  tbinfo = &tblinfo[curtblindx];
8229  if (tbinfo->dobj.catId.oid == tgrelid)
8230  break;
8231  }
8232  if (curtblindx >= numTables)
8233  pg_fatal("unrecognized table OID %u", tgrelid);
8234 
8235  /* Save data for this table */
8236  tbinfo->triggers = tginfo + j;
8237  tbinfo->numTriggers = numtrigs;
8238 
8239  for (int c = 0; c < numtrigs; c++, j++)
8240  {
8241  tginfo[j].dobj.objType = DO_TRIGGER;
8242  tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
8243  tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
8244  AssignDumpId(&tginfo[j].dobj);
8245  tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
8246  tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
8247  tginfo[j].tgtable = tbinfo;
8248  tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
8249  tginfo[j].tgispartition = *(PQgetvalue(res, j, i_tgispartition)) == 't';
8250  tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
8251  }
8252  }
8253 
8254  PQclear(res);
8255 
8256  destroyPQExpBuffer(query);
8257  destroyPQExpBuffer(tbloids);
8258 }
8259 
8260 /*
8261  * getEventTriggers
8262  * get information about event triggers
8263  */
8264 void
8266 {
8267  int i;
8268  PQExpBuffer query;
8269  PGresult *res;
8270  EventTriggerInfo *evtinfo;
8271  int i_tableoid,
8272  i_oid,
8273  i_evtname,
8274  i_evtevent,
8275  i_evtowner,
8276  i_evttags,
8277  i_evtfname,
8278  i_evtenabled;
8279  int ntups;
8280 
8281  /* Before 9.3, there are no event triggers */
8282  if (fout->remoteVersion < 90300)
8283  return;
8284 
8285  query = createPQExpBuffer();
8286 
8287  appendPQExpBufferStr(query,
8288  "SELECT e.tableoid, e.oid, evtname, evtenabled, "
8289  "evtevent, evtowner, "
8290  "array_to_string(array("
8291  "select quote_literal(x) "
8292  " from unnest(evttags) as t(x)), ', ') as evttags, "
8293  "e.evtfoid::regproc as evtfname "
8294  "FROM pg_event_trigger e "
8295  "ORDER BY e.oid");
8296 
8297  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8298 
8299  ntups = PQntuples(res);
8300 
8301  evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
8302 
8303  i_tableoid = PQfnumber(res, "tableoid");
8304  i_oid = PQfnumber(res, "oid");
8305  i_evtname = PQfnumber(res, "evtname");
8306  i_evtevent = PQfnumber(res, "evtevent");
8307  i_evtowner = PQfnumber(res, "evtowner");
8308  i_evttags = PQfnumber(res, "evttags");
8309  i_evtfname = PQfnumber(res, "evtfname");
8310  i_evtenabled = PQfnumber(res, "evtenabled");
8311 
8312  for (i = 0; i < ntups; i++)
8313  {
8314  evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
8315  evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8316  evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8317  AssignDumpId(&evtinfo[i].dobj);
8318  evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
8319  evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
8320  evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
8321  evtinfo[i].evtowner = getRoleName(PQgetvalue(res, i, i_evtowner));
8322  evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
8323  evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
8324  evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
8325 
8326  /* Decide whether we want to dump it */
8327  selectDumpableObject(&(evtinfo[i].dobj), fout);
8328  }
8329 
8330  PQclear(res);
8331 
8332  destroyPQExpBuffer(query);
8333 }
8334 
8335 /*
8336  * getProcLangs
8337  * get basic information about every procedural language in the system
8338  *
8339  * NB: this must run after getFuncs() because we assume we can do
8340  * findFuncByOid().
8341  */
8342 void
8344 {
8345  PGresult *res;
8346  int ntups;
8347  int i;
8348  PQExpBuffer query = createPQExpBuffer();
8349  ProcLangInfo *planginfo;
8350  int i_tableoid;
8351  int i_oid;
8352  int i_lanname;
8353  int i_lanpltrusted;
8354  int i_lanplcallfoid;
8355  int i_laninline;
8356  int i_lanvalidator;
8357  int i_lanacl;
8358  int i_acldefault;
8359  int i_lanowner;
8360 
8361  appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8362  "lanname, lanpltrusted, lanplcallfoid, "
8363  "laninline, lanvalidator, "
8364  "lanacl, "
8365  "acldefault('l', lanowner) AS acldefault, "
8366  "lanowner "
8367  "FROM pg_language "
8368  "WHERE lanispl "
8369  "ORDER BY oid");
8370 
8371  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8372 
8373  ntups = PQntuples(res);
8374 
8375  planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
8376 
8377  i_tableoid = PQfnumber(res, "tableoid");
8378  i_oid = PQfnumber(res, "oid");
8379  i_lanname = PQfnumber(res, "lanname");
8380  i_lanpltrusted = PQfnumber(res, "lanpltrusted");
8381  i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
8382  i_laninline = PQfnumber(res, "laninline");
8383  i_lanvalidator = PQfnumber(res, "lanvalidator");
8384  i_lanacl = PQfnumber(res, "lanacl");
8385  i_acldefault = PQfnumber(res, "acldefault");
8386  i_lanowner = PQfnumber(res, "lanowner");
8387 
8388  for (i = 0; i < ntups; i++)
8389  {
8390  planginfo[i].dobj.objType = DO_PROCLANG;
8391  planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8392  planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8393  AssignDumpId(&planginfo[i].dobj);
8394 
8395  planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
8396  planginfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_lanacl));
8397  planginfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
8398  planginfo[i].dacl.privtype = 0;
8399  planginfo[i].dacl.initprivs = NULL;
8400  planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
8401  planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
8402  planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
8403  planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
8404  planginfo[i].lanowner = getRoleName(PQgetvalue(res, i, i_lanowner));
8405 
8406  /* Decide whether we want to dump it */
8407  selectDumpableProcLang(&(planginfo[i]), fout);
8408 
8409  /* Mark whether language has an ACL */
8410  if (!PQgetisnull(res, i, i_lanacl))
8411  planginfo[i].dobj.components |= DUMP_COMPONENT_ACL;
8412  }
8413 
8414  PQclear(res);
8415 
8416  destroyPQExpBuffer(query);
8417 }
8418 
8419 /*
8420  * getCasts
8421  * get basic information about most casts in the system
8422  *
8423  * Skip casts from a range to its multirange, since we'll create those
8424  * automatically.
8425  */
8426 void
8428 {
8429  PGresult *res;
8430  int ntups;
8431  int i;
8432  PQExpBuffer query = createPQExpBuffer();
8433  CastInfo *castinfo;
8434  int i_tableoid;
8435  int i_oid;
8436  int i_castsource;
8437  int i_casttarget;
8438  int i_castfunc;
8439  int i_castcontext;
8440  int i_castmethod;
8441 
8442  if (fout->remoteVersion >= 140000)
8443  {
8444  appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8445  "castsource, casttarget, castfunc, castcontext, "
8446  "castmethod "
8447  "FROM pg_cast c "
8448  "WHERE NOT EXISTS ( "
8449  "SELECT 1 FROM pg_range r "
8450  "WHERE c.castsource = r.rngtypid "
8451  "AND c.casttarget = r.rngmultitypid "
8452  ") "
8453  "ORDER BY 3,4");
8454  }
8455  else
8456  {
8457  appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8458  "castsource, casttarget, castfunc, castcontext, "
8459  "castmethod "
8460  "FROM pg_cast ORDER BY 3,4");
8461  }
8462 
8463  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8464 
8465  ntups = PQntuples(res);
8466 
8467  castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
8468 
8469  i_tableoid = PQfnumber(res, "tableoid");
8470  i_oid = PQfnumber(res, "oid");
8471  i_castsource = PQfnumber(res, "castsource");
8472  i_casttarget = PQfnumber(res, "casttarget");
8473  i_castfunc = PQfnumber(res, "castfunc");
8474  i_castcontext = PQfnumber(res, "castcontext");
8475  i_castmethod = PQfnumber(res, "castmethod");
8476 
8477  for (i = 0; i < ntups; i++)
8478  {
8479  PQExpBufferData namebuf;
8480  TypeInfo *sTypeInfo;
8481  TypeInfo *tTypeInfo;
8482 
8483  castinfo[i].dobj.objType = DO_CAST;
8484  castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8485  castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8486  AssignDumpId(&castinfo[i].dobj);
8487  castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
8488  castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
8489  castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
8490  castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
8491  castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
8492 
8493  /*
8494  * Try to name cast as concatenation of typnames. This is only used
8495  * for purposes of sorting. If we fail to find either type, the name
8496  * will be an empty string.
8497  */
8498  initPQExpBuffer(&namebuf);
8499  sTypeInfo = findTypeByOid(castinfo[i].castsource);
8500  tTypeInfo = findTypeByOid(castinfo[i].casttarget);
8501  if (sTypeInfo && tTypeInfo)
8502  appendPQExpBuffer(&namebuf, "%s %s",
8503  sTypeInfo->dobj.name, tTypeInfo->dobj.name);
8504  castinfo[i].dobj.name = namebuf.data;
8505 
8506  /* Decide whether we want to dump it */
8507  selectDumpableCast(&(castinfo[i]), fout);
8508  }
8509 
8510  PQclear(res);
8511 
8512  destroyPQExpBuffer(query);
8513 }
8514 
8515 static char *
8517 {
8518  PQExpBuffer query;
8519  PGresult *res;
8520  char *lanname;
8521 
8522  query = createPQExpBuffer();
8523  appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
8524  res = ExecuteSqlQueryForSingleRow(fout, query->data);
8525  lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
8526  destroyPQExpBuffer(query);
8527  PQclear(res);
8528 
8529  return lanname;
8530 }
8531 
8532 /*
8533  * getTransforms
8534  * get basic information about every transform in the system
8535  */
8536 void
8538 {
8539  PGresult *res;
8540  int ntups;
8541  int i;
8542  PQExpBuffer query;
8543  TransformInfo *transforminfo;
8544  int i_tableoid;
8545  int i_oid;
8546  int i_trftype;
8547  int i_trflang;
8548  int i_trffromsql;
8549  int i_trftosql;
8550 
8551  /* Transforms didn't exist pre-9.5 */
8552  if (fout->remoteVersion < 90500)
8553  return;
8554 
8555  query = createPQExpBuffer();
8556 
8557  appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8558  "trftype, trflang, trffromsql::oid, trftosql::oid "
8559  "FROM pg_transform "
8560  "ORDER BY 3,4");
8561 
8562  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8563 
8564  ntups = PQntuples(res);
8565 
8566  transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
8567 
8568  i_tableoid = PQfnumber(res, "tableoid");
8569  i_oid = PQfnumber(res, "oid");
8570  i_trftype = PQfnumber(res, "trftype");
8571  i_trflang = PQfnumber(res, "trflang");
8572  i_trffromsql = PQfnumber(res, "trffromsql");
8573  i_trftosql = PQfnumber(res, "trftosql");
8574 
8575  for (i = 0; i < ntups; i++)
8576  {
8577  PQExpBufferData namebuf;
8578  TypeInfo *typeInfo;
8579  char *lanname;
8580 
8581  transforminfo[i].dobj.objType = DO_TRANSFORM;
8582  transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8583  transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8584  AssignDumpId(&transforminfo[i].dobj);
8585  transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
8586  transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
8587  transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
8588  transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
8589 
8590  /*
8591  * Try to name transform as concatenation of type and language name.
8592  * This is only used for purposes of sorting. If we fail to find
8593  * either, the name will be an empty string.
8594  */
8595  initPQExpBuffer(&namebuf);
8596  typeInfo = findTypeByOid(transforminfo[i].trftype);
8597  lanname = get_language_name(fout, transforminfo[i].trflang);
8598  if (typeInfo && lanname)
8599  appendPQExpBuffer(&namebuf, "%s %s",
8600  typeInfo->dobj.name, lanname);
8601  transforminfo[i].dobj.name = namebuf.data;
8602  free(lanname);
8603 
8604  /* Decide whether we want to dump it */
8605  selectDumpableObject(&(transforminfo[i].dobj), fout);
8606  }
8607 
8608  PQclear(res);
8609 
8610  destroyPQExpBuffer(query);
8611 }
8612 
8613 /*
8614  * getTableAttrs -
8615  * for each interesting table, read info about its attributes
8616  * (names, types, default values, CHECK constraints, etc)
8617  *
8618  * modifies tblinfo
8619  */
8620 void
8621 getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
8622 {
8623  DumpOptions *dopt = fout->dopt;
8625  PQExpBuffer tbloids = createPQExpBuffer();
8626  PQExpBuffer checkoids = createPQExpBuffer();
8627  PGresult *res;
8628  int ntups;
8629  int curtblindx;
8630  int i_attrelid;
8631  int i_attnum;
8632  int i_attname;
8633  int i_atttypname;
8634  int i_attstattarget;
8635  int i_attstorage;
8636  int i_typstorage;
8637  int i_attidentity;
8638  int i_attgenerated;
8639  int i_attisdropped;
8640  int i_attlen;
8641  int i_attalign;
8642  int i_attislocal;
8643  int i_attnotnull;
8644  int i_attoptions;
8645  int i_attcollation;
8646  int i_attcompression;
8647  int i_attfdwoptions;
8648  int i_attmissingval;
8649  int i_atthasdef;
8650 
8651  /*
8652  * We want to perform just one query against pg_attribute, and then just
8653  * one against pg_attrdef (for DEFAULTs) and one against pg_constraint
8654  * (for CHECK constraints). However, we mustn't try to select every row
8655  * of those catalogs and then sort it out on the client side, because some
8656  * of the server-side functions we need would be unsafe to apply to tables
8657  * we don't have lock on. Hence, we build an array of the OIDs of tables
8658  * we care about (and now have lock on!), and use a WHERE clause to
8659  * constrain which rows are selected.
8660  */
8661  appendPQExpBufferChar(tbloids, '{');
8662  appendPQExpBufferChar(checkoids, '{');
8663  for (int i = 0; i < numTables; i++)
8664  {
8665  TableInfo *tbinfo = &tblinfo[i];
8666 
8667  /* Don't bother to collect info for sequences */
8668  if (tbinfo->relkind == RELKIND_SEQUENCE)
8669  continue;
8670 
8671  /* Don't bother with uninteresting tables, either */
8672  if (!tbinfo->interesting)
8673  continue;
8674 
8675  /* OK, we need info for this table */
8676  if (tbloids->len > 1) /* do we have more than the '{'? */
8677  appendPQExpBufferChar(tbloids, ',');
8678  appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
8679 
8680  if (tbinfo->ncheck > 0)
8681  {
8682  /* Also make a list of the ones with check constraints */
8683  if (checkoids->len > 1) /* do we have more than the '{'? */
8684  appendPQExpBufferChar(checkoids, ',');
8685  appendPQExpBuffer(checkoids, "%u", tbinfo->dobj.catId.oid);
8686  }
8687  }
8688  appendPQExpBufferChar(tbloids, '}');
8689  appendPQExpBufferChar(checkoids, '}');
8690 
8691  /*
8692  * Find all the user attributes and their types.
8693  *
8694  * Since we only want to dump COLLATE clauses for attributes whose
8695  * collation is different from their type's default, we use a CASE here to
8696  * suppress uninteresting attcollations cheaply.
8697  */
8699  "SELECT\n"
8700  "a.attrelid,\n"
8701  "a.attnum,\n"
8702  "a.attname,\n"
8703  "a.attstattarget,\n"
8704  "a.attstorage,\n"
8705  "t.typstorage,\n"
8706  "a.attnotnull,\n"
8707  "a.atthasdef,\n"
8708  "a.attisdropped,\n"
8709  "a.attlen,\n"
8710  "a.attalign,\n"
8711  "a.attislocal,\n"
8712  "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n"
8713  "array_to_string(a.attoptions, ', ') AS attoptions,\n"
8714  "CASE WHEN a.attcollation <> t.typcollation "
8715  "THEN a.attcollation ELSE 0 END AS attcollation,\n"
8716  "pg_catalog.array_to_string(ARRAY("
8717  "SELECT pg_catalog.quote_ident(option_name) || "
8718  "' ' || pg_catalog.quote_literal(option_value) "
8719  "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
8720  "ORDER BY option_name"
8721  "), E',\n ') AS attfdwoptions,\n");
8722 
8723  if (fout->remoteVersion >= 140000)
8725  "a.attcompression AS attcompression,\n");
8726  else
8728  "'' AS attcompression,\n");
8729 
8730  if (fout->remoteVersion >= 100000)
8732  "a.attidentity,\n");
8733  else
8735  "'' AS attidentity,\n");
8736 
8737  if (fout->remoteVersion >= 110000)
8739  "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
8740  "THEN a.attmissingval ELSE null END AS attmissingval,\n");
8741  else
8743  "NULL AS attmissingval,\n");
8744 
8745  if (fout->remoteVersion >= 120000)
8747  "a.attgenerated\n");
8748  else
8750  "'' AS attgenerated\n");
8751 
8752  /* need left join to pg_type to not fail on dropped columns ... */
8754  "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8755  "JOIN pg_catalog.pg_attribute a ON (src.tbloid = a.attrelid) "
8756  "LEFT JOIN pg_catalog.pg_type t "
8757  "ON (a.atttypid = t.oid)\n"
8758  "WHERE a.attnum > 0::pg_catalog.int2\n"
8759  "ORDER BY a.attrelid, a.attnum",
8760  tbloids->data);
8761 
8762  res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8763 
8764  ntups = PQntuples(res);
8765 
8766  i_attrelid = PQfnumber(res, "attrelid");
8767  i_attnum = PQfnumber(res, "attnum");
8768  i_attname = PQfnumber(res, "attname");
8769  i_atttypname = PQfnumber(res, "atttypname");
8770  i_attstattarget = PQfnumber(res, "attstattarget");
8771  i_attstorage = PQfnumber(res, "attstorage");
8772  i_typstorage = PQfnumber(res, "typstorage");
8773  i_attidentity = PQfnumber(res, "attidentity");
8774  i_attgenerated = PQfnumber(res, "attgenerated");
8775  i_attisdropped = PQfnumber(res, "attisdropped");
8776  i_attlen = PQfnumber(res, "attlen");
8777  i_attalign = PQfnumber(res, "attalign");
8778  i_attislocal = PQfnumber(res, "attislocal");
8779  i_attnotnull = PQfnumber(res, "attnotnull");
8780  i_attoptions = PQfnumber(res, "attoptions");
8781  i_attcollation = PQfnumber(res, "attcollation");
8782  i_attcompression = PQfnumber(res, "attcompression");
8783  i_attfdwoptions = PQfnumber(res, "attfdwoptions");
8784  i_attmissingval = PQfnumber(res, "attmissingval");
8785  i_atthasdef = PQfnumber(res, "atthasdef");
8786 
8787  /* Within the next loop, we'll accumulate OIDs of tables with defaults */
8788  resetPQExpBuffer(tbloids);
8789  appendPQExpBufferChar(tbloids, '{');
8790 
8791  /*
8792  * Outer loop iterates once per table, not once per row. Incrementing of
8793  * r is handled by the inner loop.
8794  */
8795  curtblindx = -1;
8796  for (int r = 0; r < ntups;)
8797  {
8798  Oid attrelid = atooid(PQgetvalue(res, r, i_attrelid));
8799  TableInfo *tbinfo = NULL;
8800  int numatts;
8801  bool hasdefaults;
8802 
8803  /* Count rows for this table */
8804  for (numatts = 1; numatts < ntups - r; numatts++)
8805  if (atooid(PQgetvalue(res, r + numatts, i_attrelid)) != attrelid)
8806  break;
8807 
8808  /*
8809  * Locate the associated TableInfo; we rely on tblinfo[] being in OID
8810  * order.
8811  */
8812  while (++curtblindx < numTables)
8813  {
8814  tbinfo = &tblinfo[curtblindx];
8815  if (tbinfo->dobj.catId.oid == attrelid)
8816  break;
8817  }
8818  if (curtblindx >= numTables)
8819  pg_fatal("unrecognized table OID %u", attrelid);
8820  /* cross-check that we only got requested tables */
8821  if (tbinfo->relkind == RELKIND_SEQUENCE ||
8822  !tbinfo->interesting)
8823  pg_fatal("unexpected column data for table \"%s\"",
8824  tbinfo->dobj.name);
8825 
8826  /* Save data for this table */
8827  tbinfo->numatts = numatts;
8828  tbinfo->attnames = (char **) pg_malloc(numatts * sizeof(char *));
8829  tbinfo->atttypnames = (char **) pg_malloc(numatts * sizeof(char *));
8830  tbinfo->attstattarget = (int *) pg_malloc(numatts * sizeof(int));
8831  tbinfo->attstorage = (char *) pg_malloc(numatts * sizeof(char));
8832  tbinfo->typstorage = (char *) pg_malloc(numatts * sizeof(char));
8833  tbinfo->attidentity = (char *) pg_malloc(numatts * sizeof(char));
8834  tbinfo->attgenerated = (char *) pg_malloc(numatts * sizeof(char));
8835  tbinfo->attisdropped = (bool *) pg_malloc(numatts * sizeof(bool));
8836  tbinfo->attlen = (int *) pg_malloc(numatts * sizeof(int));
8837  tbinfo->attalign = (char *) pg_malloc(numatts * sizeof(char));
8838  tbinfo->attislocal = (bool *) pg_malloc(numatts * sizeof(bool));
8839  tbinfo->attoptions = (char **) pg_malloc(numatts * sizeof(char *));
8840  tbinfo->attcollation = (Oid *) pg_malloc(numatts * sizeof(Oid));
8841  tbinfo->attcompression = (char *) pg_malloc(numatts * sizeof(char));
8842  tbinfo->attfdwoptions = (char **) pg_malloc(numatts * sizeof(char *));
8843  tbinfo->attmissingval = (char **) pg_malloc(numatts * sizeof(char *));
8844  tbinfo->notnull = (bool *) pg_malloc(numatts * sizeof(bool));
8845  tbinfo->inhNotNull = (bool *) pg_malloc(numatts * sizeof(bool));
8846  tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(numatts * sizeof(AttrDefInfo *));
8847  hasdefaults = false;
8848 
8849  for (int j = 0; j < numatts; j++, r++)
8850  {
8851  if (j + 1 != atoi(PQgetvalue(res, r, i_attnum)))
8852  pg_fatal("invalid column numbering in table \"%s\"",
8853  tbinfo->dobj.name);
8854  tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, r, i_attname));
8855  tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, r, i_atttypname));
8856  if (PQgetisnull(res, r, i_attstattarget))
8857  tbinfo->attstattarget[j] = -1;
8858  else
8859  tbinfo->attstattarget[j] = atoi(PQgetvalue(res, r, i_attstattarget));
8860  tbinfo->attstorage[j] = *(PQgetvalue(res, r, i_attstorage));
8861  tbinfo->typstorage[j] = *(PQgetvalue(res, r, i_typstorage));
8862  tbinfo->attidentity[j] = *(PQgetvalue(res, r, i_attidentity));
8863  tbinfo->attgenerated[j] = *(PQgetvalue(res, r, i_attgenerated));
8864  tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
8865  tbinfo->attisdropped[j] = (PQgetvalue(res, r, i_attisdropped)[0] == 't');
8866  tbinfo->attlen[j] = atoi(PQgetvalue(res, r, i_attlen));
8867  tbinfo->attalign[j] = *(PQgetvalue(res, r, i_attalign));
8868  tbinfo->attislocal[j] = (PQgetvalue(res, r, i_attislocal)[0] == 't');
8869  tbinfo->notnull[j] = (PQgetvalue(res, r, i_attnotnull)[0] == 't');
8870  tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, r, i_attoptions));
8871  tbinfo->attcollation[j] = atooid(PQgetvalue(res, r, i_attcollation));
8872  tbinfo->attcompression[j] = *(PQgetvalue(res, r, i_attcompression));
8873  tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, r, i_attfdwoptions));
8874  tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, r, i_attmissingval));
8875  tbinfo->attrdefs[j] = NULL; /* fix below */
8876  if (PQgetvalue(res, r, i_atthasdef)[0] == 't')
8877  hasdefaults = true;
8878  /* these flags will be set in flagInhAttrs() */
8879  tbinfo->inhNotNull[j] = false;
8880  }
8881 
8882  if (hasdefaults)
8883  {
8884  /* Collect OIDs of interesting tables that have defaults */
8885  if (tbloids->len > 1) /* do we have more than the '{'? */
8886  appendPQExpBufferChar(tbloids, ',');
8887  appendPQExpBuffer(tbloids, "%u", tbinfo->dobj.catId.oid);
8888  }
8889  }
8890 
8891  PQclear(res);
8892 
8893  /*
8894  * Now get info about column defaults. This is skipped for a data-only
8895  * dump, as it is only needed for table schemas.
8896  */
8897  if (!dopt->dataOnly && tbloids->len > 1)
8898  {
8899  AttrDefInfo *attrdefs;
8900  int numDefaults;
8901  TableInfo *tbinfo = NULL;
8902 
8903  pg_log_info("finding table default expressions");
8904 
8905  appendPQExpBufferChar(tbloids, '}');
8906 
8907  printfPQExpBuffer(q, "SELECT a.tableoid, a.oid, adrelid, adnum, "
8908  "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc\n"
8909  "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
8910  "JOIN pg_catalog.pg_attrdef a ON (src.tbloid = a.adrelid)\n"
8911  "ORDER BY a.adrelid, a.adnum",
8912  tbloids->data);
8913 
8914  res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8915 
8916  numDefaults = PQntuples(res);
8917  attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
8918 
8919  curtblindx = -1;
8920  for (int j = 0; j < numDefaults; j++)
8921  {
8922  Oid adtableoid = atooid(PQgetvalue(res, j, 0));
8923  Oid adoid = atooid(PQgetvalue(res, j, 1));
8924  Oid adrelid = atooid(PQgetvalue(res, j, 2));
8925  int adnum = atoi(PQgetvalue(res, j, 3));
8926  char *adsrc = PQgetvalue(res, j, 4);
8927 
8928  /*
8929  * Locate the associated TableInfo; we rely on tblinfo[] being in
8930  * OID order.
8931  */
8932  if (tbinfo == NULL || tbinfo->dobj.catId.oid != adrelid)
8933  {
8934  while (++curtblindx < numTables)
8935  {
8936  tbinfo = &tblinfo[curtblindx];
8937  if (tbinfo->dobj.catId.oid == adrelid)
8938  break;
8939  }
8940  if (curtblindx >= numTables)
8941  pg_fatal("unrecognized table OID %u", adrelid);
8942  }
8943 
8944  if (adnum <= 0 || adnum > tbinfo->numatts)
8945  pg_fatal("invalid adnum value %d for table \"%s\"",
8946  adnum, tbinfo->dobj.name);
8947 
8948  /*
8949  * dropped columns shouldn't have defaults, but just in case,
8950  * ignore 'em
8951  */
8952  if (tbinfo->attisdropped[adnum - 1])
8953  continue;
8954 
8955  attrdefs[j].dobj.objType = DO_ATTRDEF;
8956  attrdefs[j].dobj.catId.tableoid = adtableoid;
8957  attrdefs[j].dobj.catId.oid = adoid;
8958  AssignDumpId(&attrdefs[j].dobj);
8959  attrdefs[j].adtable = tbinfo;
8960  attrdefs[j].adnum = adnum;
8961  attrdefs[j].adef_expr = pg_strdup(adsrc);
8962 
8963  attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
8964  attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
8965 
8966  attrdefs[j].dobj.dump = tbinfo->dobj.dump;
8967 
8968  /*
8969  * Figure out whether the default/generation expression should be
8970  * dumped as part of the main CREATE TABLE (or similar) command or
8971  * as a separate ALTER TABLE (or similar) command. The preference
8972  * is to put it into the CREATE command, but in some cases that's
8973  * not possible.
8974  */
8975  if (tbinfo->attgenerated[adnum - 1])
8976  {
8977  /*
8978  * Column generation expressions cannot be dumped separately,
8979  * because there is no syntax for it. By setting separate to
8980  * false here we prevent the "default" from being processed as
8981  * its own dumpable object. Later, flagInhAttrs() will mark
8982  * it as not to be dumped at all, if possible (that is, if it
8983  * can be inherited from a parent).
8984  */
8985  attrdefs[j].separate = false;
8986  }
8987  else if (tbinfo->relkind == RELKIND_VIEW)
8988  {
8989  /*
8990  * Defaults on a VIEW must always be dumped as separate ALTER
8991  * TABLE commands.
8992  */
8993  attrdefs[j].separate = true;
8994  }
8995  else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
8996  {
8997  /* column will be suppressed, print default separately */
8998  attrdefs[j].separate = true;
8999  }
9000  else
9001  {
9002  attrdefs[j].separate = false;
9003  }
9004 
9005  if (!attrdefs[j].separate)
9006  {
9007  /*
9008  * Mark the default as needing to appear before the table, so
9009  * that any dependencies it has must be emitted before the
9010  * CREATE TABLE. If this is not possible, we'll change to
9011  * "separate" mode while sorting dependencies.
9012  */
9013  addObjectDependency(&tbinfo->dobj,
9014  attrdefs[j].dobj.dumpId);
9015  }
9016 
9017  tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
9018  }
9019 
9020  PQclear(res);
9021  }
9022 
9023  /*
9024  * Get info about table CHECK constraints. This is skipped for a
9025  * data-only dump, as it is only needed for table schemas.
9026  */
9027  if (!dopt->dataOnly && checkoids->len > 2)
9028  {
9029  ConstraintInfo *constrs;
9030  int numConstrs;
9031  int i_tableoid;
9032  int i_oid;
9033  int i_conrelid;
9034  int i_conname;
9035  int i_consrc;
9036  int i_conislocal;
9037  int i_convalidated;
9038 
9039  pg_log_info("finding table check constraints");
9040 
9041  resetPQExpBuffer(q);
9043  "SELECT c.tableoid, c.oid, conrelid, conname, "
9044  "pg_catalog.pg_get_constraintdef(c.oid) AS consrc, "
9045  "conislocal, convalidated "
9046  "FROM unnest('%s'::pg_catalog.oid[]) AS src(tbloid)\n"
9047  "JOIN pg_catalog.pg_constraint c ON (src.tbloid = c.conrelid)\n"
9048  "WHERE contype = 'c' "
9049  "ORDER BY c.conrelid, c.conname",
9050  checkoids->data);
9051 
9052  res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
9053 
9054  numConstrs = PQntuples(res);
9055  constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
9056 
9057  i_tableoid = PQfnumber(res, "tableoid");
9058  i_oid = PQfnumber(res, "oid");
9059  i_conrelid = PQfnumber(res, "conrelid");
9060  i_conname = PQfnumber(res, "conname");
9061  i_consrc = PQfnumber(res, "consrc");
9062  i_conislocal = PQfnumber(res, "conislocal");
9063  i_convalidated = PQfnumber(res, "convalidated");
9064 
9065  /* As above, this loop iterates once per table, not once per row */
9066  curtblindx = -1;
9067  for (int j = 0; j < numConstrs;)
9068  {
9069  Oid conrelid = atooid(PQgetvalue(res, j, i_conrelid));
9070  TableInfo *tbinfo = NULL;
9071  int numcons;
9072 
9073  /* Count rows for this table */
9074  for (numcons = 1; numcons < numConstrs - j; numcons++)
9075  if (atooid(PQgetvalue(res, j + numcons, i_conrelid)) != conrelid)
9076  break;
9077 
9078  /*
9079  * Locate the associated TableInfo; we rely on tblinfo[] being in
9080  * OID order.
9081  */
9082  while (++curtblindx < numTables)
9083  {
9084  tbinfo = &tblinfo[curtblindx];
9085  if (tbinfo->dobj.catId.oid == conrelid)
9086  break;
9087  }
9088  if (curtblindx >= numTables)
9089  pg_fatal("unrecognized table OID %u", conrelid);
9090 
9091  if (numcons != tbinfo->ncheck)
9092  {
9093  pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
9094  "expected %d check constraints on table \"%s\" but found %d",
9095  tbinfo->ncheck),
9096  tbinfo->ncheck, tbinfo->dobj.name, numcons);
9097  pg_log_error_hint("The system catalogs might be corrupted.");
9098  exit_nicely(1);
9099  }
9100 
9101  tbinfo->checkexprs = constrs + j;
9102 
9103  for (int c = 0; c < numcons; c++, j++)
9104  {
9105  bool validated = PQgetvalue(res, j, i_convalidated)[0] == 't';
9106 
9107  constrs[j].dobj.objType = DO_CONSTRAINT;
9108  constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
9109  constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
9110  AssignDumpId(&constrs[j].dobj);
9111  constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
9112  constrs[j].dobj.namespace = tbinfo->dobj.namespace;
9113  constrs[j].contable = tbinfo;
9114  constrs[j].condomain = NULL;
9115  constrs[j].contype = 'c';
9116  constrs[j].condef = pg_strdup(PQgetvalue(res, j, i_consrc));
9117  constrs[j].confrelid = InvalidOid;
9118  constrs[j].conindex = 0;
9119  constrs[j].condeferrable = false;
9120  constrs[j].condeferred = false;
9121  constrs[j].conislocal = (PQgetvalue(res, j, i_conislocal)[0] == 't');
9122 
9123  /*
9124  * An unvalidated constraint needs to be dumped separately, so
9125  * that potentially-violating existing data is loaded before
9126  * the constraint.
9127  */
9128  constrs[j].separate = !validated;
9129 
9130  constrs[j].dobj.dump = tbinfo->dobj.dump;
9131 
9132  /*
9133  * Mark the constraint as needing to appear before the table
9134  * --- this is so that any other dependencies of the
9135  * constraint will be emitted before we try to create the
9136  * table. If the constraint is to be dumped separately, it
9137  * will be dumped after data is loaded anyway, so don't do it.
9138  * (There's an automatic dependency in the opposite direction
9139  * anyway, so don't need to add one manually here.)
9140  */
9141  if (!constrs[j].separate)
9142  addObjectDependency(&tbinfo->dobj,
9143  constrs[j].dobj.dumpId);
9144 
9145  /*
9146  * We will detect later whether the constraint must be split
9147  * out from the table definition.
9148  */
9149  }
9150  }
9151 
9152  PQclear(res);
9153  }
9154 
9155  destroyPQExpBuffer(q);
9156  destroyPQExpBuffer(tbloids);
9157  destroyPQExpBuffer(checkoids);
9158 }
9159 
9160 /*
9161  * Test whether a column should be printed as part of table's CREATE TABLE.
9162  * Column number is zero-based.
9163  *
9164  * Normally this is always true, but it's false for dropped columns, as well
9165  * as those that were inherited without any local definition. (If we print
9166  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
9167  * For partitions, it's always true, because we want the partitions to be
9168  * created independently and ATTACH PARTITION used afterwards.
9169  *
9170  * In binary_upgrade mode, we must print all columns and fix the attislocal/
9171  * attisdropped state later, so as to keep control of the physical column
9172  * order.
9173  *
9174  * This function exists because there are scattered nonobvious places that
9175  * must be kept in sync with this decision.
9176  */
9177 bool
9178 shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
9179 {
9180  if (dopt->binary_upgrade)
9181  return true;
9182  if (tbinfo->attisdropped[colno])
9183  return false;
9184  return (tbinfo->attislocal[colno] || tbinfo->ispartition);
9185 }
9186 
9187 
9188 /*
9189  * getTSParsers:
9190  * get information about all text search parsers in the system catalogs
9191  */
9192 void
9194 {
9195  PGresult *res;
9196  int ntups;
9197  int i;
9198  PQExpBuffer query;
9199  TSParserInfo *prsinfo;
9200  int i_tableoid;
9201  int i_oid;
9202  int i_prsname;
9203  int i_prsnamespace;
9204  int i_prsstart;
9205  int i_prstoken;
9206  int i_prsend;
9207  int i_prsheadline;
9208  int i_prslextype;
9209 
9210  query = createPQExpBuffer();
9211 
9212  /*
9213  * find all text search objects, including builtin ones; we filter out
9214  * system-defined objects at dump-out time.
9215  */
9216 
9217  appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
9218  "prsstart::oid, prstoken::oid, "
9219  "prsend::oid, prsheadline::oid, prslextype::oid "
9220  "FROM pg_ts_parser");
9221 
9222  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9223 
9224  ntups = PQntuples(res);
9225 
9226  prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
9227 
9228  i_tableoid = PQfnumber(res, "tableoid");
9229  i_oid = PQfnumber(res, "oid");
9230  i_prsname = PQfnumber(res, "prsname");
9231  i_prsnamespace = PQfnumber(res, "prsnamespace");
9232  i_prsstart = PQfnumber(res, "prsstart");
9233  i_prstoken = PQfnumber(res, "prstoken");
9234  i_prsend = PQfnumber(res, "prsend");
9235  i_prsheadline = PQfnumber(res, "prsheadline");
9236  i_prslextype = PQfnumber(res, "prslextype");
9237 
9238  for (i = 0; i < ntups; i++)
9239  {
9240  prsinfo[i].dobj.objType = DO_TSPARSER;
9241  prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9242  prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9243  AssignDumpId(&prsinfo[i].dobj);
9244  prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
9245  prsinfo[i].dobj.namespace =
9246  findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)));
9247  prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
9248  prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
9249  prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
9250  prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
9251  prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
9252 
9253  /* Decide whether we want to dump it */
9254  selectDumpableObject(&(prsinfo[i].dobj), fout);
9255  }
9256 
9257  PQclear(res);
9258 
9259  destroyPQExpBuffer(query);
9260 }
9261 
9262 /*
9263  * getTSDictionaries:
9264  * get information about all text search dictionaries in the system catalogs
9265  */
9266 void
9268 {
9269  PGresult *res;
9270  int ntups;
9271  int i;
9272  PQExpBuffer query;
9273  TSDictInfo *dictinfo;
9274  int i_tableoid;
9275  int i_oid;
9276  int i_dictname;
9277  int i_dictnamespace;
9278  int i_dictowner;
9279  int i_dicttemplate;
9280  int i_dictinitoption;
9281 
9282  query = createPQExpBuffer();
9283 
9284  appendPQExpBufferStr(query, "SELECT tableoid, oid, dictname, "
9285  "dictnamespace, dictowner, "
9286  "dicttemplate, dictinitoption "
9287  "FROM pg_ts_dict");
9288 
9289  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9290 
9291  ntups = PQntuples(res);
9292 
9293  dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
9294 
9295  i_tableoid = PQfnumber(res, "tableoid");
9296  i_oid = PQfnumber(res, "oid");
9297  i_dictname = PQfnumber(res, "dictname");
9298  i_dictnamespace = PQfnumber(res, "dictnamespace");
9299  i_dictowner = PQfnumber(res, "dictowner");
9300  i_dictinitoption = PQfnumber(res, "dictinitoption");
9301  i_dicttemplate = PQfnumber(res, "dicttemplate");
9302 
9303  for (i = 0; i < ntups; i++)
9304  {
9305  dictinfo[i].dobj.objType = DO_TSDICT;
9306  dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9307  dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9308  AssignDumpId(&dictinfo[i].dobj);
9309  dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
9310  dictinfo[i].dobj.namespace =
9311  findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)));
9312  dictinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_dictowner));
9313  dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
9314  if (PQgetisnull(res, i, i_dictinitoption))
9315  dictinfo[i].dictinitoption = NULL;
9316  else
9317  dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
9318 
9319  /* Decide whether we want to dump it */
9320  selectDumpableObject(&(dictinfo[i].dobj), fout);
9321  }
9322 
9323  PQclear(res);
9324 
9325  destroyPQExpBuffer(query);
9326 }
9327 
9328 /*
9329  * getTSTemplates:
9330  * get information about all text search templates in the system catalogs
9331  */
9332 void
9334 {
9335  PGresult *res;
9336  int ntups;
9337  int i;
9338  PQExpBuffer query;
9339  TSTemplateInfo *tmplinfo;
9340  int i_tableoid;
9341  int i_oid;
9342  int i_tmplname;
9343  int i_tmplnamespace;
9344  int i_tmplinit;
9345  int i_tmpllexize;
9346 
9347  query = createPQExpBuffer();
9348 
9349  appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
9350  "tmplnamespace, tmplinit::oid, tmpllexize::oid "
9351  "FROM pg_ts_template");
9352 
9353  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9354 
9355  ntups = PQntuples(res);
9356 
9357  tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
9358 
9359  i_tableoid = PQfnumber(res, "tableoid");
9360  i_oid = PQfnumber(res, "oid");
9361  i_tmplname = PQfnumber(res, "tmplname");
9362  i_tmplnamespace = PQfnumber(res, "tmplnamespace");
9363  i_tmplinit = PQfnumber(res, "tmplinit");
9364  i_tmpllexize = PQfnumber(res, "tmpllexize");
9365 
9366  for (i = 0; i < ntups; i++)
9367  {
9368  tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
9369  tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9370  tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9371  AssignDumpId(&tmplinfo[i].dobj);
9372  tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
9373  tmplinfo[i].dobj.namespace =
9374  findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)));
9375  tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
9376  tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
9377 
9378  /* Decide whether we want to dump it */
9379  selectDumpableObject(&(tmplinfo[i].dobj), fout);
9380  }
9381 
9382  PQclear(res);
9383 
9384  destroyPQExpBuffer(query);
9385 }
9386 
9387 /*
9388  * getTSConfigurations:
9389  * get information about all text search configurations
9390  */
9391 void
9393 {
9394  PGresult *res;
9395  int ntups;
9396  int i;
9397  PQExpBuffer query;
9398  TSConfigInfo *cfginfo;
9399  int i_tableoid;
9400  int i_oid;
9401  int i_cfgname;
9402  int i_cfgnamespace;
9403  int i_cfgowner;
9404  int i_cfgparser;
9405 
9406  query = createPQExpBuffer();
9407 
9408  appendPQExpBufferStr(query, "SELECT tableoid, oid, cfgname, "
9409  "cfgnamespace, cfgowner, cfgparser "
9410  "FROM pg_ts_config");
9411 
9412  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9413 
9414  ntups = PQntuples(res);
9415 
9416  cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
9417 
9418  i_tableoid = PQfnumber(res, "tableoid");
9419  i_oid = PQfnumber(res, "oid");
9420  i_cfgname = PQfnumber(res, "cfgname");
9421  i_cfgnamespace = PQfnumber(res, "cfgnamespace");
9422  i_cfgowner = PQfnumber(res, "cfgowner");
9423  i_cfgparser = PQfnumber(res, "cfgparser");
9424 
9425  for (i = 0; i < ntups; i++)
9426  {
9427  cfginfo[i].dobj.objType = DO_TSCONFIG;
9428  cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9429  cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9430  AssignDumpId(&cfginfo[i].dobj);
9431  cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
9432  cfginfo[i].dobj.namespace =
9433  findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)));
9434  cfginfo[i].rolname = getRoleName(PQgetvalue(res, i, i_cfgowner));
9435  cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
9436 
9437  /* Decide whether we want to dump it */
9438  selectDumpableObject(&(cfginfo[i].dobj), fout);
9439  }
9440 
9441  PQclear(res);
9442 
9443  destroyPQExpBuffer(query);
9444 }
9445 
9446 /*
9447  * getForeignDataWrappers:
9448  * get information about all foreign-data wrappers in the system catalogs
9449  */
9450 void
9452 {
9453  PGresult *res;
9454  int ntups;
9455  int i;
9456  PQExpBuffer query;
9457  FdwInfo *fdwinfo;
9458  int i_tableoid;
9459  int i_oid;
9460  int i_fdwname;
9461  int i_fdwowner;
9462  int i_fdwhandler;
9463  int i_fdwvalidator;
9464  int i_fdwacl;
9465  int i_acldefault;
9466  int i_fdwoptions;
9467 
9468  query = createPQExpBuffer();
9469 
9470  appendPQExpBufferStr(query, "SELECT tableoid, oid, fdwname, "
9471  "fdwowner, "
9472  "fdwhandler::pg_catalog.regproc, "
9473  "fdwvalidator::pg_catalog.regproc, "
9474  "fdwacl, "
9475  "acldefault('F', fdwowner) AS acldefault, "
9476  "array_to_string(ARRAY("
9477  "SELECT quote_ident(option_name) || ' ' || "
9478  "quote_literal(option_value) "
9479  "FROM pg_options_to_table(fdwoptions) "
9480  "ORDER BY option_name"
9481  "), E',\n ') AS fdwoptions "
9482  "FROM pg_foreign_data_wrapper");
9483 
9484  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9485 
9486  ntups = PQntuples(res);
9487 
9488  fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
9489 
9490  i_tableoid = PQfnumber(res, "tableoid");
9491  i_oid = PQfnumber(res, "oid");
9492  i_fdwname = PQfnumber(res, "fdwname");
9493  i_fdwowner = PQfnumber(res, "fdwowner");
9494  i_fdwhandler = PQfnumber(res, "fdwhandler");
9495  i_fdwvalidator = PQfnumber(res, "fdwvalidator");
9496  i_fdwacl = PQfnumber(res, "fdwacl");
9497  i_acldefault = PQfnumber(res, "acldefault");
9498  i_fdwoptions = PQfnumber(res, "fdwoptions");
9499 
9500  for (i = 0; i < ntups; i++)
9501  {
9502  fdwinfo[i].dobj.objType = DO_FDW;
9503  fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9504  fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9505  AssignDumpId(&fdwinfo[i].dobj);
9506  fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
9507  fdwinfo[i].dobj.namespace = NULL;
9508  fdwinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
9509  fdwinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
9510  fdwinfo[i].dacl.privtype = 0;
9511  fdwinfo[i].dacl.initprivs = NULL;
9512  fdwinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_fdwowner));
9513  fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
9514  fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
9515  fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
9516 
9517  /* Decide whether we want to dump it */
9518  selectDumpableObject(&(fdwinfo[i].dobj), fout);
9519 
9520  /* Mark whether FDW has an ACL */
9521  if (!PQgetisnull(res, i, i_fdwacl))
9522  fdwinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
9523  }
9524 
9525  PQclear(res);
9526 
9527  destroyPQExpBuffer(query);
9528 }
9529 
9530 /*
9531  * getForeignServers:
9532  * get information about all foreign servers in the system catalogs
9533  */
9534 void
9536 {
9537  PGresult *res;
9538  int ntups;
9539  int i;
9540  PQExpBuffer query;
9541  ForeignServerInfo *srvinfo;
9542  int i_tableoid;
9543  int i_oid;
9544  int i_srvname;
9545  int i_srvowner;
9546  int i_srvfdw;
9547  int i_srvtype;
9548  int i_srvversion;
9549  int i_srvacl;
9550  int i_acldefault;
9551  int i_srvoptions;
9552 
9553  query = createPQExpBuffer();
9554 
9555  appendPQExpBufferStr(query, "SELECT tableoid, oid, srvname, "
9556  "srvowner, "
9557  "srvfdw, srvtype, srvversion, srvacl, "
9558  "acldefault('S', srvowner) AS acldefault, "
9559  "array_to_string(ARRAY("
9560  "SELECT quote_ident(option_name) || ' ' || "
9561  "quote_literal(option_value) "
9562  "FROM pg_options_to_table(srvoptions) "
9563  "ORDER BY option_name"
9564  "), E',\n ') AS srvoptions "
9565  "FROM pg_foreign_server");
9566 
9567  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9568 
9569  ntups = PQntuples(res);
9570 
9571  srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
9572 
9573  i_tableoid = PQfnumber(res, "tableoid");
9574  i_oid = PQfnumber(res, "oid");
9575  i_srvname = PQfnumber(res, "srvname");
9576  i_srvowner = PQfnumber(res, "srvowner");
9577  i_srvfdw = PQfnumber(res, "srvfdw");
9578  i_srvtype = PQfnumber(res, "srvtype");
9579  i_srvversion = PQfnumber(res, "srvversion");
9580  i_srvacl = PQfnumber(res, "srvacl");
9581  i_acldefault = PQfnumber(res, "acldefault");
9582  i_srvoptions = PQfnumber(res, "srvoptions");
9583 
9584  for (i = 0; i < ntups; i++)
9585  {
9586  srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
9587  srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9588  srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9589  AssignDumpId(&srvinfo[i].dobj);
9590  srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
9591  srvinfo[i].dobj.namespace = NULL;
9592  srvinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_srvacl));
9593  srvinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
9594  srvinfo[i].dacl.privtype = 0;
9595  srvinfo[i].dacl.initprivs = NULL;
9596  srvinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_srvowner));
9597  srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
9598  srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
9599  srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
9600  srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
9601 
9602  /* Decide whether we want to dump it */
9603  selectDumpableObject(&(srvinfo[i].dobj), fout);
9604 
9605  /* Servers have user mappings */
9607 
9608  /* Mark whether server has an ACL */
9609  if (!PQgetisnull(res, i, i_srvacl))
9610  srvinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
9611  }
9612 
9613  PQclear(res);
9614 
9615  destroyPQExpBuffer(query);
9616 }
9617 
9618 /*
9619  * getDefaultACLs:
9620  * get information about all default ACL information in the system catalogs
9621  */
9622 void
9624 {
9625  DumpOptions *dopt = fout->dopt;
9626  DefaultACLInfo *daclinfo;
9627  PQExpBuffer query;
9628  PGresult *res;
9629  int i_oid;
9630  int i_tableoid;
9631  int i_defaclrole;
9632  int i_defaclnamespace;
9633  int i_defaclobjtype;
9634  int i_defaclacl;
9635  int i_acldefault;
9636  int i,
9637  ntups;
9638 
9639  query = createPQExpBuffer();
9640 
9641  /*
9642  * Global entries (with defaclnamespace=0) replace the hard-wired default
9643  * ACL for their object type. We should dump them as deltas from the
9644  * default ACL, since that will be used as a starting point for
9645  * interpreting the ALTER DEFAULT PRIVILEGES commands. On the other hand,
9646  * non-global entries can only add privileges not revoke them. We must
9647  * dump those as-is (i.e., as deltas from an empty ACL).
9648  *
9649  * We can use defaclobjtype as the object type for acldefault(), except
9650  * for the case of 'S' (DEFACLOBJ_SEQUENCE) which must be converted to
9651  * 's'.
9652  */
9653  appendPQExpBufferStr(query,
9654  "SELECT oid, tableoid, "
9655  "defaclrole, "
9656  "defaclnamespace, "
9657  "defaclobjtype, "
9658  "defaclacl, "
9659  "CASE WHEN defaclnamespace = 0 THEN "
9660  "acldefault(CASE WHEN defaclobjtype = 'S' "
9661  "THEN 's'::\"char\" ELSE defaclobjtype END, "
9662  "defaclrole) ELSE '{}' END AS acldefault "
9663  "FROM pg_default_acl");
9664 
9665  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9666 
9667  ntups = PQntuples(res);
9668 
9669  daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
9670 
9671  i_oid = PQfnumber(res, "oid");
9672  i_tableoid = PQfnumber(res, "tableoid");
9673  i_defaclrole = PQfnumber(res, "defaclrole");
9674  i_defaclnamespace = PQfnumber(res, "defaclnamespace");
9675  i_defaclobjtype = PQfnumber(res, "defaclobjtype");
9676  i_defaclacl = PQfnumber(res, "defaclacl");
9677  i_acldefault = PQfnumber(res, "acldefault");
9678 
9679  for (i = 0; i < ntups; i++)
9680  {
9681  Oid nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
9682 
9683  daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
9684  daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9685  daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9686  AssignDumpId(&daclinfo[i].dobj);
9687  /* cheesy ... is it worth coming up with a better object name? */
9688  daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
9689 
9690  if (nspid != InvalidOid)
9691  daclinfo[i].dobj.namespace = findNamespace(nspid);
9692  else
9693  daclinfo[i].dobj.namespace = NULL;
9694 
9695  daclinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
9696  daclinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
9697  daclinfo[i].dacl.privtype = 0;
9698  daclinfo[i].dacl.initprivs = NULL;
9699  daclinfo[i].defaclrole = getRoleName(PQgetvalue(res, i, i_defaclrole));
9700  daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
9701 
9702  /* Default ACLs are ACLs, of course */
9703  daclinfo[i].dobj.components |= DUMP_COMPONENT_ACL;
9704 
9705  /* Decide whether we want to dump it */
9706  selectDumpableDefaultACL(&(daclinfo[i]), dopt);
9707  }
9708 
9709  PQclear(res);
9710 
9711  destroyPQExpBuffer(query);
9712 }
9713 
9714 /*
9715  * getRoleName -- look up the name of a role, given its OID
9716  *
9717  * In current usage, we don't expect failures, so error out for a bad OID.
9718  */
9719 static const char *
9720 getRoleName(const char *roleoid_str)
9721 {
9722  Oid roleoid = atooid(roleoid_str);
9723 
9724  /*
9725  * Do binary search to find the appropriate item.
9726  */
9727  if (nrolenames > 0)
9728  {
9729  RoleNameItem *low = &rolenames[0];
9730  RoleNameItem *high = &rolenames[nrolenames - 1];
9731 
9732  while (low <= high)
9733  {
9734  RoleNameItem *middle = low + (high - low) / 2;
9735 
9736  if (roleoid < middle->roleoid)
9737  high = middle - 1;
9738  else if (roleoid > middle->roleoid)
9739  low = middle + 1;
9740  else
9741  return middle->rolename; /* found a match */
9742  }
9743  }
9744 
9745  pg_fatal("role with OID %u does not exist", roleoid);
9746  return NULL; /* keep compiler quiet */
9747 }
9748 
9749 /*
9750  * collectRoleNames --
9751  *
9752  * Construct a table of all known roles.
9753  * The table is sorted by OID for speed in lookup.
9754  */
9755 static void
9757 {
9758  PGresult *res;
9759  const char *query;
9760  int i;
9761 
9762  query = "SELECT oid, rolname FROM pg_catalog.pg_roles ORDER BY 1";
9763 
9764  res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
9765 
9767 
9769 
9770  for (i = 0; i < nrolenames; i++)
9771  {
9774  }
9775 
9776  PQclear(res);
9777 }
9778 
9779 /*
9780  * getAdditionalACLs
9781  *
9782  * We have now created all the DumpableObjects, and collected the ACL data
9783  * that appears in the directly-associated catalog entries. However, there's
9784  * more ACL-related info to collect. If any of a table's columns have ACLs,
9785  * we must set the TableInfo's DUMP_COMPONENT_ACL components flag, as well as
9786  * its hascolumnACLs flag (we won't store the ACLs themselves here, though).
9787  * Also, in versions having the pg_init_privs catalog, read that and load the
9788  * information into the relevant DumpableObjects.
9789  */
9790 static void
9792 {
9793  PQExpBuffer query = createPQExpBuffer();
9794  PGresult *res;
9795  int ntups,
9796  i;
9797 
9798  /* Check for per-column ACLs */
9799  appendPQExpBufferStr(query,
9800  "SELECT DISTINCT attrelid FROM pg_attribute "
9801  "WHERE attacl IS NOT NULL");
9802 
9803  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9804 
9805  ntups = PQntuples(res);
9806  for (i = 0; i < ntups; i++)
9807  {
9808  Oid relid = atooid(PQgetvalue(res, i, 0));
9809  TableInfo *tblinfo;
9810 
9811  tblinfo = findTableByOid(relid);
9812  /* OK to ignore tables we haven't got a DumpableObject for */
9813  if (tblinfo)
9814  {
9815  tblinfo->dobj.components |= DUMP_COMPONENT_ACL;
9816  tblinfo->hascolumnACLs = true;
9817  }
9818  }
9819  PQclear(res);
9820 
9821  /* Fetch initial-privileges data */
9822  if (fout->remoteVersion >= 90600)
9823  {
9824  printfPQExpBuffer(query,
9825  "SELECT objoid, classoid, objsubid, privtype, initprivs "
9826  "FROM pg_init_privs");
9827 
9828  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9829 
9830  ntups = PQntuples(res);
9831  for (i = 0; i < ntups; i++)
9832  {
9833  Oid objoid = atooid(PQgetvalue(res, i, 0));
9834  Oid classoid = atooid(PQgetvalue(res, i, 1));
9835  int objsubid = atoi(PQgetvalue(res, i, 2));
9836  char privtype = *(PQgetvalue(res, i, 3));
9837  char *initprivs = PQgetvalue(res, i, 4);
9838  CatalogId objId;
9839  DumpableObject *dobj;
9840 
9841  objId.tableoid = classoid;
9842  objId.oid = objoid;
9843  dobj = findObjectByCatalogId(objId);
9844  /* OK to ignore entries we haven't got a DumpableObject for */
9845  if (dobj)
9846  {
9847  /* Cope with sub-object initprivs */
9848  if (objsubid != 0)
9849  {
9850  if (dobj->objType == DO_TABLE)
9851  {
9852  /* For a column initprivs, set the table's ACL flags */
9853  dobj->components |= DUMP_COMPONENT_ACL;
9854  ((TableInfo *) dobj)->hascolumnACLs = true;
9855  }
9856  else
9857  pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
9858  classoid, objoid, objsubid);
9859  continue;
9860  }
9861 
9862  /*
9863  * We ignore any pg_init_privs.initprivs entry for the public
9864  * schema, as explained in getNamespaces().
9865  */
9866  if (dobj->objType == DO_NAMESPACE &&
9867  strcmp(dobj->name, "public") == 0)
9868  continue;
9869 
9870  /* Else it had better be of a type we think has ACLs */
9871  if (dobj->objType == DO_NAMESPACE ||
9872  dobj->objType == DO_TYPE ||
9873  dobj->objType == DO_FUNC ||
9874  dobj->objType == DO_AGG ||
9875  dobj->objType == DO_TABLE ||
9876  dobj->objType == DO_PROCLANG ||
9877  dobj->objType == DO_FDW ||
9878  dobj->objType == DO_FOREIGN_SERVER)
9879  {
9880  DumpableObjectWithAcl *daobj = (DumpableObjectWithAcl *) dobj;
9881 
9882  daobj->dacl.privtype = privtype;
9883  daobj->dacl.initprivs = pstrdup(initprivs);
9884  }
9885  else
9886  pg_log_warning("unsupported pg_init_privs entry: %u %u %d",
9887  classoid, objoid, objsubid);
9888  }
9889  }
9890  PQclear(res);
9891  }
9892 
9893  destroyPQExpBuffer(query);
9894 }
9895 
9896 /*
9897  * dumpCommentExtended --
9898  *
9899  * This routine is used to dump any comments associated with the
9900  * object handed to this routine. The routine takes the object type
9901  * and object name (ready to print, except for schema decoration), plus
9902  * the namespace and owner of the object (for labeling the ArchiveEntry),
9903  * plus catalog ID and subid which are the lookup key for pg_description,
9904  * plus the dump ID for the object (for setting a dependency).
9905  * If a matching pg_description entry is found, it is dumped.
9906  *
9907  * Note: in some cases, such as comments for triggers and rules, the "type"
9908  * string really looks like, e.g., "TRIGGER name ON". This is a bit of a hack
9909  * but it doesn't seem worth complicating the API for all callers to make
9910  * it cleaner.
9911  *
9912  * Note: although this routine takes a dumpId for dependency purposes,
9913  * that purpose is just to mark the dependency in the emitted dump file
9914  * for possible future use by pg_restore. We do NOT use it for determining
9915  * ordering of the comment in the dump file, because this routine is called
9916  * after dependency sorting occurs. This routine should be called just after
9917  * calling ArchiveEntry() for the specified object.
9918  */
9919 static void
9920 dumpCommentExtended(Archive *fout, const char *type,
9921  const char *name, const char *namespace,
9922  const char *owner, CatalogId catalogId,
9923  int subid, DumpId dumpId,
9924  const char *initdb_comment)
9925 {
9926  DumpOptions *dopt = fout->dopt;
9928  int ncomments;
9929 
9930  /* do nothing, if --no-comments is supplied */
9931  if (dopt->no_comments)
9932  return;
9933 
9934  /* Comments are schema not data ... except LO comments are data */
9935  if (strcmp(type, "LARGE OBJECT") != 0)
9936  {
9937  if (dopt->dataOnly)
9938  return;
9939  }
9940  else
9941  {
9942  /* We do dump LO comments in binary-upgrade mode */
9943  if (dopt->schemaOnly && !dopt->binary_upgrade)
9944  return;
9945  }
9946 
9947  /* Search for comments associated with catalogId, using table */
9948  ncomments = findComments(catalogId.tableoid, catalogId.oid,
9949  &comments);
9950 
9951  /* Is there one matching the subid? */
9952  while (ncomments > 0)
9953  {
9954  if (comments->objsubid == subid)
9955  break;
9956  comments++;
9957  ncomments--;
9958  }
9959 
9960  if (initdb_comment != NULL)
9961  {
9962  static CommentItem empty_comment = {.descr = ""};
9963 
9964  /*
9965  * initdb creates this object with a comment. Skip dumping the
9966  * initdb-provided comment, which would complicate matters for
9967  * non-superuser use of pg_dump. When the DBA has removed initdb's
9968  * comment, replicate that.
9969  */
9970  if (ncomments == 0)
9971  {
9972  comments = &empty_comment;
9973  ncomments = 1;
9974  }
9975  else if (strcmp(comments->descr, initdb_comment) == 0)
9976  ncomments = 0;
9977  }
9978 
9979  /* If a comment exists, build COMMENT ON statement */
9980  if (ncomments > 0)
9981  {
9982  PQExpBuffer query = createPQExpBuffer();
9984 
9985  appendPQExpBuffer(query, "COMMENT ON %s ", type);
9986  if (namespace && *namespace)
9987  appendPQExpBuffer(query, "%s.", fmtId(namespace));
9988  appendPQExpBuffer(query, "%s IS ", name);
9989  appendStringLiteralAH(query, comments->descr, fout);
9990  appendPQExpBufferStr(query, ";\n");
9991 
9992  appendPQExpBuffer(tag, "%s %s", type, name);
9993 
9994  /*
9995  * We mark comments as SECTION_NONE because they really belong in the
9996  * same section as their parent, whether that is pre-data or
9997  * post-data.
9998  */
10000  ARCHIVE_OPTS(.tag = tag->data,
10001  .namespace = namespace,
10002  .owner = owner,
10003  .description = "COMMENT",
10004  .section = SECTION_NONE,
10005  .createStmt = query->data,
10006  .deps = &dumpId,
10007  .nDeps = 1));
10008 
10009  destroyPQExpBuffer(query);
10010  destroyPQExpBuffer(tag);
10011  }
10012 }
10013 
10014 /*
10015  * dumpComment --
10016  *
10017  * Typical simplification of the above function.
10018  */
10019 static inline void
10020 dumpComment(Archive *fout, const char *type,
10021  const char *name, const char *namespace,
10022  const char *owner, CatalogId catalogId,
10023  int subid, DumpId dumpId)
10024 {
10025  dumpCommentExtended(fout, type, name, namespace, owner,
10026  catalogId, subid, dumpId, NULL);
10027 }
10028 
10029 /*
10030  * dumpTableComment --
10031  *
10032  * As above, but dump comments for both the specified table (or view)
10033  * and its columns.
10034  */
10035 static void
10036 dumpTableComment(Archive *fout, const TableInfo *tbinfo,
10037  const char *reltypename)
10038 {
10039  DumpOptions *dopt = fout->dopt;
10041  int ncomments;
10042  PQExpBuffer query;
10043  PQExpBuffer tag;
10044 
10045  /* do nothing, if --no-comments is supplied */
10046  if (dopt->no_comments)
10047  return;
10048 
10049  /* Comments are SCHEMA not data */
10050  if (dopt->dataOnly)
10051  return;
10052 
10053  /* Search for comments associated with relation, using table */
10055  tbinfo->dobj.catId.oid,
10056  &comments);
10057 
10058  /* If comments exist, build COMMENT ON statements */
10059  if (ncomments <= 0)
10060  return;
10061 
10062  query = createPQExpBuffer();
10063  tag = createPQExpBuffer();
10064 
10065  while (ncomments > 0)
10066  {
10067  const char *descr = comments->descr;
10068  int objsubid = comments->objsubid;
10069 
10070  if (objsubid == 0)
10071  {
10072  resetPQExpBuffer(tag);
10073  appendPQExpBuffer(tag, "%s %s", reltypename,
10074  fmtId(tbinfo->dobj.name));
10075 
10076  resetPQExpBuffer(query);
10077  appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
10078  fmtQualifiedDumpable(tbinfo));
10079  appendStringLiteralAH(query, descr, fout);
10080  appendPQExpBufferStr(query, ";\n");
10081 
10083  ARCHIVE_OPTS(.tag = tag->data,
10084  .namespace = tbinfo->dobj.namespace->dobj.name,
10085  .owner = tbinfo->rolname,
10086  .description = "COMMENT",
10087  .section = SECTION_NONE,
10088  .createStmt = query->data,
10089  .deps = &(tbinfo->dobj.dumpId),
10090  .nDeps = 1));
10091  }
10092  else if (objsubid > 0 && objsubid <= tbinfo->numatts)
10093  {
10094  resetPQExpBuffer(tag);
10095  appendPQExpBuffer(tag, "COLUMN %s.",
10096  fmtId(tbinfo->dobj.name));
10097  appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
10098 
10099  resetPQExpBuffer(query);
10100  appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
10101  fmtQualifiedDumpable(tbinfo));
10102  appendPQExpBuffer(query, "%s IS ",
10103  fmtId(tbinfo->attnames[objsubid - 1]));
10104  appendStringLiteralAH(query, descr, fout);
10105  appendPQExpBufferStr(query, ";\n");
10106 
10108  ARCHIVE_OPTS(.tag = tag->data,
10109  .namespace = tbinfo->dobj.namespace->dobj.name,
10110  .owner = tbinfo->rolname,
10111  .description = "COMMENT",
10112  .section = SECTION_NONE,
10113  .createStmt = query->data,
10114  .deps = &(tbinfo->dobj.dumpId),
10115  .nDeps = 1));
10116  }
10117 
10118  comments++;
10119  ncomments--;
10120  }
10121 
10122  destroyPQExpBuffer(query);
10123  destroyPQExpBuffer(tag);
10124 }
10125 
10126 /*
10127  * findComments --
10128  *
10129  * Find the comment(s), if any, associated with the given object. All the
10130  * objsubid values associated with the given classoid/objoid are found with
10131  * one search.
10132  */
10133 static int
10134 findComments(Oid classoid, Oid objoid, CommentItem **items)
10135 {
10136  CommentItem *middle = NULL;
10137  CommentItem *low;
10138  CommentItem *high;
10139  int nmatch;
10140 
10141  /*
10142  * Do binary search to find some item matching the object.
10143  */
10144  low = &comments[0];
10145  high = &comments[ncomments - 1];
10146  while (low <= high)
10147  {
10148  middle = low + (high - low) / 2;
10149 
10150  if (classoid < middle->classoid)
10151  high = middle - 1;
10152  else if (classoid > middle->classoid)
10153  low = middle + 1;
10154  else if (objoid < middle->objoid)
10155  high = middle - 1;
10156  else if (objoid > middle->objoid)
10157  low = middle + 1;
10158  else
10159  break; /* found a match */
10160  }
10161 
10162  if (low > high) /* no matches */
10163  {
10164  *items = NULL;
10165  return 0;
10166  }
10167 
10168  /*
10169  * Now determine how many items match the object. The search loop
10170  * invariant still holds: only items between low and high inclusive could
10171  * match.
10172  */
10173  nmatch = 1;
10174  while (middle > low)
10175  {
10176  if (classoid != middle[-1].classoid ||
10177  objoid != middle[-1].objoid)
10178  break;
10179  middle--;
10180  nmatch++;
10181  }
10182 
10183  *items = middle;
10184 
10185  middle += nmatch;
10186  while (middle <= high)
10187  {
10188  if (classoid != middle->classoid ||
10189  objoid != middle->objoid)
10190  break;
10191  middle++;
10192  nmatch++;
10193  }
10194 
10195  return nmatch;
10196 }
10197 
10198 /*
10199  * collectComments --
10200  *
10201  * Construct a table of all comments available for database objects;
10202  * also set the has-comment component flag for each relevant object.
10203  *
10204  * We used to do per-object queries for the comments, but it's much faster
10205  * to pull them all over at once, and on most databases the memory cost
10206  * isn't high.
10207  *
10208  * The table is sorted by classoid/objid/objsubid for speed in lookup.
10209  */
10210 static void
10212 {
10213  PGresult *res;
10214  PQExpBuffer query;
10215  int i_description;
10216  int i_classoid;
10217  int i_objoid;
10218  int i_objsubid;
10219  int ntups;
10220  int i;
10221  DumpableObject *dobj;
10222 
10223  query = createPQExpBuffer();
10224 
10225  appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
10226  "FROM pg_catalog.pg_description "
10227  "ORDER BY classoid, objoid, objsubid");
10228 
10229  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10230 
10231  /* Construct lookup table containing OIDs in numeric form */
10232 
10233  i_description = PQfnumber(res, "description");
10234  i_classoid = PQfnumber(res, "classoid");
10235  i_objoid = PQfnumber(res, "objoid");
10236  i_objsubid = PQfnumber(res, "objsubid");
10237 
10238  ntups = PQntuples(res);
10239 
10240  comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
10241  ncomments = 0;
10242  dobj = NULL;
10243 
10244  for (i = 0; i < ntups; i++)
10245  {
10246  CatalogId objId;
10247  int subid;
10248 
10249  objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
10250  objId.oid = atooid(PQgetvalue(res, i, i_objoid));
10251  subid = atoi(PQgetvalue(res, i, i_objsubid));
10252 
10253  /* We needn't remember comments that don't match any dumpable object */
10254  if (dobj == NULL ||
10255  dobj->catId.tableoid != objId.tableoid ||
10256  dobj->catId.oid != objId.oid)
10257  dobj = findObjectByCatalogId(objId);
10258  if (dobj == NULL)
10259  continue;
10260 
10261  /*
10262  * Comments on columns of composite types are linked to the type's
10263  * pg_class entry, but we need to set the DUMP_COMPONENT_COMMENT flag
10264  * in the type's own DumpableObject.
10265  */
10266  if (subid != 0 && dobj->objType == DO_TABLE &&
10267  ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
10268  {
10269  TypeInfo *cTypeInfo;
10270 
10271  cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
10272  if (cTypeInfo)
10273  cTypeInfo->dobj.components |= DUMP_COMPONENT_COMMENT;
10274  }
10275  else
10276  dobj->components |= DUMP_COMPONENT_COMMENT;
10277 
10278  comments[ncomments].descr = pg_strdup(PQgetvalue(res, i, i_description));
10280  comments[ncomments].objoid = objId.oid;
10281  comments[ncomments].objsubid = subid;
10282  ncomments++;
10283  }
10284 
10285  PQclear(res);
10286  destroyPQExpBuffer(query);
10287 }
10288 
10289 /*
10290  * dumpDumpableObject
10291  *
10292  * This routine and its subsidiaries are responsible for creating
10293  * ArchiveEntries (TOC objects) for each object to be dumped.
10294  */
10295 static void
10297 {
10298  /*
10299  * Clear any dump-request bits for components that don't exist for this
10300  * object. (This makes it safe to initially use DUMP_COMPONENT_ALL as the
10301  * request for every kind of object.)
10302  */
10303  dobj->dump &= dobj->components;
10304 
10305  /* Now, short-circuit if there's nothing to be done here. */
10306  if (dobj->dump == 0)
10307  return;
10308 
10309  switch (dobj->objType)
10310  {
10311  case DO_NAMESPACE:
10312  dumpNamespace(fout, (const NamespaceInfo *) dobj);
10313  break;
10314  case DO_EXTENSION:
10315  dumpExtension(fout, (const ExtensionInfo *) dobj);
10316  break;
10317  case DO_TYPE:
10318  dumpType(fout, (const TypeInfo *) dobj);
10319  break;
10320  case DO_SHELL_TYPE:
10321  dumpShellType(fout, (const ShellTypeInfo *) dobj);
10322  break;
10323  case DO_FUNC:
10324  dumpFunc(fout, (const FuncInfo *) dobj);
10325  break;
10326  case DO_AGG:
10327  dumpAgg(fout, (const AggInfo *) dobj);
10328  break;
10329  case DO_OPERATOR:
10330  dumpOpr(fout, (const OprInfo *) dobj);
10331  break;
10332  case DO_ACCESS_METHOD:
10333  dumpAccessMethod(fout, (const AccessMethodInfo *) dobj);
10334  break;
10335  case DO_OPCLASS:
10336  dumpOpclass(fout, (const OpclassInfo *) dobj);
10337  break;
10338  case DO_OPFAMILY:
10339  dumpOpfamily(fout, (const OpfamilyInfo *) dobj);
10340  break;
10341  case DO_COLLATION:
10342  dumpCollation(fout, (const CollInfo *) dobj);
10343  break;
10344  case DO_CONVERSION:
10345  dumpConversion(fout, (const ConvInfo *) dobj);
10346  break;
10347  case DO_TABLE:
10348  dumpTable(fout, (const TableInfo *) dobj);
10349  break;
10350  case DO_TABLE_ATTACH:
10351  dumpTableAttach(fout, (const TableAttachInfo *) dobj);
10352  break;
10353  case DO_ATTRDEF:
10354  dumpAttrDef(fout, (const AttrDefInfo *) dobj);
10355  break;
10356  case DO_INDEX:
10357  dumpIndex(fout, (const IndxInfo *) dobj);
10358  break;
10359  case DO_INDEX_ATTACH:
10360  dumpIndexAttach(fout, (const IndexAttachInfo *) dobj);
10361  break;
10362  case DO_STATSEXT:
10363  dumpStatisticsExt(fout, (const StatsExtInfo *) dobj);
10364  break;
10365  case DO_REFRESH_MATVIEW:
10366  refreshMatViewData(fout, (const TableDataInfo *) dobj);
10367  break;
10368  case DO_RULE:
10369  dumpRule(fout, (const RuleInfo *) dobj);
10370  break;
10371  case DO_TRIGGER:
10372  dumpTrigger(fout, (const TriggerInfo *) dobj);
10373  break;
10374  case DO_EVENT_TRIGGER:
10375  dumpEventTrigger(fout, (const EventTriggerInfo *) dobj);
10376  break;
10377  case DO_CONSTRAINT:
10378  dumpConstraint(fout, (const ConstraintInfo *) dobj);
10379  break;
10380  case DO_FK_CONSTRAINT:
10381  dumpConstraint(fout, (const ConstraintInfo *) dobj);
10382  break;
10383  case DO_PROCLANG:
10384  dumpProcLang(fout, (const ProcLangInfo *) dobj);
10385  break;
10386  case DO_CAST:
10387  dumpCast(fout, (const CastInfo *) dobj);
10388  break;
10389  case DO_TRANSFORM:
10390  dumpTransform(fout, (const TransformInfo *) dobj);
10391  break;
10392  case DO_SEQUENCE_SET:
10393  dumpSequenceData(fout, (const TableDataInfo *) dobj);
10394  break;
10395  case DO_TABLE_DATA:
10396  dumpTableData(fout, (const TableDataInfo *) dobj);
10397  break;
10398  case DO_DUMMY_TYPE:
10399  /* table rowtypes and array types are never dumped separately */
10400  break;
10401  case DO_TSPARSER:
10402  dumpTSParser(fout, (const TSParserInfo *) dobj);
10403  break;
10404  case DO_TSDICT:
10405  dumpTSDictionary(fout, (const TSDictInfo *) dobj);
10406  break;
10407  case DO_TSTEMPLATE:
10408  dumpTSTemplate(fout, (const TSTemplateInfo *) dobj);
10409  break;
10410  case DO_TSCONFIG:
10411  dumpTSConfig(fout, (const TSConfigInfo *) dobj);
10412  break;
10413  case DO_FDW:
10414  dumpForeignDataWrapper(fout, (const FdwInfo *) dobj);
10415  break;
10416  case DO_FOREIGN_SERVER:
10417  dumpForeignServer(fout, (const ForeignServerInfo *) dobj);
10418  break;
10419  case DO_DEFAULT_ACL:
10420  dumpDefaultACL(fout, (const DefaultACLInfo *) dobj);
10421  break;
10422  case DO_LARGE_OBJECT:
10423  dumpLO(fout, (const LoInfo *) dobj);
10424  break;
10425  case DO_LARGE_OBJECT_DATA:
10426  if (dobj->dump & DUMP_COMPONENT_DATA)
10427  {
10428  LoInfo *loinfo;
10429  TocEntry *te;
10430 
10431  loinfo = (LoInfo *) findObjectByDumpId(dobj->dependencies[0]);
10432  if (loinfo == NULL)
10433  pg_fatal("missing metadata for large objects \"%s\"",
10434  dobj->name);
10435 
10436  te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
10437  ARCHIVE_OPTS(.tag = dobj->name,
10438  .owner = loinfo->rolname,
10439  .description = "BLOBS",
10440  .section = SECTION_DATA,
10441  .deps = dobj->dependencies,
10442  .nDeps = dobj->nDeps,
10443  .dumpFn = dumpLOs,
10444  .dumpArg = loinfo));
10445 
10446  /*
10447  * Set the TocEntry's dataLength in case we are doing a
10448  * parallel dump and want to order dump jobs by table size.
10449  * (We need some size estimate for every TocEntry with a
10450  * DataDumper function.) We don't currently have any cheap
10451  * way to estimate the size of LOs, but fortunately it doesn't
10452  * matter too much as long as we get large batches of LOs
10453  * processed reasonably early. Assume 8K per blob.
10454  */
10455  te->dataLength = loinfo->numlos * (pgoff_t) 8192;
10456  }
10457  break;
10458  case DO_POLICY:
10459  dumpPolicy(fout, (const PolicyInfo *) dobj);
10460  break;
10461  case DO_PUBLICATION:
10462  dumpPublication(fout, (const PublicationInfo *) dobj);
10463  break;
10464  case DO_PUBLICATION_REL:
10465  dumpPublicationTable(fout, (const PublicationRelInfo *) dobj);
10466  break;
10469  (const PublicationSchemaInfo *) dobj);
10470  break;
10471  case DO_SUBSCRIPTION:
10472  dumpSubscription(fout, (const SubscriptionInfo *) dobj);
10473  break;
10474  case DO_SUBSCRIPTION_REL:
10475  dumpSubscriptionTable(fout, (const SubRelInfo *) dobj);
10476  break;
10477  case DO_PRE_DATA_BOUNDARY:
10478  case DO_POST_DATA_BOUNDARY:
10479  /* never dumped, nothing to do */
10480  break;
10481  }
10482 }
10483 
10484 /*
10485  * dumpNamespace
10486  * writes out to fout the queries to recreate a user-defined namespace
10487  */
10488 static void
10489 dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
10490 {
10491  DumpOptions *dopt = fout->dopt;
10492  PQExpBuffer q;
10493  PQExpBuffer delq;
10494  char *qnspname;
10495 
10496  /* Do nothing in data-only dump */
10497  if (dopt->dataOnly)
10498  return;
10499 
10500  q = createPQExpBuffer();
10501  delq = createPQExpBuffer();
10502 
10503  qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
10504 
10505  if (nspinfo->create)
10506  {
10507  appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
10508  appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
10509  }
10510  else
10511  {
10512  /* see selectDumpableNamespace() */
10513  appendPQExpBufferStr(delq,
10514  "-- *not* dropping schema, since initdb creates it\n");
10516  "-- *not* creating schema, since initdb creates it\n");
10517  }
10518 
10519  if (dopt->binary_upgrade)
10521  "SCHEMA", qnspname, NULL);
10522 
10523  if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10524  ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
10525  ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
10526  .owner = nspinfo->rolname,
10527  .description = "SCHEMA",
10528  .section = SECTION_PRE_DATA,
10529  .createStmt = q->data,
10530  .dropStmt = delq->data));
10531 
10532  /* Dump Schema Comments and Security Labels */
10533  if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10534  {
10535  const char *initdb_comment = NULL;
10536 
10537  if (!nspinfo->create && strcmp(qnspname, "public") == 0)
10538  initdb_comment = "standard public schema";
10539  dumpCommentExtended(fout, "SCHEMA", qnspname,
10540  NULL, nspinfo->rolname,
10541  nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId,
10542  initdb_comment);
10543  }
10544 
10545  if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10546  dumpSecLabel(fout, "SCHEMA", qnspname,
10547  NULL, nspinfo->rolname,
10548  nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
10549 
10550  if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
10551  dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
10552  qnspname, NULL, NULL,
10553  NULL, nspinfo->rolname, &nspinfo->dacl);
10554 
10555  free(qnspname);
10556 
10557  destroyPQExpBuffer(q);
10558  destroyPQExpBuffer(delq);
10559 }
10560 
10561 /*
10562  * dumpExtension
10563  * writes out to fout the queries to recreate an extension
10564  */
10565 static void
10566 dumpExtension(Archive *fout, const ExtensionInfo *extinfo)
10567 {
10568  DumpOptions *dopt = fout->dopt;
10569  PQExpBuffer q;
10570  PQExpBuffer delq;
10571  char *qextname;
10572 
10573  /* Do nothing in data-only dump */
10574  if (dopt->dataOnly)
10575  return;
10576 
10577  q = createPQExpBuffer();
10578  delq = createPQExpBuffer();
10579 
10580  qextname = pg_strdup(fmtId(extinfo->dobj.name));
10581 
10582  appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
10583 
10584  if (!dopt->binary_upgrade)
10585  {
10586  /*
10587  * In a regular dump, we simply create the extension, intentionally
10588  * not specifying a version, so that the destination installation's
10589  * default version is used.
10590  *
10591  * Use of IF NOT EXISTS here is unlike our behavior for other object
10592  * types; but there are various scenarios in which it's convenient to
10593  * manually create the desired extension before restoring, so we
10594  * prefer to allow it to exist already.
10595  */
10596  appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
10597  qextname, fmtId(extinfo->namespace));
10598  }
10599  else
10600  {
10601  /*
10602  * In binary-upgrade mode, it's critical to reproduce the state of the
10603  * database exactly, so our procedure is to create an empty extension,
10604  * restore all the contained objects normally, and add them to the
10605  * extension one by one. This function performs just the first of
10606  * those steps. binary_upgrade_extension_member() takes care of
10607  * adding member objects as they're created.
10608  */
10609  int i;
10610  int n;
10611 
10612  appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
10613 
10614  /*
10615  * We unconditionally create the extension, so we must drop it if it
10616  * exists. This could happen if the user deleted 'plpgsql' and then
10617  * readded it, causing its oid to be greater than g_last_builtin_oid.
10618  */
10619  appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
10620 
10622  "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
10623  appendStringLiteralAH(q, extinfo->dobj.name, fout);
10624  appendPQExpBufferStr(q, ", ");
10625  appendStringLiteralAH(q, extinfo->namespace, fout);
10626  appendPQExpBufferStr(q, ", ");
10627  appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
10628  appendStringLiteralAH(q, extinfo->extversion, fout);
10629  appendPQExpBufferStr(q, ", ");
10630 
10631  /*
10632  * Note that we're pushing extconfig (an OID array) back into
10633  * pg_extension exactly as-is. This is OK because pg_class OIDs are
10634  * preserved in binary upgrade.
10635  */
10636  if (strlen(extinfo->extconfig) > 2)
10637  appendStringLiteralAH(q, extinfo->extconfig, fout);
10638  else
10639  appendPQExpBufferStr(q, "NULL");
10640  appendPQExpBufferStr(q, ", ");
10641  if (strlen(extinfo->extcondition) > 2)
10642  appendStringLiteralAH(q, extinfo->extcondition, fout);
10643  else
10644  appendPQExpBufferStr(q, "NULL");
10645  appendPQExpBufferStr(q, ", ");
10646  appendPQExpBufferStr(q, "ARRAY[");
10647  n = 0;
10648  for (i = 0; i < extinfo->dobj.nDeps; i++)
10649  {
10650  DumpableObject *extobj;
10651 
10652  extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
10653  if (extobj && extobj->objType == DO_EXTENSION)
10654  {
10655  if (n++ > 0)
10656  appendPQExpBufferChar(q, ',');
10657  appendStringLiteralAH(q, extobj->name, fout);
10658  }
10659  }
10660  appendPQExpBufferStr(q, "]::pg_catalog.text[]");
10661  appendPQExpBufferStr(q, ");\n");
10662  }
10663 
10664  if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10665  ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
10666  ARCHIVE_OPTS(.tag = extinfo->dobj.name,
10667  .description = "EXTENSION",
10668  .section = SECTION_PRE_DATA,
10669  .createStmt = q->data,
10670  .dropStmt = delq->data));
10671 
10672  /* Dump Extension Comments and Security Labels */
10673  if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10674  dumpComment(fout, "EXTENSION", qextname,
10675  NULL, "",
10676  extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
10677 
10678  if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10679  dumpSecLabel(fout, "EXTENSION", qextname,
10680  NULL, "",
10681  extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
10682 
10683  free(qextname);
10684 
10685  destroyPQExpBuffer(q);
10686  destroyPQExpBuffer(delq);
10687 }
10688 
10689 /*
10690  * dumpType
10691  * writes out to fout the queries to recreate a user-defined type
10692  */
10693 static void
10694 dumpType(Archive *fout, const TypeInfo *tyinfo)
10695 {
10696  DumpOptions *dopt = fout->dopt;
10697 
10698  /* Do nothing in data-only dump */
10699  if (dopt->dataOnly)
10700  return;
10701 
10702  /* Dump out in proper style */
10703  if (tyinfo->typtype == TYPTYPE_BASE)
10704  dumpBaseType(fout, tyinfo);
10705  else if (tyinfo->typtype == TYPTYPE_DOMAIN)
10706  dumpDomain(fout, tyinfo);
10707  else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
10708  dumpCompositeType(fout, tyinfo);
10709  else if (tyinfo->typtype == TYPTYPE_ENUM)
10710  dumpEnumType(fout, tyinfo);
10711  else if (tyinfo->typtype == TYPTYPE_RANGE)
10712  dumpRangeType(fout, tyinfo);
10713  else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
10714  dumpUndefinedType(fout, tyinfo);
10715  else
10716  pg_log_warning("typtype of data type \"%s\" appears to be invalid",
10717  tyinfo->dobj.name);
10718 }
10719 
10720 /*
10721  * dumpEnumType
10722  * writes out to fout the queries to recreate a user-defined enum type
10723  */
10724 static void
10725 dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
10726 {
10727  DumpOptions *dopt = fout->dopt;
10729  PQExpBuffer delq = createPQExpBuffer();
10730  PQExpBuffer query = createPQExpBuffer();
10731  PGresult *res;
10732  int num,
10733  i;
10734  Oid enum_oid;
10735  char *qtypname;
10736  char *qualtypname;
10737  char *label;
10738  int i_enumlabel;
10739  int i_oid;
10740 
10741  if (!fout->is_prepared[PREPQUERY_DUMPENUMTYPE])
10742  {
10743  /* Set up query for enum-specific details */
10744  appendPQExpBufferStr(query,
10745  "PREPARE dumpEnumType(pg_catalog.oid) AS\n"
10746  "SELECT oid, enumlabel "
10747  "FROM pg_catalog.pg_enum "
10748  "WHERE enumtypid = $1 "
10749  "ORDER BY enumsortorder");
10750 
10751  ExecuteSqlStatement(fout, query->data);
10752 
10753  fout->is_prepared[PREPQUERY_DUMPENUMTYPE] = true;
10754  }
10755 
10756  printfPQExpBuffer(query,
10757  "EXECUTE dumpEnumType('%u')",
10758  tyinfo->dobj.catId.oid);
10759 
10760  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10761 
10762  num = PQntuples(res);
10763 
10764  qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10765  qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10766 
10767  /*
10768  * CASCADE shouldn't be required here as for normal types since the I/O
10769  * functions are generic and do not get dropped.
10770  */
10771  appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10772 
10773  if (dopt->binary_upgrade)
10775  tyinfo->dobj.catId.oid,
10776  false, false);
10777 
10778  appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
10779  qualtypname);
10780 
10781  if (!dopt->binary_upgrade)
10782  {
10783  i_enumlabel = PQfnumber(res, "enumlabel");
10784 
10785  /* Labels with server-assigned oids */
10786  for (i = 0; i < num; i++)
10787  {
10788  label = PQgetvalue(res, i, i_enumlabel);
10789  if (i > 0)
10790  appendPQExpBufferChar(q, ',');
10791  appendPQExpBufferStr(q, "\n ");
10792  appendStringLiteralAH(q, label, fout);
10793  }
10794  }
10795 
10796  appendPQExpBufferStr(q, "\n);\n");
10797 
10798  if (dopt->binary_upgrade)
10799  {
10800  i_oid = PQfnumber(res, "oid");
10801  i_enumlabel = PQfnumber(res, "enumlabel");
10802 
10803  /* Labels with dump-assigned (preserved) oids */
10804  for (i = 0; i < num; i++)
10805  {
10806  enum_oid = atooid(PQgetvalue(res, i, i_oid));
10807  label = PQgetvalue(res, i, i_enumlabel);
10808 
10809  if (i == 0)
10810  appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
10812  "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
10813  enum_oid);
10814  appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
10815  appendStringLiteralAH(q, label, fout);
10816  appendPQExpBufferStr(q, ";\n\n");
10817  }
10818  }
10819 
10820  if (dopt->binary_upgrade)
10822  "TYPE", qtypname,
10823  tyinfo->dobj.namespace->dobj.name);
10824 
10825  if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10826  ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10827  ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10828  .namespace = tyinfo->dobj.namespace->dobj.name,
10829  .owner = tyinfo->rolname,
10830  .description = "TYPE",
10831  .section = SECTION_PRE_DATA,
10832  .createStmt = q->data,
10833  .dropStmt = delq->data));
10834 
10835  /* Dump Type Comments and Security Labels */
10836  if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10837  dumpComment(fout, "TYPE", qtypname,
10838  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10839  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10840 
10841  if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10842  dumpSecLabel(fout, "TYPE", qtypname,
10843  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10844  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10845 
10846  if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10847  dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
10848  qtypname, NULL,
10849  tyinfo->dobj.namespace->dobj.name,
10850  NULL, tyinfo->rolname, &tyinfo->dacl);
10851 
10852  PQclear(res);
10853  destroyPQExpBuffer(q);
10854  destroyPQExpBuffer(delq);
10855  destroyPQExpBuffer(query);
10856  free(qtypname);
10857  free(qualtypname);
10858 }
10859 
10860 /*
10861  * dumpRangeType
10862  * writes out to fout the queries to recreate a user-defined range type
10863  */
10864 static void
10865 dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
10866 {
10867  DumpOptions *dopt = fout->dopt;
10869  PQExpBuffer delq = createPQExpBuffer();
10870  PQExpBuffer query = createPQExpBuffer();
10871  PGresult *res;
10872  Oid collationOid;
10873  char *qtypname;
10874  char *qualtypname;
10875  char *procname;
10876 
10878  {
10879  /* Set up query for range-specific details */
10880  appendPQExpBufferStr(query,
10881  "PREPARE dumpRangeType(pg_catalog.oid) AS\n");
10882 
10883  appendPQExpBufferStr(query,
10884  "SELECT ");
10885 
10886  if (fout->remoteVersion >= 140000)
10887  appendPQExpBufferStr(query,
10888  "pg_catalog.format_type(rngmultitypid, NULL) AS rngmultitype, ");
10889  else
10890  appendPQExpBufferStr(query,
10891  "NULL AS rngmultitype, ");
10892 
10893  appendPQExpBufferStr(query,
10894  "pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
10895  "opc.opcname AS opcname, "
10896  "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
10897  " WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
10898  "opc.opcdefault, "
10899  "CASE WHEN rngcollation = st.typcollation THEN 0 "
10900  " ELSE rngcollation END AS collation, "
10901  "rngcanonical, rngsubdiff "
10902  "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
10903  " pg_catalog.pg_opclass opc "
10904  "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
10905  "rngtypid = $1");
10906 
10907  ExecuteSqlStatement(fout, query->data);
10908 
10909  fout->is_prepared[PREPQUERY_DUMPRANGETYPE] = true;
10910  }
10911 
10912  printfPQExpBuffer(query,
10913  "EXECUTE dumpRangeType('%u')",
10914  tyinfo->dobj.catId.oid);
10915 
10916  res = ExecuteSqlQueryForSingleRow(fout, query->data);
10917 
10918  qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10919  qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10920 
10921  /*
10922  * CASCADE shouldn't be required here as for normal types since the I/O
10923  * functions are generic and do not get dropped.
10924  */
10925  appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10926 
10927  if (dopt->binary_upgrade)
10929  tyinfo->dobj.catId.oid,
10930  false, true);
10931 
10932  appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
10933  qualtypname);
10934 
10935  appendPQExpBuffer(q, "\n subtype = %s",
10936  PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
10937 
10938  if (!PQgetisnull(res, 0, PQfnumber(res, "rngmultitype")))
10939  appendPQExpBuffer(q, ",\n multirange_type_name = %s",
10940  PQgetvalue(res, 0, PQfnumber(res, "rngmultitype")));
10941 
10942  /* print subtype_opclass only if not default for subtype */
10943  if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
10944  {
10945  char *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
10946  char *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
10947 
10948  appendPQExpBuffer(q, ",\n subtype_opclass = %s.",
10949  fmtId(nspname));
10950  appendPQExpBufferStr(q, fmtId(opcname));
10951  }
10952 
10953  collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
10954  if (OidIsValid(collationOid))
10955  {
10956  CollInfo *coll = findCollationByOid(collationOid);
10957 
10958  if (coll)
10959  appendPQExpBuffer(q, ",\n collation = %s",
10960  fmtQualifiedDumpable(coll));
10961  }
10962 
10963  procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
10964  if (strcmp(procname, "-") != 0)
10965  appendPQExpBuffer(q, ",\n canonical = %s", procname);
10966 
10967  procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
10968  if (strcmp(procname, "-") != 0)
10969  appendPQExpBuffer(q, ",\n subtype_diff = %s", procname);
10970 
10971  appendPQExpBufferStr(q, "\n);\n");
10972 
10973  if (dopt->binary_upgrade)
10975  "TYPE", qtypname,
10976  tyinfo->dobj.namespace->dobj.name);
10977 
10978  if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10979  ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10980  ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10981  .namespace = tyinfo->dobj.namespace->dobj.name,
10982  .owner = tyinfo->rolname,
10983  .description = "TYPE",
10984  .section = SECTION_PRE_DATA,
10985  .createStmt = q->data,
10986  .dropStmt = delq->data));
10987 
10988  /* Dump Type Comments and Security Labels */
10989  if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10990  dumpComment(fout, "TYPE", qtypname,
10991  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10992  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10993 
10994  if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10995  dumpSecLabel(fout, "TYPE", qtypname,
10996  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10997  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10998 
10999  if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
11000  dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
11001  qtypname, NULL,
11002  tyinfo->dobj.namespace->dobj.name,
11003  NULL, tyinfo->rolname, &tyinfo->dacl);
11004 
11005  PQclear(res);
11006  destroyPQExpBuffer(q);
11007  destroyPQExpBuffer(delq);
11008  destroyPQExpBuffer(query);
11009  free(qtypname);
11010  free(qualtypname);
11011 }
11012 
11013 /*
11014  * dumpUndefinedType
11015  * writes out to fout the queries to recreate a !typisdefined type
11016  *
11017  * This is a shell type, but we use different terminology to distinguish
11018  * this case from where we have to emit a shell type definition to break
11019  * circular dependencies. An undefined type shouldn't ever have anything
11020  * depending on it.
11021  */
11022 static void
11023 dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo)
11024 {
11025  DumpOptions *dopt = fout->dopt;
11027  PQExpBuffer delq = createPQExpBuffer();
11028  char *qtypname;
11029  char *qualtypname;
11030 
11031  qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
11032  qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
11033 
11034  appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
11035 
11036  if (dopt->binary_upgrade)
11038  tyinfo->dobj.catId.oid,
11039  false, false);
11040 
11041  appendPQExpBuffer(q, "CREATE TYPE %s;\n",
11042  qualtypname);
11043 
11044  if (dopt->binary_upgrade)
11046  "TYPE", qtypname,
11047  tyinfo->dobj.namespace->dobj.name);
11048 
11049  if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11050  ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
11051  ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
11052  .namespace = tyinfo->dobj.namespace->dobj.name,
11053  .owner = tyinfo->rolname,
11054  .description = "TYPE",
11055  .section = SECTION_PRE_DATA,
11056  .createStmt = q->data,
11057  .dropStmt = delq->data));
11058 
11059  /* Dump Type Comments and Security Labels */
11060  if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11061  dumpComment(fout, "TYPE", qtypname,
11062  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11063  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11064 
11065  if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11066  dumpSecLabel(fout, "TYPE", qtypname,
11067  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11068  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11069 
11070  if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
11071  dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
11072  qtypname, NULL,
11073  tyinfo->dobj.namespace->dobj.name,
11074  NULL, tyinfo->rolname, &tyinfo->dacl);
11075 
11076  destroyPQExpBuffer(q);
11077  destroyPQExpBuffer(delq);
11078  free(qtypname);
11079  free(qualtypname);
11080 }
11081 
11082 /*
11083  * dumpBaseType
11084  * writes out to fout the queries to recreate a user-defined base type
11085  */
11086 static void
11087 dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
11088 {
11089  DumpOptions *dopt = fout->dopt;
11091  PQExpBuffer delq = createPQExpBuffer();
11092  PQExpBuffer query = createPQExpBuffer();
11093  PGresult *res;
11094  char *qtypname;
11095  char *qualtypname;
11096  char *typlen;
11097  char *typinput;
11098  char *typoutput;
11099  char *typreceive;
11100  char *typsend;
11101  char *typmodin;
11102  char *typmodout;
11103  char *typanalyze;
11104  char *typsubscript;
11105  Oid typreceiveoid;
11106  Oid typsendoid;
11107  Oid typmodinoid;
11108  Oid typmodoutoid;
11109  Oid typanalyzeoid;
11110  Oid typsubscriptoid;
11111  char *typcategory;
11112  char *typispreferred;
11113  char *typdelim;
11114  char *typbyval;
11115  char *typalign;
11116  char *typstorage;
11117  char *typcollatable;
11118  char *typdefault;
11119  bool typdefault_is_literal = false;
11120 
11121  if (!fout->is_prepared[PREPQUERY_DUMPBASETYPE])
11122  {
11123  /* Set up query for type-specific details */
11124  appendPQExpBufferStr(query,
11125  "PREPARE dumpBaseType(pg_catalog.oid) AS\n"
11126  "SELECT typlen, "
11127  "typinput, typoutput, typreceive, typsend, "
11128  "typreceive::pg_catalog.oid AS typreceiveoid, "
11129  "typsend::pg_catalog.oid AS typsendoid, "
11130  "typanalyze, "
11131  "typanalyze::pg_catalog.oid AS typanalyzeoid, "
11132  "typdelim, typbyval, typalign, typstorage, "
11133  "typmodin, typmodout, "
11134  "typmodin::pg_catalog.oid AS typmodinoid, "
11135  "typmodout::pg_catalog.oid AS typmodoutoid, "
11136  "typcategory, typispreferred, "
11137  "(typcollation <> 0) AS typcollatable, "
11138  "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault, ");
11139 
11140  if (fout->remoteVersion >= 140000)
11141  appendPQExpBufferStr(query,
11142  "typsubscript, "
11143  "typsubscript::pg_catalog.oid AS typsubscriptoid ");
11144  else
11145  appendPQExpBufferStr(query,
11146  "'-' AS typsubscript, 0 AS typsubscriptoid ");
11147 
11148  appendPQExpBufferStr(query, "FROM pg_catalog.pg_type "
11149  "WHERE oid = $1");
11150 
11151  ExecuteSqlStatement(fout, query->data);
11152 
11153  fout->is_prepared[PREPQUERY_DUMPBASETYPE] = true;
11154  }
11155 
11156  printfPQExpBuffer(query,
11157  "EXECUTE dumpBaseType('%u')",
11158  tyinfo->dobj.catId.oid);
11159 
11160  res = ExecuteSqlQueryForSingleRow(fout, query->data);
11161 
11162  typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
11163  typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
11164  typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
11165  typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
11166  typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
11167  typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
11168  typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
11169  typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
11170  typsubscript = PQgetvalue(res, 0, PQfnumber(res, "typsubscript"));
11171  typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
11172  typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
11173  typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
11174  typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
11175  typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
11176  typsubscriptoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsubscriptoid")));
11177  typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
11178  typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
11179  typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
11180  typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
11181  typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
11182  typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
11183  typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
11184  if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
11185  typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
11186  else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
11187  {
11188  typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
11189  typdefault_is_literal = true; /* it needs quotes */
11190  }
11191  else
11192  typdefault = NULL;
11193 
11194  qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
11195  qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
11196 
11197  /*
11198  * The reason we include CASCADE is that the circular dependency between
11199  * the type and its I/O functions makes it impossible to drop the type any
11200  * other way.
11201  */
11202  appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
11203 
11204  /*
11205  * We might already have a shell type, but setting pg_type_oid is
11206  * harmless, and in any case we'd better set the array type OID.
11207  */
11208  if (dopt->binary_upgrade)
11210  tyinfo->dobj.catId.oid,
11211  false, false);
11212 
11214  "CREATE TYPE %s (\n"
11215  " INTERNALLENGTH = %s",
11216  qualtypname,
11217  (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
11218 
11219  /* regproc result is sufficiently quoted already */
11220  appendPQExpBuffer(q, ",\n INPUT = %s", typinput);
11221  appendPQExpBuffer(q, ",\n OUTPUT = %s", typoutput);
11222  if (OidIsValid(typreceiveoid))
11223  appendPQExpBuffer(q, ",\n RECEIVE = %s", typreceive);
11224  if (OidIsValid(typsendoid))
11225  appendPQExpBuffer(q, ",\n SEND = %s", typsend);
11226  if (OidIsValid(typmodinoid))
11227  appendPQExpBuffer(q, ",\n TYPMOD_IN = %s", typmodin);
11228  if (OidIsValid(typmodoutoid))
11229  appendPQExpBuffer(q, ",\n TYPMOD_OUT = %s", typmodout);
11230  if (OidIsValid(typanalyzeoid))
11231  appendPQExpBuffer(q, ",\n ANALYZE = %s", typanalyze);
11232 
11233  if (strcmp(typcollatable, "t") == 0)
11234  appendPQExpBufferStr(q, ",\n COLLATABLE = true");
11235 
11236  if (typdefault != NULL)
11237  {
11238  appendPQExpBufferStr(q, ",\n DEFAULT = ");
11239  if (typdefault_is_literal)
11240  appendStringLiteralAH(q, typdefault, fout);
11241  else
11242  appendPQExpBufferStr(q, typdefault);
11243  }
11244 
11245  if (OidIsValid(typsubscriptoid))
11246  appendPQExpBuffer(q, ",\n SUBSCRIPT = %s", typsubscript);
11247 
11248  if (OidIsValid(tyinfo->typelem))
11249  appendPQExpBuffer(q, ",\n ELEMENT = %s",
11250  getFormattedTypeName(fout, tyinfo->typelem,
11251  zeroIsError));
11252 
11253  if (strcmp(typcategory, "U") != 0)
11254  {
11255  appendPQExpBufferStr(q, ",\n CATEGORY = ");
11256  appendStringLiteralAH(q, typcategory, fout);
11257  }
11258 
11259  if (strcmp(typispreferred, "t") == 0)
11260  appendPQExpBufferStr(q, ",\n PREFERRED = true");
11261 
11262  if (typdelim && strcmp(typdelim, ",") != 0)
11263  {
11264  appendPQExpBufferStr(q, ",\n DELIMITER = ");
11265  appendStringLiteralAH(q, typdelim, fout);
11266  }
11267 
11268  if (*typalign == TYPALIGN_CHAR)
11269  appendPQExpBufferStr(q, ",\n ALIGNMENT = char");
11270  else if (*typalign == TYPALIGN_SHORT)
11271  appendPQExpBufferStr(q, ",\n ALIGNMENT = int2");
11272  else if (*typalign == TYPALIGN_INT)
11273  appendPQExpBufferStr(q, ",\n ALIGNMENT = int4");
11274  else if (*typalign == TYPALIGN_DOUBLE)
11275  appendPQExpBufferStr(q, ",\n ALIGNMENT = double");
11276 
11277  if (*typstorage == TYPSTORAGE_PLAIN)
11278  appendPQExpBufferStr(q, ",\n STORAGE = plain");
11279  else if (*typstorage == TYPSTORAGE_EXTERNAL)
11280  appendPQExpBufferStr(q, ",\n STORAGE = external");
11281  else if (*typstorage == TYPSTORAGE_EXTENDED)
11282  appendPQExpBufferStr(q, ",\n STORAGE = extended");
11283  else if (*typstorage == TYPSTORAGE_MAIN)
11284  appendPQExpBufferStr(q, ",\n STORAGE = main");
11285 
11286  if (strcmp(typbyval, "t") == 0)
11287  appendPQExpBufferStr(q, ",\n PASSEDBYVALUE");
11288 
11289  appendPQExpBufferStr(q, "\n);\n");
11290 
11291  if (dopt->binary_upgrade)
11293  "TYPE", qtypname,
11294  tyinfo->dobj.namespace->dobj.name);
11295 
11296  if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11297  ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
11298  ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
11299  .namespace = tyinfo->dobj.namespace->dobj.name,
11300  .owner = tyinfo->rolname,
11301  .description = "TYPE",
11302  .section = SECTION_PRE_DATA,
11303  .createStmt = q->data,
11304  .dropStmt = delq->data));
11305 
11306  /* Dump Type Comments and Security Labels */
11307  if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11308  dumpComment(fout, "TYPE", qtypname,
11309  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11310  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11311 
11312  if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11313  dumpSecLabel(fout, "TYPE", qtypname,
11314  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11315  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11316 
11317  if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
11318  dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
11319  qtypname, NULL,
11320  tyinfo->dobj.namespace->dobj.name,
11321  NULL, tyinfo->rolname, &tyinfo->dacl);
11322 
11323  PQclear(res);
11324  destroyPQExpBuffer(q);
11325  destroyPQExpBuffer(delq);
11326  destroyPQExpBuffer(query);
11327  free(qtypname);
11328  free(qualtypname);
11329 }
11330 
11331 /*
11332  * dumpDomain
11333  * writes out to fout the queries to recreate a user-defined domain
11334  */
11335 static void
11336 dumpDomain(Archive *fout, const TypeInfo *tyinfo)
11337 {
11338  DumpOptions *dopt = fout->dopt;
11340  PQExpBuffer delq = createPQExpBuffer();
11341  PQExpBuffer query = createPQExpBuffer();
11342  PGresult *res;
11343  int i;
11344  char *qtypname;
11345  char *qualtypname;
11346  char *typnotnull;
11347  char *typdefn;
11348  char *typdefault;
11349  Oid typcollation;
11350  bool typdefault_is_literal = false;
11351 
11352  if (!fout->is_prepared[PREPQUERY_DUMPDOMAIN])
11353  {
11354  /* Set up query for domain-specific details */
11355  appendPQExpBufferStr(query,
11356  "PREPARE dumpDomain(pg_catalog.oid) AS\n");
11357 
11358  appendPQExpBufferStr(query, "SELECT t.typnotnull, "
11359  "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
11360  "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
11361  "t.typdefault, "
11362  "CASE WHEN t.typcollation <> u.typcollation "
11363  "THEN t.typcollation ELSE 0 END AS typcollation "
11364  "FROM pg_catalog.pg_type t "
11365  "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
11366  "WHERE t.oid = $1");
11367 
11368  ExecuteSqlStatement(fout, query->data);
11369 
11370  fout->is_prepared[PREPQUERY_DUMPDOMAIN] = true;
11371  }
11372 
11373  printfPQExpBuffer(query,
11374  "EXECUTE dumpDomain('%u')",
11375  tyinfo->dobj.catId.oid);
11376 
11377  res = ExecuteSqlQueryForSingleRow(fout, query->data);
11378 
11379  typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
11380  typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
11381  if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
11382  typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
11383  else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
11384  {
11385  typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
11386  typdefault_is_literal = true; /* it needs quotes */
11387  }
11388  else
11389  typdefault = NULL;
11390  typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
11391 
11392  if (dopt->binary_upgrade)
11394  tyinfo->dobj.catId.oid,
11395  true, /* force array type */
11396  false); /* force multirange type */
11397 
11398  qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
11399  qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
11400 
11402  "CREATE DOMAIN %s AS %s",
11403  qualtypname,
11404  typdefn);
11405 
11406  /* Print collation only if different from base type's collation */
11407  if (OidIsValid(typcollation))
11408  {
11409  CollInfo *coll;
11410 
11411  coll = findCollationByOid(typcollation);
11412  if (coll)
11413  appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
11414  }
11415 
11416  if (typnotnull[0] == 't')
11417  appendPQExpBufferStr(q, " NOT NULL");
11418 
11419  if (typdefault != NULL)
11420  {
11421  appendPQExpBufferStr(q, " DEFAULT ");
11422  if (typdefault_is_literal)
11423  appendStringLiteralAH(q, typdefault, fout);
11424  else
11425  appendPQExpBufferStr(q, typdefault);
11426  }
11427 
11428  PQclear(res);
11429 
11430  /*
11431  * Add any CHECK constraints for the domain
11432  */
11433  for (i = 0; i < tyinfo->nDomChecks; i++)
11434  {
11435  ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
11436 
11437  if (!domcheck->separate)
11438  appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
11439  fmtId(domcheck->dobj.name), domcheck->condef);
11440  }
11441 
11442  appendPQExpBufferStr(q, ";\n");
11443 
11444  appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
11445 
11446  if (dopt->binary_upgrade)
11448  "DOMAIN", qtypname,
11449  tyinfo->dobj.namespace->dobj.name);
11450 
11451  if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11452  ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
11453  ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
11454  .namespace = tyinfo->dobj.namespace->dobj.name,
11455  .owner = tyinfo->rolname,
11456  .description = "DOMAIN",
11457  .section = SECTION_PRE_DATA,
11458  .createStmt = q->data,
11459  .dropStmt = delq->data));
11460 
11461  /* Dump Domain Comments and Security Labels */
11462  if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11463  dumpComment(fout, "DOMAIN", qtypname,
11464  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11465  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11466 
11467  if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11468  dumpSecLabel(fout, "DOMAIN", qtypname,
11469  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11470  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11471 
11472  if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
11473  dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
11474  qtypname, NULL,
11475  tyinfo->dobj.namespace->dobj.name,
11476  NULL, tyinfo->rolname, &tyinfo->dacl);
11477 
11478  /* Dump any per-constraint comments */
11479  for (i = 0; i < tyinfo->nDomChecks; i++)
11480  {
11481  ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
11482  PQExpBuffer conprefix = createPQExpBuffer();
11483 
11484  appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
11485  fmtId(domcheck->dobj.name));
11486 
11487  if (domcheck->dobj.dump & DUMP_COMPONENT_COMMENT)
11488  dumpComment(fout, conprefix->data, qtypname,
11489  tyinfo->dobj.namespace->dobj.name,
11490  tyinfo->rolname,
11491  domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
11492 
11493  destroyPQExpBuffer(conprefix);
11494  }
11495 
11496  destroyPQExpBuffer(q);
11497  destroyPQExpBuffer(delq);
11498  destroyPQExpBuffer(query);
11499  free(qtypname);
11500  free(qualtypname);
11501 }
11502 
11503 /*
11504  * dumpCompositeType
11505  * writes out to fout the queries to recreate a user-defined stand-alone
11506  * composite type
11507  */
11508 static void
11509 dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
11510 {
11511  DumpOptions *dopt = fout->dopt;
11513  PQExpBuffer dropped = createPQExpBuffer();
11514  PQExpBuffer delq = createPQExpBuffer();
11515  PQExpBuffer query = createPQExpBuffer();
11516  PGresult *res;
11517  char *qtypname;
11518  char *qualtypname;
11519  int ntups;
11520  int i_attname;
11521  int i_atttypdefn;
11522  int i_attlen;
11523  int i_attalign;
11524  int i_attisdropped;
11525  int i_attcollation;
11526  int i;
11527  int actual_atts;
11528 
11530  {
11531  /*
11532  * Set up query for type-specific details.
11533  *
11534  * Since we only want to dump COLLATE clauses for attributes whose
11535  * collation is different from their type's default, we use a CASE
11536  * here to suppress uninteresting attcollations cheaply. atttypid
11537  * will be 0 for dropped columns; collation does not matter for those.
11538  */
11539  appendPQExpBufferStr(query,
11540  "PREPARE dumpCompositeType(pg_catalog.oid) AS\n"
11541  "SELECT a.attname, a.attnum, "
11542  "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
11543  "a.attlen, a.attalign, a.attisdropped, "
11544  "CASE WHEN a.attcollation <> at.typcollation "
11545  "THEN a.attcollation ELSE 0 END AS attcollation "
11546  "FROM pg_catalog.pg_type ct "
11547  "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
11548  "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
11549  "WHERE ct.oid = $1 "
11550  "ORDER BY a.attnum");
11551 
11552  ExecuteSqlStatement(fout, query->data);
11553 
11555  }
11556 
11557  printfPQExpBuffer(query,
11558  "EXECUTE dumpCompositeType('%u')",
11559  tyinfo->dobj.catId.oid);
11560 
11561  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11562 
11563  ntups = PQntuples(res);
11564 
11565  i_attname = PQfnumber(res, "attname");
11566  i_atttypdefn = PQfnumber(res, "atttypdefn");
11567  i_attlen = PQfnumber(res, "attlen");
11568  i_attalign = PQfnumber(res, "attalign");
11569  i_attisdropped = PQfnumber(res, "attisdropped");
11570  i_attcollation = PQfnumber(res, "attcollation");
11571 
11572  if (dopt->binary_upgrade)
11573  {
11575  tyinfo->dobj.catId.oid,
11576  false, false);
11577  binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid);
11578  }
11579 
11580  qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
11581  qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
11582 
11583  appendPQExpBuffer(q, "CREATE TYPE %s AS (",
11584  qualtypname);
11585 
11586  actual_atts = 0;
11587  for (i = 0; i < ntups; i++)
11588  {
11589  char *attname;
11590  char *atttypdefn;
11591  char *attlen;
11592  char *attalign;
11593  bool attisdropped;
11594  Oid attcollation;
11595 
11596  attname = PQgetvalue(res, i, i_attname);
11597  atttypdefn = PQgetvalue(res, i, i_atttypdefn);
11598  attlen = PQgetvalue(res, i, i_attlen);
11599  attalign = PQgetvalue(res, i, i_attalign);
11600  attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
11601  attcollation = atooid(PQgetvalue(res, i, i_attcollation));
11602 
11603  if (attisdropped && !dopt->binary_upgrade)
11604  continue;
11605 
11606  /* Format properly if not first attr */
11607  if (actual_atts++ > 0)
11608  appendPQExpBufferChar(q, ',');
11609  appendPQExpBufferStr(q, "\n\t");
11610 
11611  if (!attisdropped)
11612  {
11613  appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
11614 
11615  /* Add collation if not default for the column type */
11616  if (OidIsValid(attcollation))
11617  {
11618  CollInfo *coll;
11619 
11620  coll = findCollationByOid(attcollation);
11621  if (coll)
11622  appendPQExpBuffer(q, " COLLATE %s",
11623  fmtQualifiedDumpable(coll));
11624  }
11625  }
11626  else
11627  {
11628  /*
11629  * This is a dropped attribute and we're in binary_upgrade mode.
11630  * Insert a placeholder for it in the CREATE TYPE command, and set
11631  * length and alignment with direct UPDATE to the catalogs
11632  * afterwards. See similar code in dumpTableSchema().
11633  */
11634  appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
11635 
11636  /* stash separately for insertion after the CREATE TYPE */
11637  appendPQExpBufferStr(dropped,
11638  "\n-- For binary upgrade, recreate dropped column.\n");
11639  appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
11640  "SET attlen = %s, "
11641  "attalign = '%s', attbyval = false\n"
11642  "WHERE attname = ", attlen, attalign);
11643  appendStringLiteralAH(dropped, attname, fout);
11644  appendPQExpBufferStr(dropped, "\n AND attrelid = ");
11645  appendStringLiteralAH(dropped, qualtypname, fout);
11646  appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
11647 
11648  appendPQExpBuffer(dropped, "ALTER TYPE %s ",
11649  qualtypname);
11650  appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
11651  fmtId(attname));
11652  }
11653  }
11654  appendPQExpBufferStr(q, "\n);\n");
11655  appendPQExpBufferStr(q, dropped->data);
11656 
11657  appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
11658 
11659  if (dopt->binary_upgrade)
11661  "TYPE", qtypname,
11662  tyinfo->dobj.namespace->dobj.name);
11663 
11664  if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11665  ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
11666  ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
11667  .namespace = tyinfo->dobj.namespace->dobj.name,
11668  .owner = tyinfo->rolname,
11669  .description = "TYPE",
11670  .section = SECTION_PRE_DATA,
11671  .createStmt = q->data,
11672  .dropStmt = delq->data));
11673 
11674 
11675  /* Dump Type Comments and Security Labels */
11676  if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11677  dumpComment(fout, "TYPE", qtypname,
11678  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11679  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11680 
11681  if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11682  dumpSecLabel(fout, "TYPE", qtypname,
11683  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11684  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11685 
11686  if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
11687  dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
11688  qtypname, NULL,
11689  tyinfo->dobj.namespace->dobj.name,
11690  NULL, tyinfo->rolname, &tyinfo->dacl);
11691 
11692  /* Dump any per-column comments */
11693  if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11694  dumpCompositeTypeColComments(fout, tyinfo, res);
11695 
11696  PQclear(res);
11697  destroyPQExpBuffer(q);
11698  destroyPQExpBuffer(dropped);
11699  destroyPQExpBuffer(delq);
11700  destroyPQExpBuffer(query);
11701  free(qtypname);
11702  free(qualtypname);
11703 }
11704 
11705 /*
11706  * dumpCompositeTypeColComments
11707  * writes out to fout the queries to recreate comments on the columns of
11708  * a user-defined stand-alone composite type.
11709  *
11710  * The caller has already made a query to collect the names and attnums
11711  * of the type's columns, so we just pass that result into here rather
11712  * than reading them again.
11713  */
11714 static void
11716  PGresult *res)
11717 {
11719  int ncomments;
11720  PQExpBuffer query;
11721  PQExpBuffer target;
11722  int i;
11723  int ntups;
11724  int i_attname;
11725  int i_attnum;
11726  int i_attisdropped;
11727 
11728  /* do nothing, if --no-comments is supplied */
11729  if (fout->dopt->no_comments)
11730  return;
11731 
11732  /* Search for comments associated with type's pg_class OID */
11733  ncomments = findComments(RelationRelationId, tyinfo->typrelid,
11734  &comments);
11735 
11736  /* If no comments exist, we're done */
11737  if (ncomments <= 0)
11738  return;
11739 
11740  /* Build COMMENT ON statements */
11741  query = createPQExpBuffer();
11742  target = createPQExpBuffer();
11743 
11744  ntups = PQntuples(res);
11745  i_attnum = PQfnumber(res, "attnum");
11746  i_attname = PQfnumber(res, "attname");
11747  i_attisdropped = PQfnumber(res, "attisdropped");
11748  while (ncomments > 0)
11749  {
11750  const char *attname;
11751 
11752  attname = NULL;
11753  for (i = 0; i < ntups; i++)
11754  {
11755  if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid &&
11756  PQgetvalue(res, i, i_attisdropped)[0] != 't')
11757  {
11758  attname = PQgetvalue(res, i, i_attname);
11759  break;
11760  }
11761  }
11762  if (attname) /* just in case we don't find it */
11763  {
11764  const char *descr = comments->descr;
11765 
11766  resetPQExpBuffer(target);
11767  appendPQExpBuffer(target, "COLUMN %s.",
11768  fmtId(tyinfo->dobj.name));
11770 
11771  resetPQExpBuffer(query);
11772  appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
11773  fmtQualifiedDumpable(tyinfo));
11774  appendPQExpBuffer(query, "%s IS ", fmtId(attname));
11775  appendStringLiteralAH(query, descr, fout);
11776  appendPQExpBufferStr(query, ";\n");
11777 
11779  ARCHIVE_OPTS(.tag = target->data,
11780  .namespace = tyinfo->dobj.namespace->dobj.name,
11781  .owner = tyinfo->rolname,
11782  .description = "COMMENT",
11783  .section = SECTION_NONE,
11784  .createStmt = query->data,
11785  .deps = &(tyinfo->dobj.dumpId),
11786  .nDeps = 1));
11787  }
11788 
11789  comments++;
11790  ncomments--;
11791  }
11792 
11793  destroyPQExpBuffer(query);
11794  destroyPQExpBuffer(target);
11795 }
11796 
11797 /*
11798  * dumpShellType
11799  * writes out to fout the queries to create a shell type
11800  *
11801  * We dump a shell definition in advance of the I/O functions for the type.
11802  */
11803 static void
11804 dumpShellType(Archive *fout, const ShellTypeInfo *stinfo)
11805 {
11806  DumpOptions *dopt = fout->dopt;
11807  PQExpBuffer q;
11808 
11809  /* Do nothing in data-only dump */
11810  if (dopt->dataOnly)
11811  return;
11812 
11813  q = createPQExpBuffer();
11814 
11815  /*
11816  * Note the lack of a DROP command for the shell type; any required DROP
11817  * is driven off the base type entry, instead. This interacts with
11818  * _printTocEntry()'s use of the presence of a DROP command to decide
11819  * whether an entry needs an ALTER OWNER command. We don't want to alter
11820  * the shell type's owner immediately on creation; that should happen only
11821  * after it's filled in, otherwise the backend complains.
11822  */
11823 
11824  if (dopt->binary_upgrade)
11826  stinfo->baseType->dobj.catId.oid,
11827  false, false);
11828 
11829  appendPQExpBuffer(q, "CREATE TYPE %s;\n",
11830  fmtQualifiedDumpable(stinfo));
11831 
11832  if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11833  ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
11834  ARCHIVE_OPTS(.tag = stinfo->dobj.name,
11835  .namespace = stinfo->dobj.namespace->dobj.name,
11836  .owner = stinfo->baseType->rolname,
11837  .description = "SHELL TYPE",
11838  .section = SECTION_PRE_DATA,
11839  .createStmt = q->data));
11840 
11841  destroyPQExpBuffer(q);
11842 }
11843 
11844 /*
11845  * dumpProcLang
11846  * writes out to fout the queries to recreate a user-defined
11847  * procedural language
11848  */
11849 static void
11850 dumpProcLang(Archive *fout, const ProcLangInfo *plang)
11851 {
11852  DumpOptions *dopt = fout->dopt;
11853  PQExpBuffer defqry;
11854  PQExpBuffer delqry;
11855  bool useParams;
11856  char *qlanname;
11857  FuncInfo *funcInfo;
11858  FuncInfo *inlineInfo = NULL;
11859  FuncInfo *validatorInfo = NULL;
11860 
11861  /* Do nothing in data-only dump */
11862  if (dopt->dataOnly)
11863  return;
11864 
11865  /*
11866  * Try to find the support function(s). It is not an error if we don't
11867  * find them --- if the functions are in the pg_catalog schema, as is
11868  * standard in 8.1 and up, then we won't have loaded them. (In this case
11869  * we will emit a parameterless CREATE LANGUAGE command, which will
11870  * require PL template knowledge in the backend to reload.)
11871  */
11872 
11873  funcInfo = findFuncByOid(plang->lanplcallfoid);
11874  if (funcInfo != NULL && !funcInfo->dobj.dump)
11875  funcInfo = NULL; /* treat not-dumped same as not-found */
11876 
11877  if (OidIsValid(plang->laninline))
11878  {
11879  inlineInfo = findFuncByOid(plang->laninline);
11880  if (inlineInfo != NULL && !inlineInfo->dobj.dump)
11881  inlineInfo = NULL;
11882  }
11883 
11884  if (OidIsValid(plang->lanvalidator))
11885  {
11886  validatorInfo = findFuncByOid(plang->lanvalidator);
11887  if (validatorInfo != NULL && !validatorInfo->dobj.dump)
11888  validatorInfo = NULL;
11889  }
11890 
11891  /*
11892  * If the functions are dumpable then emit a complete CREATE LANGUAGE with
11893  * parameters. Otherwise, we'll write a parameterless command, which will
11894  * be interpreted as CREATE EXTENSION.
11895  */
11896  useParams = (funcInfo != NULL &&
11897  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
11898  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
11899 
11900  defqry = createPQExpBuffer();
11901  delqry = createPQExpBuffer();
11902 
11903  qlanname = pg_strdup(fmtId(plang->dobj.name));
11904 
11905  appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
11906  qlanname);
11907 
11908  if (useParams)
11909  {
11910  appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
11911  plang->lanpltrusted ? "TRUSTED " : "",
11912  qlanname);
11913  appendPQExpBuffer(defqry, " HANDLER %s",
11914  fmtQualifiedDumpable(funcInfo));
11915  if (OidIsValid(plang->laninline))
11916  appendPQExpBuffer(defqry, " INLINE %s",
11917  fmtQualifiedDumpable(inlineInfo));
11918  if (OidIsValid(plang->lanvalidator))
11919  appendPQExpBuffer(defqry, " VALIDATOR %s",
11920  fmtQualifiedDumpable(validatorInfo));
11921  }
11922  else
11923  {
11924  /*
11925  * If not dumping parameters, then use CREATE OR REPLACE so that the
11926  * command will not fail if the language is preinstalled in the target
11927  * database.
11928  *
11929  * Modern servers will interpret this as CREATE EXTENSION IF NOT
11930  * EXISTS; perhaps we should emit that instead? But it might just add
11931  * confusion.
11932  */
11933  appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
11934  qlanname);
11935  }
11936  appendPQExpBufferStr(defqry, ";\n");
11937 
11938  if (dopt->binary_upgrade)
11939  binary_upgrade_extension_member(defqry, &plang->dobj,
11940  "LANGUAGE", qlanname, NULL);
11941 
11942  if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
11943  ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
11944  ARCHIVE_OPTS(.tag = plang->dobj.name,
11945  .owner = plang->lanowner,
11946  .description = "PROCEDURAL LANGUAGE",
11947  .section = SECTION_PRE_DATA,
11948  .createStmt = defqry->data,
11949  .dropStmt = delqry->data,
11950  ));
11951 
11952  /* Dump Proc Lang Comments and Security Labels */
11953  if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
11954  dumpComment(fout, "LANGUAGE", qlanname,
11955  NULL, plang->lanowner,
11956  plang->dobj.catId, 0, plang->dobj.dumpId);
11957 
11958  if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
11959  dumpSecLabel(fout, "LANGUAGE", qlanname,
11960  NULL, plang->lanowner,
11961  plang->dobj.catId, 0, plang->dobj.dumpId);
11962 
11963  if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
11964  dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
11965  qlanname, NULL, NULL,
11966  NULL, plang->lanowner, &plang->dacl);
11967 
11968  free(qlanname);
11969 
11970  destroyPQExpBuffer(defqry);
11971  destroyPQExpBuffer(delqry);
11972 }
11973 
11974 /*
11975  * format_function_arguments: generate function name and argument list
11976  *
11977  * This is used when we can rely on pg_get_function_arguments to format
11978  * the argument list. Note, however, that pg_get_function_arguments
11979  * does not special-case zero-argument aggregates.
11980  */
11981 static char *
11982 format_function_arguments(const FuncInfo *finfo, const char *funcargs, bool is_agg)
11983 {
11985 
11986  initPQExpBuffer(&fn);
11987  appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
11988  if (is_agg && finfo->nargs == 0)
11989  appendPQExpBufferStr(&fn, "(*)");
11990  else
11991  appendPQExpBuffer(&fn, "(%s)", funcargs);
11992  return fn.data;
11993 }
11994 
11995 /*
11996  * format_function_signature: generate function name and argument list
11997  *
11998  * Only a minimal list of input argument types is generated; this is
11999  * sufficient to reference the function, but not to define it.
12000  *
12001  * If honor_quotes is false then the function name is never quoted.
12002  * This is appropriate for use in TOC tags, but not in SQL commands.
12003  */
12004 static char *
12005 format_function_signature(Archive *fout, const FuncInfo *finfo, bool honor_quotes)
12006 {
12008  int j;
12009 
12010  initPQExpBuffer(&fn);
12011  if (honor_quotes)
12012  appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
12013  else
12014  appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
12015  for (j = 0; j < finfo->nargs; j++)
12016  {
12017  if (j > 0)
12018  appendPQExpBufferStr(&fn, ", ");
12019 
12021  getFormattedTypeName(fout, finfo->argtypes[j],
12022  zeroIsError));
12023  }
12024  appendPQExpBufferChar(&fn, ')');
12025  return fn.data;
12026 }
12027 
12028 
12029 /*
12030  * dumpFunc:
12031  * dump out one function
12032  */
12033 static void
12034 dumpFunc(Archive *fout, const FuncInfo *finfo)
12035 {
12036  DumpOptions *dopt = fout->dopt;
12037  PQExpBuffer query;
12038  PQExpBuffer q;
12039  PQExpBuffer delqry;
12040  PQExpBuffer asPart;
12041  PGresult *res;
12042  char *funcsig; /* identity signature */
12043  char *funcfullsig = NULL; /* full signature */
12044  char *funcsig_tag;
12045  char *qual_funcsig;
12046  char *proretset;
12047  char *prosrc;
12048  char *probin;
12049  char *prosqlbody;
12050  char *funcargs;
12051  char *funciargs;
12052  char *funcresult;
12053  char *protrftypes;
12054  char *prokind;
12055  char *provolatile;
12056  char *proisstrict;
12057  char *prosecdef;
12058  char *proleakproof;
12059  char *proconfig;
12060  char *procost;
12061  char *prorows;
12062  char *prosupport;
12063  char *proparallel;
12064  char *lanname;
12065  char **configitems = NULL;
12066  int nconfigitems = 0;
12067  const char *keyword;
12068 
12069  /* Do nothing in data-only dump */
12070  if (dopt->dataOnly)
12071  return;
12072 
12073  query = createPQExpBuffer();
12074  q = createPQExpBuffer();
12075  delqry = createPQExpBuffer();
12076  asPart = createPQExpBuffer();
12077 
12078  if (!fout->is_prepared[PREPQUERY_DUMPFUNC])
12079  {
12080  /* Set up query for function-specific details */
12081  appendPQExpBufferStr(query,
12082  "PREPARE dumpFunc(pg_catalog.oid) AS\n");
12083 
12084  appendPQExpBufferStr(query,
12085  "SELECT\n"
12086  "proretset,\n"
12087  "prosrc,\n"
12088  "probin,\n"
12089  "provolatile,\n"
12090  "proisstrict,\n"
12091  "prosecdef,\n"
12092  "lanname,\n"
12093  "proconfig,\n"
12094  "procost,\n"
12095  "prorows,\n"
12096  "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
12097  "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n"
12098  "pg_catalog.pg_get_function_result(p.oid) AS funcresult,\n"
12099  "proleakproof,\n");
12100 
12101  if (fout->remoteVersion >= 90500)
12102  appendPQExpBufferStr(query,
12103  "array_to_string(protrftypes, ' ') AS protrftypes,\n");
12104  else
12105  appendPQExpBufferStr(query,
12106  "NULL AS protrftypes,\n");
12107 
12108  if (fout->remoteVersion >= 90600)
12109  appendPQExpBufferStr(query,
12110  "proparallel,\n");
12111  else
12112  appendPQExpBufferStr(query,
12113  "'u' AS proparallel,\n");
12114 
12115  if (fout->remoteVersion >= 110000)
12116  appendPQExpBufferStr(query,
12117  "prokind,\n");
12118  else
12119  appendPQExpBufferStr(query,
12120  "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind,\n");
12121 
12122  if (fout->remoteVersion >= 120000)
12123  appendPQExpBufferStr(query,
12124  "prosupport,\n");
12125  else
12126  appendPQExpBufferStr(query,
12127  "'-' AS prosupport,\n");
12128 
12129  if (fout->remoteVersion >= 140000)
12130  appendPQExpBufferStr(query,
12131  "pg_get_function_sqlbody(p.oid) AS prosqlbody\n");
12132  else
12133  appendPQExpBufferStr(query,
12134  "NULL AS prosqlbody\n");
12135 
12136  appendPQExpBufferStr(query,
12137  "FROM pg_catalog.pg_proc p, pg_catalog.pg_language l\n"
12138  "WHERE p.oid = $1 "
12139  "AND l.oid = p.prolang");
12140 
12141  ExecuteSqlStatement(fout, query->data);
12142 
12143  fout->is_prepared[PREPQUERY_DUMPFUNC] = true;
12144  }
12145 
12146  printfPQExpBuffer(query,
12147  "EXECUTE dumpFunc('%u')",
12148  finfo->dobj.catId.oid);
12149 
12150  res = ExecuteSqlQueryForSingleRow(fout, query->data);
12151 
12152  proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
12153  if (PQgetisnull(res, 0, PQfnumber(res, "prosqlbody")))
12154  {
12155  prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
12156  probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
12157  prosqlbody = NULL;
12158  }
12159  else
12160  {
12161  prosrc = NULL;
12162  probin = NULL;
12163  prosqlbody = PQgetvalue(res, 0, PQfnumber(res, "prosqlbody"));
12164  }
12165  funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
12166  funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
12167  funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
12168  protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
12169  prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
12170  provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
12171  proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
12172  prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
12173  proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
12174  proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
12175  procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
12176  prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
12177  prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
12178  proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
12179  lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
12180 
12181  /*
12182  * See backend/commands/functioncmds.c for details of how the 'AS' clause
12183  * is used.
12184  */
12185  if (prosqlbody)
12186  {
12187  appendPQExpBufferStr(asPart, prosqlbody);
12188  }
12189  else if (probin[0] != '\0')
12190  {
12191  appendPQExpBufferStr(asPart, "AS ");
12192  appendStringLiteralAH(asPart, probin, fout);
12193  if (prosrc[0] != '\0')
12194  {
12195  appendPQExpBufferStr(asPart, ", ");
12196 
12197  /*
12198  * where we have bin, use dollar quoting if allowed and src
12199  * contains quote or backslash; else use regular quoting.
12200  */
12201  if (dopt->disable_dollar_quoting ||
12202  (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
12203  appendStringLiteralAH(asPart, prosrc, fout);
12204  else
12205  appendStringLiteralDQ(asPart, prosrc, NULL);
12206  }
12207  }
12208  else
12209  {
12210  appendPQExpBufferStr(asPart, "AS ");
12211  /* with no bin, dollar quote src unconditionally if allowed */
12212  if (dopt->disable_dollar_quoting)
12213  appendStringLiteralAH(asPart, prosrc, fout);
12214  else
12215  appendStringLiteralDQ(asPart, prosrc, NULL);
12216  }
12217 
12218  if (*proconfig)
12219  {
12220  if (!parsePGArray(proconfig, &configitems, &nconfigitems))
12221  pg_fatal("could not parse %s array", "proconfig");
12222  }
12223  else
12224  {
12225  configitems = NULL;
12226  nconfigitems = 0;
12227  }
12228 
12229  funcfullsig = format_function_arguments(finfo, funcargs, false);
12230  funcsig = format_function_arguments(finfo, funciargs, false);
12231 
12232  funcsig_tag = format_function_signature(fout, finfo, false);
12233 
12234  qual_funcsig = psprintf("%s.%s",
12235  fmtId(finfo->dobj.namespace->dobj.name),
12236  funcsig);
12237 
12238  if (prokind[0] == PROKIND_PROCEDURE)
12239  keyword = "PROCEDURE";
12240  else
12241  keyword = "FUNCTION"; /* works for window functions too */
12242 
12243  appendPQExpBuffer(delqry, "DROP %s %s;\n",
12244  keyword, qual_funcsig);
12245 
12246  appendPQExpBuffer(q, "CREATE %s %s.%s",
12247  keyword,
12248  fmtId(finfo->dobj.namespace->dobj.name),
12249  funcfullsig ? funcfullsig :
12250  funcsig);
12251 
12252  if (prokind[0] == PROKIND_PROCEDURE)
12253  /* no result type to output */ ;
12254  else if (funcresult)
12255  appendPQExpBuffer(q, " RETURNS %s", funcresult);
12256  else
12257  appendPQExpBuffer(q, " RETURNS %s%s",
12258  (proretset[0] == 't') ? "SETOF " : "",
12259  getFormattedTypeName(fout, finfo->prorettype,
12260  zeroIsError));
12261 
12262  appendPQExpBuffer(q, "\n LANGUAGE %s", fmtId(lanname));
12263 
12264  if (*protrftypes)
12265  {
12266  Oid *typeids = palloc(FUNC_MAX_ARGS * sizeof(Oid));
12267  int i;
12268 
12269  appendPQExpBufferStr(q, " TRANSFORM ");
12270  parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
12271  for (i = 0; typeids[i]; i++)
12272  {
12273  if (i != 0)
12274  appendPQExpBufferStr(q, ", ");
12275  appendPQExpBuffer(q, "FOR TYPE %s",
12276  getFormattedTypeName(fout, typeids[i], zeroAsNone));
12277  }
12278  }
12279 
12280  if (prokind[0] == PROKIND_WINDOW)
12281  appendPQExpBufferStr(q, " WINDOW");
12282 
12283  if (provolatile[0] != PROVOLATILE_VOLATILE)
12284  {
12285  if (provolatile[0] == PROVOLATILE_IMMUTABLE)
12286  appendPQExpBufferStr(q, " IMMUTABLE");
12287  else if (provolatile[0] == PROVOLATILE_STABLE)
12288  appendPQExpBufferStr(q, " STABLE");
12289  else if (provolatile[0] != PROVOLATILE_VOLATILE)
12290  pg_fatal("unrecognized provolatile value for function \"%s\"",
12291  finfo->dobj.name);
12292  }
12293 
12294  if (proisstrict[0] == 't')
12295  appendPQExpBufferStr(q, " STRICT");
12296 
12297  if (prosecdef[0] == 't')
12298  appendPQExpBufferStr(q, " SECURITY DEFINER");
12299 
12300  if (proleakproof[0] == 't')
12301  appendPQExpBufferStr(q, " LEAKPROOF");
12302 
12303  /*
12304  * COST and ROWS are emitted only if present and not default, so as not to
12305  * break backwards-compatibility of the dump without need. Keep this code
12306  * in sync with the defaults in functioncmds.c.
12307  */
12308  if (strcmp(procost, "0") != 0)
12309  {
12310  if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
12311  {
12312  /* default cost is 1 */
12313  if (strcmp(procost, "1") != 0)
12314  appendPQExpBuffer(q, " COST %s", procost);
12315  }
12316  else
12317  {
12318  /* default cost is 100 */
12319  if (strcmp(procost, "100") != 0)
12320  appendPQExpBuffer(q, " COST %s", procost);
12321  }
12322  }
12323  if (proretset[0] == 't' &&
12324  strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
12325  appendPQExpBuffer(q, " ROWS %s", prorows);
12326 
12327  if (strcmp(prosupport, "-") != 0)
12328  {
12329  /* We rely on regprocout to provide quoting and qualification */
12330  appendPQExpBuffer(q, " SUPPORT %s", prosupport);
12331  }
12332 
12333  if (proparallel[0] != PROPARALLEL_UNSAFE)
12334  {
12335  if (proparallel[0] == PROPARALLEL_SAFE)
12336  appendPQExpBufferStr(q, " PARALLEL SAFE");
12337  else if (proparallel[0] == PROPARALLEL_RESTRICTED)
12338  appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
12339  else if (proparallel[0] != PROPARALLEL_UNSAFE)
12340  pg_fatal("unrecognized proparallel value for function \"%s\"",
12341  finfo->dobj.name);
12342  }
12343 
12344  for (int i = 0; i < nconfigitems; i++)
12345  {
12346  /* we feel free to scribble on configitems[] here */
12347  char *configitem = configitems[i];
12348  char *pos;
12349 
12350  pos = strchr(configitem, '=');
12351  if (pos == NULL)
12352  continue;
12353  *pos++ = '\0';
12354  appendPQExpBuffer(q, "\n SET %s TO ", fmtId(configitem));
12355 
12356  /*
12357  * Variables that are marked GUC_LIST_QUOTE were already fully quoted
12358  * by flatten_set_variable_args() before they were put into the
12359  * proconfig array. However, because the quoting rules used there
12360  * aren't exactly like SQL's, we have to break the list value apart
12361  * and then quote the elements as string literals. (The elements may
12362  * be double-quoted as-is, but we can't just feed them to the SQL
12363  * parser; it would do the wrong thing with elements that are
12364  * zero-length or longer than NAMEDATALEN.)
12365  *
12366  * Variables that are not so marked should just be emitted as simple
12367  * string literals. If the variable is not known to
12368  * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
12369  * to use GUC_LIST_QUOTE for extension variables.
12370  */
12371  if (variable_is_guc_list_quote(configitem))
12372  {
12373  char **namelist;
12374  char **nameptr;
12375 
12376  /* Parse string into list of identifiers */
12377  /* this shouldn't fail really */
12378  if (SplitGUCList(pos, ',', &namelist))
12379  {
12380  for (nameptr = namelist; *nameptr; nameptr++)
12381  {
12382  if (nameptr != namelist)
12383  appendPQExpBufferStr(q, ", ");
12384  appendStringLiteralAH(q, *nameptr, fout);
12385  }
12386  }
12387  pg_free(namelist);
12388  }
12389  else
12390  appendStringLiteralAH(q, pos, fout);
12391  }
12392 
12393  appendPQExpBuffer(q, "\n %s;\n", asPart->data);
12394 
12395  append_depends_on_extension(fout, q, &finfo->dobj,
12396  "pg_catalog.pg_proc", keyword,
12397  qual_funcsig);
12398 
12399  if (dopt->binary_upgrade)
12401  keyword, funcsig,
12402  finfo->dobj.namespace->dobj.name);
12403 
12404  if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12405  ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
12406  ARCHIVE_OPTS(.tag = funcsig_tag,
12407  .namespace = finfo->dobj.namespace->dobj.name,
12408  .owner = finfo->rolname,
12409  .description = keyword,
12410  .section = finfo->postponed_def ?
12412  .createStmt = q->data,
12413  .dropStmt = delqry->data));
12414 
12415  /* Dump Function Comments and Security Labels */
12416  if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12417  dumpComment(fout, keyword, funcsig,
12418  finfo->dobj.namespace->dobj.name, finfo->rolname,
12419  finfo->dobj.catId, 0, finfo->dobj.dumpId);
12420 
12421  if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
12422  dumpSecLabel(fout, keyword, funcsig,
12423  finfo->dobj.namespace->dobj.name, finfo->rolname,
12424  finfo->dobj.catId, 0, finfo->dobj.dumpId);
12425 
12426  if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
12427  dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, keyword,
12428  funcsig, NULL,
12429  finfo->dobj.namespace->dobj.name,
12430  NULL, finfo->rolname, &finfo->dacl);
12431 
12432  PQclear(res);
12433 
12434  destroyPQExpBuffer(query);
12435  destroyPQExpBuffer(q);
12436  destroyPQExpBuffer(delqry);
12437  destroyPQExpBuffer(asPart);
12438  free(funcsig);
12439  free(funcfullsig);
12440  free(funcsig_tag);
12441  free(qual_funcsig);
12442  free(configitems);
12443 }
12444 
12445 
12446 /*
12447  * Dump a user-defined cast
12448  */
12449 static void
12450 dumpCast(Archive *fout, const CastInfo *cast)
12451 {
12452  DumpOptions *dopt = fout->dopt;
12453  PQExpBuffer defqry;
12454  PQExpBuffer delqry;
12455  PQExpBuffer labelq;
12456  PQExpBuffer castargs;
12457  FuncInfo *funcInfo = NULL;
12458  const char *sourceType;
12459  const char *targetType;
12460 
12461  /* Do nothing in data-only dump */
12462  if (dopt->dataOnly)
12463  return;
12464 
12465  /* Cannot dump if we don't have the cast function's info */
12466  if (OidIsValid(cast->castfunc))
12467  {
12468  funcInfo = findFuncByOid(cast->castfunc);
12469  if (funcInfo == NULL)
12470  pg_fatal("could not find function definition for function with OID %u",
12471  cast->castfunc);
12472  }
12473 
12474  defqry = createPQExpBuffer();
12475  delqry = createPQExpBuffer();
12476  labelq = createPQExpBuffer();
12477  castargs = createPQExpBuffer();
12478 
12479  sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
12480  targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
12481  appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
12482  sourceType, targetType);
12483 
12484  appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
12485  sourceType, targetType);
12486 
12487  switch (cast->castmethod)
12488  {
12489  case COERCION_METHOD_BINARY:
12490  appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
12491  break;
12492  case COERCION_METHOD_INOUT:
12493  appendPQExpBufferStr(defqry, "WITH INOUT");
12494  break;
12495  case COERCION_METHOD_FUNCTION:
12496  if (funcInfo)
12497  {
12498  char *fsig = format_function_signature(fout, funcInfo, true);
12499 
12500  /*
12501  * Always qualify the function name (format_function_signature
12502  * won't qualify it).
12503  */
12504  appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
12505  fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
12506  free(fsig);
12507  }
12508  else
12509  pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
12510  break;
12511  default:
12512  pg_log_warning("bogus value in pg_cast.castmethod field");
12513  }
12514 
12515  if (cast->castcontext == 'a')
12516  appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
12517  else if (cast->castcontext == 'i')
12518  appendPQExpBufferStr(defqry, " AS IMPLICIT");
12519  appendPQExpBufferStr(defqry, ";\n");
12520 
12521  appendPQExpBuffer(labelq, "CAST (%s AS %s)",
12522  sourceType, targetType);
12523 
12524  appendPQExpBuffer(castargs, "(%s AS %s)",
12525  sourceType, targetType);
12526 
12527  if (dopt->binary_upgrade)
12528  binary_upgrade_extension_member(defqry, &cast->dobj,
12529  "CAST", castargs->data, NULL);
12530 
12531  if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
12532  ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
12533  ARCHIVE_OPTS(.tag = labelq->data,
12534  .description = "CAST",
12535  .section = SECTION_PRE_DATA,
12536  .createStmt = defqry->data,
12537  .dropStmt = delqry->data));
12538 
12539  /* Dump Cast Comments */
12540  if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
12541  dumpComment(fout, "CAST", castargs->data,
12542  NULL, "",
12543  cast->dobj.catId, 0, cast->dobj.dumpId);
12544 
12545  destroyPQExpBuffer(defqry);
12546  destroyPQExpBuffer(delqry);
12547  destroyPQExpBuffer(labelq);
12548  destroyPQExpBuffer(castargs);
12549 }
12550 
12551 /*
12552  * Dump a transform
12553  */
12554 static void
12555 dumpTransform(Archive *fout, const TransformInfo *transform)
12556 {
12557  DumpOptions *dopt = fout->dopt;
12558  PQExpBuffer defqry;
12559  PQExpBuffer delqry;
12560  PQExpBuffer labelq;
12561  PQExpBuffer transformargs;
12562  FuncInfo *fromsqlFuncInfo = NULL;
12563  FuncInfo *tosqlFuncInfo = NULL;
12564  char *lanname;
12565  const char *transformType;
12566 
12567  /* Do nothing in data-only dump */
12568  if (dopt->dataOnly)
12569  return;
12570 
12571  /* Cannot dump if we don't have the transform functions' info */
12572  if (OidIsValid(transform->trffromsql))
12573  {
12574  fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
12575  if (fromsqlFuncInfo == NULL)
12576  pg_fatal("could not find function definition for function with OID %u",
12577  transform->trffromsql);
12578  }
12579  if (OidIsValid(transform->trftosql))
12580  {
12581  tosqlFuncInfo = findFuncByOid(transform->trftosql);
12582  if (tosqlFuncInfo == NULL)
12583  pg_fatal("could not find function definition for function with OID %u",
12584  transform->trftosql);
12585  }
12586 
12587  defqry = createPQExpBuffer();
12588  delqry = createPQExpBuffer();
12589  labelq = createPQExpBuffer();
12590  transformargs = createPQExpBuffer();
12591 
12592  lanname = get_language_name(fout, transform->trflang);
12593  transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
12594 
12595  appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
12596  transformType, lanname);
12597 
12598  appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
12599  transformType, lanname);
12600 
12601  if (!transform->trffromsql && !transform->trftosql)
12602  pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
12603 
12604  if (transform->trffromsql)
12605  {
12606  if (fromsqlFuncInfo)
12607  {
12608  char *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
12609 
12610  /*
12611  * Always qualify the function name (format_function_signature
12612  * won't qualify it).
12613  */
12614  appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
12615  fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
12616  free(fsig);
12617  }
12618  else
12619  pg_log_warning("bogus value in pg_transform.trffromsql field");
12620  }
12621 
12622  if (transform->trftosql)
12623  {
12624  if (transform->trffromsql)
12625  appendPQExpBufferStr(defqry, ", ");
12626 
12627  if (tosqlFuncInfo)
12628  {
12629  char *fsig = format_function_signature(fout, tosqlFuncInfo, true);
12630 
12631  /*
12632  * Always qualify the function name (format_function_signature
12633  * won't qualify it).
12634  */
12635  appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
12636  fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
12637  free(fsig);
12638  }
12639  else
12640  pg_log_warning("bogus value in pg_transform.trftosql field");
12641  }
12642 
12643  appendPQExpBufferStr(defqry, ");\n");
12644 
12645  appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
12646  transformType, lanname);
12647 
12648  appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
12649  transformType, lanname);
12650 
12651  if (dopt->binary_upgrade)
12652  binary_upgrade_extension_member(defqry, &transform->dobj,
12653  "TRANSFORM", transformargs->data, NULL);
12654 
12655  if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
12656  ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
12657  ARCHIVE_OPTS(.tag = labelq->data,
12658  .description = "TRANSFORM",
12659  .section = SECTION_PRE_DATA,
12660  .createStmt = defqry->data,
12661  .dropStmt = delqry->data,
12662  .deps = transform->dobj.dependencies,
12663  .nDeps = transform->dobj.nDeps));
12664 
12665  /* Dump Transform Comments */
12666  if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
12667  dumpComment(fout, "TRANSFORM", transformargs->data,
12668  NULL, "",
12669  transform->dobj.catId, 0, transform->dobj.dumpId);
12670 
12671  free(lanname);
12672  destroyPQExpBuffer(defqry);
12673  destroyPQExpBuffer(delqry);
12674  destroyPQExpBuffer(labelq);
12675  destroyPQExpBuffer(transformargs);
12676 }
12677 
12678 
12679 /*
12680  * dumpOpr
12681  * write out a single operator definition
12682  */
12683 static void
12684 dumpOpr(Archive *fout, const OprInfo *oprinfo)
12685 {
12686  DumpOptions *dopt = fout->dopt;
12687  PQExpBuffer query;
12688  PQExpBuffer q;
12689  PQExpBuffer delq;
12691  PQExpBuffer details;
12692  PGresult *res;
12693  int i_oprkind;
12694  int i_oprcode;
12695  int i_oprleft;
12696  int i_oprright;
12697  int i_oprcom;
12698  int i_oprnegate;
12699  int i_oprrest;
12700  int i_oprjoin;
12701  int i_oprcanmerge;
12702  int i_oprcanhash;
12703  char *oprkind;
12704  char *oprcode;
12705  char *oprleft;
12706  char *oprright;
12707  char *oprcom;
12708  char *oprnegate;
12709  char *oprrest;
12710  char *oprjoin;
12711  char *oprcanmerge;
12712  char *oprcanhash;
12713  char *oprregproc;
12714  char *oprref;
12715 
12716  /* Do nothing in data-only dump */
12717  if (dopt->dataOnly)
12718  return;
12719 
12720  /*
12721  * some operators are invalid because they were the result of user
12722  * defining operators before commutators exist
12723  */
12724  if (!OidIsValid(oprinfo->oprcode))
12725  return;
12726 
12727  query = createPQExpBuffer();
12728  q = createPQExpBuffer();
12729  delq = createPQExpBuffer();
12731  details = createPQExpBuffer();
12732 
12733  if (!fout->is_prepared[PREPQUERY_DUMPOPR])
12734  {
12735  /* Set up query for operator-specific details */
12736  appendPQExpBufferStr(query,
12737  "PREPARE dumpOpr(pg_catalog.oid) AS\n"
12738  "SELECT oprkind, "
12739  "oprcode::pg_catalog.regprocedure, "
12740  "oprleft::pg_catalog.regtype, "
12741  "oprright::pg_catalog.regtype, "
12742  "oprcom, "
12743  "oprnegate, "
12744  "oprrest::pg_catalog.regprocedure, "
12745  "oprjoin::pg_catalog.regprocedure, "
12746  "oprcanmerge, oprcanhash "
12747  "FROM pg_catalog.pg_operator "
12748  "WHERE oid = $1");
12749 
12750  ExecuteSqlStatement(fout, query->data);
12751 
12752  fout->is_prepared[PREPQUERY_DUMPOPR] = true;
12753  }
12754 
12755  printfPQExpBuffer(query,
12756  "EXECUTE dumpOpr('%u')",
12757  oprinfo->dobj.catId.oid);
12758 
12759  res = ExecuteSqlQueryForSingleRow(fout, query->data);
12760 
12761  i_oprkind = PQfnumber(res, "oprkind");
12762  i_oprcode = PQfnumber(res, "oprcode");
12763  i_oprleft = PQfnumber(res, "oprleft");
12764  i_oprright = PQfnumber(res, "oprright");
12765  i_oprcom = PQfnumber(res, "oprcom");
12766  i_oprnegate = PQfnumber(res, "oprnegate");
12767  i_oprrest = PQfnumber(res, "oprrest");
12768  i_oprjoin = PQfnumber(res, "oprjoin");
12769  i_oprcanmerge = PQfnumber(res, "oprcanmerge");
12770  i_oprcanhash = PQfnumber(res, "oprcanhash");
12771 
12772  oprkind = PQgetvalue(res, 0, i_oprkind);
12773  oprcode = PQgetvalue(res, 0, i_oprcode);
12774  oprleft = PQgetvalue(res, 0, i_oprleft);
12775  oprright = PQgetvalue(res, 0, i_oprright);
12776  oprcom = PQgetvalue(res, 0, i_oprcom);
12777  oprnegate = PQgetvalue(res, 0, i_oprnegate);
12778  oprrest = PQgetvalue(res, 0, i_oprrest);
12779  oprjoin = PQgetvalue(res, 0, i_oprjoin);
12780  oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
12781  oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
12782 
12783  /* In PG14 upwards postfix operator support does not exist anymore. */
12784  if (strcmp(oprkind, "r") == 0)
12785  pg_log_warning("postfix operators are not supported anymore (operator \"%s\")",
12786  oprcode);
12787 
12788  oprregproc = convertRegProcReference(oprcode);
12789  if (oprregproc)
12790  {
12791  appendPQExpBuffer(details, " FUNCTION = %s", oprregproc);
12792  free(oprregproc);
12793  }
12794 
12795  appendPQExpBuffer(oprid, "%s (",
12796  oprinfo->dobj.name);
12797 
12798  /*
12799  * right unary means there's a left arg and left unary means there's a
12800  * right arg. (Although the "r" case is dead code for PG14 and later,
12801  * continue to support it in case we're dumping from an old server.)
12802  */
12803  if (strcmp(oprkind, "r") == 0 ||
12804  strcmp(oprkind, "b") == 0)
12805  {
12806  appendPQExpBuffer(details, ",\n LEFTARG = %s", oprleft);
12807  appendPQExpBufferStr(oprid, oprleft);
12808  }
12809  else
12810  appendPQExpBufferStr(oprid, "NONE");
12811 
12812  if (strcmp(oprkind, "l") == 0 ||
12813  strcmp(oprkind, "b") == 0)
12814  {
12815  appendPQExpBuffer(details, ",\n RIGHTARG = %s", oprright);
12816  appendPQExpBuffer(oprid, ", %s)", oprright);
12817  }
12818  else
12819  appendPQExpBufferStr(oprid, ", NONE)");
12820 
12821  oprref = getFormattedOperatorName(oprcom);
12822  if (oprref)
12823  {
12824  appendPQExpBuffer(details, ",\n COMMUTATOR = %s", oprref);
12825  free(oprref);
12826  }
12827 
12828  oprref = getFormattedOperatorName(oprnegate);
12829  if (oprref)
12830  {
12831  appendPQExpBuffer(details, ",\n NEGATOR = %s", oprref);
12832  free(oprref);
12833  }
12834 
12835  if (strcmp(oprcanmerge, "t") == 0)
12836  appendPQExpBufferStr(details, ",\n MERGES");
12837 
12838  if (strcmp(oprcanhash, "t") == 0)
12839  appendPQExpBufferStr(details, ",\n HASHES");
12840 
12841  oprregproc = convertRegProcReference(oprrest);
12842  if (oprregproc)
12843  {
12844  appendPQExpBuffer(details, ",\n RESTRICT = %s", oprregproc);
12845  free(oprregproc);
12846  }
12847 
12848  oprregproc = convertRegProcReference(oprjoin);
12849  if (oprregproc)
12850  {
12851  appendPQExpBuffer(details, ",\n JOIN = %s", oprregproc);
12852  free(oprregproc);
12853  }
12854 
12855  appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
12856  fmtId(oprinfo->dobj.namespace->dobj.name),
12857  oprid->data);
12858 
12859  appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
12860  fmtId(oprinfo->dobj.namespace->dobj.name),
12861  oprinfo->dobj.name, details->data);
12862 
12863  if (dopt->binary_upgrade)
12865  "OPERATOR", oprid->data,
12866  oprinfo->dobj.namespace->dobj.name);
12867 
12868  if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12869  ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
12870  ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
12871  .namespace = oprinfo->dobj.namespace->dobj.name,
12872  .owner = oprinfo->rolname,
12873  .description = "OPERATOR",
12874  .section = SECTION_PRE_DATA,
12875  .createStmt = q->data,
12876  .dropStmt = delq->data));
12877 
12878  /* Dump Operator Comments */
12879  if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12880  dumpComment(fout, "OPERATOR", oprid->data,
12881  oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
12882  oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
12883 
12884  PQclear(res);
12885 
12886  destroyPQExpBuffer(query);
12887  destroyPQExpBuffer(q);
12888  destroyPQExpBuffer(delq);
12890  destroyPQExpBuffer(details);
12891 }
12892 
12893 /*
12894  * Convert a function reference obtained from pg_operator
12895  *
12896  * Returns allocated string of what to print, or NULL if function references
12897  * is InvalidOid. Returned string is expected to be free'd by the caller.
12898  *
12899  * The input is a REGPROCEDURE display; we have to strip the argument-types
12900  * part.
12901  */
12902 static char *
12903 convertRegProcReference(const char *proc)
12904 {
12905  char *name;
12906  char *paren;
12907  bool inquote;
12908 
12909  /* In all cases "-" means a null reference */
12910  if (strcmp(proc, "-") == 0)
12911  return NULL;
12912 
12913  name = pg_strdup(proc);
12914  /* find non-double-quoted left paren */
12915  inquote = false;
12916  for (paren = name; *paren; paren++)
12917  {
12918  if (*paren == '(' && !inquote)
12919  {
12920  *paren = '\0';
12921  break;
12922  }
12923  if (*paren == '"')
12924  inquote = !inquote;
12925  }
12926  return name;
12927 }
12928 
12929 /*
12930  * getFormattedOperatorName - retrieve the operator name for the
12931  * given operator OID (presented in string form).
12932  *
12933  * Returns an allocated string, or NULL if the given OID is invalid.
12934  * Caller is responsible for free'ing result string.
12935  *
12936  * What we produce has the format "OPERATOR(schema.oprname)". This is only
12937  * useful in commands where the operator's argument types can be inferred from
12938  * context. We always schema-qualify the name, though. The predecessor to
12939  * this code tried to skip the schema qualification if possible, but that led
12940  * to wrong results in corner cases, such as if an operator and its negator
12941  * are in different schemas.
12942  */
12943 static char *
12944 getFormattedOperatorName(const char *oproid)
12945 {
12946  OprInfo *oprInfo;
12947 
12948  /* In all cases "0" means a null reference */
12949  if (strcmp(oproid, "0") == 0)
12950  return NULL;
12951 
12952  oprInfo = findOprByOid(atooid(oproid));
12953  if (oprInfo == NULL)
12954  {
12955  pg_log_warning("could not find operator with OID %s",
12956  oproid);
12957  return NULL;
12958  }
12959 
12960  return psprintf("OPERATOR(%s.%s)",
12961  fmtId(oprInfo->dobj.namespace->dobj.name),
12962  oprInfo->dobj.name);
12963 }
12964 
12965 /*
12966  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
12967  *
12968  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
12969  * argument lists of these functions are predetermined. Note that the
12970  * caller should ensure we are in the proper schema, because the results
12971  * are search path dependent!
12972  */
12973 static char *
12975 {
12976  char *result;
12977  char query[128];
12978  PGresult *res;
12979 
12980  snprintf(query, sizeof(query),
12981  "SELECT '%u'::pg_catalog.regproc", funcOid);
12982  res = ExecuteSqlQueryForSingleRow(fout, query);
12983 
12984  result = pg_strdup(PQgetvalue(res, 0, 0));
12985 
12986  PQclear(res);
12987 
12988  return result;
12989 }
12990 
12991 /*
12992  * dumpAccessMethod
12993  * write out a single access method definition
12994  */
12995 static void
12997 {
12998  DumpOptions *dopt = fout->dopt;
12999  PQExpBuffer q;
13000  PQExpBuffer delq;
13001  char *qamname;
13002 
13003  /* Do nothing in data-only dump */
13004  if (dopt->dataOnly)
13005  return;
13006 
13007  q = createPQExpBuffer();
13008  delq = createPQExpBuffer();
13009 
13010  qamname = pg_strdup(fmtId(aminfo->dobj.name));
13011 
13012  appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
13013 
13014  switch (aminfo->amtype)
13015  {
13016  case AMTYPE_INDEX:
13017  appendPQExpBufferStr(q, "TYPE INDEX ");
13018  break;
13019  case AMTYPE_TABLE:
13020  appendPQExpBufferStr(q, "TYPE TABLE ");
13021  break;
13022  default:
13023  pg_log_warning("invalid type \"%c\" of access method \"%s\"",
13024  aminfo->amtype, qamname);
13025  destroyPQExpBuffer(q);
13026  destroyPQExpBuffer(delq);
13027  free(qamname);
13028  return;
13029  }
13030 
13031  appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
13032 
13033  appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
13034  qamname);
13035 
13036  if (dopt->binary_upgrade)
13038  "ACCESS METHOD", qamname, NULL);
13039 
13040  if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13041  ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
13042  ARCHIVE_OPTS(.tag = aminfo->dobj.name,
13043  .description = "ACCESS METHOD",
13044  .section = SECTION_PRE_DATA,
13045  .createStmt = q->data,
13046  .dropStmt = delq->data));
13047 
13048  /* Dump Access Method Comments */
13049  if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13050  dumpComment(fout, "ACCESS METHOD", qamname,
13051  NULL, "",
13052  aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
13053 
13054  destroyPQExpBuffer(q);
13055  destroyPQExpBuffer(delq);
13056  free(qamname);
13057 }
13058 
13059 /*
13060  * dumpOpclass
13061  * write out a single operator class definition
13062  */
13063 static void
13064 dumpOpclass(Archive *fout, const OpclassInfo *opcinfo)
13065 {
13066  DumpOptions *dopt = fout->dopt;
13067  PQExpBuffer query;
13068  PQExpBuffer q;
13069  PQExpBuffer delq;
13070  PQExpBuffer nameusing;
13071  PGresult *res;
13072  int ntups;
13073  int i_opcintype;
13074  int i_opckeytype;
13075  int i_opcdefault;
13076  int i_opcfamily;
13077  int i_opcfamilyname;
13078  int i_opcfamilynsp;
13079  int i_amname;
13080  int i_amopstrategy;
13081  int i_amopopr;
13082  int i_sortfamily;
13083  int i_sortfamilynsp;
13084  int i_amprocnum;
13085  int i_amproc;
13086  int i_amproclefttype;
13087  int i_amprocrighttype;
13088  char *opcintype;
13089  char *opckeytype;
13090  char *opcdefault;
13091  char *opcfamily;
13092  char *opcfamilyname;
13093  char *opcfamilynsp;
13094  char *amname;
13095  char *amopstrategy;
13096  char *amopopr;
13097  char *sortfamily;
13098  char *sortfamilynsp;
13099  char *amprocnum;
13100  char *amproc;
13101  char *amproclefttype;
13102  char *amprocrighttype;
13103  bool needComma;
13104  int i;
13105 
13106  /* Do nothing in data-only dump */
13107  if (dopt->dataOnly)
13108  return;
13109 
13110  query = createPQExpBuffer();
13111  q = createPQExpBuffer();
13112  delq = createPQExpBuffer();
13113  nameusing = createPQExpBuffer();
13114 
13115  /* Get additional fields from the pg_opclass row */
13116  appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
13117  "opckeytype::pg_catalog.regtype, "
13118  "opcdefault, opcfamily, "
13119  "opfname AS opcfamilyname, "
13120  "nspname AS opcfamilynsp, "
13121  "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
13122  "FROM pg_catalog.pg_opclass c "
13123  "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
13124  "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
13125  "WHERE c.oid = '%u'::pg_catalog.oid",
13126  opcinfo->dobj.catId.oid);
13127 
13128  res = ExecuteSqlQueryForSingleRow(fout, query->data);
13129 
13130  i_opcintype = PQfnumber(res, "opcintype");
13131  i_opckeytype = PQfnumber(res, "opckeytype");
13132  i_opcdefault = PQfnumber(res, "opcdefault");
13133  i_opcfamily = PQfnumber(res, "opcfamily");
13134  i_opcfamilyname = PQfnumber(res, "opcfamilyname");
13135  i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
13136  i_amname = PQfnumber(res, "amname");
13137 
13138  /* opcintype may still be needed after we PQclear res */
13139  opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
13140  opckeytype = PQgetvalue(res, 0, i_opckeytype);
13141  opcdefault = PQgetvalue(res, 0, i_opcdefault);
13142  /* opcfamily will still be needed after we PQclear res */
13143  opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
13144  opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
13145  opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
13146  /* amname will still be needed after we PQclear res */
13147  amname = pg_strdup(PQgetvalue(res, 0, i_amname));
13148 
13149  appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
13150  fmtQualifiedDumpable(opcinfo));
13151  appendPQExpBuffer(delq, " USING %s;\n",
13152  fmtId(amname));
13153 
13154  /* Build the fixed portion of the CREATE command */
13155  appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n ",
13156  fmtQualifiedDumpable(opcinfo));
13157  if (strcmp(opcdefault, "t") == 0)
13158  appendPQExpBufferStr(q, "DEFAULT ");
13159  appendPQExpBuffer(q, "FOR TYPE %s USING %s",
13160  opcintype,
13161  fmtId(amname));
13162  if (strlen(opcfamilyname) > 0)
13163  {
13164  appendPQExpBufferStr(q, " FAMILY ");
13165  appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
13166  appendPQExpBufferStr(q, fmtId(opcfamilyname));
13167  }
13168  appendPQExpBufferStr(q, " AS\n ");
13169 
13170  needComma = false;
13171 
13172  if (strcmp(opckeytype, "-") != 0)
13173  {
13174  appendPQExpBuffer(q, "STORAGE %s",
13175  opckeytype);
13176  needComma = true;
13177  }
13178 
13179  PQclear(res);
13180 
13181  /*
13182  * Now fetch and print the OPERATOR entries (pg_amop rows).
13183  *
13184  * Print only those opfamily members that are tied to the opclass by
13185  * pg_depend entries.
13186  */
13187  resetPQExpBuffer(query);
13188  appendPQExpBuffer(query, "SELECT amopstrategy, "
13189  "amopopr::pg_catalog.regoperator, "
13190  "opfname AS sortfamily, "
13191  "nspname AS sortfamilynsp "
13192  "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
13193  "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
13194  "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
13195  "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
13196  "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
13197  "AND refobjid = '%u'::pg_catalog.oid "
13198  "AND amopfamily = '%s'::pg_catalog.oid "
13199  "ORDER BY amopstrategy",
13200  opcinfo->dobj.catId.oid,
13201  opcfamily);
13202 
13203  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13204 
13205  ntups = PQntuples(res);
13206 
13207  i_amopstrategy = PQfnumber(res, "amopstrategy");
13208  i_amopopr = PQfnumber(res, "amopopr");
13209  i_sortfamily = PQfnumber(res, "sortfamily");
13210  i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
13211 
13212  for (i = 0; i < ntups; i++)
13213  {
13214  amopstrategy = PQgetvalue(res, i, i_amopstrategy);
13215  amopopr = PQgetvalue(res, i, i_amopopr);
13216  sortfamily = PQgetvalue(res, i, i_sortfamily);
13217  sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
13218 
13219  if (needComma)
13220  appendPQExpBufferStr(q, " ,\n ");
13221 
13222  appendPQExpBuffer(q, "OPERATOR %s %s",
13223  amopstrategy, amopopr);
13224 
13225  if (strlen(sortfamily) > 0)
13226  {
13227  appendPQExpBufferStr(q, " FOR ORDER BY ");
13228  appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
13229  appendPQExpBufferStr(q, fmtId(sortfamily));
13230  }
13231 
13232  needComma = true;
13233  }
13234 
13235  PQclear(res);
13236 
13237  /*
13238  * Now fetch and print the FUNCTION entries (pg_amproc rows).
13239  *
13240  * Print only those opfamily members that are tied to the opclass by
13241  * pg_depend entries.
13242  *
13243  * We print the amproclefttype/amprocrighttype even though in most cases
13244  * the backend could deduce the right values, because of the corner case
13245  * of a btree sort support function for a cross-type comparison.
13246  */
13247  resetPQExpBuffer(query);
13248 
13249  appendPQExpBuffer(query, "SELECT amprocnum, "
13250  "amproc::pg_catalog.regprocedure, "
13251  "amproclefttype::pg_catalog.regtype, "
13252  "amprocrighttype::pg_catalog.regtype "
13253  "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
13254  "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
13255  "AND refobjid = '%u'::pg_catalog.oid "
13256  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
13257  "AND objid = ap.oid "
13258  "ORDER BY amprocnum",
13259  opcinfo->dobj.catId.oid);
13260 
13261  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13262 
13263  ntups = PQntuples(res);
13264 
13265  i_amprocnum = PQfnumber(res, "amprocnum");
13266  i_amproc = PQfnumber(res, "amproc");
13267  i_amproclefttype = PQfnumber(res, "amproclefttype");
13268  i_amprocrighttype = PQfnumber(res, "amprocrighttype");
13269 
13270  for (i = 0; i < ntups; i++)
13271  {
13272  amprocnum = PQgetvalue(res, i, i_amprocnum);
13273  amproc = PQgetvalue(res, i, i_amproc);
13274  amproclefttype = PQgetvalue(res, i, i_amproclefttype);
13275  amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
13276 
13277  if (needComma)
13278  appendPQExpBufferStr(q, " ,\n ");
13279 
13280  appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
13281 
13282  if (*amproclefttype && *amprocrighttype)
13283  appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
13284 
13285  appendPQExpBuffer(q, " %s", amproc);
13286 
13287  needComma = true;
13288  }
13289 
13290  PQclear(res);
13291 
13292  /*
13293  * If needComma is still false it means we haven't added anything after
13294  * the AS keyword. To avoid printing broken SQL, append a dummy STORAGE
13295  * clause with the same datatype. This isn't sanctioned by the
13296  * documentation, but actually DefineOpClass will treat it as a no-op.
13297  */
13298  if (!needComma)
13299  appendPQExpBuffer(q, "STORAGE %s", opcintype);
13300 
13301  appendPQExpBufferStr(q, ";\n");
13302 
13303  appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
13304  appendPQExpBuffer(nameusing, " USING %s",
13305  fmtId(amname));
13306 
13307  if (dopt->binary_upgrade)
13309  "OPERATOR CLASS", nameusing->data,
13310  opcinfo->dobj.namespace->dobj.name);
13311 
13312  if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13313  ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
13314  ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
13315  .namespace = opcinfo->dobj.namespace->dobj.name,
13316  .owner = opcinfo->rolname,
13317  .description = "OPERATOR CLASS",
13318  .section = SECTION_PRE_DATA,
13319  .createStmt = q->data,
13320  .dropStmt = delq->data));
13321 
13322  /* Dump Operator Class Comments */
13323  if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13324  dumpComment(fout, "OPERATOR CLASS", nameusing->data,
13325  opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
13326  opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
13327 
13328  free(opcintype);
13329  free(opcfamily);
13330  free(amname);
13331  destroyPQExpBuffer(query);
13332  destroyPQExpBuffer(q);
13333  destroyPQExpBuffer(delq);
13334  destroyPQExpBuffer(nameusing);
13335 }
13336 
13337 /*
13338  * dumpOpfamily
13339  * write out a single operator family definition
13340  *
13341  * Note: this also dumps any "loose" operator members that aren't bound to a
13342  * specific opclass within the opfamily.
13343  */
13344 static void
13345 dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo)
13346 {
13347  DumpOptions *dopt = fout->dopt;
13348  PQExpBuffer query;
13349  PQExpBuffer q;
13350  PQExpBuffer delq;
13351  PQExpBuffer nameusing;
13352  PGresult *res;
13353  PGresult *res_ops;
13354  PGresult *res_procs;
13355  int ntups;
13356  int i_amname;
13357  int i_amopstrategy;
13358  int i_amopopr;
13359  int i_sortfamily;
13360  int i_sortfamilynsp;
13361  int i_amprocnum;
13362  int i_amproc;
13363  int i_amproclefttype;
13364  int i_amprocrighttype;
13365  char *amname;
13366  char *amopstrategy;
13367  char *amopopr;
13368  char *sortfamily;
13369  char *sortfamilynsp;
13370  char *amprocnum;
13371  char *amproc;
13372  char *amproclefttype;
13373  char *amprocrighttype;
13374  bool needComma;
13375  int i;
13376 
13377  /* Do nothing in data-only dump */
13378  if (dopt->dataOnly)
13379  return;
13380 
13381  query = createPQExpBuffer();
13382  q = createPQExpBuffer();
13383  delq = createPQExpBuffer();
13384  nameusing = createPQExpBuffer();
13385 
13386  /*
13387  * Fetch only those opfamily members that are tied directly to the
13388  * opfamily by pg_depend entries.
13389  */
13390  appendPQExpBuffer(query, "SELECT amopstrategy, "
13391  "amopopr::pg_catalog.regoperator, "
13392  "opfname AS sortfamily, "
13393  "nspname AS sortfamilynsp "
13394  "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
13395  "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
13396  "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
13397  "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
13398  "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13399  "AND refobjid = '%u'::pg_catalog.oid "
13400  "AND amopfamily = '%u'::pg_catalog.oid "
13401  "ORDER BY amopstrategy",
13402  opfinfo->dobj.catId.oid,
13403  opfinfo->dobj.catId.oid);
13404 
13405  res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13406 
13407  resetPQExpBuffer(query);
13408 
13409  appendPQExpBuffer(query, "SELECT amprocnum, "
13410  "amproc::pg_catalog.regprocedure, "
13411  "amproclefttype::pg_catalog.regtype, "
13412  "amprocrighttype::pg_catalog.regtype "
13413  "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
13414  "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13415  "AND refobjid = '%u'::pg_catalog.oid "
13416  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
13417  "AND objid = ap.oid "
13418  "ORDER BY amprocnum",
13419  opfinfo->dobj.catId.oid);
13420 
13421  res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13422 
13423  /* Get additional fields from the pg_opfamily row */
13424  resetPQExpBuffer(query);
13425 
13426  appendPQExpBuffer(query, "SELECT "
13427  "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
13428  "FROM pg_catalog.pg_opfamily "
13429  "WHERE oid = '%u'::pg_catalog.oid",
13430  opfinfo->dobj.catId.oid);
13431 
13432  res = ExecuteSqlQueryForSingleRow(fout, query->data);
13433 
13434  i_amname = PQfnumber(res, "amname");
13435 
13436  /* amname will still be needed after we PQclear res */
13437  amname = pg_strdup(PQgetvalue(res, 0, i_amname));
13438 
13439  appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
13440  fmtQualifiedDumpable(opfinfo));
13441  appendPQExpBuffer(delq, " USING %s;\n",
13442  fmtId(amname));
13443 
13444  /* Build the fixed portion of the CREATE command */
13445  appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
13446  fmtQualifiedDumpable(opfinfo));
13447  appendPQExpBuffer(q, " USING %s;\n",
13448  fmtId(amname));
13449 
13450  PQclear(res);
13451 
13452  /* Do we need an ALTER to add loose members? */
13453  if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
13454  {
13455  appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
13456  fmtQualifiedDumpable(opfinfo));
13457  appendPQExpBuffer(q, " USING %s ADD\n ",
13458  fmtId(amname));
13459 
13460  needComma = false;
13461 
13462  /*
13463  * Now fetch and print the OPERATOR entries (pg_amop rows).
13464  */
13465  ntups = PQntuples(res_ops);
13466 
13467  i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
13468  i_amopopr = PQfnumber(res_ops, "amopopr");
13469  i_sortfamily = PQfnumber(res_ops, "sortfamily");
13470  i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
13471 
13472  for (i = 0; i < ntups; i++)
13473  {
13474  amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
13475  amopopr = PQgetvalue(res_ops, i, i_amopopr);
13476  sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
13477  sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
13478 
13479  if (needComma)
13480  appendPQExpBufferStr(q, " ,\n ");
13481 
13482  appendPQExpBuffer(q, "OPERATOR %s %s",
13483  amopstrategy, amopopr);
13484 
13485  if (strlen(sortfamily) > 0)
13486  {
13487  appendPQExpBufferStr(q, " FOR ORDER BY ");
13488  appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
13489  appendPQExpBufferStr(q, fmtId(sortfamily));
13490  }
13491 
13492  needComma = true;
13493  }
13494 
13495  /*
13496  * Now fetch and print the FUNCTION entries (pg_amproc rows).
13497  */
13498  ntups = PQntuples(res_procs);
13499 
13500  i_amprocnum = PQfnumber(res_procs, "amprocnum");
13501  i_amproc = PQfnumber(res_procs, "amproc");
13502  i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
13503  i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
13504 
13505  for (i = 0; i < ntups; i++)
13506  {
13507  amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
13508  amproc = PQgetvalue(res_procs, i, i_amproc);
13509  amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
13510  amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
13511 
13512  if (needComma)
13513  appendPQExpBufferStr(q, " ,\n ");
13514 
13515  appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
13516  amprocnum, amproclefttype, amprocrighttype,
13517  amproc);
13518 
13519  needComma = true;
13520  }
13521 
13522  appendPQExpBufferStr(q, ";\n");
13523  }
13524 
13525  appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
13526  appendPQExpBuffer(nameusing, " USING %s",
13527  fmtId(amname));
13528 
13529  if (dopt->binary_upgrade)
13531  "OPERATOR FAMILY", nameusing->data,
13532  opfinfo->dobj.namespace->dobj.name);
13533 
13534  if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13535  ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
13536  ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
13537  .namespace = opfinfo->dobj.namespace->dobj.name,
13538  .owner = opfinfo->rolname,
13539  .description = "OPERATOR FAMILY",
13540  .section = SECTION_PRE_DATA,
13541  .createStmt = q->data,
13542  .dropStmt = delq->data));
13543 
13544  /* Dump Operator Family Comments */
13545  if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13546  dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
13547  opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
13548  opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
13549 
13550  free(amname);
13551  PQclear(res_ops);
13552  PQclear(res_procs);
13553  destroyPQExpBuffer(query);
13554  destroyPQExpBuffer(q);
13555  destroyPQExpBuffer(delq);
13556  destroyPQExpBuffer(nameusing);
13557 }
13558 
13559 /*
13560  * dumpCollation
13561  * write out a single collation definition
13562  */
13563 static void
13564 dumpCollation(Archive *fout, const CollInfo *collinfo)
13565 {
13566  DumpOptions *dopt = fout->dopt;
13567  PQExpBuffer query;
13568  PQExpBuffer q;
13569  PQExpBuffer delq;
13570  char *qcollname;
13571  PGresult *res;
13572  int i_collprovider;
13573  int i_collisdeterministic;
13574  int i_collcollate;
13575  int i_collctype;
13576  int i_colllocale;
13577  int i_collicurules;
13578  const char *collprovider;
13579  const char *collcollate;
13580  const char *collctype;
13581  const char *colllocale;
13582  const char *collicurules;
13583 
13584  /* Do nothing in data-only dump */
13585  if (dopt->dataOnly)
13586  return;
13587 
13588  query = createPQExpBuffer();
13589  q = createPQExpBuffer();
13590  delq = createPQExpBuffer();
13591 
13592  qcollname = pg_strdup(fmtId(collinfo->dobj.name));
13593 
13594  /* Get collation-specific details */
13595  appendPQExpBufferStr(query, "SELECT ");
13596 
13597  if (fout->remoteVersion >= 100000)
13598  appendPQExpBufferStr(query,
13599  "collprovider, "
13600  "collversion, ");
13601  else
13602  appendPQExpBufferStr(query,
13603  "'c' AS collprovider, "
13604  "NULL AS collversion, ");
13605 
13606  if (fout->remoteVersion >= 120000)
13607  appendPQExpBufferStr(query,
13608  "collisdeterministic, ");
13609  else
13610  appendPQExpBufferStr(query,
13611  "true AS collisdeterministic, ");
13612 
13613  if (fout->remoteVersion >= 170000)
13614  appendPQExpBufferStr(query,
13615  "colllocale, ");
13616  else if (fout->remoteVersion >= 150000)
13617  appendPQExpBufferStr(query,
13618  "colliculocale AS colllocale, ");
13619  else
13620  appendPQExpBufferStr(query,
13621  "NULL AS colllocale, ");
13622 
13623  if (fout->remoteVersion >= 160000)
13624  appendPQExpBufferStr(query,
13625  "collicurules, ");
13626  else
13627  appendPQExpBufferStr(query,
13628  "NULL AS collicurules, ");
13629 
13630  appendPQExpBuffer(query,
13631  "collcollate, "
13632  "collctype "
13633  "FROM pg_catalog.pg_collation c "
13634  "WHERE c.oid = '%u'::pg_catalog.oid",
13635  collinfo->dobj.catId.oid);
13636 
13637  res = ExecuteSqlQueryForSingleRow(fout, query->data);
13638 
13639  i_collprovider = PQfnumber(res, "collprovider");
13640  i_collisdeterministic = PQfnumber(res, "collisdeterministic");
13641  i_collcollate = PQfnumber(res, "collcollate");
13642  i_collctype = PQfnumber(res, "collctype");
13643  i_colllocale = PQfnumber(res, "colllocale");
13644  i_collicurules = PQfnumber(res, "collicurules");
13645 
13646  collprovider = PQgetvalue(res, 0, i_collprovider);
13647 
13648  if (!PQgetisnull(res, 0, i_collcollate))
13649  collcollate = PQgetvalue(res, 0, i_collcollate);
13650  else
13651  collcollate = NULL;
13652 
13653  if (!PQgetisnull(res, 0, i_collctype))
13654  collctype = PQgetvalue(res, 0, i_collctype);
13655  else
13656  collctype = NULL;
13657 
13658  /*
13659  * Before version 15, collcollate and collctype were of type NAME and
13660  * non-nullable. Treat empty strings as NULL for consistency.
13661  */
13662  if (fout->remoteVersion < 150000)
13663  {
13664  if (collcollate[0] == '\0')
13665  collcollate = NULL;
13666  if (collctype[0] == '\0')
13667  collctype = NULL;
13668  }
13669 
13670  if (!PQgetisnull(res, 0, i_colllocale))
13671  colllocale = PQgetvalue(res, 0, i_colllocale);
13672  else
13673  colllocale = NULL;
13674 
13675  if (!PQgetisnull(res, 0, i_collicurules))
13676  collicurules = PQgetvalue(res, 0, i_collicurules);
13677  else
13678  collicurules = NULL;
13679 
13680  appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
13681  fmtQualifiedDumpable(collinfo));
13682 
13683  appendPQExpBuffer(q, "CREATE COLLATION %s (",
13684  fmtQualifiedDumpable(collinfo));
13685 
13686  appendPQExpBufferStr(q, "provider = ");
13687  if (collprovider[0] == 'b')
13688  appendPQExpBufferStr(q, "builtin");
13689  else if (collprovider[0] == 'c')
13690  appendPQExpBufferStr(q, "libc");
13691  else if (collprovider[0] == 'i')
13692  appendPQExpBufferStr(q, "icu");
13693  else if (collprovider[0] == 'd')
13694  /* to allow dumping pg_catalog; not accepted on input */
13695  appendPQExpBufferStr(q, "default");
13696  else
13697  pg_fatal("unrecognized collation provider: %s",
13698  collprovider);
13699 
13700  if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
13701  appendPQExpBufferStr(q, ", deterministic = false");
13702 
13703  if (collprovider[0] == 'd')
13704  {
13705  if (collcollate || collctype || colllocale || collicurules)
13706  pg_log_warning("invalid collation \"%s\"", qcollname);
13707 
13708  /* no locale -- the default collation cannot be reloaded anyway */
13709  }
13710  else if (collprovider[0] == 'b')
13711  {
13712  if (collcollate || collctype || !colllocale || collicurules)
13713  pg_log_warning("invalid collation \"%s\"", qcollname);
13714 
13715  appendPQExpBufferStr(q, ", locale = ");
13716  appendStringLiteralAH(q, colllocale ? colllocale : "",
13717  fout);
13718  }
13719  else if (collprovider[0] == 'i')
13720  {
13721  if (fout->remoteVersion >= 150000)
13722  {
13723  if (collcollate || collctype || !colllocale)
13724  pg_log_warning("invalid collation \"%s\"", qcollname);
13725 
13726  appendPQExpBufferStr(q, ", locale = ");
13727  appendStringLiteralAH(q, colllocale ? colllocale : "",
13728  fout);
13729  }
13730  else
13731  {
13732  if (!collcollate || !collctype || colllocale ||
13733  strcmp(collcollate, collctype) != 0)
13734  pg_log_warning("invalid collation \"%s\"", qcollname);
13735 
13736  appendPQExpBufferStr(q, ", locale = ");
13737  appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
13738  }
13739 
13740  if (collicurules)
13741  {
13742  appendPQExpBufferStr(q, ", rules = ");
13743  appendStringLiteralAH(q, collicurules ? collicurules : "", fout);
13744  }
13745  }
13746  else if (collprovider[0] == 'c')
13747  {
13748  if (colllocale || collicurules || !collcollate || !collctype)
13749  pg_log_warning("invalid collation \"%s\"", qcollname);
13750 
13751  if (collcollate && collctype && strcmp(collcollate, collctype) == 0)
13752  {
13753  appendPQExpBufferStr(q, ", locale = ");
13754  appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
13755  }
13756  else
13757  {
13758  appendPQExpBufferStr(q, ", lc_collate = ");
13759  appendStringLiteralAH(q, collcollate ? collcollate : "", fout);
13760  appendPQExpBufferStr(q, ", lc_ctype = ");
13761  appendStringLiteralAH(q, collctype ? collctype : "", fout);
13762  }
13763  }
13764  else
13765  pg_fatal("unrecognized collation provider: %s", collprovider);
13766 
13767  /*
13768  * For binary upgrade, carry over the collation version. For normal
13769  * dump/restore, omit the version, so that it is computed upon restore.
13770  */
13771  if (dopt->binary_upgrade)
13772  {
13773  int i_collversion;
13774 
13775  i_collversion = PQfnumber(res, "collversion");
13776  if (!PQgetisnull(res, 0, i_collversion))
13777  {
13778  appendPQExpBufferStr(q, ", version = ");
13780  PQgetvalue(res, 0, i_collversion),
13781  fout);
13782  }
13783  }
13784 
13785  appendPQExpBufferStr(q, ");\n");
13786 
13787  if (dopt->binary_upgrade)
13788  binary_upgrade_extension_member(q, &collinfo->dobj,
13789  "COLLATION", qcollname,
13790  collinfo->dobj.namespace->dobj.name);
13791 
13792  if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13793  ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
13794  ARCHIVE_OPTS(.tag = collinfo->dobj.name,
13795  .namespace = collinfo->dobj.namespace->dobj.name,
13796  .owner = collinfo->rolname,
13797  .description = "COLLATION",
13798  .section = SECTION_PRE_DATA,
13799  .createStmt = q->data,
13800  .dropStmt = delq->data));
13801 
13802  /* Dump Collation Comments */
13803  if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13804  dumpComment(fout, "COLLATION", qcollname,
13805  collinfo->dobj.namespace->dobj.name, collinfo->rolname,
13806  collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
13807 
13808  PQclear(res);
13809 
13810  destroyPQExpBuffer(query);
13811  destroyPQExpBuffer(q);
13812  destroyPQExpBuffer(delq);
13813  free(qcollname);
13814 }
13815 
13816 /*
13817  * dumpConversion
13818  * write out a single conversion definition
13819  */
13820 static void
13821 dumpConversion(Archive *fout, const ConvInfo *convinfo)
13822 {
13823  DumpOptions *dopt = fout->dopt;
13824  PQExpBuffer query;
13825  PQExpBuffer q;
13826  PQExpBuffer delq;
13827  char *qconvname;
13828  PGresult *res;
13829  int i_conforencoding;
13830  int i_contoencoding;
13831  int i_conproc;
13832  int i_condefault;
13833  const char *conforencoding;
13834  const char *contoencoding;
13835  const char *conproc;
13836  bool condefault;
13837 
13838  /* Do nothing in data-only dump */
13839  if (dopt->dataOnly)
13840  return;
13841 
13842  query = createPQExpBuffer();
13843  q = createPQExpBuffer();
13844  delq = createPQExpBuffer();
13845 
13846  qconvname = pg_strdup(fmtId(convinfo->dobj.name));
13847 
13848  /* Get conversion-specific details */
13849  appendPQExpBuffer(query, "SELECT "
13850  "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
13851  "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
13852  "conproc, condefault "
13853  "FROM pg_catalog.pg_conversion c "
13854  "WHERE c.oid = '%u'::pg_catalog.oid",
13855  convinfo->dobj.catId.oid);
13856 
13857  res = ExecuteSqlQueryForSingleRow(fout, query->data);
13858 
13859  i_conforencoding = PQfnumber(res, "conforencoding");
13860  i_contoencoding = PQfnumber(res, "contoencoding");
13861  i_conproc = PQfnumber(res, "conproc");
13862  i_condefault = PQfnumber(res, "condefault");
13863 
13864  conforencoding = PQgetvalue(res, 0, i_conforencoding);
13865  contoencoding = PQgetvalue(res, 0, i_contoencoding);
13866  conproc = PQgetvalue(res, 0, i_conproc);
13867  condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
13868 
13869  appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
13870  fmtQualifiedDumpable(convinfo));
13871 
13872  appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
13873  (condefault) ? "DEFAULT " : "",
13874  fmtQualifiedDumpable(convinfo));
13875  appendStringLiteralAH(q, conforencoding, fout);
13876  appendPQExpBufferStr(q, " TO ");
13877  appendStringLiteralAH(q, contoencoding, fout);
13878  /* regproc output is already sufficiently quoted */
13879  appendPQExpBuffer(q, " FROM %s;\n", conproc);
13880 
13881  if (dopt->binary_upgrade)
13882  binary_upgrade_extension_member(q, &convinfo->dobj,
13883  "CONVERSION", qconvname,
13884  convinfo->dobj.namespace->dobj.name);
13885 
13886  if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13887  ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
13888  ARCHIVE_OPTS(.tag = convinfo->dobj.name,
13889  .namespace = convinfo->dobj.namespace->dobj.name,
13890  .owner = convinfo->rolname,
13891  .description = "CONVERSION",
13892  .section = SECTION_PRE_DATA,
13893  .createStmt = q->data,
13894  .dropStmt = delq->data));
13895 
13896  /* Dump Conversion Comments */
13897  if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13898  dumpComment(fout, "CONVERSION", qconvname,
13899  convinfo->dobj.namespace->dobj.name, convinfo->rolname,
13900  convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
13901 
13902  PQclear(res);
13903 
13904  destroyPQExpBuffer(query);
13905  destroyPQExpBuffer(q);
13906  destroyPQExpBuffer(delq);
13907  free(qconvname);
13908 }
13909 
13910 /*
13911  * format_aggregate_signature: generate aggregate name and argument list
13912  *
13913  * The argument type names are qualified if needed. The aggregate name
13914  * is never qualified.
13915  */
13916 static char *
13917 format_aggregate_signature(const AggInfo *agginfo, Archive *fout, bool honor_quotes)
13918 {
13920  int j;
13921 
13922  initPQExpBuffer(&buf);
13923  if (honor_quotes)
13924  appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
13925  else
13926  appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
13927 
13928  if (agginfo->aggfn.nargs == 0)
13929  appendPQExpBufferStr(&buf, "(*)");
13930  else
13931  {
13932  appendPQExpBufferChar(&buf, '(');
13933  for (j = 0; j < agginfo->aggfn.nargs; j++)
13934  appendPQExpBuffer(&buf, "%s%s",
13935  (j > 0) ? ", " : "",
13936  getFormattedTypeName(fout,
13937  agginfo->aggfn.argtypes[j],
13938  zeroIsError));
13939  appendPQExpBufferChar(&buf, ')');
13940  }
13941  return buf.data;
13942 }
13943 
13944 /*
13945  * dumpAgg
13946  * write out a single aggregate definition
13947  */
13948 static void
13949 dumpAgg(Archive *fout, const AggInfo *agginfo)
13950 {
13951  DumpOptions *dopt = fout->dopt;
13952  PQExpBuffer query;
13953  PQExpBuffer q;
13954  PQExpBuffer delq;
13955  PQExpBuffer details;
13956  char *aggsig; /* identity signature */
13957  char *aggfullsig = NULL; /* full signature */
13958  char *aggsig_tag;
13959  PGresult *res;
13960  int i_agginitval;
13961  int i_aggminitval;
13962  const char *aggtransfn;
13963  const char *aggfinalfn;
13964  const char *aggcombinefn;
13965  const char *aggserialfn;
13966  const char *aggdeserialfn;
13967  const char *aggmtransfn;
13968  const char *aggminvtransfn;
13969  const char *aggmfinalfn;
13970  bool aggfinalextra;
13971  bool aggmfinalextra;
13972  char aggfinalmodify;
13973  char aggmfinalmodify;
13974  const char *aggsortop;
13975  char *aggsortconvop;
13976  char aggkind;
13977  const char *aggtranstype;
13978  const char *aggtransspace;
13979  const char *aggmtranstype;
13980  const char *aggmtransspace;
13981  const char *agginitval;
13982  const char *aggminitval;
13983  const char *proparallel;
13984  char defaultfinalmodify;
13985 
13986  /* Do nothing in data-only dump */
13987  if (dopt->dataOnly)
13988  return;
13989 
13990  query = createPQExpBuffer();
13991  q = createPQExpBuffer();
13992  delq = createPQExpBuffer();
13993  details = createPQExpBuffer();
13994 
13995  if (!fout->is_prepared[PREPQUERY_DUMPAGG])
13996  {
13997  /* Set up query for aggregate-specific details */
13998  appendPQExpBufferStr(query,
13999  "PREPARE dumpAgg(pg_catalog.oid) AS\n");
14000 
14001  appendPQExpBufferStr(query,
14002  "SELECT "
14003  "aggtransfn,\n"
14004  "aggfinalfn,\n"
14005  "aggtranstype::pg_catalog.regtype,\n"
14006  "agginitval,\n"
14007  "aggsortop,\n"
14008  "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs,\n"
14009  "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs,\n");
14010 
14011  if (fout->remoteVersion >= 90400)
14012  appendPQExpBufferStr(query,
14013  "aggkind,\n"
14014  "aggmtransfn,\n"
14015  "aggminvtransfn,\n"
14016  "aggmfinalfn,\n"
14017  "aggmtranstype::pg_catalog.regtype,\n"
14018  "aggfinalextra,\n"
14019  "aggmfinalextra,\n"
14020  "aggtransspace,\n"
14021  "aggmtransspace,\n"
14022  "aggminitval,\n");
14023  else
14024  appendPQExpBufferStr(query,
14025  "'n' AS aggkind,\n"
14026  "'-' AS aggmtransfn,\n"
14027  "'-' AS aggminvtransfn,\n"
14028  "'-' AS aggmfinalfn,\n"
14029  "0 AS aggmtranstype,\n"
14030  "false AS aggfinalextra,\n"
14031  "false AS aggmfinalextra,\n"
14032  "0 AS aggtransspace,\n"
14033  "0 AS aggmtransspace,\n"
14034  "NULL AS aggminitval,\n");
14035 
14036  if (fout->remoteVersion >= 90600)
14037  appendPQExpBufferStr(query,
14038  "aggcombinefn,\n"
14039  "aggserialfn,\n"
14040  "aggdeserialfn,\n"
14041  "proparallel,\n");
14042  else
14043  appendPQExpBufferStr(query,
14044  "'-' AS aggcombinefn,\n"
14045  "'-' AS aggserialfn,\n"
14046  "'-' AS aggdeserialfn,\n"
14047  "'u' AS proparallel,\n");
14048 
14049  if (fout->remoteVersion >= 110000)
14050  appendPQExpBufferStr(query,
14051  "aggfinalmodify,\n"
14052  "aggmfinalmodify\n");
14053  else
14054  appendPQExpBufferStr(query,
14055  "'0' AS aggfinalmodify,\n"
14056  "'0' AS aggmfinalmodify\n");
14057 
14058  appendPQExpBufferStr(query,
14059  "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
14060  "WHERE a.aggfnoid = p.oid "
14061  "AND p.oid = $1");
14062 
14063  ExecuteSqlStatement(fout, query->data);
14064 
14065  fout->is_prepared[PREPQUERY_DUMPAGG] = true;
14066  }
14067 
14068  printfPQExpBuffer(query,
14069  "EXECUTE dumpAgg('%u')",
14070  agginfo->aggfn.dobj.catId.oid);
14071 
14072  res = ExecuteSqlQueryForSingleRow(fout, query->data);
14073 
14074  i_agginitval = PQfnumber(res, "agginitval");
14075  i_aggminitval = PQfnumber(res, "aggminitval");
14076 
14077  aggtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggtransfn"));
14078  aggfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggfinalfn"));
14079  aggcombinefn = PQgetvalue(res, 0, PQfnumber(res, "aggcombinefn"));
14080  aggserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggserialfn"));
14081  aggdeserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggdeserialfn"));
14082  aggmtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggmtransfn"));
14083  aggminvtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggminvtransfn"));
14084  aggmfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalfn"));
14085  aggfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggfinalextra"))[0] == 't');
14086  aggmfinalextra = (PQgetvalue(res, 0, PQfnumber(res, "aggmfinalextra"))[0] == 't');
14087  aggfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggfinalmodify"))[0];
14088  aggmfinalmodify = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalmodify"))[0];
14089  aggsortop = PQgetvalue(res, 0, PQfnumber(res, "aggsortop"));
14090  aggkind = PQgetvalue(res, 0, PQfnumber(res, "aggkind"))[0];
14091  aggtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggtranstype"));
14092  aggtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggtransspace"));
14093  aggmtranstype = PQgetvalue(res, 0, PQfnumber(res, "aggmtranstype"));
14094  aggmtransspace = PQgetvalue(res, 0, PQfnumber(res, "aggmtransspace"));
14095  agginitval = PQgetvalue(res, 0, i_agginitval);
14096  aggminitval = PQgetvalue(res, 0, i_aggminitval);
14097  proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
14098 
14099  {
14100  char *funcargs;
14101  char *funciargs;
14102 
14103  funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
14104  funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
14105  aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
14106  aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
14107  }
14108 
14109  aggsig_tag = format_aggregate_signature(agginfo, fout, false);
14110 
14111  /* identify default modify flag for aggkind (must match DefineAggregate) */
14112  defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
14113  /* replace omitted flags for old versions */
14114  if (aggfinalmodify == '0')
14115  aggfinalmodify = defaultfinalmodify;
14116  if (aggmfinalmodify == '0')
14117  aggmfinalmodify = defaultfinalmodify;
14118 
14119  /* regproc and regtype output is already sufficiently quoted */
14120  appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
14121  aggtransfn, aggtranstype);
14122 
14123  if (strcmp(aggtransspace, "0") != 0)
14124  {
14125  appendPQExpBuffer(details, ",\n SSPACE = %s",
14126  aggtransspace);
14127  }
14128 
14129  if (!PQgetisnull(res, 0, i_agginitval))
14130  {
14131  appendPQExpBufferStr(details, ",\n INITCOND = ");
14132  appendStringLiteralAH(details, agginitval, fout);
14133  }
14134 
14135  if (strcmp(aggfinalfn, "-") != 0)
14136  {
14137  appendPQExpBuffer(details, ",\n FINALFUNC = %s",
14138  aggfinalfn);
14139  if (aggfinalextra)
14140  appendPQExpBufferStr(details, ",\n FINALFUNC_EXTRA");
14141  if (aggfinalmodify != defaultfinalmodify)
14142  {
14143  switch (aggfinalmodify)
14144  {
14145  case AGGMODIFY_READ_ONLY:
14146  appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = READ_ONLY");
14147  break;
14148  case AGGMODIFY_SHAREABLE:
14149  appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = SHAREABLE");
14150  break;
14151  case AGGMODIFY_READ_WRITE:
14152  appendPQExpBufferStr(details, ",\n FINALFUNC_MODIFY = READ_WRITE");
14153  break;
14154  default:
14155  pg_fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
14156  agginfo->aggfn.dobj.name);
14157  break;
14158  }
14159  }
14160  }
14161 
14162  if (strcmp(aggcombinefn, "-") != 0)
14163  appendPQExpBuffer(details, ",\n COMBINEFUNC = %s", aggcombinefn);
14164 
14165  if (strcmp(aggserialfn, "-") != 0)
14166  appendPQExpBuffer(details, ",\n SERIALFUNC = %s", aggserialfn);
14167 
14168  if (strcmp(aggdeserialfn, "-") != 0)
14169  appendPQExpBuffer(details, ",\n DESERIALFUNC = %s", aggdeserialfn);
14170 
14171  if (strcmp(aggmtransfn, "-") != 0)
14172  {
14173  appendPQExpBuffer(details, ",\n MSFUNC = %s,\n MINVFUNC = %s,\n MSTYPE = %s",
14174  aggmtransfn,
14175  aggminvtransfn,
14176  aggmtranstype);
14177  }
14178 
14179  if (strcmp(aggmtransspace, "0") != 0)
14180  {
14181  appendPQExpBuffer(details, ",\n MSSPACE = %s",
14182  aggmtransspace);
14183  }
14184 
14185  if (!PQgetisnull(res, 0, i_aggminitval))
14186  {
14187  appendPQExpBufferStr(details, ",\n MINITCOND = ");
14188  appendStringLiteralAH(details, aggminitval, fout);
14189  }
14190 
14191  if (strcmp(aggmfinalfn, "-") != 0)
14192  {
14193  appendPQExpBuffer(details, ",\n MFINALFUNC = %s",
14194  aggmfinalfn);
14195  if (aggmfinalextra)
14196  appendPQExpBufferStr(details, ",\n MFINALFUNC_EXTRA");
14197  if (aggmfinalmodify != defaultfinalmodify)
14198  {
14199  switch (aggmfinalmodify)
14200  {
14201  case AGGMODIFY_READ_ONLY:
14202  appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = READ_ONLY");
14203  break;
14204  case AGGMODIFY_SHAREABLE:
14205  appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = SHAREABLE");
14206  break;
14207  case AGGMODIFY_READ_WRITE:
14208  appendPQExpBufferStr(details, ",\n MFINALFUNC_MODIFY = READ_WRITE");
14209  break;
14210  default:
14211  pg_fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
14212  agginfo->aggfn.dobj.name);
14213  break;
14214  }
14215  }
14216  }
14217 
14218  aggsortconvop = getFormattedOperatorName(aggsortop);
14219  if (aggsortconvop)
14220  {
14221  appendPQExpBuffer(details, ",\n SORTOP = %s",
14222  aggsortconvop);
14223  free(aggsortconvop);
14224  }
14225 
14226  if (aggkind == AGGKIND_HYPOTHETICAL)
14227  appendPQExpBufferStr(details, ",\n HYPOTHETICAL");
14228 
14229  if (proparallel[0] != PROPARALLEL_UNSAFE)
14230  {
14231  if (proparallel[0] == PROPARALLEL_SAFE)
14232  appendPQExpBufferStr(details, ",\n PARALLEL = safe");
14233  else if (proparallel[0] == PROPARALLEL_RESTRICTED)
14234  appendPQExpBufferStr(details, ",\n PARALLEL = restricted");
14235  else if (proparallel[0] != PROPARALLEL_UNSAFE)
14236  pg_fatal("unrecognized proparallel value for function \"%s\"",
14237  agginfo->aggfn.dobj.name);
14238  }
14239 
14240  appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
14241  fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
14242  aggsig);
14243 
14244  appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
14245  fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
14246  aggfullsig ? aggfullsig : aggsig, details->data);
14247 
14248  if (dopt->binary_upgrade)
14249  binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
14250  "AGGREGATE", aggsig,
14251  agginfo->aggfn.dobj.namespace->dobj.name);
14252 
14253  if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
14254  ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
14255  agginfo->aggfn.dobj.dumpId,
14256  ARCHIVE_OPTS(.tag = aggsig_tag,
14257  .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
14258  .owner = agginfo->aggfn.rolname,
14259  .description = "AGGREGATE",
14260  .section = SECTION_PRE_DATA,
14261  .createStmt = q->data,
14262  .dropStmt = delq->data));
14263 
14264  /* Dump Aggregate Comments */
14265  if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
14266  dumpComment(fout, "AGGREGATE", aggsig,
14267  agginfo->aggfn.dobj.namespace->dobj.name,
14268  agginfo->aggfn.rolname,
14269  agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
14270 
14271  if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
14272  dumpSecLabel(fout, "AGGREGATE", aggsig,
14273  agginfo->aggfn.dobj.namespace->dobj.name,
14274  agginfo->aggfn.rolname,
14275  agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
14276 
14277  /*
14278  * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
14279  * command look like a function's GRANT; in particular this affects the
14280  * syntax for zero-argument aggregates and ordered-set aggregates.
14281  */
14282  free(aggsig);
14283 
14284  aggsig = format_function_signature(fout, &agginfo->aggfn, true);
14285 
14286  if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
14287  dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
14288  "FUNCTION", aggsig, NULL,
14289  agginfo->aggfn.dobj.namespace->dobj.name,
14290  NULL, agginfo->aggfn.rolname, &agginfo->aggfn.dacl);
14291 
14292  free(aggsig);
14293  free(aggfullsig);
14294  free(aggsig_tag);
14295 
14296  PQclear(res);
14297 
14298  destroyPQExpBuffer(query);
14299  destroyPQExpBuffer(q);
14300  destroyPQExpBuffer(delq);
14301  destroyPQExpBuffer(details);
14302 }
14303 
14304 /*
14305  * dumpTSParser
14306  * write out a single text search parser
14307  */
14308 static void
14309 dumpTSParser(Archive *fout, const TSParserInfo *prsinfo)
14310 {
14311  DumpOptions *dopt = fout->dopt;
14312  PQExpBuffer q;
14313  PQExpBuffer delq;
14314  char *qprsname;
14315 
14316  /* Do nothing in data-only dump */
14317  if (dopt->dataOnly)
14318  return;
14319 
14320  q = createPQExpBuffer();
14321  delq = createPQExpBuffer();
14322 
14323  qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
14324 
14325  appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
14326  fmtQualifiedDumpable(prsinfo));
14327 
14328  appendPQExpBuffer(q, " START = %s,\n",
14329  convertTSFunction(fout, prsinfo->prsstart));
14330  appendPQExpBuffer(q, " GETTOKEN = %s,\n",
14331  convertTSFunction(fout, prsinfo->prstoken));
14332  appendPQExpBuffer(q, " END = %s,\n",
14333  convertTSFunction(fout, prsinfo->prsend));
14334  if (prsinfo->prsheadline != InvalidOid)
14335  appendPQExpBuffer(q, " HEADLINE = %s,\n",
14336  convertTSFunction(fout, prsinfo->prsheadline));
14337  appendPQExpBuffer(q, " LEXTYPES = %s );\n",
14338  convertTSFunction(fout, prsinfo->prslextype));
14339 
14340  appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
14341  fmtQualifiedDumpable(prsinfo));
14342 
14343  if (dopt->binary_upgrade)
14345  "TEXT SEARCH PARSER", qprsname,
14346  prsinfo->dobj.namespace->dobj.name);
14347 
14348  if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14349  ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
14350  ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
14351  .namespace = prsinfo->dobj.namespace->dobj.name,
14352  .description = "TEXT SEARCH PARSER",
14353  .section = SECTION_PRE_DATA,
14354  .createStmt = q->data,
14355  .dropStmt = delq->data));
14356 
14357  /* Dump Parser Comments */
14358  if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14359  dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
14360  prsinfo->dobj.namespace->dobj.name, "",
14361  prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
14362 
14363  destroyPQExpBuffer(q);
14364  destroyPQExpBuffer(delq);
14365  free(qprsname);
14366 }
14367 
14368 /*
14369  * dumpTSDictionary
14370  * write out a single text search dictionary
14371  */
14372 static void
14373 dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo)
14374 {
14375  DumpOptions *dopt = fout->dopt;
14376  PQExpBuffer q;
14377  PQExpBuffer delq;
14378  PQExpBuffer query;
14379  char *qdictname;
14380  PGresult *res;
14381  char *nspname;
14382  char *tmplname;
14383 
14384  /* Do nothing in data-only dump */
14385  if (dopt->dataOnly)
14386  return;
14387 
14388  q = createPQExpBuffer();
14389  delq = createPQExpBuffer();
14390  query = createPQExpBuffer();
14391 
14392  qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
14393 
14394  /* Fetch name and namespace of the dictionary's template */
14395  appendPQExpBuffer(query, "SELECT nspname, tmplname "
14396  "FROM pg_ts_template p, pg_namespace n "
14397  "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
14398  dictinfo->dicttemplate);
14399  res = ExecuteSqlQueryForSingleRow(fout, query->data);
14400  nspname = PQgetvalue(res, 0, 0);
14401  tmplname = PQgetvalue(res, 0, 1);
14402 
14403  appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
14404  fmtQualifiedDumpable(dictinfo));
14405 
14406  appendPQExpBufferStr(q, " TEMPLATE = ");
14407  appendPQExpBuffer(q, "%s.", fmtId(nspname));
14408  appendPQExpBufferStr(q, fmtId(tmplname));
14409 
14410  PQclear(res);
14411 
14412  /* the dictinitoption can be dumped straight into the command */
14413  if (dictinfo->dictinitoption)
14414  appendPQExpBuffer(q, ",\n %s", dictinfo->dictinitoption);
14415 
14416  appendPQExpBufferStr(q, " );\n");
14417 
14418  appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
14419  fmtQualifiedDumpable(dictinfo));
14420 
14421  if (dopt->binary_upgrade)
14422  binary_upgrade_extension_member(q, &dictinfo->dobj,
14423  "TEXT SEARCH DICTIONARY", qdictname,
14424  dictinfo->dobj.namespace->dobj.name);
14425 
14426  if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14427  ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
14428  ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
14429  .namespace = dictinfo->dobj.namespace->dobj.name,
14430  .owner = dictinfo->rolname,
14431  .description = "TEXT SEARCH DICTIONARY",
14432  .section = SECTION_PRE_DATA,
14433  .createStmt = q->data,
14434  .dropStmt = delq->data));
14435 
14436  /* Dump Dictionary Comments */
14437  if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14438  dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
14439  dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
14440  dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
14441 
14442  destroyPQExpBuffer(q);
14443  destroyPQExpBuffer(delq);
14444  destroyPQExpBuffer(query);
14445  free(qdictname);
14446 }
14447 
14448 /*
14449  * dumpTSTemplate
14450  * write out a single text search template
14451  */
14452 static void
14453 dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo)
14454 {
14455  DumpOptions *dopt = fout->dopt;
14456  PQExpBuffer q;
14457  PQExpBuffer delq;
14458  char *qtmplname;
14459 
14460  /* Do nothing in data-only dump */
14461  if (dopt->dataOnly)
14462  return;
14463 
14464  q = createPQExpBuffer();
14465  delq = createPQExpBuffer();
14466 
14467  qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
14468 
14469  appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
14470  fmtQualifiedDumpable(tmplinfo));
14471 
14472  if (tmplinfo->tmplinit != InvalidOid)
14473  appendPQExpBuffer(q, " INIT = %s,\n",
14474  convertTSFunction(fout, tmplinfo->tmplinit));
14475  appendPQExpBuffer(q, " LEXIZE = %s );\n",
14476  convertTSFunction(fout, tmplinfo->tmpllexize));
14477 
14478  appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
14479  fmtQualifiedDumpable(tmplinfo));
14480 
14481  if (dopt->binary_upgrade)
14482  binary_upgrade_extension_member(q, &tmplinfo->dobj,
14483  "TEXT SEARCH TEMPLATE", qtmplname,
14484  tmplinfo->dobj.namespace->dobj.name);
14485 
14486  if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14487  ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
14488  ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
14489  .namespace = tmplinfo->dobj.namespace->dobj.name,
14490  .description = "TEXT SEARCH TEMPLATE",
14491  .section = SECTION_PRE_DATA,
14492  .createStmt = q->data,
14493  .dropStmt = delq->data));
14494 
14495  /* Dump Template Comments */
14496  if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14497  dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
14498  tmplinfo->dobj.namespace->dobj.name, "",
14499  tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
14500 
14501  destroyPQExpBuffer(q);
14502  destroyPQExpBuffer(delq);
14503  free(qtmplname);
14504 }
14505 
14506 /*
14507  * dumpTSConfig
14508  * write out a single text search configuration
14509  */
14510 static void
14511 dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo)
14512 {
14513  DumpOptions *dopt = fout->dopt;
14514  PQExpBuffer q;
14515  PQExpBuffer delq;
14516  PQExpBuffer query;
14517  char *qcfgname;
14518  PGresult *res;
14519  char *nspname;
14520  char *prsname;
14521  int ntups,
14522  i;
14523  int i_tokenname;
14524  int i_dictname;
14525 
14526  /* Do nothing in data-only dump */
14527  if (dopt->dataOnly)
14528  return;
14529 
14530  q = createPQExpBuffer();
14531  delq = createPQExpBuffer();
14532  query = createPQExpBuffer();
14533 
14534  qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
14535 
14536  /* Fetch name and namespace of the config's parser */
14537  appendPQExpBuffer(query, "SELECT nspname, prsname "
14538  "FROM pg_ts_parser p, pg_namespace n "
14539  "WHERE p.oid = '%u' AND n.oid = prsnamespace",
14540  cfginfo->cfgparser);
14541  res = ExecuteSqlQueryForSingleRow(fout, query->data);
14542  nspname = PQgetvalue(res, 0, 0);
14543  prsname = PQgetvalue(res, 0, 1);
14544 
14545  appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
14546  fmtQualifiedDumpable(cfginfo));
14547 
14548  appendPQExpBuffer(q, " PARSER = %s.", fmtId(nspname));
14549  appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
14550 
14551  PQclear(res);
14552 
14553  resetPQExpBuffer(query);
14554  appendPQExpBuffer(query,
14555  "SELECT\n"
14556  " ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
14557  " WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
14558  " m.mapdict::pg_catalog.regdictionary AS dictname\n"
14559  "FROM pg_catalog.pg_ts_config_map AS m\n"
14560  "WHERE m.mapcfg = '%u'\n"
14561  "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
14562  cfginfo->cfgparser, cfginfo->dobj.catId.oid);
14563 
14564  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14565  ntups = PQntuples(res);
14566 
14567  i_tokenname = PQfnumber(res, "tokenname");
14568  i_dictname = PQfnumber(res, "dictname");
14569 
14570  for (i = 0; i < ntups; i++)
14571  {
14572  char *tokenname = PQgetvalue(res, i, i_tokenname);
14573  char *dictname = PQgetvalue(res, i, i_dictname);
14574 
14575  if (i == 0 ||
14576  strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
14577  {
14578  /* starting a new token type, so start a new command */
14579  if (i > 0)
14580  appendPQExpBufferStr(q, ";\n");
14581  appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
14582  fmtQualifiedDumpable(cfginfo));
14583  /* tokenname needs quoting, dictname does NOT */
14584  appendPQExpBuffer(q, " ADD MAPPING FOR %s WITH %s",
14585  fmtId(tokenname), dictname);
14586  }
14587  else
14588  appendPQExpBuffer(q, ", %s", dictname);
14589  }
14590 
14591  if (ntups > 0)
14592  appendPQExpBufferStr(q, ";\n");
14593 
14594  PQclear(res);
14595 
14596  appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
14597  fmtQualifiedDumpable(cfginfo));
14598 
14599  if (dopt->binary_upgrade)
14601  "TEXT SEARCH CONFIGURATION", qcfgname,
14602  cfginfo->dobj.namespace->dobj.name);
14603 
14604  if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14605  ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
14606  ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
14607  .namespace = cfginfo->dobj.namespace->dobj.name,
14608  .owner = cfginfo->rolname,
14609  .description = "TEXT SEARCH CONFIGURATION",
14610  .section = SECTION_PRE_DATA,
14611  .createStmt = q->data,
14612  .dropStmt = delq->data));
14613 
14614  /* Dump Configuration Comments */
14615  if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14616  dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
14617  cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
14618  cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
14619 
14620  destroyPQExpBuffer(q);
14621  destroyPQExpBuffer(delq);
14622  destroyPQExpBuffer(query);
14623  free(qcfgname);
14624 }
14625 
14626 /*
14627  * dumpForeignDataWrapper
14628  * write out a single foreign-data wrapper definition
14629  */
14630 static void
14632 {
14633  DumpOptions *dopt = fout->dopt;
14634  PQExpBuffer q;
14635  PQExpBuffer delq;
14636  char *qfdwname;
14637 
14638  /* Do nothing in data-only dump */
14639  if (dopt->dataOnly)
14640  return;
14641 
14642  q = createPQExpBuffer();
14643  delq = createPQExpBuffer();
14644 
14645  qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
14646 
14647  appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
14648  qfdwname);
14649 
14650  if (strcmp(fdwinfo->fdwhandler, "-") != 0)
14651  appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
14652 
14653  if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
14654  appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
14655 
14656  if (strlen(fdwinfo->fdwoptions) > 0)
14657  appendPQExpBuffer(q, " OPTIONS (\n %s\n)", fdwinfo->fdwoptions);
14658 
14659  appendPQExpBufferStr(q, ";\n");
14660 
14661  appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
14662  qfdwname);
14663 
14664  if (dopt->binary_upgrade)
14666  "FOREIGN DATA WRAPPER", qfdwname,
14667  NULL);
14668 
14669  if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14670  ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14671  ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
14672  .owner = fdwinfo->rolname,
14673  .description = "FOREIGN DATA WRAPPER",
14674  .section = SECTION_PRE_DATA,
14675  .createStmt = q->data,
14676  .dropStmt = delq->data));
14677 
14678  /* Dump Foreign Data Wrapper Comments */
14679  if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14680  dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
14681  NULL, fdwinfo->rolname,
14682  fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
14683 
14684  /* Handle the ACL */
14685  if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
14686  dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
14687  "FOREIGN DATA WRAPPER", qfdwname, NULL, NULL,
14688  NULL, fdwinfo->rolname, &fdwinfo->dacl);
14689 
14690  free(qfdwname);
14691 
14692  destroyPQExpBuffer(q);
14693  destroyPQExpBuffer(delq);
14694 }
14695 
14696 /*
14697  * dumpForeignServer
14698  * write out a foreign server definition
14699  */
14700 static void
14702 {
14703  DumpOptions *dopt = fout->dopt;
14704  PQExpBuffer q;
14705  PQExpBuffer delq;
14706  PQExpBuffer query;
14707  PGresult *res;
14708  char *qsrvname;
14709  char *fdwname;
14710 
14711  /* Do nothing in data-only dump */
14712  if (dopt->dataOnly)
14713  return;
14714 
14715  q = createPQExpBuffer();
14716  delq = createPQExpBuffer();
14717  query = createPQExpBuffer();
14718 
14719  qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
14720 
14721  /* look up the foreign-data wrapper */
14722  appendPQExpBuffer(query, "SELECT fdwname "
14723  "FROM pg_foreign_data_wrapper w "
14724  "WHERE w.oid = '%u'",
14725  srvinfo->srvfdw);
14726  res = ExecuteSqlQueryForSingleRow(fout, query->data);
14727  fdwname = PQgetvalue(res, 0, 0);
14728 
14729  appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
14730  if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
14731  {
14732  appendPQExpBufferStr(q, " TYPE ");
14733  appendStringLiteralAH(q, srvinfo->srvtype, fout);
14734  }
14735  if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
14736  {
14737  appendPQExpBufferStr(q, " VERSION ");
14738  appendStringLiteralAH(q, srvinfo->srvversion, fout);
14739  }
14740 
14741  appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
14742  appendPQExpBufferStr(q, fmtId(fdwname));
14743 
14744  if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
14745  appendPQExpBuffer(q, " OPTIONS (\n %s\n)", srvinfo->srvoptions);
14746 
14747  appendPQExpBufferStr(q, ";\n");
14748 
14749  appendPQExpBuffer(delq, "DROP SERVER %s;\n",
14750  qsrvname);
14751 
14752  if (dopt->binary_upgrade)
14754  "SERVER", qsrvname, NULL);
14755 
14756  if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14757  ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14758  ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
14759  .owner = srvinfo->rolname,
14760  .description = "SERVER",
14761  .section = SECTION_PRE_DATA,
14762  .createStmt = q->data,
14763  .dropStmt = delq->data));
14764 
14765  /* Dump Foreign Server Comments */
14766  if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14767  dumpComment(fout, "SERVER", qsrvname,
14768  NULL, srvinfo->rolname,
14769  srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
14770 
14771  /* Handle the ACL */
14772  if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
14773  dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
14774  "FOREIGN SERVER", qsrvname, NULL, NULL,
14775  NULL, srvinfo->rolname, &srvinfo->dacl);
14776 
14777  /* Dump user mappings */
14778  if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
14779  dumpUserMappings(fout,
14780  srvinfo->dobj.name, NULL,
14781  srvinfo->rolname,
14782  srvinfo->dobj.catId, srvinfo->dobj.dumpId);
14783 
14784  PQclear(res);
14785 
14786  free(qsrvname);
14787 
14788  destroyPQExpBuffer(q);
14789  destroyPQExpBuffer(delq);
14790  destroyPQExpBuffer(query);
14791 }
14792 
14793 /*
14794  * dumpUserMappings
14795  *
14796  * This routine is used to dump any user mappings associated with the
14797  * server handed to this routine. Should be called after ArchiveEntry()
14798  * for the server.
14799  */
14800 static void
14802  const char *servername, const char *namespace,
14803  const char *owner,
14804  CatalogId catalogId, DumpId dumpId)
14805 {
14806  PQExpBuffer q;
14807  PQExpBuffer delq;
14808  PQExpBuffer query;
14809  PQExpBuffer tag;
14810  PGresult *res;
14811  int ntups;
14812  int i_usename;
14813  int i_umoptions;
14814  int i;
14815 
14816  q = createPQExpBuffer();
14817  tag = createPQExpBuffer();
14818  delq = createPQExpBuffer();
14819  query = createPQExpBuffer();
14820 
14821  /*
14822  * We read from the publicly accessible view pg_user_mappings, so as not
14823  * to fail if run by a non-superuser. Note that the view will show
14824  * umoptions as null if the user hasn't got privileges for the associated
14825  * server; this means that pg_dump will dump such a mapping, but with no
14826  * OPTIONS clause. A possible alternative is to skip such mappings
14827  * altogether, but it's not clear that that's an improvement.
14828  */
14829  appendPQExpBuffer(query,
14830  "SELECT usename, "
14831  "array_to_string(ARRAY("
14832  "SELECT quote_ident(option_name) || ' ' || "
14833  "quote_literal(option_value) "
14834  "FROM pg_options_to_table(umoptions) "
14835  "ORDER BY option_name"
14836  "), E',\n ') AS umoptions "
14837  "FROM pg_user_mappings "
14838  "WHERE srvid = '%u' "
14839  "ORDER BY usename",
14840  catalogId.oid);
14841 
14842  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14843 
14844  ntups = PQntuples(res);
14845  i_usename = PQfnumber(res, "usename");
14846  i_umoptions = PQfnumber(res, "umoptions");
14847 
14848  for (i = 0; i < ntups; i++)
14849  {
14850  char *usename;
14851  char *umoptions;
14852 
14853  usename = PQgetvalue(res, i, i_usename);
14854  umoptions = PQgetvalue(res, i, i_umoptions);
14855 
14856  resetPQExpBuffer(q);
14857  appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
14858  appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
14859 
14860  if (umoptions && strlen(umoptions) > 0)
14861  appendPQExpBuffer(q, " OPTIONS (\n %s\n)", umoptions);
14862 
14863  appendPQExpBufferStr(q, ";\n");
14864 
14865  resetPQExpBuffer(delq);
14866  appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
14867  appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
14868 
14869  resetPQExpBuffer(tag);
14870  appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
14871  usename, servername);
14872 
14874  ARCHIVE_OPTS(.tag = tag->data,
14875  .namespace = namespace,
14876  .owner = owner,
14877  .description = "USER MAPPING",
14878  .section = SECTION_PRE_DATA,
14879  .createStmt = q->data,
14880  .dropStmt = delq->data));
14881  }
14882 
14883  PQclear(res);
14884 
14885  destroyPQExpBuffer(query);
14886  destroyPQExpBuffer(delq);
14887  destroyPQExpBuffer(tag);
14888  destroyPQExpBuffer(q);
14889 }
14890 
14891 /*
14892  * Write out default privileges information
14893  */
14894 static void
14895 dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
14896 {
14897  DumpOptions *dopt = fout->dopt;
14898  PQExpBuffer q;
14899  PQExpBuffer tag;
14900  const char *type;
14901 
14902  /* Do nothing in data-only dump, or if we're skipping ACLs */
14903  if (dopt->dataOnly || dopt->aclsSkip)
14904  return;
14905 
14906  q = createPQExpBuffer();
14907  tag = createPQExpBuffer();
14908 
14909  switch (daclinfo->defaclobjtype)
14910  {
14911  case DEFACLOBJ_RELATION:
14912  type = "TABLES";
14913  break;
14914  case DEFACLOBJ_SEQUENCE:
14915  type = "SEQUENCES";
14916  break;
14917  case DEFACLOBJ_FUNCTION:
14918  type = "FUNCTIONS";
14919  break;
14920  case DEFACLOBJ_TYPE:
14921  type = "TYPES";
14922  break;
14923  case DEFACLOBJ_NAMESPACE:
14924  type = "SCHEMAS";
14925  break;
14926  default:
14927  /* shouldn't get here */
14928  pg_fatal("unrecognized object type in default privileges: %d",
14929  (int) daclinfo->defaclobjtype);
14930  type = ""; /* keep compiler quiet */
14931  }
14932 
14933  appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
14934 
14935  /* build the actual command(s) for this tuple */
14937  daclinfo->dobj.namespace != NULL ?
14938  daclinfo->dobj.namespace->dobj.name : NULL,
14939  daclinfo->dacl.acl,
14940  daclinfo->dacl.acldefault,
14941  daclinfo->defaclrole,
14942  fout->remoteVersion,
14943  q))
14944  pg_fatal("could not parse default ACL list (%s)",
14945  daclinfo->dacl.acl);
14946 
14947  if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
14948  ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
14949  ARCHIVE_OPTS(.tag = tag->data,
14950  .namespace = daclinfo->dobj.namespace ?
14951  daclinfo->dobj.namespace->dobj.name : NULL,
14952  .owner = daclinfo->defaclrole,
14953  .description = "DEFAULT ACL",
14954  .section = SECTION_POST_DATA,
14955  .createStmt = q->data));
14956 
14957  destroyPQExpBuffer(tag);
14958  destroyPQExpBuffer(q);
14959 }
14960 
14961 /*----------
14962  * Write out grant/revoke information
14963  *
14964  * 'objDumpId' is the dump ID of the underlying object.
14965  * 'altDumpId' can be a second dumpId that the ACL entry must also depend on,
14966  * or InvalidDumpId if there is no need for a second dependency.
14967  * 'type' must be one of
14968  * TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
14969  * FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
14970  * 'name' is the formatted name of the object. Must be quoted etc. already.
14971  * 'subname' is the formatted name of the sub-object, if any. Must be quoted.
14972  * (Currently we assume that subname is only provided for table columns.)
14973  * 'nspname' is the namespace the object is in (NULL if none).
14974  * 'tag' is the tag to use for the ACL TOC entry; typically, this is NULL
14975  * to use the default for the object type.
14976  * 'owner' is the owner, NULL if there is no owner (for languages).
14977  * 'dacl' is the DumpableAcl struct for the object.
14978  *
14979  * Returns the dump ID assigned to the ACL TocEntry, or InvalidDumpId if
14980  * no ACL entry was created.
14981  *----------
14982  */
14983 static DumpId
14984 dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
14985  const char *type, const char *name, const char *subname,
14986  const char *nspname, const char *tag, const char *owner,
14987  const DumpableAcl *dacl)
14988 {
14989  DumpId aclDumpId = InvalidDumpId;
14990  DumpOptions *dopt = fout->dopt;
14991  const char *acls = dacl->acl;
14992  const char *acldefault = dacl->acldefault;
14993  char privtype = dacl->privtype;
14994  const char *initprivs = dacl->initprivs;
14995  const char *baseacls;
14996  PQExpBuffer sql;
14997 
14998  /* Do nothing if ACL dump is not enabled */
14999  if (dopt->aclsSkip)
15000  return InvalidDumpId;
15001 
15002  /* --data-only skips ACLs *except* large object ACLs */
15003  if (dopt->dataOnly && strcmp(type, "LARGE OBJECT") != 0)
15004  return InvalidDumpId;
15005 
15006  sql = createPQExpBuffer();
15007 
15008  /*
15009  * In binary upgrade mode, we don't run an extension's script but instead
15010  * dump out the objects independently and then recreate them. To preserve
15011  * any initial privileges which were set on extension objects, we need to
15012  * compute the set of GRANT and REVOKE commands necessary to get from the
15013  * default privileges of an object to its initial privileges as recorded
15014  * in pg_init_privs.
15015  *
15016  * At restore time, we apply these commands after having called
15017  * binary_upgrade_set_record_init_privs(true). That tells the backend to
15018  * copy the results into pg_init_privs. This is how we preserve the
15019  * contents of that catalog across binary upgrades.
15020  */
15021  if (dopt->binary_upgrade && privtype == 'e' &&
15022  initprivs && *initprivs != '\0')
15023  {
15024  appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
15025  if (!buildACLCommands(name, subname, nspname, type,
15026  initprivs, acldefault, owner,
15027  "", fout->remoteVersion, sql))
15028  pg_fatal("could not parse initial ACL list (%s) or default (%s) for object \"%s\" (%s)",
15029  initprivs, acldefault, name, type);
15030  appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
15031  }
15032 
15033  /*
15034  * Now figure the GRANT and REVOKE commands needed to get to the object's
15035  * actual current ACL, starting from the initprivs if given, else from the
15036  * object-type-specific default. Also, while buildACLCommands will assume
15037  * that a NULL/empty acls string means it needn't do anything, what that
15038  * actually represents is the object-type-specific default; so we need to
15039  * substitute the acldefault string to get the right results in that case.
15040  */
15041  if (initprivs && *initprivs != '\0')
15042  {
15043  baseacls = initprivs;
15044  if (acls == NULL || *acls == '\0')
15045  acls = acldefault;
15046  }
15047  else
15048  baseacls = acldefault;
15049 
15050  if (!buildACLCommands(name, subname, nspname, type,
15051  acls, baseacls, owner,
15052  "", fout->remoteVersion, sql))
15053  pg_fatal("could not parse ACL list (%s) or default (%s) for object \"%s\" (%s)",
15054  acls, baseacls, name, type);
15055 
15056  if (sql->len > 0)
15057  {
15058  PQExpBuffer tagbuf = createPQExpBuffer();
15059  DumpId aclDeps[2];
15060  int nDeps = 0;
15061 
15062  if (tag)
15063  appendPQExpBufferStr(tagbuf, tag);
15064  else if (subname)
15065  appendPQExpBuffer(tagbuf, "COLUMN %s.%s", name, subname);
15066  else
15067  appendPQExpBuffer(tagbuf, "%s %s", type, name);
15068 
15069  aclDeps[nDeps++] = objDumpId;
15070  if (altDumpId != InvalidDumpId)
15071  aclDeps[nDeps++] = altDumpId;
15072 
15073  aclDumpId = createDumpId();
15074 
15075  ArchiveEntry(fout, nilCatalogId, aclDumpId,
15076  ARCHIVE_OPTS(.tag = tagbuf->data,
15077  .namespace = nspname,
15078  .owner = owner,
15079  .description = "ACL",
15080  .section = SECTION_NONE,
15081  .createStmt = sql->data,
15082  .deps = aclDeps,
15083  .nDeps = nDeps));
15084 
15085  destroyPQExpBuffer(tagbuf);
15086  }
15087 
15088  destroyPQExpBuffer(sql);
15089 
15090  return aclDumpId;
15091 }
15092 
15093 /*
15094  * dumpSecLabel
15095  *
15096  * This routine is used to dump any security labels associated with the
15097  * object handed to this routine. The routine takes the object type
15098  * and object name (ready to print, except for schema decoration), plus
15099  * the namespace and owner of the object (for labeling the ArchiveEntry),
15100  * plus catalog ID and subid which are the lookup key for pg_seclabel,
15101  * plus the dump ID for the object (for setting a dependency).
15102  * If a matching pg_seclabel entry is found, it is dumped.
15103  *
15104  * Note: although this routine takes a dumpId for dependency purposes,
15105  * that purpose is just to mark the dependency in the emitted dump file
15106  * for possible future use by pg_restore. We do NOT use it for determining
15107  * ordering of the label in the dump file, because this routine is called
15108  * after dependency sorting occurs. This routine should be called just after
15109  * calling ArchiveEntry() for the specified object.
15110  */
15111 static void
15112 dumpSecLabel(Archive *fout, const char *type, const char *name,
15113  const char *namespace, const char *owner,
15114  CatalogId catalogId, int subid, DumpId dumpId)
15115 {
15116  DumpOptions *dopt = fout->dopt;
15117  SecLabelItem *labels;
15118  int nlabels;
15119  int i;
15120  PQExpBuffer query;
15121 
15122  /* do nothing, if --no-security-labels is supplied */
15123  if (dopt->no_security_labels)
15124  return;
15125 
15126  /*
15127  * Security labels are schema not data ... except large object labels are
15128  * data
15129  */
15130  if (strcmp(type, "LARGE OBJECT") != 0)
15131  {
15132  if (dopt->dataOnly)
15133  return;
15134  }
15135  else
15136  {
15137  /* We do dump large object security labels in binary-upgrade mode */
15138  if (dopt->schemaOnly && !dopt->binary_upgrade)
15139  return;
15140  }
15141 
15142  /* Search for security labels associated with catalogId, using table */
15143  nlabels = findSecLabels(catalogId.tableoid, catalogId.oid, &labels);
15144 
15145  query = createPQExpBuffer();
15146 
15147  for (i = 0; i < nlabels; i++)
15148  {
15149  /*
15150  * Ignore label entries for which the subid doesn't match.
15151  */
15152  if (labels[i].objsubid != subid)
15153  continue;
15154 
15155  appendPQExpBuffer(query,
15156  "SECURITY LABEL FOR %s ON %s ",
15157  fmtId(labels[i].provider), type);
15158  if (namespace && *namespace)
15159  appendPQExpBuffer(query, "%s.", fmtId(namespace));
15160  appendPQExpBuffer(query, "%s IS ", name);
15161  appendStringLiteralAH(query, labels[i].label, fout);
15162  appendPQExpBufferStr(query, ";\n");
15163  }
15164 
15165  if (query->len > 0)
15166  {
15168 
15169  appendPQExpBuffer(tag, "%s %s", type, name);
15171  ARCHIVE_OPTS(.tag = tag->data,
15172  .namespace = namespace,
15173  .owner = owner,
15174  .description = "SECURITY LABEL",
15175  .section = SECTION_NONE,
15176  .createStmt = query->data,
15177  .deps = &dumpId,
15178  .nDeps = 1));
15179  destroyPQExpBuffer(tag);
15180  }
15181 
15182  destroyPQExpBuffer(query);
15183 }
15184 
15185 /*
15186  * dumpTableSecLabel
15187  *
15188  * As above, but dump security label for both the specified table (or view)
15189  * and its columns.
15190  */
15191 static void
15192 dumpTableSecLabel(Archive *fout, const TableInfo *tbinfo, const char *reltypename)
15193 {
15194  DumpOptions *dopt = fout->dopt;
15195  SecLabelItem *labels;
15196  int nlabels;
15197  int i;
15198  PQExpBuffer query;
15199  PQExpBuffer target;
15200 
15201  /* do nothing, if --no-security-labels is supplied */
15202  if (dopt->no_security_labels)
15203  return;
15204 
15205  /* SecLabel are SCHEMA not data */
15206  if (dopt->dataOnly)
15207  return;
15208 
15209  /* Search for comments associated with relation, using table */
15210  nlabels = findSecLabels(tbinfo->dobj.catId.tableoid,
15211  tbinfo->dobj.catId.oid,
15212  &labels);
15213 
15214  /* If security labels exist, build SECURITY LABEL statements */
15215  if (nlabels <= 0)
15216  return;
15217 
15218  query = createPQExpBuffer();
15219  target = createPQExpBuffer();
15220 
15221  for (i = 0; i < nlabels; i++)
15222  {
15223  const char *colname;
15224  const char *provider = labels[i].provider;
15225  const char *label = labels[i].label;
15226  int objsubid = labels[i].objsubid;
15227 
15228  resetPQExpBuffer(target);
15229  if (objsubid == 0)
15230  {
15231  appendPQExpBuffer(target, "%s %s", reltypename,
15232  fmtQualifiedDumpable(tbinfo));
15233  }
15234  else
15235  {
15236  colname = getAttrName(objsubid, tbinfo);
15237  /* first fmtXXX result must be consumed before calling again */
15238  appendPQExpBuffer(target, "COLUMN %s",
15239  fmtQualifiedDumpable(tbinfo));
15240  appendPQExpBuffer(target, ".%s", fmtId(colname));
15241  }
15242  appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
15243  fmtId(provider), target->data);
15244  appendStringLiteralAH(query, label, fout);
15245  appendPQExpBufferStr(query, ";\n");
15246  }
15247  if (query->len > 0)
15248  {
15249  resetPQExpBuffer(target);
15250  appendPQExpBuffer(target, "%s %s", reltypename,
15251  fmtId(tbinfo->dobj.name));
15253  ARCHIVE_OPTS(.tag = target->data,
15254  .namespace = tbinfo->dobj.namespace->dobj.name,
15255  .owner = tbinfo->rolname,
15256  .description = "SECURITY LABEL",
15257  .section = SECTION_NONE,
15258  .createStmt = query->data,
15259  .deps = &(tbinfo->dobj.dumpId),
15260  .nDeps = 1));
15261  }
15262  destroyPQExpBuffer(query);
15263  destroyPQExpBuffer(target);
15264 }
15265 
15266 /*
15267  * findSecLabels
15268  *
15269  * Find the security label(s), if any, associated with the given object.
15270  * All the objsubid values associated with the given classoid/objoid are
15271  * found with one search.
15272  */
15273 static int
15275 {
15276  SecLabelItem *middle = NULL;
15277  SecLabelItem *low;
15278  SecLabelItem *high;
15279  int nmatch;
15280 
15281  if (nseclabels <= 0) /* no labels, so no match is possible */
15282  {
15283  *items = NULL;
15284  return 0;
15285  }
15286 
15287  /*
15288  * Do binary search to find some item matching the object.
15289  */
15290  low = &seclabels[0];
15291  high = &seclabels[nseclabels - 1];
15292  while (low <= high)
15293  {
15294  middle = low + (high - low) / 2;
15295 
15296  if (classoid < middle->classoid)
15297  high = middle - 1;
15298  else if (classoid > middle->classoid)
15299  low = middle + 1;
15300  else if (objoid < middle->objoid)
15301  high = middle - 1;
15302  else if (objoid > middle->objoid)
15303  low = middle + 1;
15304  else
15305  break; /* found a match */
15306  }
15307 
15308  if (low > high) /* no matches */
15309  {
15310  *items = NULL;
15311  return 0;
15312  }
15313 
15314  /*
15315  * Now determine how many items match the object. The search loop
15316  * invariant still holds: only items between low and high inclusive could
15317  * match.
15318  */
15319  nmatch = 1;
15320  while (middle > low)
15321  {
15322  if (classoid != middle[-1].classoid ||
15323  objoid != middle[-1].objoid)
15324  break;
15325  middle--;
15326  nmatch++;
15327  }
15328 
15329  *items = middle;
15330 
15331  middle += nmatch;
15332  while (middle <= high)
15333  {
15334  if (classoid != middle->classoid ||
15335  objoid != middle->objoid)
15336  break;
15337  middle++;
15338  nmatch++;
15339  }
15340 
15341  return nmatch;
15342 }
15343 
15344 /*
15345  * collectSecLabels
15346  *
15347  * Construct a table of all security labels available for database objects;
15348  * also set the has-seclabel component flag for each relevant object.
15349  *
15350  * The table is sorted by classoid/objid/objsubid for speed in lookup.
15351  */
15352 static void
15354 {
15355  PGresult *res;
15356  PQExpBuffer query;
15357  int i_label;
15358  int i_provider;
15359  int i_classoid;
15360  int i_objoid;
15361  int i_objsubid;
15362  int ntups;
15363  int i;
15364  DumpableObject *dobj;
15365 
15366  query = createPQExpBuffer();
15367 
15368  appendPQExpBufferStr(query,
15369  "SELECT label, provider, classoid, objoid, objsubid "
15370  "FROM pg_catalog.pg_seclabel "
15371  "ORDER BY classoid, objoid, objsubid");
15372 
15373  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15374 
15375  /* Construct lookup table containing OIDs in numeric form */
15376  i_label = PQfnumber(res, "label");
15377  i_provider = PQfnumber(res, "provider");
15378  i_classoid = PQfnumber(res, "classoid");
15379  i_objoid = PQfnumber(res, "objoid");
15380  i_objsubid = PQfnumber(res, "objsubid");
15381 
15382  ntups = PQntuples(res);
15383 
15384  seclabels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
15385  nseclabels = 0;
15386  dobj = NULL;
15387 
15388  for (i = 0; i < ntups; i++)
15389  {
15390  CatalogId objId;
15391  int subid;
15392 
15393  objId.tableoid = atooid(PQgetvalue(res, i, i_classoid));
15394  objId.oid = atooid(PQgetvalue(res, i, i_objoid));
15395  subid = atoi(PQgetvalue(res, i, i_objsubid));
15396 
15397  /* We needn't remember labels that don't match any dumpable object */
15398  if (dobj == NULL ||
15399  dobj->catId.tableoid != objId.tableoid ||
15400  dobj->catId.oid != objId.oid)
15401  dobj = findObjectByCatalogId(objId);
15402  if (dobj == NULL)
15403  continue;
15404 
15405  /*
15406  * Labels on columns of composite types are linked to the type's
15407  * pg_class entry, but we need to set the DUMP_COMPONENT_SECLABEL flag
15408  * in the type's own DumpableObject.
15409  */
15410  if (subid != 0 && dobj->objType == DO_TABLE &&
15411  ((TableInfo *) dobj)->relkind == RELKIND_COMPOSITE_TYPE)
15412  {
15413  TypeInfo *cTypeInfo;
15414 
15415  cTypeInfo = findTypeByOid(((TableInfo *) dobj)->reltype);
15416  if (cTypeInfo)
15417  cTypeInfo->dobj.components |= DUMP_COMPONENT_SECLABEL;
15418  }
15419  else
15420  dobj->components |= DUMP_COMPONENT_SECLABEL;
15421 
15425  seclabels[nseclabels].objoid = objId.oid;
15426  seclabels[nseclabels].objsubid = subid;
15427  nseclabels++;
15428  }
15429 
15430  PQclear(res);
15431  destroyPQExpBuffer(query);
15432 }
15433 
15434 /*
15435  * dumpTable
15436  * write out to fout the declarations (not data) of a user-defined table
15437  */
15438 static void
15439 dumpTable(Archive *fout, const TableInfo *tbinfo)
15440 {
15441  DumpOptions *dopt = fout->dopt;
15442  DumpId tableAclDumpId = InvalidDumpId;
15443  char *namecopy;
15444 
15445  /* Do nothing in data-only dump */
15446  if (dopt->dataOnly)
15447  return;
15448 
15449  if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
15450  {
15451  if (tbinfo->relkind == RELKIND_SEQUENCE)
15452  dumpSequence(fout, tbinfo);
15453  else
15454  dumpTableSchema(fout, tbinfo);
15455  }
15456 
15457  /* Handle the ACL here */
15458  namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
15459  if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15460  {
15461  const char *objtype =
15462  (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
15463 
15464  tableAclDumpId =
15465  dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
15466  objtype, namecopy, NULL,
15467  tbinfo->dobj.namespace->dobj.name,
15468  NULL, tbinfo->rolname, &tbinfo->dacl);
15469  }
15470 
15471  /*
15472  * Handle column ACLs, if any. Note: we pull these with a separate query
15473  * rather than trying to fetch them during getTableAttrs, so that we won't
15474  * miss ACLs on system columns. Doing it this way also allows us to dump
15475  * ACLs for catalogs that we didn't mark "interesting" back in getTables.
15476  */
15477  if ((tbinfo->dobj.dump & DUMP_COMPONENT_ACL) && tbinfo->hascolumnACLs)
15478  {
15479  PQExpBuffer query = createPQExpBuffer();
15480  PGresult *res;
15481  int i;
15482 
15484  {
15485  /* Set up query for column ACLs */
15486  appendPQExpBufferStr(query,
15487  "PREPARE getColumnACLs(pg_catalog.oid) AS\n");
15488 
15489  if (fout->remoteVersion >= 90600)
15490  {
15491  /*
15492  * In principle we should call acldefault('c', relowner) to
15493  * get the default ACL for a column. However, we don't
15494  * currently store the numeric OID of the relowner in
15495  * TableInfo. We could convert the owner name using regrole,
15496  * but that creates a risk of failure due to concurrent role
15497  * renames. Given that the default ACL for columns is empty
15498  * and is likely to stay that way, it's not worth extra cycles
15499  * and risk to avoid hard-wiring that knowledge here.
15500  */
15501  appendPQExpBufferStr(query,
15502  "SELECT at.attname, "
15503  "at.attacl, "
15504  "'{}' AS acldefault, "
15505  "pip.privtype, pip.initprivs "
15506  "FROM pg_catalog.pg_attribute at "
15507  "LEFT JOIN pg_catalog.pg_init_privs pip ON "
15508  "(at.attrelid = pip.objoid "
15509  "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
15510  "AND at.attnum = pip.objsubid) "
15511  "WHERE at.attrelid = $1 AND "
15512  "NOT at.attisdropped "
15513  "AND (at.attacl IS NOT NULL OR pip.initprivs IS NOT NULL) "
15514  "ORDER BY at.attnum");
15515  }
15516  else
15517  {
15518  appendPQExpBufferStr(query,
15519  "SELECT attname, attacl, '{}' AS acldefault, "
15520  "NULL AS privtype, NULL AS initprivs "
15521  "FROM pg_catalog.pg_attribute "
15522  "WHERE attrelid = $1 AND NOT attisdropped "
15523  "AND attacl IS NOT NULL "
15524  "ORDER BY attnum");
15525  }
15526 
15527  ExecuteSqlStatement(fout, query->data);
15528 
15529  fout->is_prepared[PREPQUERY_GETCOLUMNACLS] = true;
15530  }
15531 
15532  printfPQExpBuffer(query,
15533  "EXECUTE getColumnACLs('%u')",
15534  tbinfo->dobj.catId.oid);
15535 
15536  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15537 
15538  for (i = 0; i < PQntuples(res); i++)
15539  {
15540  char *attname = PQgetvalue(res, i, 0);
15541  char *attacl = PQgetvalue(res, i, 1);
15542  char *acldefault = PQgetvalue(res, i, 2);
15543  char privtype = *(PQgetvalue(res, i, 3));
15544  char *initprivs = PQgetvalue(res, i, 4);
15545  DumpableAcl coldacl;
15546  char *attnamecopy;
15547 
15548  coldacl.acl = attacl;
15549  coldacl.acldefault = acldefault;
15550  coldacl.privtype = privtype;
15551  coldacl.initprivs = initprivs;
15552  attnamecopy = pg_strdup(fmtId(attname));
15553 
15554  /*
15555  * Column's GRANT type is always TABLE. Each column ACL depends
15556  * on the table-level ACL, since we can restore column ACLs in
15557  * parallel but the table-level ACL has to be done first.
15558  */
15559  dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
15560  "TABLE", namecopy, attnamecopy,
15561  tbinfo->dobj.namespace->dobj.name,
15562  NULL, tbinfo->rolname, &coldacl);
15563  free(attnamecopy);
15564  }
15565  PQclear(res);
15566  destroyPQExpBuffer(query);
15567  }
15568 
15569  free(namecopy);
15570 }
15571 
15572 /*
15573  * Create the AS clause for a view or materialized view. The semicolon is
15574  * stripped because a materialized view must add a WITH NO DATA clause.
15575  *
15576  * This returns a new buffer which must be freed by the caller.
15577  */
15578 static PQExpBuffer
15579 createViewAsClause(Archive *fout, const TableInfo *tbinfo)
15580 {
15581  PQExpBuffer query = createPQExpBuffer();
15582  PQExpBuffer result = createPQExpBuffer();
15583  PGresult *res;
15584  int len;
15585 
15586  /* Fetch the view definition */
15587  appendPQExpBuffer(query,
15588  "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
15589  tbinfo->dobj.catId.oid);
15590 
15591  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15592 
15593  if (PQntuples(res) != 1)
15594  {
15595  if (PQntuples(res) < 1)
15596  pg_fatal("query to obtain definition of view \"%s\" returned no data",
15597  tbinfo->dobj.name);
15598  else
15599  pg_fatal("query to obtain definition of view \"%s\" returned more than one definition",
15600  tbinfo->dobj.name);
15601  }
15602 
15603  len = PQgetlength(res, 0, 0);
15604 
15605  if (len == 0)
15606  pg_fatal("definition of view \"%s\" appears to be empty (length zero)",
15607  tbinfo->dobj.name);
15608 
15609  /* Strip off the trailing semicolon so that other things may follow. */
15610  Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
15611  appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
15612 
15613  PQclear(res);
15614  destroyPQExpBuffer(query);
15615 
15616  return result;
15617 }
15618 
15619 /*
15620  * Create a dummy AS clause for a view. This is used when the real view
15621  * definition has to be postponed because of circular dependencies.
15622  * We must duplicate the view's external properties -- column names and types
15623  * (including collation) -- so that it works for subsequent references.
15624  *
15625  * This returns a new buffer which must be freed by the caller.
15626  */
15627 static PQExpBuffer
15629 {
15630  PQExpBuffer result = createPQExpBuffer();
15631  int j;
15632 
15633  appendPQExpBufferStr(result, "SELECT");
15634 
15635  for (j = 0; j < tbinfo->numatts; j++)
15636  {
15637  if (j > 0)
15638  appendPQExpBufferChar(result, ',');
15639  appendPQExpBufferStr(result, "\n ");
15640 
15641  appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
15642 
15643  /*
15644  * Must add collation if not default for the type, because CREATE OR
15645  * REPLACE VIEW won't change it
15646  */
15647  if (OidIsValid(tbinfo->attcollation[j]))
15648  {
15649  CollInfo *coll;
15650 
15651  coll = findCollationByOid(tbinfo->attcollation[j]);
15652  if (coll)
15653  appendPQExpBuffer(result, " COLLATE %s",
15654  fmtQualifiedDumpable(coll));
15655  }
15656 
15657  appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
15658  }
15659 
15660  return result;
15661 }
15662 
15663 /*
15664  * dumpTableSchema
15665  * write the declaration (not data) of one user-defined table or view
15666  */
15667 static void
15668 dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
15669 {
15670  DumpOptions *dopt = fout->dopt;
15672  PQExpBuffer delq = createPQExpBuffer();
15673  char *qrelname;
15674  char *qualrelname;
15675  int numParents;
15676  TableInfo **parents;
15677  int actual_atts; /* number of attrs in this CREATE statement */
15678  const char *reltypename;
15679  char *storage;
15680  int j,
15681  k;
15682 
15683  /* We had better have loaded per-column details about this table */
15684  Assert(tbinfo->interesting);
15685 
15686  qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
15687  qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
15688 
15689  if (tbinfo->hasoids)
15690  pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
15691  qrelname);
15692 
15693  if (dopt->binary_upgrade)
15694  binary_upgrade_set_type_oids_by_rel(fout, q, tbinfo);
15695 
15696  /* Is it a table or a view? */
15697  if (tbinfo->relkind == RELKIND_VIEW)
15698  {
15699  PQExpBuffer result;
15700 
15701  /*
15702  * Note: keep this code in sync with the is_view case in dumpRule()
15703  */
15704 
15705  reltypename = "VIEW";
15706 
15707  appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
15708 
15709  if (dopt->binary_upgrade)
15711  tbinfo->dobj.catId.oid);
15712 
15713  appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
15714 
15715  if (tbinfo->dummy_view)
15716  result = createDummyViewAsClause(fout, tbinfo);
15717  else
15718  {
15719  if (nonemptyReloptions(tbinfo->reloptions))
15720  {
15721  appendPQExpBufferStr(q, " WITH (");
15722  appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15723  appendPQExpBufferChar(q, ')');
15724  }
15725  result = createViewAsClause(fout, tbinfo);
15726  }
15727  appendPQExpBuffer(q, " AS\n%s", result->data);
15728  destroyPQExpBuffer(result);
15729 
15730  if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
15731  appendPQExpBuffer(q, "\n WITH %s CHECK OPTION", tbinfo->checkoption);
15732  appendPQExpBufferStr(q, ";\n");
15733  }
15734  else
15735  {
15736  char *partkeydef = NULL;
15737  char *ftoptions = NULL;
15738  char *srvname = NULL;
15739  char *foreign = "";
15740 
15741  /*
15742  * Set reltypename, and collect any relkind-specific data that we
15743  * didn't fetch during getTables().
15744  */
15745  switch (tbinfo->relkind)
15746  {
15747  case RELKIND_PARTITIONED_TABLE:
15748  {
15749  PQExpBuffer query = createPQExpBuffer();
15750  PGresult *res;
15751 
15752  reltypename = "TABLE";
15753 
15754  /* retrieve partition key definition */
15755  appendPQExpBuffer(query,
15756  "SELECT pg_get_partkeydef('%u')",
15757  tbinfo->dobj.catId.oid);
15758  res = ExecuteSqlQueryForSingleRow(fout, query->data);
15759  partkeydef = pg_strdup(PQgetvalue(res, 0, 0));
15760  PQclear(res);
15761  destroyPQExpBuffer(query);
15762  break;
15763  }
15764  case RELKIND_FOREIGN_TABLE:
15765  {
15766  PQExpBuffer query = createPQExpBuffer();
15767  PGresult *res;
15768  int i_srvname;
15769  int i_ftoptions;
15770 
15771  reltypename = "FOREIGN TABLE";
15772 
15773  /* retrieve name of foreign server and generic options */
15774  appendPQExpBuffer(query,
15775  "SELECT fs.srvname, "
15776  "pg_catalog.array_to_string(ARRAY("
15777  "SELECT pg_catalog.quote_ident(option_name) || "
15778  "' ' || pg_catalog.quote_literal(option_value) "
15779  "FROM pg_catalog.pg_options_to_table(ftoptions) "
15780  "ORDER BY option_name"
15781  "), E',\n ') AS ftoptions "
15782  "FROM pg_catalog.pg_foreign_table ft "
15783  "JOIN pg_catalog.pg_foreign_server fs "
15784  "ON (fs.oid = ft.ftserver) "
15785  "WHERE ft.ftrelid = '%u'",
15786  tbinfo->dobj.catId.oid);
15787  res = ExecuteSqlQueryForSingleRow(fout, query->data);
15788  i_srvname = PQfnumber(res, "srvname");
15789  i_ftoptions = PQfnumber(res, "ftoptions");
15790  srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
15791  ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
15792  PQclear(res);
15793  destroyPQExpBuffer(query);
15794 
15795  foreign = "FOREIGN ";
15796  break;
15797  }
15798  case RELKIND_MATVIEW:
15799  reltypename = "MATERIALIZED VIEW";
15800  break;
15801  default:
15802  reltypename = "TABLE";
15803  break;
15804  }
15805 
15806  numParents = tbinfo->numParents;
15807  parents = tbinfo->parents;
15808 
15809  appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
15810 
15811  if (dopt->binary_upgrade)
15813  tbinfo->dobj.catId.oid);
15814 
15815  appendPQExpBuffer(q, "CREATE %s%s %s",
15816  tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
15817  "UNLOGGED " : "",
15818  reltypename,
15819  qualrelname);
15820 
15821  /*
15822  * Attach to type, if reloftype; except in case of a binary upgrade,
15823  * we dump the table normally and attach it to the type afterward.
15824  */
15825  if (OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade)
15826  appendPQExpBuffer(q, " OF %s",
15827  getFormattedTypeName(fout, tbinfo->reloftype,
15828  zeroIsError));
15829 
15830  if (tbinfo->relkind != RELKIND_MATVIEW)
15831  {
15832  /* Dump the attributes */
15833  actual_atts = 0;
15834  for (j = 0; j < tbinfo->numatts; j++)
15835  {
15836  /*
15837  * Normally, dump if it's locally defined in this table, and
15838  * not dropped. But for binary upgrade, we'll dump all the
15839  * columns, and then fix up the dropped and nonlocal cases
15840  * below.
15841  */
15842  if (shouldPrintColumn(dopt, tbinfo, j))
15843  {
15844  bool print_default;
15845  bool print_notnull;
15846 
15847  /*
15848  * Default value --- suppress if to be printed separately
15849  * or not at all.
15850  */
15851  print_default = (tbinfo->attrdefs[j] != NULL &&
15852  tbinfo->attrdefs[j]->dobj.dump &&
15853  !tbinfo->attrdefs[j]->separate);
15854 
15855  /*
15856  * Not Null constraint --- suppress if inherited, except
15857  * if partition, or in binary-upgrade case where that
15858  * won't work.
15859  */
15860  print_notnull = (tbinfo->notnull[j] &&
15861  (!tbinfo->inhNotNull[j] ||
15862  tbinfo->ispartition || dopt->binary_upgrade));
15863 
15864  /*
15865  * Skip column if fully defined by reloftype, except in
15866  * binary upgrade
15867  */
15868  if (OidIsValid(tbinfo->reloftype) &&
15869  !print_default && !print_notnull &&
15870  !dopt->binary_upgrade)
15871  continue;
15872 
15873  /* Format properly if not first attr */
15874  if (actual_atts == 0)
15875  appendPQExpBufferStr(q, " (");
15876  else
15877  appendPQExpBufferChar(q, ',');
15878  appendPQExpBufferStr(q, "\n ");
15879  actual_atts++;
15880 
15881  /* Attribute name */
15882  appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
15883 
15884  if (tbinfo->attisdropped[j])
15885  {
15886  /*
15887  * ALTER TABLE DROP COLUMN clears
15888  * pg_attribute.atttypid, so we will not have gotten a
15889  * valid type name; insert INTEGER as a stopgap. We'll
15890  * clean things up later.
15891  */
15892  appendPQExpBufferStr(q, " INTEGER /* dummy */");
15893  /* and skip to the next column */
15894  continue;
15895  }
15896 
15897  /*
15898  * Attribute type; print it except when creating a typed
15899  * table ('OF type_name'), but in binary-upgrade mode,
15900  * print it in that case too.
15901  */
15902  if (dopt->binary_upgrade || !OidIsValid(tbinfo->reloftype))
15903  {
15904  appendPQExpBuffer(q, " %s",
15905  tbinfo->atttypnames[j]);
15906  }
15907 
15908  if (print_default)
15909  {
15910  if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
15911  appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
15912  tbinfo->attrdefs[j]->adef_expr);
15913  else
15914  appendPQExpBuffer(q, " DEFAULT %s",
15915  tbinfo->attrdefs[j]->adef_expr);
15916  }
15917 
15918 
15919  if (print_notnull)
15920  appendPQExpBufferStr(q, " NOT NULL");
15921 
15922  /* Add collation if not default for the type */
15923  if (OidIsValid(tbinfo->attcollation[j]))
15924  {
15925  CollInfo *coll;
15926 
15927  coll = findCollationByOid(tbinfo->attcollation[j]);
15928  if (coll)
15929  appendPQExpBuffer(q, " COLLATE %s",
15930  fmtQualifiedDumpable(coll));
15931  }
15932  }
15933  }
15934 
15935  /*
15936  * Add non-inherited CHECK constraints, if any.
15937  *
15938  * For partitions, we need to include check constraints even if
15939  * they're not defined locally, because the ALTER TABLE ATTACH
15940  * PARTITION that we'll emit later expects the constraint to be
15941  * there. (No need to fix conislocal: ATTACH PARTITION does that)
15942  */
15943  for (j = 0; j < tbinfo->ncheck; j++)
15944  {
15945  ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
15946 
15947  if (constr->separate ||
15948  (!constr->conislocal && !tbinfo->ispartition))
15949  continue;
15950 
15951  if (actual_atts == 0)
15952  appendPQExpBufferStr(q, " (\n ");
15953  else
15954  appendPQExpBufferStr(q, ",\n ");
15955 
15956  appendPQExpBuffer(q, "CONSTRAINT %s ",
15957  fmtId(constr->dobj.name));
15958  appendPQExpBufferStr(q, constr->condef);
15959 
15960  actual_atts++;
15961  }
15962 
15963  if (actual_atts)
15964  appendPQExpBufferStr(q, "\n)");
15965  else if (!(OidIsValid(tbinfo->reloftype) && !dopt->binary_upgrade))
15966  {
15967  /*
15968  * No attributes? we must have a parenthesized attribute list,
15969  * even though empty, when not using the OF TYPE syntax.
15970  */
15971  appendPQExpBufferStr(q, " (\n)");
15972  }
15973 
15974  /*
15975  * Emit the INHERITS clause (not for partitions), except in
15976  * binary-upgrade mode.
15977  */
15978  if (numParents > 0 && !tbinfo->ispartition &&
15979  !dopt->binary_upgrade)
15980  {
15981  appendPQExpBufferStr(q, "\nINHERITS (");
15982  for (k = 0; k < numParents; k++)
15983  {
15984  TableInfo *parentRel = parents[k];
15985 
15986  if (k > 0)
15987  appendPQExpBufferStr(q, ", ");
15989  }
15990  appendPQExpBufferChar(q, ')');
15991  }
15992 
15993  if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15994  appendPQExpBuffer(q, "\nPARTITION BY %s", partkeydef);
15995 
15996  if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
15997  appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
15998  }
15999 
16000  if (nonemptyReloptions(tbinfo->reloptions) ||
16002  {
16003  bool addcomma = false;
16004 
16005  appendPQExpBufferStr(q, "\nWITH (");
16006  if (nonemptyReloptions(tbinfo->reloptions))
16007  {
16008  addcomma = true;
16009  appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
16010  }
16011  if (nonemptyReloptions(tbinfo->toast_reloptions))
16012  {
16013  if (addcomma)
16014  appendPQExpBufferStr(q, ", ");
16015  appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
16016  fout);
16017  }
16018  appendPQExpBufferChar(q, ')');
16019  }
16020 
16021  /* Dump generic options if any */
16022  if (ftoptions && ftoptions[0])
16023  appendPQExpBuffer(q, "\nOPTIONS (\n %s\n)", ftoptions);
16024 
16025  /*
16026  * For materialized views, create the AS clause just like a view. At
16027  * this point, we always mark the view as not populated.
16028  */
16029  if (tbinfo->relkind == RELKIND_MATVIEW)
16030  {
16031  PQExpBuffer result;
16032 
16033  result = createViewAsClause(fout, tbinfo);
16034  appendPQExpBuffer(q, " AS\n%s\n WITH NO DATA;\n",
16035  result->data);
16036  destroyPQExpBuffer(result);
16037  }
16038  else
16039  appendPQExpBufferStr(q, ";\n");
16040 
16041  /* Materialized views can depend on extensions */
16042  if (tbinfo->relkind == RELKIND_MATVIEW)
16043  append_depends_on_extension(fout, q, &tbinfo->dobj,
16044  "pg_catalog.pg_class",
16045  "MATERIALIZED VIEW",
16046  qualrelname);
16047 
16048  /*
16049  * in binary upgrade mode, update the catalog with any missing values
16050  * that might be present.
16051  */
16052  if (dopt->binary_upgrade)
16053  {
16054  for (j = 0; j < tbinfo->numatts; j++)
16055  {
16056  if (tbinfo->attmissingval[j][0] != '\0')
16057  {
16058  appendPQExpBufferStr(q, "\n-- set missing value.\n");
16060  "SELECT pg_catalog.binary_upgrade_set_missing_value(");
16061  appendStringLiteralAH(q, qualrelname, fout);
16062  appendPQExpBufferStr(q, "::pg_catalog.regclass,");
16063  appendStringLiteralAH(q, tbinfo->attnames[j], fout);
16064  appendPQExpBufferChar(q, ',');
16065  appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
16066  appendPQExpBufferStr(q, ");\n\n");
16067  }
16068  }
16069  }
16070 
16071  /*
16072  * To create binary-compatible heap files, we have to ensure the same
16073  * physical column order, including dropped columns, as in the
16074  * original. Therefore, we create dropped columns above and drop them
16075  * here, also updating their attlen/attalign values so that the
16076  * dropped column can be skipped properly. (We do not bother with
16077  * restoring the original attbyval setting.) Also, inheritance
16078  * relationships are set up by doing ALTER TABLE INHERIT rather than
16079  * using an INHERITS clause --- the latter would possibly mess up the
16080  * column order. That also means we have to take care about setting
16081  * attislocal correctly, plus fix up any inherited CHECK constraints.
16082  * Analogously, we set up typed tables using ALTER TABLE / OF here.
16083  *
16084  * We process foreign and partitioned tables here, even though they
16085  * lack heap storage, because they can participate in inheritance
16086  * relationships and we want this stuff to be consistent across the
16087  * inheritance tree. We can exclude indexes, toast tables, sequences
16088  * and matviews, even though they have storage, because we don't
16089  * support altering or dropping columns in them, nor can they be part
16090  * of inheritance trees.
16091  */
16092  if (dopt->binary_upgrade &&
16093  (tbinfo->relkind == RELKIND_RELATION ||
16094  tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
16095  tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
16096  {
16097  for (j = 0; j < tbinfo->numatts; j++)
16098  {
16099  if (tbinfo->attisdropped[j])
16100  {
16101  appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
16102  appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
16103  "SET attlen = %d, "
16104  "attalign = '%c', attbyval = false\n"
16105  "WHERE attname = ",
16106  tbinfo->attlen[j],
16107  tbinfo->attalign[j]);
16108  appendStringLiteralAH(q, tbinfo->attnames[j], fout);
16109  appendPQExpBufferStr(q, "\n AND attrelid = ");
16110  appendStringLiteralAH(q, qualrelname, fout);
16111  appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16112 
16113  if (tbinfo->relkind == RELKIND_RELATION ||
16114  tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
16115  appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16116  qualrelname);
16117  else
16118  appendPQExpBuffer(q, "ALTER FOREIGN TABLE ONLY %s ",
16119  qualrelname);
16120  appendPQExpBuffer(q, "DROP COLUMN %s;\n",
16121  fmtId(tbinfo->attnames[j]));
16122  }
16123  else if (!tbinfo->attislocal[j])
16124  {
16125  appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
16126  appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
16127  "SET attislocal = false\n"
16128  "WHERE attname = ");
16129  appendStringLiteralAH(q, tbinfo->attnames[j], fout);
16130  appendPQExpBufferStr(q, "\n AND attrelid = ");
16131  appendStringLiteralAH(q, qualrelname, fout);
16132  appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16133  }
16134  }
16135 
16136  /*
16137  * Add inherited CHECK constraints, if any.
16138  *
16139  * For partitions, they were already dumped, and conislocal
16140  * doesn't need fixing.
16141  */
16142  for (k = 0; k < tbinfo->ncheck; k++)
16143  {
16144  ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
16145 
16146  if (constr->separate || constr->conislocal || tbinfo->ispartition)
16147  continue;
16148 
16149  appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
16150  appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ADD CONSTRAINT %s %s;\n",
16151  foreign, qualrelname,
16152  fmtId(constr->dobj.name),
16153  constr->condef);
16154  appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
16155  "SET conislocal = false\n"
16156  "WHERE contype = 'c' AND conname = ");
16157  appendStringLiteralAH(q, constr->dobj.name, fout);
16158  appendPQExpBufferStr(q, "\n AND conrelid = ");
16159  appendStringLiteralAH(q, qualrelname, fout);
16160  appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16161  }
16162 
16163  if (numParents > 0 && !tbinfo->ispartition)
16164  {
16165  appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
16166  for (k = 0; k < numParents; k++)
16167  {
16168  TableInfo *parentRel = parents[k];
16169 
16170  appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s INHERIT %s;\n", foreign,
16171  qualrelname,
16172  fmtQualifiedDumpable(parentRel));
16173  }
16174  }
16175 
16176  if (OidIsValid(tbinfo->reloftype))
16177  {
16178  appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
16179  appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
16180  qualrelname,
16181  getFormattedTypeName(fout, tbinfo->reloftype,
16182  zeroIsError));
16183  }
16184  }
16185 
16186  /*
16187  * In binary_upgrade mode, arrange to restore the old relfrozenxid and
16188  * relminmxid of all vacuumable relations. (While vacuum.c processes
16189  * TOAST tables semi-independently, here we see them only as children
16190  * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
16191  * child toast table is handled below.)
16192  */
16193  if (dopt->binary_upgrade &&
16194  (tbinfo->relkind == RELKIND_RELATION ||
16195  tbinfo->relkind == RELKIND_MATVIEW))
16196  {
16197  appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
16198  appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
16199  "SET relfrozenxid = '%u', relminmxid = '%u'\n"
16200  "WHERE oid = ",
16201  tbinfo->frozenxid, tbinfo->minmxid);
16202  appendStringLiteralAH(q, qualrelname, fout);
16203  appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16204 
16205  if (tbinfo->toast_oid)
16206  {
16207  /*
16208  * The toast table will have the same OID at restore, so we
16209  * can safely target it by OID.
16210  */
16211  appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
16212  appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
16213  "SET relfrozenxid = '%u', relminmxid = '%u'\n"
16214  "WHERE oid = '%u';\n",
16215  tbinfo->toast_frozenxid,
16216  tbinfo->toast_minmxid, tbinfo->toast_oid);
16217  }
16218  }
16219 
16220  /*
16221  * In binary_upgrade mode, restore matviews' populated status by
16222  * poking pg_class directly. This is pretty ugly, but we can't use
16223  * REFRESH MATERIALIZED VIEW since it's possible that some underlying
16224  * matview is not populated even though this matview is; in any case,
16225  * we want to transfer the matview's heap storage, not run REFRESH.
16226  */
16227  if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
16228  tbinfo->relispopulated)
16229  {
16230  appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
16231  appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
16232  "SET relispopulated = 't'\n"
16233  "WHERE oid = ");
16234  appendStringLiteralAH(q, qualrelname, fout);
16235  appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16236  }
16237 
16238  /*
16239  * Dump additional per-column properties that we can't handle in the
16240  * main CREATE TABLE command.
16241  */
16242  for (j = 0; j < tbinfo->numatts; j++)
16243  {
16244  /* None of this applies to dropped columns */
16245  if (tbinfo->attisdropped[j])
16246  continue;
16247 
16248  /*
16249  * If we didn't dump the column definition explicitly above, and
16250  * it is not-null and did not inherit that property from a parent,
16251  * we have to mark it separately.
16252  */
16253  if (!shouldPrintColumn(dopt, tbinfo, j) &&
16254  tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
16256  "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET NOT NULL;\n",
16257  foreign, qualrelname,
16258  fmtId(tbinfo->attnames[j]));
16259 
16260  /*
16261  * Dump per-column statistics information. We only issue an ALTER
16262  * TABLE statement if the attstattarget entry for this column is
16263  * not the default value.
16264  */
16265  if (tbinfo->attstattarget[j] >= 0)
16266  appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STATISTICS %d;\n",
16267  foreign, qualrelname,
16268  fmtId(tbinfo->attnames[j]),
16269  tbinfo->attstattarget[j]);
16270 
16271  /*
16272  * Dump per-column storage information. The statement is only
16273  * dumped if the storage has been changed from the type's default.
16274  */
16275  if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
16276  {
16277  switch (tbinfo->attstorage[j])
16278  {
16279  case TYPSTORAGE_PLAIN:
16280  storage = "PLAIN";
16281  break;
16282  case TYPSTORAGE_EXTERNAL:
16283  storage = "EXTERNAL";
16284  break;
16285  case TYPSTORAGE_EXTENDED:
16286  storage = "EXTENDED";
16287  break;
16288  case TYPSTORAGE_MAIN:
16289  storage = "MAIN";
16290  break;
16291  default:
16292  storage = NULL;
16293  }
16294 
16295  /*
16296  * Only dump the statement if it's a storage type we recognize
16297  */
16298  if (storage != NULL)
16299  appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET STORAGE %s;\n",
16300  foreign, qualrelname,
16301  fmtId(tbinfo->attnames[j]),
16302  storage);
16303  }
16304 
16305  /*
16306  * Dump per-column compression, if it's been set.
16307  */
16308  if (!dopt->no_toast_compression)
16309  {
16310  const char *cmname;
16311 
16312  switch (tbinfo->attcompression[j])
16313  {
16314  case 'p':
16315  cmname = "pglz";
16316  break;
16317  case 'l':
16318  cmname = "lz4";
16319  break;
16320  default:
16321  cmname = NULL;
16322  break;
16323  }
16324 
16325  if (cmname != NULL)
16326  appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET COMPRESSION %s;\n",
16327  foreign, qualrelname,
16328  fmtId(tbinfo->attnames[j]),
16329  cmname);
16330  }
16331 
16332  /*
16333  * Dump per-column attributes.
16334  */
16335  if (tbinfo->attoptions[j][0] != '\0')
16336  appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET (%s);\n",
16337  foreign, qualrelname,
16338  fmtId(tbinfo->attnames[j]),
16339  tbinfo->attoptions[j]);
16340 
16341  /*
16342  * Dump per-column fdw options.
16343  */
16344  if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
16345  tbinfo->attfdwoptions[j][0] != '\0')
16347  "ALTER FOREIGN TABLE %s ALTER COLUMN %s OPTIONS (\n"
16348  " %s\n"
16349  ");\n",
16350  qualrelname,
16351  fmtId(tbinfo->attnames[j]),
16352  tbinfo->attfdwoptions[j]);
16353  } /* end loop over columns */
16354 
16355  free(partkeydef);
16356  free(ftoptions);
16357  free(srvname);
16358  }
16359 
16360  /*
16361  * dump properties we only have ALTER TABLE syntax for
16362  */
16363  if ((tbinfo->relkind == RELKIND_RELATION ||
16364  tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
16365  tbinfo->relkind == RELKIND_MATVIEW) &&
16366  tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
16367  {
16368  if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
16369  {
16370  /* nothing to do, will be set when the index is dumped */
16371  }
16372  else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
16373  {
16374  appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
16375  qualrelname);
16376  }
16377  else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
16378  {
16379  appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
16380  qualrelname);
16381  }
16382  }
16383 
16384  if (tbinfo->forcerowsec)
16385  appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
16386  qualrelname);
16387 
16388  if (dopt->binary_upgrade)
16390  reltypename, qrelname,
16391  tbinfo->dobj.namespace->dobj.name);
16392 
16393  if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16394  {
16395  char *tablespace = NULL;
16396  char *tableam = NULL;
16397 
16398  /*
16399  * _selectTablespace() relies on tablespace-enabled objects in the
16400  * default tablespace to have a tablespace of "" (empty string) versus
16401  * non-tablespace-enabled objects to have a tablespace of NULL.
16402  * getTables() sets tbinfo->reltablespace to "" for the default
16403  * tablespace (not NULL).
16404  */
16405  if (RELKIND_HAS_TABLESPACE(tbinfo->relkind))
16406  tablespace = tbinfo->reltablespace;
16407 
16408  if (RELKIND_HAS_TABLE_AM(tbinfo->relkind) ||
16409  tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
16410  tableam = tbinfo->amname;
16411 
16412  ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
16413  ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
16414  .namespace = tbinfo->dobj.namespace->dobj.name,
16415  .tablespace = tablespace,
16416  .tableam = tableam,
16417  .relkind = tbinfo->relkind,
16418  .owner = tbinfo->rolname,
16419  .description = reltypename,
16420  .section = tbinfo->postponed_def ?
16422  .createStmt = q->data,
16423  .dropStmt = delq->data));
16424  }
16425 
16426  /* Dump Table Comments */
16427  if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16428  dumpTableComment(fout, tbinfo, reltypename);
16429 
16430  /* Dump Table Security Labels */
16431  if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
16432  dumpTableSecLabel(fout, tbinfo, reltypename);
16433 
16434  /* Dump comments on inlined table constraints */
16435  for (j = 0; j < tbinfo->ncheck; j++)
16436  {
16437  ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
16438 
16439  if (constr->separate || !constr->conislocal)
16440  continue;
16441 
16442  if (constr->dobj.dump & DUMP_COMPONENT_COMMENT)
16443  dumpTableConstraintComment(fout, constr);
16444  }
16445 
16446  destroyPQExpBuffer(q);
16447  destroyPQExpBuffer(delq);
16448  free(qrelname);
16449  free(qualrelname);
16450 }
16451 
16452 /*
16453  * dumpTableAttach
16454  * write to fout the commands to attach a child partition
16455  *
16456  * Child partitions are always made by creating them separately
16457  * and then using ATTACH PARTITION, rather than using
16458  * CREATE TABLE ... PARTITION OF. This is important for preserving
16459  * any possible discrepancy in column layout, to allow assigning the
16460  * correct tablespace if different, and so that it's possible to restore
16461  * a partition without restoring its parent. (You'll get an error from
16462  * the ATTACH PARTITION command, but that can be ignored, or skipped
16463  * using "pg_restore -L" if you prefer.) The last point motivates
16464  * treating ATTACH PARTITION as a completely separate ArchiveEntry
16465  * rather than emitting it within the child partition's ArchiveEntry.
16466  */
16467 static void
16468 dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
16469 {
16470  DumpOptions *dopt = fout->dopt;
16471  PQExpBuffer q;
16472  PGresult *res;
16473  char *partbound;
16474 
16475  /* Do nothing in data-only dump */
16476  if (dopt->dataOnly)
16477  return;
16478 
16479  q = createPQExpBuffer();
16480 
16482  {
16483  /* Set up query for partbound details */
16485  "PREPARE dumpTableAttach(pg_catalog.oid) AS\n");
16486 
16488  "SELECT pg_get_expr(c.relpartbound, c.oid) "
16489  "FROM pg_class c "
16490  "WHERE c.oid = $1");
16491 
16492  ExecuteSqlStatement(fout, q->data);
16493 
16494  fout->is_prepared[PREPQUERY_DUMPTABLEATTACH] = true;
16495  }
16496 
16498  "EXECUTE dumpTableAttach('%u')",
16499  attachinfo->partitionTbl->dobj.catId.oid);
16500 
16501  res = ExecuteSqlQueryForSingleRow(fout, q->data);
16502  partbound = PQgetvalue(res, 0, 0);
16503 
16504  /* Perform ALTER TABLE on the parent */
16506  "ALTER TABLE ONLY %s ",
16507  fmtQualifiedDumpable(attachinfo->parentTbl));
16509  "ATTACH PARTITION %s %s;\n",
16510  fmtQualifiedDumpable(attachinfo->partitionTbl),
16511  partbound);
16512 
16513  /*
16514  * There is no point in creating a drop query as the drop is done by table
16515  * drop. (If you think to change this, see also _printTocEntry().)
16516  * Although this object doesn't really have ownership as such, set the
16517  * owner field anyway to ensure that the command is run by the correct
16518  * role at restore time.
16519  */
16520  ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
16521  ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
16522  .namespace = attachinfo->dobj.namespace->dobj.name,
16523  .owner = attachinfo->partitionTbl->rolname,
16524  .description = "TABLE ATTACH",
16525  .section = SECTION_PRE_DATA,
16526  .createStmt = q->data));
16527 
16528  PQclear(res);
16529  destroyPQExpBuffer(q);
16530 }
16531 
16532 /*
16533  * dumpAttrDef --- dump an attribute's default-value declaration
16534  */
16535 static void
16536 dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo)
16537 {
16538  DumpOptions *dopt = fout->dopt;
16539  TableInfo *tbinfo = adinfo->adtable;
16540  int adnum = adinfo->adnum;
16541  PQExpBuffer q;
16542  PQExpBuffer delq;
16543  char *qualrelname;
16544  char *tag;
16545  char *foreign;
16546 
16547  /* Do nothing in data-only dump */
16548  if (dopt->dataOnly)
16549  return;
16550 
16551  /* Skip if not "separate"; it was dumped in the table's definition */
16552  if (!adinfo->separate)
16553  return;
16554 
16555  q = createPQExpBuffer();
16556  delq = createPQExpBuffer();
16557 
16558  qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
16559 
16560  foreign = tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
16561 
16563  "ALTER %sTABLE ONLY %s ALTER COLUMN %s SET DEFAULT %s;\n",
16564  foreign, qualrelname, fmtId(tbinfo->attnames[adnum - 1]),
16565  adinfo->adef_expr);
16566 
16567  appendPQExpBuffer(delq, "ALTER %sTABLE %s ALTER COLUMN %s DROP DEFAULT;\n",
16568  foreign, qualrelname,
16569  fmtId(tbinfo->attnames[adnum - 1]));
16570 
16571  tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
16572 
16573  if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16574  ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
16575  ARCHIVE_OPTS(.tag = tag,
16576  .namespace = tbinfo->dobj.namespace->dobj.name,
16577  .owner = tbinfo->rolname,
16578  .description = "DEFAULT",
16579  .section = SECTION_PRE_DATA,
16580  .createStmt = q->data,
16581  .dropStmt = delq->data));
16582 
16583  free(tag);
16584  destroyPQExpBuffer(q);
16585  destroyPQExpBuffer(delq);
16586  free(qualrelname);
16587 }
16588 
16589 /*
16590  * getAttrName: extract the correct name for an attribute
16591  *
16592  * The array tblInfo->attnames[] only provides names of user attributes;
16593  * if a system attribute number is supplied, we have to fake it.
16594  * We also do a little bit of bounds checking for safety's sake.
16595  */
16596 static const char *
16597 getAttrName(int attrnum, const TableInfo *tblInfo)
16598 {
16599  if (attrnum > 0 && attrnum <= tblInfo->numatts)
16600  return tblInfo->attnames[attrnum - 1];
16601  switch (attrnum)
16602  {
16604  return "ctid";
16606  return "xmin";
16608  return "cmin";
16610  return "xmax";
16612  return "cmax";
16614  return "tableoid";
16615  }
16616  pg_fatal("invalid column number %d for table \"%s\"",
16617  attrnum, tblInfo->dobj.name);
16618  return NULL; /* keep compiler quiet */
16619 }
16620 
16621 /*
16622  * dumpIndex
16623  * write out to fout a user-defined index
16624  */
16625 static void
16626 dumpIndex(Archive *fout, const IndxInfo *indxinfo)
16627 {
16628  DumpOptions *dopt = fout->dopt;
16629  TableInfo *tbinfo = indxinfo->indextable;
16630  bool is_constraint = (indxinfo->indexconstraint != 0);
16631  PQExpBuffer q;
16632  PQExpBuffer delq;
16633  char *qindxname;
16634  char *qqindxname;
16635 
16636  /* Do nothing in data-only dump */
16637  if (dopt->dataOnly)
16638  return;
16639 
16640  q = createPQExpBuffer();
16641  delq = createPQExpBuffer();
16642 
16643  qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
16644  qqindxname = pg_strdup(fmtQualifiedDumpable(indxinfo));
16645 
16646  /*
16647  * If there's an associated constraint, don't dump the index per se, but
16648  * do dump any comment for it. (This is safe because dependency ordering
16649  * will have ensured the constraint is emitted first.) Note that the
16650  * emitted comment has to be shown as depending on the constraint, not the
16651  * index, in such cases.
16652  */
16653  if (!is_constraint)
16654  {
16655  char *indstatcols = indxinfo->indstatcols;
16656  char *indstatvals = indxinfo->indstatvals;
16657  char **indstatcolsarray = NULL;
16658  char **indstatvalsarray = NULL;
16659  int nstatcols = 0;
16660  int nstatvals = 0;
16661 
16662  if (dopt->binary_upgrade)
16664  indxinfo->dobj.catId.oid);
16665 
16666  /* Plain secondary index */
16667  appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
16668 
16669  /*
16670  * Append ALTER TABLE commands as needed to set properties that we
16671  * only have ALTER TABLE syntax for. Keep this in sync with the
16672  * similar code in dumpConstraint!
16673  */
16674 
16675  /* If the index is clustered, we need to record that. */
16676  if (indxinfo->indisclustered)
16677  {
16678  appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16679  fmtQualifiedDumpable(tbinfo));
16680  /* index name is not qualified in this syntax */
16681  appendPQExpBuffer(q, " ON %s;\n",
16682  qindxname);
16683  }
16684 
16685  /*
16686  * If the index has any statistics on some of its columns, generate
16687  * the associated ALTER INDEX queries.
16688  */
16689  if (strlen(indstatcols) != 0 || strlen(indstatvals) != 0)
16690  {
16691  int j;
16692 
16693  if (!parsePGArray(indstatcols, &indstatcolsarray, &nstatcols))
16694  pg_fatal("could not parse index statistic columns");
16695  if (!parsePGArray(indstatvals, &indstatvalsarray, &nstatvals))
16696  pg_fatal("could not parse index statistic values");
16697  if (nstatcols != nstatvals)
16698  pg_fatal("mismatched number of columns and values for index statistics");
16699 
16700  for (j = 0; j < nstatcols; j++)
16701  {
16702  appendPQExpBuffer(q, "ALTER INDEX %s ", qqindxname);
16703 
16704  /*
16705  * Note that this is a column number, so no quotes should be
16706  * used.
16707  */
16708  appendPQExpBuffer(q, "ALTER COLUMN %s ",
16709  indstatcolsarray[j]);
16710  appendPQExpBuffer(q, "SET STATISTICS %s;\n",
16711  indstatvalsarray[j]);
16712  }
16713  }
16714 
16715  /* Indexes can depend on extensions */
16716  append_depends_on_extension(fout, q, &indxinfo->dobj,
16717  "pg_catalog.pg_class",
16718  "INDEX", qqindxname);
16719 
16720  /* If the index defines identity, we need to record that. */
16721  if (indxinfo->indisreplident)
16722  {
16723  appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
16724  fmtQualifiedDumpable(tbinfo));
16725  /* index name is not qualified in this syntax */
16726  appendPQExpBuffer(q, " INDEX %s;\n",
16727  qindxname);
16728  }
16729 
16730  appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
16731 
16732  if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16733  ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
16734  ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
16735  .namespace = tbinfo->dobj.namespace->dobj.name,
16736  .tablespace = indxinfo->tablespace,
16737  .owner = tbinfo->rolname,
16738  .description = "INDEX",
16739  .section = SECTION_POST_DATA,
16740  .createStmt = q->data,
16741  .dropStmt = delq->data));
16742 
16743  free(indstatcolsarray);
16744  free(indstatvalsarray);
16745  }
16746 
16747  /* Dump Index Comments */
16748  if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16749  dumpComment(fout, "INDEX", qindxname,
16750  tbinfo->dobj.namespace->dobj.name,
16751  tbinfo->rolname,
16752  indxinfo->dobj.catId, 0,
16753  is_constraint ? indxinfo->indexconstraint :
16754  indxinfo->dobj.dumpId);
16755 
16756  destroyPQExpBuffer(q);
16757  destroyPQExpBuffer(delq);
16758  free(qindxname);
16759  free(qqindxname);
16760 }
16761 
16762 /*
16763  * dumpIndexAttach
16764  * write out to fout a partitioned-index attachment clause
16765  */
16766 static void
16767 dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo)
16768 {
16769  /* Do nothing in data-only dump */
16770  if (fout->dopt->dataOnly)
16771  return;
16772 
16773  if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
16774  {
16776 
16777  appendPQExpBuffer(q, "ALTER INDEX %s ",
16778  fmtQualifiedDumpable(attachinfo->parentIdx));
16779  appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
16780  fmtQualifiedDumpable(attachinfo->partitionIdx));
16781 
16782  /*
16783  * There is no point in creating a drop query as the drop is done by
16784  * index drop. (If you think to change this, see also
16785  * _printTocEntry().) Although this object doesn't really have
16786  * ownership as such, set the owner field anyway to ensure that the
16787  * command is run by the correct role at restore time.
16788  */
16789  ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
16790  ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
16791  .namespace = attachinfo->dobj.namespace->dobj.name,
16792  .owner = attachinfo->parentIdx->indextable->rolname,
16793  .description = "INDEX ATTACH",
16794  .section = SECTION_POST_DATA,
16795  .createStmt = q->data));
16796 
16797  destroyPQExpBuffer(q);
16798  }
16799 }
16800 
16801 /*
16802  * dumpStatisticsExt
16803  * write out to fout an extended statistics object
16804  */
16805 static void
16806 dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo)
16807 {
16808  DumpOptions *dopt = fout->dopt;
16809  PQExpBuffer q;
16810  PQExpBuffer delq;
16811  PQExpBuffer query;
16812  char *qstatsextname;
16813  PGresult *res;
16814  char *stxdef;
16815 
16816  /* Do nothing in data-only dump */
16817  if (dopt->dataOnly)
16818  return;
16819 
16820  q = createPQExpBuffer();
16821  delq = createPQExpBuffer();
16822  query = createPQExpBuffer();
16823 
16824  qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
16825 
16826  appendPQExpBuffer(query, "SELECT "
16827  "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
16828  statsextinfo->dobj.catId.oid);
16829 
16830  res = ExecuteSqlQueryForSingleRow(fout, query->data);
16831 
16832  stxdef = PQgetvalue(res, 0, 0);
16833 
16834  /* Result of pg_get_statisticsobjdef is complete except for semicolon */
16835  appendPQExpBuffer(q, "%s;\n", stxdef);
16836 
16837  /*
16838  * We only issue an ALTER STATISTICS statement if the stxstattarget entry
16839  * for this statistics object is not the default value.
16840  */
16841  if (statsextinfo->stattarget >= 0)
16842  {
16843  appendPQExpBuffer(q, "ALTER STATISTICS %s ",
16844  fmtQualifiedDumpable(statsextinfo));
16845  appendPQExpBuffer(q, "SET STATISTICS %d;\n",
16846  statsextinfo->stattarget);
16847  }
16848 
16849  appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
16850  fmtQualifiedDumpable(statsextinfo));
16851 
16852  if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16853  ArchiveEntry(fout, statsextinfo->dobj.catId,
16854  statsextinfo->dobj.dumpId,
16855  ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
16856  .namespace = statsextinfo->dobj.namespace->dobj.name,
16857  .owner = statsextinfo->rolname,
16858  .description = "STATISTICS",
16859  .section = SECTION_POST_DATA,
16860  .createStmt = q->data,
16861  .dropStmt = delq->data));
16862 
16863  /* Dump Statistics Comments */
16864  if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16865  dumpComment(fout, "STATISTICS", qstatsextname,
16866  statsextinfo->dobj.namespace->dobj.name,
16867  statsextinfo->rolname,
16868  statsextinfo->dobj.catId, 0,
16869  statsextinfo->dobj.dumpId);
16870 
16871  PQclear(res);
16872  destroyPQExpBuffer(q);
16873  destroyPQExpBuffer(delq);
16874  destroyPQExpBuffer(query);
16875  free(qstatsextname);
16876 }
16877 
16878 /*
16879  * dumpConstraint
16880  * write out to fout a user-defined constraint
16881  */
16882 static void
16883 dumpConstraint(Archive *fout, const ConstraintInfo *coninfo)
16884 {
16885  DumpOptions *dopt = fout->dopt;
16886  TableInfo *tbinfo = coninfo->contable;
16887  PQExpBuffer q;
16888  PQExpBuffer delq;
16889  char *tag = NULL;
16890  char *foreign;
16891 
16892  /* Do nothing in data-only dump */
16893  if (dopt->dataOnly)
16894  return;
16895 
16896  q = createPQExpBuffer();
16897  delq = createPQExpBuffer();
16898 
16899  foreign = tbinfo &&
16900  tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "";
16901 
16902  if (coninfo->contype == 'p' ||
16903  coninfo->contype == 'u' ||
16904  coninfo->contype == 'x')
16905  {
16906  /* Index-related constraint */
16907  IndxInfo *indxinfo;
16908  int k;
16909 
16910  indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
16911 
16912  if (indxinfo == NULL)
16913  pg_fatal("missing index for constraint \"%s\"",
16914  coninfo->dobj.name);
16915 
16916  if (dopt->binary_upgrade)
16918  indxinfo->dobj.catId.oid);
16919 
16920  appendPQExpBuffer(q, "ALTER %sTABLE ONLY %s\n", foreign,
16921  fmtQualifiedDumpable(tbinfo));
16922  appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
16923  fmtId(coninfo->dobj.name));
16924 
16925  if (coninfo->condef)
16926  {
16927  /* pg_get_constraintdef should have provided everything */
16928  appendPQExpBuffer(q, "%s;\n", coninfo->condef);
16929  }
16930  else
16931  {
16933  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
16934 
16935  /*
16936  * PRIMARY KEY constraints should not be using NULLS NOT DISTINCT
16937  * indexes. Being able to create this was fixed, but we need to
16938  * make the index distinct in order to be able to restore the
16939  * dump.
16940  */
16941  if (indxinfo->indnullsnotdistinct && coninfo->contype != 'p')
16942  appendPQExpBufferStr(q, " NULLS NOT DISTINCT");
16943  appendPQExpBufferStr(q, " (");
16944  for (k = 0; k < indxinfo->indnkeyattrs; k++)
16945  {
16946  int indkey = (int) indxinfo->indkeys[k];
16947  const char *attname;
16948 
16949  if (indkey == InvalidAttrNumber)
16950  break;
16951  attname = getAttrName(indkey, tbinfo);
16952 
16953  appendPQExpBuffer(q, "%s%s",
16954  (k == 0) ? "" : ", ",
16955  fmtId(attname));
16956  }
16957 
16958  if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
16959  appendPQExpBufferStr(q, ") INCLUDE (");
16960 
16961  for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
16962  {
16963  int indkey = (int) indxinfo->indkeys[k];
16964  const char *attname;
16965 
16966  if (indkey == InvalidAttrNumber)
16967  break;
16968  attname = getAttrName(indkey, tbinfo);
16969 
16970  appendPQExpBuffer(q, "%s%s",
16971  (k == indxinfo->indnkeyattrs) ? "" : ", ",
16972  fmtId(attname));
16973  }
16974 
16975  appendPQExpBufferChar(q, ')');
16976 
16977  if (nonemptyReloptions(indxinfo->indreloptions))
16978  {
16979  appendPQExpBufferStr(q, " WITH (");
16980  appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
16981  appendPQExpBufferChar(q, ')');
16982  }
16983 
16984  if (coninfo->condeferrable)
16985  {
16986  appendPQExpBufferStr(q, " DEFERRABLE");
16987  if (coninfo->condeferred)
16988  appendPQExpBufferStr(q, " INITIALLY DEFERRED");
16989  }
16990 
16991  appendPQExpBufferStr(q, ";\n");
16992  }
16993 
16994  /*
16995  * Append ALTER TABLE commands as needed to set properties that we
16996  * only have ALTER TABLE syntax for. Keep this in sync with the
16997  * similar code in dumpIndex!
16998  */
16999 
17000  /* If the index is clustered, we need to record that. */
17001  if (indxinfo->indisclustered)
17002  {
17003  appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
17004  fmtQualifiedDumpable(tbinfo));
17005  /* index name is not qualified in this syntax */
17006  appendPQExpBuffer(q, " ON %s;\n",
17007  fmtId(indxinfo->dobj.name));
17008  }
17009 
17010  /* If the index defines identity, we need to record that. */
17011  if (indxinfo->indisreplident)
17012  {
17013  appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
17014  fmtQualifiedDumpable(tbinfo));
17015  /* index name is not qualified in this syntax */
17016  appendPQExpBuffer(q, " INDEX %s;\n",
17017  fmtId(indxinfo->dobj.name));
17018  }
17019 
17020  /* Indexes can depend on extensions */
17021  append_depends_on_extension(fout, q, &indxinfo->dobj,
17022  "pg_catalog.pg_class", "INDEX",
17023  fmtQualifiedDumpable(indxinfo));
17024 
17025  appendPQExpBuffer(delq, "ALTER %sTABLE ONLY %s ", foreign,
17026  fmtQualifiedDumpable(tbinfo));
17027  appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
17028  fmtId(coninfo->dobj.name));
17029 
17030  tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
17031 
17032  if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17033  ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
17034  ARCHIVE_OPTS(.tag = tag,
17035  .namespace = tbinfo->dobj.namespace->dobj.name,
17036  .tablespace = indxinfo->tablespace,
17037  .owner = tbinfo->rolname,
17038  .description = "CONSTRAINT",
17039  .section = SECTION_POST_DATA,
17040  .createStmt = q->data,
17041  .dropStmt = delq->data));
17042  }
17043  else if (coninfo->contype == 'f')
17044  {
17045  char *only;
17046 
17047  /*
17048  * Foreign keys on partitioned tables are always declared as
17049  * inheriting to partitions; for all other cases, emit them as
17050  * applying ONLY directly to the named table, because that's how they
17051  * work for regular inherited tables.
17052  */
17053  only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
17054 
17055  /*
17056  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
17057  * current table data is not processed
17058  */
17059  appendPQExpBuffer(q, "ALTER %sTABLE %s%s\n", foreign,
17060  only, fmtQualifiedDumpable(tbinfo));
17061  appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
17062  fmtId(coninfo->dobj.name),
17063  coninfo->condef);
17064 
17065  appendPQExpBuffer(delq, "ALTER %sTABLE %s%s ", foreign,
17066  only, fmtQualifiedDumpable(tbinfo));
17067  appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
17068  fmtId(coninfo->dobj.name));
17069 
17070  tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
17071 
17072  if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17073  ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
17074  ARCHIVE_OPTS(.tag = tag,
17075  .namespace = tbinfo->dobj.namespace->dobj.name,
17076  .owner = tbinfo->rolname,
17077  .description = "FK CONSTRAINT",
17078  .section = SECTION_POST_DATA,
17079  .createStmt = q->data,
17080  .dropStmt = delq->data));
17081  }
17082  else if (coninfo->contype == 'c' && tbinfo)
17083  {
17084  /* CHECK constraint on a table */
17085 
17086  /* Ignore if not to be dumped separately, or if it was inherited */
17087  if (coninfo->separate && coninfo->conislocal)
17088  {
17089  /* not ONLY since we want it to propagate to children */
17090  appendPQExpBuffer(q, "ALTER %sTABLE %s\n", foreign,
17091  fmtQualifiedDumpable(tbinfo));
17092  appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
17093  fmtId(coninfo->dobj.name),
17094  coninfo->condef);
17095 
17096  appendPQExpBuffer(delq, "ALTER %sTABLE %s ", foreign,
17097  fmtQualifiedDumpable(tbinfo));
17098  appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
17099  fmtId(coninfo->dobj.name));
17100 
17101  tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
17102 
17103  if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17104  ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
17105  ARCHIVE_OPTS(.tag = tag,
17106  .namespace = tbinfo->dobj.namespace->dobj.name,
17107  .owner = tbinfo->rolname,
17108  .description = "CHECK CONSTRAINT",
17109  .section = SECTION_POST_DATA,
17110  .createStmt = q->data,
17111  .dropStmt = delq->data));
17112  }
17113  }
17114  else if (coninfo->contype == 'c' && tbinfo == NULL)
17115  {
17116  /* CHECK constraint on a domain */
17117  TypeInfo *tyinfo = coninfo->condomain;
17118 
17119  /* Ignore if not to be dumped separately */
17120  if (coninfo->separate)
17121  {
17122  appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
17123  fmtQualifiedDumpable(tyinfo));
17124  appendPQExpBuffer(q, " ADD CONSTRAINT %s %s;\n",
17125  fmtId(coninfo->dobj.name),
17126  coninfo->condef);
17127 
17128  appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
17129  fmtQualifiedDumpable(tyinfo));
17130  appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
17131  fmtId(coninfo->dobj.name));
17132 
17133  tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
17134 
17135  if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17136  ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
17137  ARCHIVE_OPTS(.tag = tag,
17138  .namespace = tyinfo->dobj.namespace->dobj.name,
17139  .owner = tyinfo->rolname,
17140  .description = "CHECK CONSTRAINT",
17141  .section = SECTION_POST_DATA,
17142  .createStmt = q->data,
17143  .dropStmt = delq->data));
17144  }
17145  }
17146  else
17147  {
17148  pg_fatal("unrecognized constraint type: %c",
17149  coninfo->contype);
17150  }
17151 
17152  /* Dump Constraint Comments --- only works for table constraints */
17153  if (tbinfo && coninfo->separate &&
17154  coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17155  dumpTableConstraintComment(fout, coninfo);
17156 
17157  free(tag);
17158  destroyPQExpBuffer(q);
17159  destroyPQExpBuffer(delq);
17160 }
17161 
17162 /*
17163  * dumpTableConstraintComment --- dump a constraint's comment if any
17164  *
17165  * This is split out because we need the function in two different places
17166  * depending on whether the constraint is dumped as part of CREATE TABLE
17167  * or as a separate ALTER command.
17168  */
17169 static void
17171 {
17172  TableInfo *tbinfo = coninfo->contable;
17173  PQExpBuffer conprefix = createPQExpBuffer();
17174  char *qtabname;
17175 
17176  qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17177 
17178  appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
17179  fmtId(coninfo->dobj.name));
17180 
17181  if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17182  dumpComment(fout, conprefix->data, qtabname,
17183  tbinfo->dobj.namespace->dobj.name,
17184  tbinfo->rolname,
17185  coninfo->dobj.catId, 0,
17186  coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
17187 
17188  destroyPQExpBuffer(conprefix);
17189  free(qtabname);
17190 }
17191 
17192 /*
17193  * dumpSequence
17194  * write the declaration (not data) of one user-defined sequence
17195  */
17196 static void
17197 dumpSequence(Archive *fout, const TableInfo *tbinfo)
17198 {
17199  DumpOptions *dopt = fout->dopt;
17200  PGresult *res;
17201  char *startv,
17202  *incby,
17203  *maxv,
17204  *minv,
17205  *cache,
17206  *seqtype;
17207  bool cycled;
17208  bool is_ascending;
17209  int64 default_minv,
17210  default_maxv;
17211  char bufm[32],
17212  bufx[32];
17213  PQExpBuffer query = createPQExpBuffer();
17214  PQExpBuffer delqry = createPQExpBuffer();
17215  char *qseqname;
17216  TableInfo *owning_tab = NULL;
17217 
17218  qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
17219 
17220  if (fout->remoteVersion >= 100000)
17221  {
17222  appendPQExpBuffer(query,
17223  "SELECT format_type(seqtypid, NULL), "
17224  "seqstart, seqincrement, "
17225  "seqmax, seqmin, "
17226  "seqcache, seqcycle "
17227  "FROM pg_catalog.pg_sequence "
17228  "WHERE seqrelid = '%u'::oid",
17229  tbinfo->dobj.catId.oid);
17230  }
17231  else
17232  {
17233  /*
17234  * Before PostgreSQL 10, sequence metadata is in the sequence itself.
17235  *
17236  * Note: it might seem that 'bigint' potentially needs to be
17237  * schema-qualified, but actually that's a keyword.
17238  */
17239  appendPQExpBuffer(query,
17240  "SELECT 'bigint' AS sequence_type, "
17241  "start_value, increment_by, max_value, min_value, "
17242  "cache_value, is_cycled FROM %s",
17243  fmtQualifiedDumpable(tbinfo));
17244  }
17245 
17246  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17247 
17248  if (PQntuples(res) != 1)
17249  pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
17250  "query to get data of sequence \"%s\" returned %d rows (expected 1)",
17251  PQntuples(res)),
17252  tbinfo->dobj.name, PQntuples(res));
17253 
17254  seqtype = PQgetvalue(res, 0, 0);
17255  startv = PQgetvalue(res, 0, 1);
17256  incby = PQgetvalue(res, 0, 2);
17257  maxv = PQgetvalue(res, 0, 3);
17258  minv = PQgetvalue(res, 0, 4);
17259  cache = PQgetvalue(res, 0, 5);
17260  cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
17261 
17262  /* Calculate default limits for a sequence of this type */
17263  is_ascending = (incby[0] != '-');
17264  if (strcmp(seqtype, "smallint") == 0)
17265  {
17266  default_minv = is_ascending ? 1 : PG_INT16_MIN;
17267  default_maxv = is_ascending ? PG_INT16_MAX : -1;
17268  }
17269  else if (strcmp(seqtype, "integer") == 0)
17270  {
17271  default_minv = is_ascending ? 1 : PG_INT32_MIN;
17272  default_maxv = is_ascending ? PG_INT32_MAX : -1;
17273  }
17274  else if (strcmp(seqtype, "bigint") == 0)
17275  {
17276  default_minv = is_ascending ? 1 : PG_INT64_MIN;
17277  default_maxv = is_ascending ? PG_INT64_MAX : -1;
17278  }
17279  else
17280  {
17281  pg_fatal("unrecognized sequence type: %s", seqtype);
17282  default_minv = default_maxv = 0; /* keep compiler quiet */
17283  }
17284 
17285  /*
17286  * 64-bit strtol() isn't very portable, so convert the limits to strings
17287  * and compare that way.
17288  */
17289  snprintf(bufm, sizeof(bufm), INT64_FORMAT, default_minv);
17290  snprintf(bufx, sizeof(bufx), INT64_FORMAT, default_maxv);
17291 
17292  /* Don't print minv/maxv if they match the respective default limit */
17293  if (strcmp(minv, bufm) == 0)
17294  minv = NULL;
17295  if (strcmp(maxv, bufx) == 0)
17296  maxv = NULL;
17297 
17298  /*
17299  * Identity sequences are not to be dropped separately.
17300  */
17301  if (!tbinfo->is_identity_sequence)
17302  {
17303  appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
17304  fmtQualifiedDumpable(tbinfo));
17305  }
17306 
17307  resetPQExpBuffer(query);
17308 
17309  if (dopt->binary_upgrade)
17310  {
17312  tbinfo->dobj.catId.oid);
17313 
17314  /*
17315  * In older PG versions a sequence will have a pg_type entry, but v14
17316  * and up don't use that, so don't attempt to preserve the type OID.
17317  */
17318  }
17319 
17320  if (tbinfo->is_identity_sequence)
17321  {
17322  owning_tab = findTableByOid(tbinfo->owning_tab);
17323 
17324  appendPQExpBuffer(query,
17325  "ALTER TABLE %s ",
17326  fmtQualifiedDumpable(owning_tab));
17327  appendPQExpBuffer(query,
17328  "ALTER COLUMN %s ADD GENERATED ",
17329  fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
17330  if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
17331  appendPQExpBufferStr(query, "ALWAYS");
17332  else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
17333  appendPQExpBufferStr(query, "BY DEFAULT");
17334  appendPQExpBuffer(query, " AS IDENTITY (\n SEQUENCE NAME %s\n",
17335  fmtQualifiedDumpable(tbinfo));
17336  }
17337  else
17338  {
17339  appendPQExpBuffer(query,
17340  "CREATE %sSEQUENCE %s\n",
17341  tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
17342  "UNLOGGED " : "",
17343  fmtQualifiedDumpable(tbinfo));
17344 
17345  if (strcmp(seqtype, "bigint") != 0)
17346  appendPQExpBuffer(query, " AS %s\n", seqtype);
17347  }
17348 
17349  appendPQExpBuffer(query, " START WITH %s\n", startv);
17350 
17351  appendPQExpBuffer(query, " INCREMENT BY %s\n", incby);
17352 
17353  if (minv)
17354  appendPQExpBuffer(query, " MINVALUE %s\n", minv);
17355  else
17356  appendPQExpBufferStr(query, " NO MINVALUE\n");
17357 
17358  if (maxv)
17359  appendPQExpBuffer(query, " MAXVALUE %s\n", maxv);
17360  else
17361  appendPQExpBufferStr(query, " NO MAXVALUE\n");
17362 
17363  appendPQExpBuffer(query,
17364  " CACHE %s%s",
17365  cache, (cycled ? "\n CYCLE" : ""));
17366 
17367  if (tbinfo->is_identity_sequence)
17368  {
17369  appendPQExpBufferStr(query, "\n);\n");
17370  if (tbinfo->relpersistence != owning_tab->relpersistence)
17371  appendPQExpBuffer(query,
17372  "ALTER SEQUENCE %s SET %s;\n",
17373  fmtQualifiedDumpable(tbinfo),
17374  tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
17375  "UNLOGGED" : "LOGGED");
17376  }
17377  else
17378  appendPQExpBufferStr(query, ";\n");
17379 
17380  /* binary_upgrade: no need to clear TOAST table oid */
17381 
17382  if (dopt->binary_upgrade)
17383  binary_upgrade_extension_member(query, &tbinfo->dobj,
17384  "SEQUENCE", qseqname,
17385  tbinfo->dobj.namespace->dobj.name);
17386 
17387  if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17388  ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
17389  ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17390  .namespace = tbinfo->dobj.namespace->dobj.name,
17391  .owner = tbinfo->rolname,
17392  .description = "SEQUENCE",
17393  .section = SECTION_PRE_DATA,
17394  .createStmt = query->data,
17395  .dropStmt = delqry->data));
17396 
17397  /*
17398  * If the sequence is owned by a table column, emit the ALTER for it as a
17399  * separate TOC entry immediately following the sequence's own entry. It's
17400  * OK to do this rather than using full sorting logic, because the
17401  * dependency that tells us it's owned will have forced the table to be
17402  * created first. We can't just include the ALTER in the TOC entry
17403  * because it will fail if we haven't reassigned the sequence owner to
17404  * match the table's owner.
17405  *
17406  * We need not schema-qualify the table reference because both sequence
17407  * and table must be in the same schema.
17408  */
17409  if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
17410  {
17411  owning_tab = findTableByOid(tbinfo->owning_tab);
17412 
17413  if (owning_tab == NULL)
17414  pg_fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
17415  tbinfo->owning_tab, tbinfo->dobj.catId.oid);
17416 
17417  if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
17418  {
17419  resetPQExpBuffer(query);
17420  appendPQExpBuffer(query, "ALTER SEQUENCE %s",
17421  fmtQualifiedDumpable(tbinfo));
17422  appendPQExpBuffer(query, " OWNED BY %s",
17423  fmtQualifiedDumpable(owning_tab));
17424  appendPQExpBuffer(query, ".%s;\n",
17425  fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
17426 
17427  if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17429  ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17430  .namespace = tbinfo->dobj.namespace->dobj.name,
17431  .owner = tbinfo->rolname,
17432  .description = "SEQUENCE OWNED BY",
17433  .section = SECTION_PRE_DATA,
17434  .createStmt = query->data,
17435  .deps = &(tbinfo->dobj.dumpId),
17436  .nDeps = 1));
17437  }
17438  }
17439 
17440  /* Dump Sequence Comments and Security Labels */
17441  if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17442  dumpComment(fout, "SEQUENCE", qseqname,
17443  tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17444  tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
17445 
17446  if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
17447  dumpSecLabel(fout, "SEQUENCE", qseqname,
17448  tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17449  tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
17450 
17451  PQclear(res);
17452 
17453  destroyPQExpBuffer(query);
17454  destroyPQExpBuffer(delqry);
17455  free(qseqname);
17456 }
17457 
17458 /*
17459  * dumpSequenceData
17460  * write the data of one user-defined sequence
17461  */
17462 static void
17464 {
17465  TableInfo *tbinfo = tdinfo->tdtable;
17466  PGresult *res;
17467  char *last;
17468  bool called;
17469  PQExpBuffer query = createPQExpBuffer();
17470 
17471  appendPQExpBuffer(query,
17472  "SELECT last_value, is_called FROM %s",
17473  fmtQualifiedDumpable(tbinfo));
17474 
17475  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17476 
17477  if (PQntuples(res) != 1)
17478  pg_fatal(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
17479  "query to get data of sequence \"%s\" returned %d rows (expected 1)",
17480  PQntuples(res)),
17481  tbinfo->dobj.name, PQntuples(res));
17482 
17483  last = PQgetvalue(res, 0, 0);
17484  called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
17485 
17486  resetPQExpBuffer(query);
17487  appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
17488  appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
17489  appendPQExpBuffer(query, ", %s, %s);\n",
17490  last, (called ? "true" : "false"));
17491 
17492  if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
17494  ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17495  .namespace = tbinfo->dobj.namespace->dobj.name,
17496  .owner = tbinfo->rolname,
17497  .description = "SEQUENCE SET",
17498  .section = SECTION_DATA,
17499  .createStmt = query->data,
17500  .deps = &(tbinfo->dobj.dumpId),
17501  .nDeps = 1));
17502 
17503  PQclear(res);
17504 
17505  destroyPQExpBuffer(query);
17506 }
17507 
17508 /*
17509  * dumpTrigger
17510  * write the declaration of one user-defined table trigger
17511  */
17512 static void
17513 dumpTrigger(Archive *fout, const TriggerInfo *tginfo)
17514 {
17515  DumpOptions *dopt = fout->dopt;
17516  TableInfo *tbinfo = tginfo->tgtable;
17517  PQExpBuffer query;
17518  PQExpBuffer delqry;
17519  PQExpBuffer trigprefix;
17520  PQExpBuffer trigidentity;
17521  char *qtabname;
17522  char *tag;
17523 
17524  /* Do nothing in data-only dump */
17525  if (dopt->dataOnly)
17526  return;
17527 
17528  query = createPQExpBuffer();
17529  delqry = createPQExpBuffer();
17530  trigprefix = createPQExpBuffer();
17531  trigidentity = createPQExpBuffer();
17532 
17533  qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17534 
17535  appendPQExpBuffer(trigidentity, "%s ", fmtId(tginfo->dobj.name));
17536  appendPQExpBuffer(trigidentity, "ON %s", fmtQualifiedDumpable(tbinfo));
17537 
17538  appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
17539  appendPQExpBuffer(delqry, "DROP TRIGGER %s;\n", trigidentity->data);
17540 
17541  /* Triggers can depend on extensions */
17542  append_depends_on_extension(fout, query, &tginfo->dobj,
17543  "pg_catalog.pg_trigger", "TRIGGER",
17544  trigidentity->data);
17545 
17546  if (tginfo->tgispartition)
17547  {
17548  Assert(tbinfo->ispartition);
17549 
17550  /*
17551  * Partition triggers only appear here because their 'tgenabled' flag
17552  * differs from its parent's. The trigger is created already, so
17553  * remove the CREATE and replace it with an ALTER. (Clear out the
17554  * DROP query too, so that pg_dump --create does not cause errors.)
17555  */
17556  resetPQExpBuffer(query);
17557  resetPQExpBuffer(delqry);
17558  appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
17559  tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
17560  fmtQualifiedDumpable(tbinfo));
17561  switch (tginfo->tgenabled)
17562  {
17563  case 'f':
17564  case 'D':
17565  appendPQExpBufferStr(query, "DISABLE");
17566  break;
17567  case 't':
17568  case 'O':
17569  appendPQExpBufferStr(query, "ENABLE");
17570  break;
17571  case 'R':
17572  appendPQExpBufferStr(query, "ENABLE REPLICA");
17573  break;
17574  case 'A':
17575  appendPQExpBufferStr(query, "ENABLE ALWAYS");
17576  break;
17577  }
17578  appendPQExpBuffer(query, " TRIGGER %s;\n",
17579  fmtId(tginfo->dobj.name));
17580  }
17581  else if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
17582  {
17583  appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
17584  tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
17585  fmtQualifiedDumpable(tbinfo));
17586  switch (tginfo->tgenabled)
17587  {
17588  case 'D':
17589  case 'f':
17590  appendPQExpBufferStr(query, "DISABLE");
17591  break;
17592  case 'A':
17593  appendPQExpBufferStr(query, "ENABLE ALWAYS");
17594  break;
17595  case 'R':
17596  appendPQExpBufferStr(query, "ENABLE REPLICA");
17597  break;
17598  default:
17599  appendPQExpBufferStr(query, "ENABLE");
17600  break;
17601  }
17602  appendPQExpBuffer(query, " TRIGGER %s;\n",
17603  fmtId(tginfo->dobj.name));
17604  }
17605 
17606  appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
17607  fmtId(tginfo->dobj.name));
17608 
17609  tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
17610 
17611  if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17612  ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
17613  ARCHIVE_OPTS(.tag = tag,
17614  .namespace = tbinfo->dobj.namespace->dobj.name,
17615  .owner = tbinfo->rolname,
17616  .description = "TRIGGER",
17617  .section = SECTION_POST_DATA,
17618  .createStmt = query->data,
17619  .dropStmt = delqry->data));
17620 
17621  if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17622  dumpComment(fout, trigprefix->data, qtabname,
17623  tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17624  tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
17625 
17626  free(tag);
17627  destroyPQExpBuffer(query);
17628  destroyPQExpBuffer(delqry);
17629  destroyPQExpBuffer(trigprefix);
17630  destroyPQExpBuffer(trigidentity);
17631  free(qtabname);
17632 }
17633 
17634 /*
17635  * dumpEventTrigger
17636  * write the declaration of one user-defined event trigger
17637  */
17638 static void
17640 {
17641  DumpOptions *dopt = fout->dopt;
17642  PQExpBuffer query;
17643  PQExpBuffer delqry;
17644  char *qevtname;
17645 
17646  /* Do nothing in data-only dump */
17647  if (dopt->dataOnly)
17648  return;
17649 
17650  query = createPQExpBuffer();
17651  delqry = createPQExpBuffer();
17652 
17653  qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
17654 
17655  appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
17656  appendPQExpBufferStr(query, qevtname);
17657  appendPQExpBufferStr(query, " ON ");
17658  appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
17659 
17660  if (strcmp("", evtinfo->evttags) != 0)
17661  {
17662  appendPQExpBufferStr(query, "\n WHEN TAG IN (");
17663  appendPQExpBufferStr(query, evtinfo->evttags);
17664  appendPQExpBufferChar(query, ')');
17665  }
17666 
17667  appendPQExpBufferStr(query, "\n EXECUTE FUNCTION ");
17668  appendPQExpBufferStr(query, evtinfo->evtfname);
17669  appendPQExpBufferStr(query, "();\n");
17670 
17671  if (evtinfo->evtenabled != 'O')
17672  {
17673  appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
17674  qevtname);
17675  switch (evtinfo->evtenabled)
17676  {
17677  case 'D':
17678  appendPQExpBufferStr(query, "DISABLE");
17679  break;
17680  case 'A':
17681  appendPQExpBufferStr(query, "ENABLE ALWAYS");
17682  break;
17683  case 'R':
17684  appendPQExpBufferStr(query, "ENABLE REPLICA");
17685  break;
17686  default:
17687  appendPQExpBufferStr(query, "ENABLE");
17688  break;
17689  }
17690  appendPQExpBufferStr(query, ";\n");
17691  }
17692 
17693  appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
17694  qevtname);
17695 
17696  if (dopt->binary_upgrade)
17697  binary_upgrade_extension_member(query, &evtinfo->dobj,
17698  "EVENT TRIGGER", qevtname, NULL);
17699 
17700  if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17701  ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
17702  ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
17703  .owner = evtinfo->evtowner,
17704  .description = "EVENT TRIGGER",
17705  .section = SECTION_POST_DATA,
17706  .createStmt = query->data,
17707  .dropStmt = delqry->data));
17708 
17709  if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17710  dumpComment(fout, "EVENT TRIGGER", qevtname,
17711  NULL, evtinfo->evtowner,
17712  evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
17713 
17714  destroyPQExpBuffer(query);
17715  destroyPQExpBuffer(delqry);
17716  free(qevtname);
17717 }
17718 
17719 /*
17720  * dumpRule
17721  * Dump a rule
17722  */
17723 static void
17724 dumpRule(Archive *fout, const RuleInfo *rinfo)
17725 {
17726  DumpOptions *dopt = fout->dopt;
17727  TableInfo *tbinfo = rinfo->ruletable;
17728  bool is_view;
17729  PQExpBuffer query;
17730  PQExpBuffer cmd;
17731  PQExpBuffer delcmd;
17732  PQExpBuffer ruleprefix;
17733  char *qtabname;
17734  PGresult *res;
17735  char *tag;
17736 
17737  /* Do nothing in data-only dump */
17738  if (dopt->dataOnly)
17739  return;
17740 
17741  /*
17742  * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
17743  * we do not want to dump it as a separate object.
17744  */
17745  if (!rinfo->separate)
17746  return;
17747 
17748  /*
17749  * If it's an ON SELECT rule, we want to print it as a view definition,
17750  * instead of a rule.
17751  */
17752  is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
17753 
17754  query = createPQExpBuffer();
17755  cmd = createPQExpBuffer();
17756  delcmd = createPQExpBuffer();
17757  ruleprefix = createPQExpBuffer();
17758 
17759  qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17760 
17761  if (is_view)
17762  {
17763  PQExpBuffer result;
17764 
17765  /*
17766  * We need OR REPLACE here because we'll be replacing a dummy view.
17767  * Otherwise this should look largely like the regular view dump code.
17768  */
17769  appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
17770  fmtQualifiedDumpable(tbinfo));
17771  if (nonemptyReloptions(tbinfo->reloptions))
17772  {
17773  appendPQExpBufferStr(cmd, " WITH (");
17774  appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
17775  appendPQExpBufferChar(cmd, ')');
17776  }
17777  result = createViewAsClause(fout, tbinfo);
17778  appendPQExpBuffer(cmd, " AS\n%s", result->data);
17779  destroyPQExpBuffer(result);
17780  if (tbinfo->checkoption != NULL)
17781  appendPQExpBuffer(cmd, "\n WITH %s CHECK OPTION",
17782  tbinfo->checkoption);
17783  appendPQExpBufferStr(cmd, ";\n");
17784  }
17785  else
17786  {
17787  /* In the rule case, just print pg_get_ruledef's result verbatim */
17788  appendPQExpBuffer(query,
17789  "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
17790  rinfo->dobj.catId.oid);
17791 
17792  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17793 
17794  if (PQntuples(res) != 1)
17795  pg_fatal("query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
17796  rinfo->dobj.name, tbinfo->dobj.name);
17797 
17798  printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
17799 
17800  PQclear(res);
17801  }
17802 
17803  /*
17804  * Add the command to alter the rules replication firing semantics if it
17805  * differs from the default.
17806  */
17807  if (rinfo->ev_enabled != 'O')
17808  {
17809  appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
17810  switch (rinfo->ev_enabled)
17811  {
17812  case 'A':
17813  appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
17814  fmtId(rinfo->dobj.name));
17815  break;
17816  case 'R':
17817  appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
17818  fmtId(rinfo->dobj.name));
17819  break;
17820  case 'D':
17821  appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
17822  fmtId(rinfo->dobj.name));
17823  break;
17824  }
17825  }
17826 
17827  if (is_view)
17828  {
17829  /*
17830  * We can't DROP a view's ON SELECT rule. Instead, use CREATE OR
17831  * REPLACE VIEW to replace the rule with something with minimal
17832  * dependencies.
17833  */
17834  PQExpBuffer result;
17835 
17836  appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
17837  fmtQualifiedDumpable(tbinfo));
17838  result = createDummyViewAsClause(fout, tbinfo);
17839  appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
17840  destroyPQExpBuffer(result);
17841  }
17842  else
17843  {
17844  appendPQExpBuffer(delcmd, "DROP RULE %s ",
17845  fmtId(rinfo->dobj.name));
17846  appendPQExpBuffer(delcmd, "ON %s;\n",
17847  fmtQualifiedDumpable(tbinfo));
17848  }
17849 
17850  appendPQExpBuffer(ruleprefix, "RULE %s ON",
17851  fmtId(rinfo->dobj.name));
17852 
17853  tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
17854 
17855  if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17856  ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
17857  ARCHIVE_OPTS(.tag = tag,
17858  .namespace = tbinfo->dobj.namespace->dobj.name,
17859  .owner = tbinfo->rolname,
17860  .description = "RULE",
17861  .section = SECTION_POST_DATA,
17862  .createStmt = cmd->data,
17863  .dropStmt = delcmd->data));
17864 
17865  /* Dump rule comments */
17866  if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17867  dumpComment(fout, ruleprefix->data, qtabname,
17868  tbinfo->dobj.namespace->dobj.name,
17869  tbinfo->rolname,
17870  rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
17871 
17872  free(tag);
17873  destroyPQExpBuffer(query);
17874  destroyPQExpBuffer(cmd);
17875  destroyPQExpBuffer(delcmd);
17876  destroyPQExpBuffer(ruleprefix);
17877  free(qtabname);
17878 }
17879 
17880 /*
17881  * getExtensionMembership --- obtain extension membership data
17882  *
17883  * We need to identify objects that are extension members as soon as they're
17884  * loaded, so that we can correctly determine whether they need to be dumped.
17885  * Generally speaking, extension member objects will get marked as *not* to
17886  * be dumped, as they will be recreated by the single CREATE EXTENSION
17887  * command. However, in binary upgrade mode we still need to dump the members
17888  * individually.
17889  */
17890 void
17892  int numExtensions)
17893 {
17894  PQExpBuffer query;
17895  PGresult *res;
17896  int ntups,
17897  i;
17898  int i_classid,
17899  i_objid,
17900  i_refobjid;
17901  ExtensionInfo *ext;
17902 
17903  /* Nothing to do if no extensions */
17904  if (numExtensions == 0)
17905  return;
17906 
17907  query = createPQExpBuffer();
17908 
17909  /* refclassid constraint is redundant but may speed the search */
17910  appendPQExpBufferStr(query, "SELECT "
17911  "classid, objid, refobjid "
17912  "FROM pg_depend "
17913  "WHERE refclassid = 'pg_extension'::regclass "
17914  "AND deptype = 'e' "
17915  "ORDER BY 3");
17916 
17917  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17918 
17919  ntups = PQntuples(res);
17920 
17921  i_classid = PQfnumber(res, "classid");
17922  i_objid = PQfnumber(res, "objid");
17923  i_refobjid = PQfnumber(res, "refobjid");
17924 
17925  /*
17926  * Since we ordered the SELECT by referenced ID, we can expect that
17927  * multiple entries for the same extension will appear together; this
17928  * saves on searches.
17929  */
17930  ext = NULL;
17931 
17932  for (i = 0; i < ntups; i++)
17933  {
17934  CatalogId objId;
17935  Oid extId;
17936 
17937  objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17938  objId.oid = atooid(PQgetvalue(res, i, i_objid));
17939  extId = atooid(PQgetvalue(res, i, i_refobjid));
17940 
17941  if (ext == NULL ||
17942  ext->dobj.catId.oid != extId)
17943  ext = findExtensionByOid(extId);
17944 
17945  if (ext == NULL)
17946  {
17947  /* shouldn't happen */
17948  pg_log_warning("could not find referenced extension %u", extId);
17949  continue;
17950  }
17951 
17952  recordExtensionMembership(objId, ext);
17953  }
17954 
17955  PQclear(res);
17956 
17957  destroyPQExpBuffer(query);
17958 }
17959 
17960 /*
17961  * processExtensionTables --- deal with extension configuration tables
17962  *
17963  * There are two parts to this process:
17964  *
17965  * 1. Identify and create dump records for extension configuration tables.
17966  *
17967  * Extensions can mark tables as "configuration", which means that the user
17968  * is able and expected to modify those tables after the extension has been
17969  * loaded. For these tables, we dump out only the data- the structure is
17970  * expected to be handled at CREATE EXTENSION time, including any indexes or
17971  * foreign keys, which brings us to-
17972  *
17973  * 2. Record FK dependencies between configuration tables.
17974  *
17975  * Due to the FKs being created at CREATE EXTENSION time and therefore before
17976  * the data is loaded, we have to work out what the best order for reloading
17977  * the data is, to avoid FK violations when the tables are restored. This is
17978  * not perfect- we can't handle circular dependencies and if any exist they
17979  * will cause an invalid dump to be produced (though at least all of the data
17980  * is included for a user to manually restore). This is currently documented
17981  * but perhaps we can provide a better solution in the future.
17982  */
17983 void
17985  int numExtensions)
17986 {
17987  DumpOptions *dopt = fout->dopt;
17988  PQExpBuffer query;
17989  PGresult *res;
17990  int ntups,
17991  i;
17992  int i_conrelid,
17993  i_confrelid;
17994 
17995  /* Nothing to do if no extensions */
17996  if (numExtensions == 0)
17997  return;
17998 
17999  /*
18000  * Identify extension configuration tables and create TableDataInfo
18001  * objects for them, ensuring their data will be dumped even though the
18002  * tables themselves won't be.
18003  *
18004  * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
18005  * user data in a configuration table is treated like schema data. This
18006  * seems appropriate since system data in a config table would get
18007  * reloaded by CREATE EXTENSION. If the extension is not listed in the
18008  * list of extensions to be included, none of its data is dumped.
18009  */
18010  for (i = 0; i < numExtensions; i++)
18011  {
18012  ExtensionInfo *curext = &(extinfo[i]);
18013  char *extconfig = curext->extconfig;
18014  char *extcondition = curext->extcondition;
18015  char **extconfigarray = NULL;
18016  char **extconditionarray = NULL;
18017  int nconfigitems = 0;
18018  int nconditionitems = 0;
18019 
18020  /*
18021  * Check if this extension is listed as to include in the dump. If
18022  * not, any table data associated with it is discarded.
18023  */
18024  if (extension_include_oids.head != NULL &&
18026  curext->dobj.catId.oid))
18027  continue;
18028 
18029  /*
18030  * Check if this extension is listed as to exclude in the dump. If
18031  * yes, any table data associated with it is discarded.
18032  */
18033  if (extension_exclude_oids.head != NULL &&
18035  curext->dobj.catId.oid))
18036  continue;
18037 
18038  if (strlen(extconfig) != 0 || strlen(extcondition) != 0)
18039  {
18040  int j;
18041 
18042  if (!parsePGArray(extconfig, &extconfigarray, &nconfigitems))
18043  pg_fatal("could not parse %s array", "extconfig");
18044  if (!parsePGArray(extcondition, &extconditionarray, &nconditionitems))
18045  pg_fatal("could not parse %s array", "extcondition");
18046  if (nconfigitems != nconditionitems)
18047  pg_fatal("mismatched number of configurations and conditions for extension");
18048 
18049  for (j = 0; j < nconfigitems; j++)
18050  {
18051  TableInfo *configtbl;
18052  Oid configtbloid = atooid(extconfigarray[j]);
18053  bool dumpobj =
18055 
18056  configtbl = findTableByOid(configtbloid);
18057  if (configtbl == NULL)
18058  continue;
18059 
18060  /*
18061  * Tables of not-to-be-dumped extensions shouldn't be dumped
18062  * unless the table or its schema is explicitly included
18063  */
18064  if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
18065  {
18066  /* check table explicitly requested */
18067  if (table_include_oids.head != NULL &&
18069  configtbloid))
18070  dumpobj = true;
18071 
18072  /* check table's schema explicitly requested */
18073  if (configtbl->dobj.namespace->dobj.dump &
18075  dumpobj = true;
18076  }
18077 
18078  /* check table excluded by an exclusion switch */
18079  if (table_exclude_oids.head != NULL &&
18081  configtbloid))
18082  dumpobj = false;
18083 
18084  /* check schema excluded by an exclusion switch */
18086  configtbl->dobj.namespace->dobj.catId.oid))
18087  dumpobj = false;
18088 
18089  if (dumpobj)
18090  {
18091  makeTableDataInfo(dopt, configtbl);
18092  if (configtbl->dataObj != NULL)
18093  {
18094  if (strlen(extconditionarray[j]) > 0)
18095  configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
18096  }
18097  }
18098  }
18099  }
18100  if (extconfigarray)
18101  free(extconfigarray);
18102  if (extconditionarray)
18103  free(extconditionarray);
18104  }
18105 
18106  /*
18107  * Now that all the TableDataInfo objects have been created for all the
18108  * extensions, check their FK dependencies and register them to try and
18109  * dump the data out in an order that they can be restored in.
18110  *
18111  * Note that this is not a problem for user tables as their FKs are
18112  * recreated after the data has been loaded.
18113  */
18114 
18115  query = createPQExpBuffer();
18116 
18117  printfPQExpBuffer(query,
18118  "SELECT conrelid, confrelid "
18119  "FROM pg_constraint "
18120  "JOIN pg_depend ON (objid = confrelid) "
18121  "WHERE contype = 'f' "
18122  "AND refclassid = 'pg_extension'::regclass "
18123  "AND classid = 'pg_class'::regclass;");
18124 
18125  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
18126  ntups = PQntuples(res);
18127 
18128  i_conrelid = PQfnumber(res, "conrelid");
18129  i_confrelid = PQfnumber(res, "confrelid");
18130 
18131  /* Now get the dependencies and register them */
18132  for (i = 0; i < ntups; i++)
18133  {
18134  Oid conrelid,
18135  confrelid;
18136  TableInfo *reftable,
18137  *contable;
18138 
18139  conrelid = atooid(PQgetvalue(res, i, i_conrelid));
18140  confrelid = atooid(PQgetvalue(res, i, i_confrelid));
18141  contable = findTableByOid(conrelid);
18142  reftable = findTableByOid(confrelid);
18143 
18144  if (reftable == NULL ||
18145  reftable->dataObj == NULL ||
18146  contable == NULL ||
18147  contable->dataObj == NULL)
18148  continue;
18149 
18150  /*
18151  * Make referencing TABLE_DATA object depend on the referenced table's
18152  * TABLE_DATA object.
18153  */
18154  addObjectDependency(&contable->dataObj->dobj,
18155  reftable->dataObj->dobj.dumpId);
18156  }
18157  PQclear(res);
18158  destroyPQExpBuffer(query);
18159 }
18160 
18161 /*
18162  * getDependencies --- obtain available dependency data
18163  */
18164 static void
18166 {
18167  PQExpBuffer query;
18168  PGresult *res;
18169  int ntups,
18170  i;
18171  int i_classid,
18172  i_objid,
18173  i_refclassid,
18174  i_refobjid,
18175  i_deptype;
18176  DumpableObject *dobj,
18177  *refdobj;
18178 
18179  pg_log_info("reading dependency data");
18180 
18181  query = createPQExpBuffer();
18182 
18183  /*
18184  * Messy query to collect the dependency data we need. Note that we
18185  * ignore the sub-object column, so that dependencies of or on a column
18186  * look the same as dependencies of or on a whole table.
18187  *
18188  * PIN dependencies aren't interesting, and EXTENSION dependencies were
18189  * already processed by getExtensionMembership.
18190  */
18191  appendPQExpBufferStr(query, "SELECT "
18192  "classid, objid, refclassid, refobjid, deptype "
18193  "FROM pg_depend "
18194  "WHERE deptype != 'p' AND deptype != 'e'\n");
18195 
18196  /*
18197  * Since we don't treat pg_amop entries as separate DumpableObjects, we
18198  * have to translate their dependencies into dependencies of their parent
18199  * opfamily. Ignore internal dependencies though, as those will point to
18200  * their parent opclass, which we needn't consider here (and if we did,
18201  * it'd just result in circular dependencies). Also, "loose" opfamily
18202  * entries will have dependencies on their parent opfamily, which we
18203  * should drop since they'd likewise become useless self-dependencies.
18204  * (But be sure to keep deps on *other* opfamilies; see amopsortfamily.)
18205  */
18206  appendPQExpBufferStr(query, "UNION ALL\n"
18207  "SELECT 'pg_opfamily'::regclass AS classid, amopfamily AS objid, refclassid, refobjid, deptype "
18208  "FROM pg_depend d, pg_amop o "
18209  "WHERE deptype NOT IN ('p', 'e', 'i') AND "
18210  "classid = 'pg_amop'::regclass AND objid = o.oid "
18211  "AND NOT (refclassid = 'pg_opfamily'::regclass AND amopfamily = refobjid)\n");
18212 
18213  /* Likewise for pg_amproc entries */
18214  appendPQExpBufferStr(query, "UNION ALL\n"
18215  "SELECT 'pg_opfamily'::regclass AS classid, amprocfamily AS objid, refclassid, refobjid, deptype "
18216  "FROM pg_depend d, pg_amproc p "
18217  "WHERE deptype NOT IN ('p', 'e', 'i') AND "
18218  "classid = 'pg_amproc'::regclass AND objid = p.oid "
18219  "AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n");
18220 
18221  /* Sort the output for efficiency below */
18222  appendPQExpBufferStr(query, "ORDER BY 1,2");
18223 
18224  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
18225 
18226  ntups = PQntuples(res);
18227 
18228  i_classid = PQfnumber(res, "classid");
18229  i_objid = PQfnumber(res, "objid");
18230  i_refclassid = PQfnumber(res, "refclassid");
18231  i_refobjid = PQfnumber(res, "refobjid");
18232  i_deptype = PQfnumber(res, "deptype");
18233 
18234  /*
18235  * Since we ordered the SELECT by referencing ID, we can expect that
18236  * multiple entries for the same object will appear together; this saves
18237  * on searches.
18238  */
18239  dobj = NULL;
18240 
18241  for (i = 0; i < ntups; i++)
18242  {
18243  CatalogId objId;
18244  CatalogId refobjId;
18245  char deptype;
18246 
18247  objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
18248  objId.oid = atooid(PQgetvalue(res, i, i_objid));
18249  refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
18250  refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
18251  deptype = *(PQgetvalue(res, i, i_deptype));
18252 
18253  if (dobj == NULL ||
18254  dobj->catId.tableoid != objId.tableoid ||
18255  dobj->catId.oid != objId.oid)
18256  dobj = findObjectByCatalogId(objId);
18257 
18258  /*
18259  * Failure to find objects mentioned in pg_depend is not unexpected,
18260  * since for example we don't collect info about TOAST tables.
18261  */
18262  if (dobj == NULL)
18263  {
18264 #ifdef NOT_USED
18265  pg_log_warning("no referencing object %u %u",
18266  objId.tableoid, objId.oid);
18267 #endif
18268  continue;
18269  }
18270 
18271  refdobj = findObjectByCatalogId(refobjId);
18272 
18273  if (refdobj == NULL)
18274  {
18275 #ifdef NOT_USED
18276  pg_log_warning("no referenced object %u %u",
18277  refobjId.tableoid, refobjId.oid);
18278 #endif
18279  continue;
18280  }
18281 
18282  /*
18283  * For 'x' dependencies, mark the object for later; we still add the
18284  * normal dependency, for possible ordering purposes. Currently
18285  * pg_dump_sort.c knows to put extensions ahead of all object types
18286  * that could possibly depend on them, but this is safer.
18287  */
18288  if (deptype == 'x')
18289  dobj->depends_on_ext = true;
18290 
18291  /*
18292  * Ordinarily, table rowtypes have implicit dependencies on their
18293  * tables. However, for a composite type the implicit dependency goes
18294  * the other way in pg_depend; which is the right thing for DROP but
18295  * it doesn't produce the dependency ordering we need. So in that one
18296  * case, we reverse the direction of the dependency.
18297  */
18298  if (deptype == 'i' &&
18299  dobj->objType == DO_TABLE &&
18300  refdobj->objType == DO_TYPE)
18301  addObjectDependency(refdobj, dobj->dumpId);
18302  else
18303  /* normal case */
18304  addObjectDependency(dobj, refdobj->dumpId);
18305  }
18306 
18307  PQclear(res);
18308 
18309  destroyPQExpBuffer(query);
18310 }
18311 
18312 
18313 /*
18314  * createBoundaryObjects - create dummy DumpableObjects to represent
18315  * dump section boundaries.
18316  */
18317 static DumpableObject *
18319 {
18320  DumpableObject *dobjs;
18321 
18322  dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
18323 
18324  dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
18325  dobjs[0].catId = nilCatalogId;
18326  AssignDumpId(dobjs + 0);
18327  dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
18328 
18329  dobjs[1].objType = DO_POST_DATA_BOUNDARY;
18330  dobjs[1].catId = nilCatalogId;
18331  AssignDumpId(dobjs + 1);
18332  dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
18333 
18334  return dobjs;
18335 }
18336 
18337 /*
18338  * addBoundaryDependencies - add dependencies as needed to enforce the dump
18339  * section boundaries.
18340  */
18341 static void
18343  DumpableObject *boundaryObjs)
18344 {
18345  DumpableObject *preDataBound = boundaryObjs + 0;
18346  DumpableObject *postDataBound = boundaryObjs + 1;
18347  int i;
18348 
18349  for (i = 0; i < numObjs; i++)
18350  {
18351  DumpableObject *dobj = dobjs[i];
18352 
18353  /*
18354  * The classification of object types here must match the SECTION_xxx
18355  * values assigned during subsequent ArchiveEntry calls!
18356  */
18357  switch (dobj->objType)
18358  {
18359  case DO_NAMESPACE:
18360  case DO_EXTENSION:
18361  case DO_TYPE:
18362  case DO_SHELL_TYPE:
18363  case DO_FUNC:
18364  case DO_AGG:
18365  case DO_OPERATOR:
18366  case DO_ACCESS_METHOD:
18367  case DO_OPCLASS:
18368  case DO_OPFAMILY:
18369  case DO_COLLATION:
18370  case DO_CONVERSION:
18371  case DO_TABLE:
18372  case DO_TABLE_ATTACH:
18373  case DO_ATTRDEF:
18374  case DO_PROCLANG:
18375  case DO_CAST:
18376  case DO_DUMMY_TYPE:
18377  case DO_TSPARSER:
18378  case DO_TSDICT:
18379  case DO_TSTEMPLATE:
18380  case DO_TSCONFIG:
18381  case DO_FDW:
18382  case DO_FOREIGN_SERVER:
18383  case DO_TRANSFORM:
18384  /* Pre-data objects: must come before the pre-data boundary */
18385  addObjectDependency(preDataBound, dobj->dumpId);
18386  break;
18387  case DO_TABLE_DATA:
18388  case DO_SEQUENCE_SET:
18389  case DO_LARGE_OBJECT:
18390  case DO_LARGE_OBJECT_DATA:
18391  /* Data objects: must come between the boundaries */
18392  addObjectDependency(dobj, preDataBound->dumpId);
18393  addObjectDependency(postDataBound, dobj->dumpId);
18394  break;
18395  case DO_INDEX:
18396  case DO_INDEX_ATTACH:
18397  case DO_STATSEXT:
18398  case DO_REFRESH_MATVIEW:
18399  case DO_TRIGGER:
18400  case DO_EVENT_TRIGGER:
18401  case DO_DEFAULT_ACL:
18402  case DO_POLICY:
18403  case DO_PUBLICATION:
18404  case DO_PUBLICATION_REL:
18406  case DO_SUBSCRIPTION:
18407  case DO_SUBSCRIPTION_REL:
18408  /* Post-data objects: must come after the post-data boundary */
18409  addObjectDependency(dobj, postDataBound->dumpId);
18410  break;
18411  case DO_RULE:
18412  /* Rules are post-data, but only if dumped separately */
18413  if (((RuleInfo *) dobj)->separate)
18414  addObjectDependency(dobj, postDataBound->dumpId);
18415  break;
18416  case DO_CONSTRAINT:
18417  case DO_FK_CONSTRAINT:
18418  /* Constraints are post-data, but only if dumped separately */
18419  if (((ConstraintInfo *) dobj)->separate)
18420  addObjectDependency(dobj, postDataBound->dumpId);
18421  break;
18422  case DO_PRE_DATA_BOUNDARY:
18423  /* nothing to do */
18424  break;
18425  case DO_POST_DATA_BOUNDARY:
18426  /* must come after the pre-data boundary */
18427  addObjectDependency(dobj, preDataBound->dumpId);
18428  break;
18429  }
18430  }
18431 }
18432 
18433 
18434 /*
18435  * BuildArchiveDependencies - create dependency data for archive TOC entries
18436  *
18437  * The raw dependency data obtained by getDependencies() is not terribly
18438  * useful in an archive dump, because in many cases there are dependency
18439  * chains linking through objects that don't appear explicitly in the dump.
18440  * For example, a view will depend on its _RETURN rule while the _RETURN rule
18441  * will depend on other objects --- but the rule will not appear as a separate
18442  * object in the dump. We need to adjust the view's dependencies to include
18443  * whatever the rule depends on that is included in the dump.
18444  *
18445  * Just to make things more complicated, there are also "special" dependencies
18446  * such as the dependency of a TABLE DATA item on its TABLE, which we must
18447  * not rearrange because pg_restore knows that TABLE DATA only depends on
18448  * its table. In these cases we must leave the dependencies strictly as-is
18449  * even if they refer to not-to-be-dumped objects.
18450  *
18451  * To handle this, the convention is that "special" dependencies are created
18452  * during ArchiveEntry calls, and an archive TOC item that has any such
18453  * entries will not be touched here. Otherwise, we recursively search the
18454  * DumpableObject data structures to build the correct dependencies for each
18455  * archive TOC item.
18456  */
18457 static void
18459 {
18460  ArchiveHandle *AH = (ArchiveHandle *) fout;
18461  TocEntry *te;
18462 
18463  /* Scan all TOC entries in the archive */
18464  for (te = AH->toc->next; te != AH->toc; te = te->next)
18465  {
18466  DumpableObject *dobj;
18467  DumpId *dependencies;
18468  int nDeps;
18469  int allocDeps;
18470 
18471  /* No need to process entries that will not be dumped */
18472  if (te->reqs == 0)
18473  continue;
18474  /* Ignore entries that already have "special" dependencies */
18475  if (te->nDeps > 0)
18476  continue;
18477  /* Otherwise, look up the item's original DumpableObject, if any */
18478  dobj = findObjectByDumpId(te->dumpId);
18479  if (dobj == NULL)
18480  continue;
18481  /* No work if it has no dependencies */
18482  if (dobj->nDeps <= 0)
18483  continue;
18484  /* Set up work array */
18485  allocDeps = 64;
18486  dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
18487  nDeps = 0;
18488  /* Recursively find all dumpable dependencies */
18489  findDumpableDependencies(AH, dobj,
18490  &dependencies, &nDeps, &allocDeps);
18491  /* And save 'em ... */
18492  if (nDeps > 0)
18493  {
18494  dependencies = (DumpId *) pg_realloc(dependencies,
18495  nDeps * sizeof(DumpId));
18496  te->dependencies = dependencies;
18497  te->nDeps = nDeps;
18498  }
18499  else
18500  free(dependencies);
18501  }
18502 }
18503 
18504 /* Recursive search subroutine for BuildArchiveDependencies */
18505 static void
18507  DumpId **dependencies, int *nDeps, int *allocDeps)
18508 {
18509  int i;
18510 
18511  /*
18512  * Ignore section boundary objects: if we search through them, we'll
18513  * report lots of bogus dependencies.
18514  */
18515  if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
18516  dobj->objType == DO_POST_DATA_BOUNDARY)
18517  return;
18518 
18519  for (i = 0; i < dobj->nDeps; i++)
18520  {
18521  DumpId depid = dobj->dependencies[i];
18522 
18523  if (TocIDRequired(AH, depid) != 0)
18524  {
18525  /* Object will be dumped, so just reference it as a dependency */
18526  if (*nDeps >= *allocDeps)
18527  {
18528  *allocDeps *= 2;
18529  *dependencies = (DumpId *) pg_realloc(*dependencies,
18530  *allocDeps * sizeof(DumpId));
18531  }
18532  (*dependencies)[*nDeps] = depid;
18533  (*nDeps)++;
18534  }
18535  else
18536  {
18537  /*
18538  * Object will not be dumped, so recursively consider its deps. We
18539  * rely on the assumption that sortDumpableObjects already broke
18540  * any dependency loops, else we might recurse infinitely.
18541  */
18542  DumpableObject *otherdobj = findObjectByDumpId(depid);
18543 
18544  if (otherdobj)
18545  findDumpableDependencies(AH, otherdobj,
18546  dependencies, nDeps, allocDeps);
18547  }
18548  }
18549 }
18550 
18551 
18552 /*
18553  * getFormattedTypeName - retrieve a nicely-formatted type name for the
18554  * given type OID.
18555  *
18556  * This does not guarantee to schema-qualify the output, so it should not
18557  * be used to create the target object name for CREATE or ALTER commands.
18558  *
18559  * Note that the result is cached and must not be freed by the caller.
18560  */
18561 static const char *
18563 {
18564  TypeInfo *typeInfo;
18565  char *result;
18566  PQExpBuffer query;
18567  PGresult *res;
18568 
18569  if (oid == 0)
18570  {
18571  if ((opts & zeroAsStar) != 0)
18572  return "*";
18573  else if ((opts & zeroAsNone) != 0)
18574  return "NONE";
18575  }
18576 
18577  /* see if we have the result cached in the type's TypeInfo record */
18578  typeInfo = findTypeByOid(oid);
18579  if (typeInfo && typeInfo->ftypname)
18580  return typeInfo->ftypname;
18581 
18582  query = createPQExpBuffer();
18583  appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
18584  oid);
18585 
18586  res = ExecuteSqlQueryForSingleRow(fout, query->data);
18587 
18588  /* result of format_type is already quoted */
18589  result = pg_strdup(PQgetvalue(res, 0, 0));
18590 
18591  PQclear(res);
18592  destroyPQExpBuffer(query);
18593 
18594  /*
18595  * Cache the result for re-use in later requests, if possible. If we
18596  * don't have a TypeInfo for the type, the string will be leaked once the
18597  * caller is done with it ... but that case really should not happen, so
18598  * leaking if it does seems acceptable.
18599  */
18600  if (typeInfo)
18601  typeInfo->ftypname = result;
18602 
18603  return result;
18604 }
18605 
18606 /*
18607  * Return a column list clause for the given relation.
18608  *
18609  * Special case: if there are no undropped columns in the relation, return
18610  * "", not an invalid "()" column list.
18611  */
18612 static const char *
18614 {
18615  int numatts = ti->numatts;
18616  char **attnames = ti->attnames;
18617  bool *attisdropped = ti->attisdropped;
18618  char *attgenerated = ti->attgenerated;
18619  bool needComma;
18620  int i;
18621 
18622  appendPQExpBufferChar(buffer, '(');
18623  needComma = false;
18624  for (i = 0; i < numatts; i++)
18625  {
18626  if (attisdropped[i])
18627  continue;
18628  if (attgenerated[i])
18629  continue;
18630  if (needComma)
18631  appendPQExpBufferStr(buffer, ", ");
18632  appendPQExpBufferStr(buffer, fmtId(attnames[i]));
18633  needComma = true;
18634  }
18635 
18636  if (!needComma)
18637  return ""; /* no undropped columns */
18638 
18639  appendPQExpBufferChar(buffer, ')');
18640  return buffer->data;
18641 }
18642 
18643 /*
18644  * Check if a reloptions array is nonempty.
18645  */
18646 static bool
18647 nonemptyReloptions(const char *reloptions)
18648 {
18649  /* Don't want to print it if it's just "{}" */
18650  return (reloptions != NULL && strlen(reloptions) > 2);
18651 }
18652 
18653 /*
18654  * Format a reloptions array and append it to the given buffer.
18655  *
18656  * "prefix" is prepended to the option names; typically it's "" or "toast.".
18657  */
18658 static void
18659 appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
18660  const char *prefix, Archive *fout)
18661 {
18662  bool res;
18663 
18664  res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
18665  fout->std_strings);
18666  if (!res)
18667  pg_log_warning("could not parse %s array", "reloptions");
18668 }
18669 
18670 /*
18671  * read_dump_filters - retrieve object identifier patterns from file
18672  *
18673  * Parse the specified filter file for include and exclude patterns, and add
18674  * them to the relevant lists. If the filename is "-" then filters will be
18675  * read from STDIN rather than a file.
18676  */
18677 static void
18679 {
18680  FilterStateData fstate;
18681  char *objname;
18682  FilterCommandType comtype;
18683  FilterObjectType objtype;
18684 
18685  filter_init(&fstate, filename, exit_nicely);
18686 
18687  while (filter_read_item(&fstate, &objname, &comtype, &objtype))
18688  {
18689  if (comtype == FILTER_COMMAND_TYPE_INCLUDE)
18690  {
18691  switch (objtype)
18692  {
18694  break;
18701  pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
18702  "include",
18703  filter_object_type_name(objtype));
18704  exit_nicely(1);
18705  break; /* unreachable */
18706 
18709  break;
18712  break;
18715  dopt->include_everything = false;
18716  break;
18719  dopt->include_everything = false;
18720  break;
18723  objname);
18724  dopt->include_everything = false;
18725  break;
18726  }
18727  }
18728  else if (comtype == FILTER_COMMAND_TYPE_EXCLUDE)
18729  {
18730  switch (objtype)
18731  {
18733  break;
18739  pg_log_filter_error(&fstate, _("%s filter for \"%s\" is not allowed"),
18740  "exclude",
18741  filter_object_type_name(objtype));
18742  exit_nicely(1);
18743  break;
18744 
18747  break;
18750  objname);
18751  break;
18754  objname);
18755  break;
18758  break;
18761  break;
18764  objname);
18765  break;
18766  }
18767  }
18768  else
18769  {
18770  Assert(comtype == FILTER_COMMAND_TYPE_NONE);
18771  Assert(objtype == FILTER_OBJECT_TYPE_NONE);
18772  }
18773 
18774  if (objname)
18775  free(objname);
18776  }
18777 
18778  filter_free(&fstate);
18779 }
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:684
void recordExtensionMembership(CatalogId catId, ExtensionInfo *ext)
Definition: common.c:1010
FuncInfo * findFuncByOid(Oid oid)
Definition: common.c:883
NamespaceInfo * findNamespaceByOid(Oid oid)
Definition: common.c:937
SubscriptionInfo * findSubscriptionByOid(Oid oid)
Definition: common.c:991
ExtensionInfo * findOwningExtension(CatalogId catalogId)
Definition: common.c:1034
TableInfo * getSchemaData(Archive *fout, int *numTablesPtr)
Definition: common.c:98
DumpableObject * findObjectByCatalogId(CatalogId catalogId)
Definition: common.c:743
void addObjectDependency(DumpableObject *dobj, DumpId refId)
Definition: common.c:783
DumpableObject * findObjectByDumpId(DumpId dumpId)
Definition: common.c:730
void parseOidArray(const char *str, Oid *array, int arraysize)
Definition: common.c:1058
TableInfo * findTableByOid(Oid oid)
Definition: common.c:828
DumpId createDumpId(void)
Definition: common.c:710
ExtensionInfo * findExtensionByOid(Oid oid)
Definition: common.c:955
void AssignDumpId(DumpableObject *dobj)
Definition: common.c:622
void getDumpableObjects(DumpableObject ***objs, int *numObjs)
Definition: common.c:762
CollInfo * findCollationByOid(Oid oid)
Definition: common.c:919
TypeInfo * findTypeByOid(Oid oid)
Definition: common.c:864
OprInfo * findOprByOid(Oid oid)
Definition: common.c:901
PublicationInfo * findPublicationByOid(Oid oid)
Definition: common.c:973
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:681
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:195
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:7136
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:7017
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:7171
int PQclientEncoding(const PGconn *conn)
Definition: fe-connect.c:7259
int PQsetClientEncoding(PGconn *conn, const char *encoding)
Definition: fe-connect.c:7267
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:390
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
static int pg_cmp_u32(uint32 a, uint32 b)
Definition: int.h:489
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:99
@ PGRES_COPY_OUT
Definition: libpq-fe.h:105
@ PGRES_TUPLES_OK
Definition: libpq-fe.h:102
#define INV_READ
Definition: libpq-fs.h:22
void pg_logging_increase_verbosity(void)
Definition: logging.c:184
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:175
#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:1696
void * palloc(Size size)
Definition: mcxt.c:1317
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:1439
static const CatalogId nilCatalogId
Definition: pg_dump.c:154
static void dumpEncoding(Archive *AH)
Definition: pg_dump.c:3534
void getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:7694
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:14984
static SimpleStringList schema_include_patterns
Definition: pg_dump.c:130
static void dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo)
Definition: pg_dump.c:16536
static void selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
Definition: pg_dump.c:1991
static void collectBinaryUpgradeClassOids(Archive *fout)
Definition: pg_dump.c:5433
static PQExpBuffer createDummyViewAsClause(Archive *fout, const TableInfo *tbinfo)
Definition: pg_dump.c:15628
static void dumpUserMappings(Archive *fout, const char *servername, const char *namespace, const char *owner, CatalogId catalogId, DumpId dumpId)
Definition: pg_dump.c:14801
static void dumpPublicationNamespace(Archive *fout, const PublicationSchemaInfo *pubsinfo)
Definition: pg_dump.c:4617
static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs, DumpableObject *boundaryObjs)
Definition: pg_dump.c:18342
void getPublicationNamespaces(Archive *fout)
Definition: pg_dump.c:4398
static void dumpSearchPath(Archive *AH)
Definition: pg_dump.c:3583
static int ncomments
Definition: pg_dump.c:166
static void selectDumpableTable(TableInfo *tbinfo, Archive *fout)
Definition: pg_dump.c:1860
static DumpableObject * createBoundaryObjects(void)
Definition: pg_dump.c:18318
static char * convertTSFunction(Archive *fout, Oid funcOid)
Definition: pg_dump.c:12974
static void dumpDatabase(Archive *fout)
Definition: pg_dump.c:3018
static SimpleStringList table_include_patterns
Definition: pg_dump.c:135
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:5241
static Oid get_next_possible_free_pg_type_oid(Archive *fout, PQExpBuffer upgrade_query)
Definition: pg_dump.c:5286
static void dumpNamespace(Archive *fout, const NamespaceInfo *nspinfo)
Definition: pg_dump.c:10489
static bool forcePartitionRootLoad(const TableInfo *tbinfo)
Definition: pg_dump.c:2594
static void dumpCast(Archive *fout, const CastInfo *cast)
Definition: pg_dump.c:12450
static SimpleOidList schema_exclude_oids
Definition: pg_dump.c:133
static bool have_extra_float_digits
Definition: pg_dump.c:157
static void dumpIndex(Archive *fout, const IndxInfo *indxinfo)
Definition: pg_dump.c:16626
void getPartitioningInfo(Archive *fout)
Definition: pg_dump.c:7245
static int nbinaryUpgradeClassOids
Definition: pg_dump.c:174
static void dumpBaseType(Archive *fout, const TypeInfo *tyinfo)
Definition: pg_dump.c:11087
OidOptions
Definition: pg_dump.c:108
@ zeroIsError
Definition: pg_dump.c:109
@ zeroAsStar
Definition: pg_dump.c:110
@ zeroAsNone
Definition: pg_dump.c:111
static SimpleOidList extension_include_oids
Definition: pg_dump.c:149
static void dumpTSDictionary(Archive *fout, const TSDictInfo *dictinfo)
Definition: pg_dump.c:14373
static void dumpAgg(Archive *fout, const AggInfo *agginfo)
Definition: pg_dump.c:13949
static int extra_float_digits
Definition: pg_dump.c:158
static void dumpTableComment(Archive *fout, const TableInfo *tbinfo, const char *reltypename)
Definition: pg_dump.c:10036
static SimpleStringList extension_include_patterns
Definition: pg_dump.c:148
static void selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
Definition: pg_dump.c:1774
void getForeignDataWrappers(Archive *fout)
Definition: pg_dump.c:9451
static void dumpTrigger(Archive *fout, const TriggerInfo *tginfo)
Definition: pg_dump.c:17513
static void binary_upgrade_set_type_oids_by_rel(Archive *fout, PQExpBuffer upgrade_buffer, const TableInfo *tbinfo)
Definition: pg_dump.c:5402
static void dumpTable(Archive *fout, const TableInfo *tbinfo)
Definition: pg_dump.c:15439
static SimpleOidList extension_exclude_oids
Definition: pg_dump.c:152
static SimpleStringList table_exclude_patterns
Definition: pg_dump.c:138
static PQExpBuffer createViewAsClause(Archive *fout, const TableInfo *tbinfo)
Definition: pg_dump.c:15579
static void dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo)
Definition: pg_dump.c:16806
void getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:3919
static void dumpRangeType(Archive *fout, const TypeInfo *tyinfo)
Definition: pg_dump.c:10865
void getExtensionMembership(Archive *fout, ExtensionInfo extinfo[], int numExtensions)
Definition: pg_dump.c:17891
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:10020
static char * getFormattedOperatorName(const char *oproid)
Definition: pg_dump.c:12944
static char * format_function_signature(Archive *fout, const FuncInfo *finfo, bool honor_quotes)
Definition: pg_dump.c:12005
static int nseclabels
Definition: pg_dump.c:170
static pg_compress_algorithm compression_algorithm
Definition: pg_dump.c:122
static void dumpStdStrings(Archive *AH)
Definition: pg_dump.c:3559
static void dumpConstraint(Archive *fout, const ConstraintInfo *coninfo)
Definition: pg_dump.c:16883
static void dumpType(Archive *fout, const TypeInfo *tyinfo)
Definition: pg_dump.c:10694
static void dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo)
Definition: pg_dump.c:16468
static void help(const char *progname)
Definition: pg_dump.c:1110
void getTypes(Archive *fout)
Definition: pg_dump.c:5805
static void dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo)
Definition: pg_dump.c:12996
int main(int argc, char **argv)
Definition: pg_dump.c:363
static void dumpOpr(Archive *fout, const OprInfo *oprinfo)
Definition: pg_dump.c:12684
static void selectDumpableStatisticsObject(StatsExtInfo *sobj, Archive *fout)
Definition: pg_dump.c:2109
static void selectDumpablePublicationObject(DumpableObject *dobj, Archive *fout)
Definition: pg_dump.c:2091
static void dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo)
Definition: pg_dump.c:17463
static void dumpFunc(Archive *fout, const FuncInfo *finfo)
Definition: pg_dump.c:12034
static void selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
Definition: pg_dump.c:1944
static void BuildArchiveDependencies(Archive *fout)
Definition: pg_dump.c:18458
void getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:7126
static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
Definition: pg_dump.c:2788
static const char * getAttrName(int attrnum, const TableInfo *tblInfo)
Definition: pg_dump.c:16597
static void dumpForeignServer(Archive *fout, const ForeignServerInfo *srvinfo)
Definition: pg_dump.c:14701
static RoleNameItem * rolenames
Definition: pg_dump.c:161
static void collectRoleNames(Archive *fout)
Definition: pg_dump.c:9756
static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions, const char *prefix, Archive *fout)
Definition: pg_dump.c:18659
void getOpclasses(Archive *fout)
Definition: pg_dump.c:6222
void getForeignServers(Archive *fout)
Definition: pg_dump.c:9535
void getFuncs(Archive *fout)
Definition: pg_dump.c:6485
static void dumpTableData(Archive *fout, const TableDataInfo *tdinfo)
Definition: pg_dump.c:2622
static void prohibit_crossdb_refs(PGconn *conn, const char *dbname, const char *pattern)
Definition: pg_dump.c:1699
static bool dosync
Definition: pg_dump.c:115
static int dumpTableData_copy(Archive *fout, const void *dcontext)
Definition: pg_dump.c:2149
#define MAX_BLOBS_PER_ARCHIVE_ENTRY
Definition: pg_dump.c:187
static const char * getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
Definition: pg_dump.c:18562
static void getDependencies(Archive *fout)
Definition: pg_dump.c:18165
static void buildMatViewRefreshDependencies(Archive *fout)
Definition: pg_dump.c:2862
void getTSDictionaries(Archive *fout)
Definition: pg_dump.c:9267
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:5317
#define DUMP_DEFAULT_ROWS_PER_INSERT
Definition: pg_dump.c:180
void getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:4485
static const char * getRoleName(const char *roleoid_str)
Definition: pg_dump.c:9720
static void dumpShellType(Archive *fout, const ShellTypeInfo *stinfo)
Definition: pg_dump.c:11804
static void refreshMatViewData(Archive *fout, const TableDataInfo *tdinfo)
Definition: pg_dump.c:2734
static int findComments(Oid classoid, Oid objoid, CommentItem **items)
Definition: pg_dump.c:10134
static SimpleStringList foreign_servers_include_patterns
Definition: pg_dump.c:145
static char * format_aggregate_signature(const AggInfo *agginfo, Archive *fout, bool honor_quotes)
Definition: pg_dump.c:13917
static void selectDumpableCast(CastInfo *cast, Archive *fout)
Definition: pg_dump.c:1966
void getCasts(Archive *fout)
Definition: pg_dump.c:8427
static void dumpPublication(Archive *fout, const PublicationInfo *pubinfo)
Definition: pg_dump.c:4302
static char * get_language_name(Archive *fout, Oid langid)
Definition: pg_dump.c:8516
static void dumpPolicy(Archive *fout, const PolicyInfo *polinfo)
Definition: pg_dump.c:4086
void getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:7305
static void setupDumpWorker(Archive *AH)
Definition: pg_dump.c:1372
static void addConstrChildIdxDeps(DumpableObject *dobj, const IndxInfo *refidx)
Definition: pg_dump.c:7859
void getTSConfigurations(Archive *fout)
Definition: pg_dump.c:9392
static int nrolenames
Definition: pg_dump.c:162
static int findSecLabels(Oid classoid, Oid objoid, SecLabelItem **items)
Definition: pg_dump.c:15274
static SimpleStringList table_include_patterns_and_children
Definition: pg_dump.c:136
static char * convertRegProcReference(const char *proc)
Definition: pg_dump.c:12903
static void getAdditionalACLs(Archive *fout)
Definition: pg_dump.c:9791
static bool is_superuser(Archive *fout)
Definition: pg_dump.c:4721
static void getTableDataFKConstraints(void)
Definition: pg_dump.c:2977
static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
Definition: pg_dump.c:2769
static SimpleOidList table_exclude_oids
Definition: pg_dump.c:140
void getAccessMethods(Archive *fout)
Definition: pg_dump.c:6160
void getConversions(Archive *fout)
Definition: pg_dump.c:6098
void getRules(Archive *fout)
Definition: pg_dump.c:7972
InhInfo * getInherits(Archive *fout, int *numInherits)
Definition: pg_dump.c:7189
static void dumpDomain(Archive *fout, const TypeInfo *tyinfo)
Definition: pg_dump.c:11336
void getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
Definition: pg_dump.c:8621
static void collectComments(Archive *fout)
Definition: pg_dump.c:10211
static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
Definition: pg_dump.c:7882
static void dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo)
Definition: pg_dump.c:13345
static void dumpDefaultACL(Archive *fout, const DefaultACLInfo *daclinfo)
Definition: pg_dump.c:14895
void getSubscriptionTables(Archive *fout)
Definition: pg_dump.c:4939
static void selectDumpableObject(DumpableObject *dobj, Archive *fout)
Definition: pg_dump.c:2127
static void dumpTSTemplate(Archive *fout, const TSTemplateInfo *tmplinfo)
Definition: pg_dump.c:14453
static void dumpIndexAttach(Archive *fout, const IndexAttachInfo *attachinfo)
Definition: pg_dump.c:16767
static void dumpSubscriptionTable(Archive *fout, const SubRelInfo *subrinfo)
Definition: pg_dump.c:5025
void getCollations(Archive *fout)
Definition: pg_dump.c:6036
static char * format_function_arguments(const FuncInfo *finfo, const char *funcargs, bool is_agg)
Definition: pg_dump.c:11982
static int strict_names
Definition: pg_dump.c:120
static void dumpTransform(Archive *fout, const TransformInfo *transform)
Definition: pg_dump.c:12555
void getAggregates(Archive *fout)
Definition: pg_dump.c:6344
static void dumpLO(Archive *fout, const LoInfo *loinfo)
Definition: pg_dump.c:3783
void getNamespaces(Archive *fout)
Definition: pg_dump.c:5601
static void dumpPublicationTable(Archive *fout, const PublicationRelInfo *pubrinfo)
Definition: pg_dump.c:4660
void getPublications(Archive *fout)
Definition: pg_dump.c:4204
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:5557
static void dumpDumpableObject(Archive *fout, DumpableObject *dobj)
Definition: pg_dump.c:10296
static void getLOs(Archive *fout)
Definition: pg_dump.c:3645
static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf, const char *dbname, Oid dboid)
Definition: pg_dump.c:3490
void getTSParsers(Archive *fout)
Definition: pg_dump.c:9193
static void setup_connection(Archive *AH, const char *dumpencoding, const char *dumpsnapshot, char *use_role)
Definition: pg_dump.c:1210
static void dumpTableConstraintComment(Archive *fout, const ConstraintInfo *coninfo)
Definition: pg_dump.c:17170
static void dumpUndefinedType(Archive *fout, const TypeInfo *tyinfo)
Definition: pg_dump.c:11023
static void selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
Definition: pg_dump.c:2024
static const char * fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
Definition: pg_dump.c:18613
static void expand_table_name_patterns(Archive *fout, SimpleStringList *patterns, SimpleOidList *oids, bool strict_names, bool with_child_tables)
Definition: pg_dump.c:1603
static void findDumpableDependencies(ArchiveHandle *AH, const DumpableObject *dobj, DumpId **dependencies, int *nDeps, int *allocDeps)
Definition: pg_dump.c:18506
static void dumpTableSchema(Archive *fout, const TableInfo *tbinfo)
Definition: pg_dump.c:15668
static void dumpTSParser(Archive *fout, const TSParserInfo *prsinfo)
Definition: pg_dump.c:14309
static void expand_foreign_server_name_patterns(Archive *fout, SimpleStringList *patterns, SimpleOidList *oids)
Definition: pg_dump.c:1551
static void dumpRule(Archive *fout, const RuleInfo *rinfo)
Definition: pg_dump.c:17724
static void dumpCompositeType(Archive *fout, const TypeInfo *tyinfo)
Definition: pg_dump.c:11509
static void dumpEnumType(Archive *fout, const TypeInfo *tyinfo)
Definition: pg_dump.c:10725
static void dumpExtension(Archive *fout, const ExtensionInfo *extinfo)
Definition: pg_dump.c:10566
#define fmtQualifiedDumpable(obj)
Definition: pg_dump.c:192
static bool nonemptyReloptions(const char *reloptions)
Definition: pg_dump.c:18647
static SimpleStringList extension_exclude_patterns
Definition: pg_dump.c:151
static BinaryUpgradeClassOidItem * binaryUpgradeClassOids
Definition: pg_dump.c:173
static SimpleOidList table_include_oids
Definition: pg_dump.c:137
void getExtendedStatistics(Archive *fout)
Definition: pg_dump.c:7615
static NamespaceInfo * findNamespace(Oid nsoid)
Definition: pg_dump.c:5715
static char * get_synchronized_snapshot(Archive *fout)
Definition: pg_dump.c:1387
static int dumpLOs(Archive *fout, const void *arg)
Definition: pg_dump.c:3873
static void dumpSubscription(Archive *fout, const SubscriptionInfo *subinfo)
Definition: pg_dump.c:5094
void processExtensionTables(Archive *fout, ExtensionInfo extinfo[], int numExtensions)
Definition: pg_dump.c:17984
static void dumpEventTrigger(Archive *fout, const EventTriggerInfo *evtinfo)
Definition: pg_dump.c:17639
static int BinaryUpgradeClassOidItemCmp(const void *p1, const void *p2)
Definition: pg_dump.c:5417
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:9920
void getDefaultACLs(Archive *fout)
Definition: pg_dump.c:9623
static SimpleStringList tabledata_exclude_patterns
Definition: pg_dump.c:141
static void dumpConversion(Archive *fout, const ConvInfo *convinfo)
Definition: pg_dump.c:13821
static void dumpForeignDataWrapper(Archive *fout, const FdwInfo *fdwinfo)
Definition: pg_dump.c:14631
static void dumpProcLang(Archive *fout, const ProcLangInfo *plang)
Definition: pg_dump.c:11850
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:15112
void getSubscriptions(Archive *fout)
Definition: pg_dump.c:4739
static void collectSecLabels(Archive *fout)
Definition: pg_dump.c:15353
static void selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
Definition: pg_dump.c:2052
static Oid g_last_builtin_oid
Definition: pg_dump.c:117
ExtensionInfo * getExtensions(Archive *fout, int *numExtensions)
Definition: pg_dump.c:5733
void getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
Definition: pg_dump.c:8069
void getTransforms(Archive *fout)
Definition: pg_dump.c:8537
void getEventTriggers(Archive *fout)
Definition: pg_dump.c:8265
static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode)
Definition: pg_dump.c:1401
static void read_dump_filters(const char *filename, DumpOptions *dopt)
Definition: pg_dump.c:18678
static void dumpTSConfig(Archive *fout, const TSConfigInfo *cfginfo)
Definition: pg_dump.c:14511
static SecLabelItem * seclabels
Definition: pg_dump.c:169
static SimpleStringList tabledata_exclude_patterns_and_children
Definition: pg_dump.c:142
static bool checkExtensionMembership(DumpableObject *dobj, Archive *fout)
Definition: pg_dump.c:1724
static CommentItem * comments
Definition: pg_dump.c:165
static int dumpTableData_insert(Archive *fout, const void *dcontext)
Definition: pg_dump.c:2308
static SimpleOidList tabledata_exclude_oids
Definition: pg_dump.c:143
static SimpleStringList table_exclude_patterns_and_children
Definition: pg_dump.c:139
TableInfo * getTables(Archive *fout, int *numTables)
Definition: pg_dump.c:6680
static void binary_upgrade_set_pg_class_oids(Archive *fout, PQExpBuffer upgrade_buffer, Oid pg_class_oid)
Definition: pg_dump.c:5467
void getTSTemplates(Archive *fout)
Definition: pg_dump.c:9333
void getProcLangs(Archive *fout)
Definition: pg_dump.c:8343
static void dumpSequence(Archive *fout, const TableInfo *tbinfo)
Definition: pg_dump.c:17197
bool shouldPrintColumn(const DumpOptions *dopt, const TableInfo *tbinfo, int colno)
Definition: pg_dump.c:9178
static TableInfo * getRootTableInfo(const TableInfo *tbinfo)
Definition: pg_dump.c:2569
void getOperators(Archive *fout)
Definition: pg_dump.c:5968
static SimpleOidList foreign_servers_include_oids
Definition: pg_dump.c:146
static void dumpCollation(Archive *fout, const CollInfo *collinfo)
Definition: pg_dump.c:13564
static void dumpTableSecLabel(Archive *fout, const TableInfo *tbinfo, const char *reltypename)
Definition: pg_dump.c:15192
static void dumpCompositeTypeColComments(Archive *fout, const TypeInfo *tyinfo, PGresult *res)
Definition: pg_dump.c:11715
static void expand_extension_name_patterns(Archive *fout, SimpleStringList *patterns, SimpleOidList *oids, bool strict_names)
Definition: pg_dump.c:1498
void getOpfamilies(Archive *fout)
Definition: pg_dump.c:6282
static void selectDumpableType(TypeInfo *tyinfo, Archive *fout)
Definition: pg_dump.c:1899
static SimpleOidList schema_include_oids
Definition: pg_dump.c:131
static void dumpOpclass(Archive *fout, const OpclassInfo *opcinfo)
Definition: pg_dump.c:13064
static SimpleStringList schema_exclude_patterns
Definition: pg_dump.c:132
#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
static 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
RelFileNumber toast_index_relfilenumber
Definition: pg_dump.c:104
RelFileNumber toast_relfilenumber
Definition: pg_dump.c:102
RelFileNumber relfilenumber
Definition: pg_dump.c:100
Oid tableoid
Definition: pg_backup.h:266
Oid classoid
Definition: pg_dump.c:82
Oid objoid
Definition: pg_dump.c:83
int objsubid
Definition: pg_dump.c:84
const char * descr
Definition: pg_dump.c:81
const char * rolename
Definition: pg_dump.c:76
Oid roleoid
Definition: pg_dump.c:75
const char * provider
Definition: pg_dump.c:89
Oid classoid
Definition: pg_dump.c:91
int objsubid
Definition: pg_dump.c:93
const char * label
Definition: pg_dump.c:90
Oid objoid
Definition: pg_dump.c:92
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:620
bool puballtables
Definition: pg_dump.h:621
bool pubtruncate
Definition: pg_dump.h:625
DumpableObject dobj
Definition: pg_dump.h:619
NamespaceInfo * pubschema
Definition: pg_dump.h:650
DumpableObject dobj
Definition: pg_dump.h:648
PublicationInfo * publication
Definition: pg_dump.h:649
DumpableObject dobj
Definition: pg_dump.h:688
char * srsublsn
Definition: pg_dump.h:692
SubscriptionInfo * subinfo
Definition: pg_dump.h:689
TableInfo * tblinfo
Definition: pg_dump.h:690
char srsubstate
Definition: pg_dump.h:691
char * suboriginremotelsn
Definition: pg_dump.h:672
char * suborigin
Definition: pg_dump.h:671
char * subbinary
Definition: pg_dump.h:661
const char * rolname
Definition: pg_dump.h:659
char * subrunasowner
Definition: pg_dump.h:666
char * subsynccommit
Definition: pg_dump.h:669
char * subpublications
Definition: pg_dump.h:670
char * subtwophasestate
Definition: pg_dump.h:663
char * subfailover
Definition: pg_dump.h:673
char * subenabled
Definition: pg_dump.h:660
char * substream
Definition: pg_dump.h:662
char * subpasswordrequired
Definition: pg_dump.h:665
char * subslotname
Definition: pg_dump.h:668
char * subdisableonerr
Definition: pg_dump.h:664
char * subconninfo
Definition: pg_dump.h:667
DumpableObject dobj
Definition: pg_dump.h:658
char * amhandler
Definition: pg_dump.h:253
DumpableObject dobj
Definition: pg_dump.h:251
struct _tocEntry * toc
DumpableObject dobj
Definition: pg_dump.h:375
char * adef_expr
Definition: pg_dump.h:378
TableInfo * adtable
Definition: pg_dump.h:376
bool separate
Definition: pg_dump.h:379
char castmethod
Definition: pg_dump.h:499
Oid casttarget
Definition: pg_dump.h:496
char castcontext
Definition: pg_dump.h:498
DumpableObject dobj
Definition: pg_dump.h:494
Oid castsource
Definition: pg_dump.h:495
Oid castfunc
Definition: pg_dump.h:497
Oid cfgparser
Definition: pg_dump.h:547
DumpableObject dobj
Definition: pg_dump.h:545
const char * rolname
Definition: pg_dump.h:546
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:470
TableInfo * contable
Definition: pg_dump.h:469
bool condeferred
Definition: pg_dump.h:476
bool conislocal
Definition: pg_dump.h:477
DumpableObject dobj
Definition: pg_dump.h:468
DumpId conindex
Definition: pg_dump.h:474
bool condeferrable
Definition: pg_dump.h:475
char * condef
Definition: pg_dump.h:472
DumpableObject dobj
Definition: pg_dump.h:276
const char * rolname
Definition: pg_dump.h:277
DumpableObject dobj
Definition: pg_dump.h:573
DumpableAcl dacl
Definition: pg_dump.h:574
const char * defaclrole
Definition: pg_dump.h:575
char defaclobjtype
Definition: pg_dump.h:576
char * dictinitoption
Definition: pg_dump.h:533
DumpableObject dobj
Definition: pg_dump.h:530
const char * rolname
Definition: pg_dump.h:531
Oid dicttemplate
Definition: pg_dump.h:532
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:451
char * evtfname
Definition: pg_dump.h:454
char evtenabled
Definition: pg_dump.h:455
char * evtname
Definition: pg_dump.h:450
const char * evtowner
Definition: pg_dump.h:452
char * evttags
Definition: pg_dump.h:453
DumpableObject dobj
Definition: pg_dump.h:449
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:555
const char * rolname
Definition: pg_dump.h:554
char * fdwvalidator
Definition: pg_dump.h:556
char * fdwoptions
Definition: pg_dump.h:557
DumpableAcl dacl
Definition: pg_dump.h:553
DumpableObject dobj
Definition: pg_dump.h:552
DumpableAcl dacl
Definition: pg_dump.h:563
char * srvoptions
Definition: pg_dump.h:568
DumpableObject dobj
Definition: pg_dump.h:562
const char * rolname
Definition: pg_dump.h:564
char * srvversion
Definition: pg_dump.h:567
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:416
DumpableObject dobj
Definition: pg_dump.h:414
IndxInfo * parentIdx
Definition: pg_dump.h:415
bool indisreplident
Definition: pg_dump.h:403
int indnkeyattrs
Definition: pg_dump.h:398
char * indstatvals
Definition: pg_dump.h:397
char * indstatcols
Definition: pg_dump.h:396
int indnattrs
Definition: pg_dump.h:399
TableInfo * indextable
Definition: pg_dump.h:392
Oid parentidx
Definition: pg_dump.h:405
Oid * indkeys
Definition: pg_dump.h:400
char * indreloptions
Definition: pg_dump.h:395
DumpId indexconstraint
Definition: pg_dump.h:409
bool indisclustered
Definition: pg_dump.h:402
SimplePtrList partattaches
Definition: pg_dump.h:406
char * tablespace
Definition: pg_dump.h:394
bool indnullsnotdistinct
Definition: pg_dump.h:404
char * indexdef
Definition: pg_dump.h:393
DumpableObject dobj
Definition: pg_dump.h:391
Oid inhparent
Definition: pg_dump.h:515
Oid inhrelid
Definition: pg_dump.h:514
const char * rolname
Definition: pg_dump.h:591
DumpableObject dobj
Definition: pg_dump.h:589
DumpableAcl dacl
Definition: pg_dump.h:590
Oid looids[FLEXIBLE_ARRAY_MEMBER]
Definition: pg_dump.h:593
int numlos
Definition: pg_dump.h:592
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:605
char * polqual
Definition: pg_dump.h:610
char polcmd
Definition: pg_dump.h:607
char * polroles
Definition: pg_dump.h:609
char * polwithcheck
Definition: pg_dump.h:611
DumpableObject dobj
Definition: pg_dump.h:604
bool polpermissive
Definition: pg_dump.h:608
char * polname
Definition: pg_dump.h:606
Oid lanvalidator
Definition: pg_dump.h:488
DumpableAcl dacl
Definition: pg_dump.h:484
DumpableObject dobj
Definition: pg_dump.h:483
Oid laninline
Definition: pg_dump.h:487
const char * lanowner
Definition: pg_dump.h:489
Oid lanplcallfoid
Definition: pg_dump.h:486
bool lanpltrusted
Definition: pg_dump.h:485
DumpableObject dobj
Definition: pg_dump.h:520
Oid prstoken
Definition: pg_dump.h:522
Oid prslextype
Definition: pg_dump.h:525
Oid prsheadline
Definition: pg_dump.h:524
Oid prsstart
Definition: pg_dump.h:521
Oid prsend
Definition: pg_dump.h:523
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:429
bool separate
Definition: pg_dump.h:434
char ev_enabled
Definition: pg_dump.h:433
bool is_instead
Definition: pg_dump.h:432
TableInfo * ruletable
Definition: pg_dump.h:430
char ev_type
Definition: pg_dump.h:431
TypeInfo * baseType
Definition: pg_dump.h:219
DumpableObject dobj
Definition: pg_dump.h:217
TableInfo * stattable
Definition: pg_dump.h:423
int stattarget
Definition: pg_dump.h:424
const char * rolname
Definition: pg_dump.h:422
DumpableObject dobj
Definition: pg_dump.h:421
TableInfo * partitionTbl
Definition: pg_dump.h:370
DumpableObject dobj
Definition: pg_dump.h:368
TableInfo * parentTbl
Definition: pg_dump.h:369
TableInfo * tdtable
Definition: pg_dump.h:385
DumpableObject dobj
Definition: pg_dump.h:384
char * filtercond
Definition: pg_dump.h:386
char * attidentity
Definition: pg_dump.h:339
char * reltablespace
Definition: pg_dump.h:292
int ncheck
Definition: pg_dump.h:308
bool ispartition
Definition: pg_dump.h:322
struct _indxInfo * indexes
Definition: pg_dump.h:360
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:363
bool * attisdropped
Definition: pg_dump.h:338
bool needs_override
Definition: pg_dump.h:353
struct _constraintInfo * checkexprs
Definition: pg_dump.h:352
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:351
char ** attoptions
Definition: pg_dump.h:344
char relreplident
Definition: pg_dump.h:291
int numTriggers
Definition: pg_dump.h:362
uint32 minmxid
Definition: pg_dump.h:304
Oid * attcollation
Definition: pg_dump.h:345
char * attstorage
Definition: pg_dump.h:336
int toastpages
Definition: pg_dump.h:317
bool * notnull
Definition: pg_dump.h:349
Oid owning_tab
Definition: pg_dump.h:313
struct _tableDataInfo * dataObj
Definition: pg_dump.h:361
char * amname
Definition: pg_dump.h:354
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:359
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 rowsec
Definition: pg_dump.h:300
bool * inhNotNull
Definition: pg_dump.h:350
Oid tmpllexize
Definition: pg_dump.h:540
Oid tmplinit
Definition: pg_dump.h:539
DumpableObject dobj
Definition: pg_dump.h:538
pgoff_t dataLength
struct _tocEntry * next
DumpId * dependencies
DumpableObject dobj
Definition: pg_dump.h:504
Oid trffromsql
Definition: pg_dump.h:507
TableInfo * tgtable
Definition: pg_dump.h:441
DumpableObject dobj
Definition: pg_dump.h:440
char tgenabled
Definition: pg_dump.h:442
char * tgdef
Definition: pg_dump.h:444
bool tgispartition
Definition: pg_dump.h:443
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:64