PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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-2017, 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 #ifdef ENABLE_NLS
37 #include <locale.h>
38 #endif
39 #ifdef HAVE_TERMIOS_H
40 #include <termios.h>
41 #endif
42 
43 #include "getopt_long.h"
44 
45 #include "access/attnum.h"
46 #include "access/sysattr.h"
47 #include "access/transam.h"
48 #include "catalog/pg_am.h"
49 #include "catalog/pg_cast.h"
50 #include "catalog/pg_class.h"
51 #include "catalog/pg_default_acl.h"
52 #include "catalog/pg_largeobject.h"
54 #include "catalog/pg_proc.h"
55 #include "catalog/pg_trigger.h"
56 #include "catalog/pg_type.h"
57 #include "libpq/libpq-fs.h"
58 
59 #include "dumputils.h"
60 #include "parallel.h"
61 #include "pg_backup_db.h"
62 #include "pg_backup_utils.h"
63 #include "pg_dump.h"
64 #include "fe_utils/string_utils.h"
65 
66 
67 typedef struct
68 {
69  const char *descr; /* comment for an object */
70  Oid classoid; /* object class (catalog OID) */
71  Oid objoid; /* object OID */
72  int objsubid; /* subobject (table column #) */
73 } CommentItem;
74 
75 typedef struct
76 {
77  const char *provider; /* label provider of this security label */
78  const char *label; /* security label for an object */
79  Oid classoid; /* object class (catalog OID) */
80  Oid objoid; /* object OID */
81  int objsubid; /* subobject (table column #) */
82 } SecLabelItem;
83 
84 typedef enum OidOptions
85 {
87  zeroAsAny = 2,
90 } OidOptions;
91 
92 /* global decls */
93 bool g_verbose; /* User wants verbose narration of our
94  * activities. */
95 
96 /* subquery used to convert user ID (eg, datdba) to user name */
97 static const char *username_subquery;
98 
99 /*
100  * For 8.0 and earlier servers, pulled from pg_database, for 8.1+ we use
101  * FirstNormalObjectId - 1.
102  */
103 static Oid g_last_builtin_oid; /* value of the last builtin oid */
104 
105 /* The specified names/patterns should to match at least one entity */
106 static int strict_names = 0;
107 
108 /*
109  * Object inclusion/exclusion lists
110  *
111  * The string lists record the patterns given by command-line switches,
112  * which we then convert to lists of OIDs of matching objects.
113  */
118 
125 
126 
127 char g_opaque_type[10]; /* name for the opaque type */
128 
129 /* placeholders for the delimiters for comments */
131 char g_comment_end[10];
132 
133 static const CatalogId nilCatalogId = {0, 0};
134 
135 static void help(const char *progname);
136 static void setup_connection(Archive *AH,
137  const char *dumpencoding, const char *dumpsnapshot,
138  char *use_role);
139 static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
140 static void expand_schema_name_patterns(Archive *fout,
141  SimpleStringList *patterns,
142  SimpleOidList *oids,
143  bool strict_names);
144 static void expand_table_name_patterns(Archive *fout,
145  SimpleStringList *patterns,
146  SimpleOidList *oids,
147  bool strict_names);
148 static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid);
149 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
150 static void refreshMatViewData(Archive *fout, TableDataInfo *tdinfo);
151 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
152 static void dumpComment(Archive *fout, const char *target,
153  const char *namespace, const char *owner,
154  CatalogId catalogId, int subid, DumpId dumpId);
155 static int findComments(Archive *fout, Oid classoid, Oid objoid,
156  CommentItem **items);
157 static int collectComments(Archive *fout, CommentItem **items);
158 static void dumpSecLabel(Archive *fout, const char *target,
159  const char *namespace, const char *owner,
160  CatalogId catalogId, int subid, DumpId dumpId);
161 static int findSecLabels(Archive *fout, Oid classoid, Oid objoid,
162  SecLabelItem **items);
163 static int collectSecLabels(Archive *fout, SecLabelItem **items);
164 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
165 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
166 static void dumpExtension(Archive *fout, ExtensionInfo *extinfo);
167 static void dumpType(Archive *fout, TypeInfo *tyinfo);
168 static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
169 static void dumpEnumType(Archive *fout, TypeInfo *tyinfo);
170 static void dumpRangeType(Archive *fout, TypeInfo *tyinfo);
171 static void dumpUndefinedType(Archive *fout, TypeInfo *tyinfo);
172 static void dumpDomain(Archive *fout, TypeInfo *tyinfo);
173 static void dumpCompositeType(Archive *fout, TypeInfo *tyinfo);
174 static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
175 static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
176 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
177 static void dumpFunc(Archive *fout, FuncInfo *finfo);
178 static void dumpCast(Archive *fout, CastInfo *cast);
179 static void dumpTransform(Archive *fout, TransformInfo *transform);
180 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
181 static void dumpAccessMethod(Archive *fout, AccessMethodInfo *oprinfo);
182 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
183 static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
184 static void dumpCollation(Archive *fout, CollInfo *collinfo);
185 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
186 static void dumpRule(Archive *fout, RuleInfo *rinfo);
187 static void dumpAgg(Archive *fout, AggInfo *agginfo);
188 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
189 static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
190 static void dumpTable(Archive *fout, TableInfo *tbinfo);
191 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
192 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
193 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
194 static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo);
195 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
196 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
197 static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
198 static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
199 static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
200 static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
201 static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
202 static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
203 static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
204 static void dumpUserMappings(Archive *fout,
205  const char *servername, const char *namespace,
206  const char *owner, CatalogId catalogId, DumpId dumpId);
207 static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
208 
209 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
210  const char *type, const char *name, const char *subname,
211  const char *tag, const char *nspname, const char *owner,
212  const char *acls, const char *racls,
213  const char *initacls, const char *initracls);
214 
215 static void getDependencies(Archive *fout);
216 static void BuildArchiveDependencies(Archive *fout);
218  DumpId **dependencies, int *nDeps, int *allocDeps);
219 
221 static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
222  DumpableObject *boundaryObjs);
223 
224 static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
225 static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, bool oids, char relkind);
226 static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo, bool oids);
227 static void buildMatViewRefreshDependencies(Archive *fout);
228 static void getTableDataFKConstraints(void);
229 static char *format_function_arguments(FuncInfo *finfo, char *funcargs,
230  bool is_agg);
231 static char *format_function_arguments_old(Archive *fout,
232  FuncInfo *finfo, int nallargs,
233  char **allargtypes,
234  char **argmodes,
235  char **argnames);
236 static char *format_function_signature(Archive *fout,
237  FuncInfo *finfo, bool honor_quotes);
238 static char *convertRegProcReference(Archive *fout,
239  const char *proc);
240 static char *convertOperatorReference(Archive *fout, const char *opr);
241 static char *convertTSFunction(Archive *fout, Oid funcOid);
242 static Oid findLastBuiltinOid_V71(Archive *fout, const char *);
243 static void selectSourceSchema(Archive *fout, const char *schemaName);
244 static char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
245 static void getBlobs(Archive *fout);
246 static void dumpBlob(Archive *fout, BlobInfo *binfo);
247 static int dumpBlobs(Archive *fout, void *arg);
248 static void dumpPolicy(Archive *fout, PolicyInfo *polinfo);
249 static void dumpPublication(Archive *fout, PublicationInfo *pubinfo);
250 static void dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo);
251 static void dumpSubscription(Archive *fout, SubscriptionInfo *subinfo);
252 static void dumpDatabase(Archive *AH);
253 static void dumpEncoding(Archive *AH);
254 static void dumpStdStrings(Archive *AH);
256  PQExpBuffer upgrade_buffer, Oid pg_type_oid);
258  PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
259 static void binary_upgrade_set_pg_class_oids(Archive *fout,
260  PQExpBuffer upgrade_buffer,
261  Oid pg_class_oid, bool is_index);
262 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
263  DumpableObject *dobj,
264  const char *objlabel);
265 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
266 static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
267 static bool nonemptyReloptions(const char *reloptions);
268 static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
269  const char *prefix, Archive *fout);
270 static char *get_synchronized_snapshot(Archive *fout);
271 static void setupDumpWorker(Archive *AHX);
272 
273 
274 int
275 main(int argc, char **argv)
276 {
277  int c;
278  const char *filename = NULL;
279  const char *format = "p";
280  TableInfo *tblinfo;
281  int numTables;
282  DumpableObject **dobjs;
283  int numObjs;
284  DumpableObject *boundaryObjs;
285  int i;
286  int optindex;
287  RestoreOptions *ropt;
288  Archive *fout; /* the script file */
289  const char *dumpencoding = NULL;
290  const char *dumpsnapshot = NULL;
291  char *use_role = NULL;
292  int numWorkers = 1;
293  trivalue prompt_password = TRI_DEFAULT;
294  int compressLevel = -1;
295  int plainText = 0;
296  ArchiveFormat archiveFormat = archUnknown;
297  ArchiveMode archiveMode;
298 
299  static DumpOptions dopt;
300 
301  static struct option long_options[] = {
302  {"data-only", no_argument, NULL, 'a'},
303  {"blobs", no_argument, NULL, 'b'},
304  {"no-blobs", no_argument, NULL, 'B'},
305  {"clean", no_argument, NULL, 'c'},
306  {"create", no_argument, NULL, 'C'},
307  {"dbname", required_argument, NULL, 'd'},
308  {"file", required_argument, NULL, 'f'},
309  {"format", required_argument, NULL, 'F'},
310  {"host", required_argument, NULL, 'h'},
311  {"jobs", 1, NULL, 'j'},
312  {"no-reconnect", no_argument, NULL, 'R'},
313  {"oids", no_argument, NULL, 'o'},
314  {"no-owner", no_argument, NULL, 'O'},
315  {"port", required_argument, NULL, 'p'},
316  {"schema", required_argument, NULL, 'n'},
317  {"exclude-schema", required_argument, NULL, 'N'},
318  {"schema-only", no_argument, NULL, 's'},
319  {"superuser", required_argument, NULL, 'S'},
320  {"table", required_argument, NULL, 't'},
321  {"exclude-table", required_argument, NULL, 'T'},
322  {"no-password", no_argument, NULL, 'w'},
323  {"password", no_argument, NULL, 'W'},
324  {"username", required_argument, NULL, 'U'},
325  {"verbose", no_argument, NULL, 'v'},
326  {"no-privileges", no_argument, NULL, 'x'},
327  {"no-acl", no_argument, NULL, 'x'},
328  {"compress", required_argument, NULL, 'Z'},
329  {"encoding", required_argument, NULL, 'E'},
330  {"help", no_argument, NULL, '?'},
331  {"version", no_argument, NULL, 'V'},
332 
333  /*
334  * the following options don't have an equivalent short option letter
335  */
336  {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
337  {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
338  {"column-inserts", no_argument, &dopt.column_inserts, 1},
339  {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
340  {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
341  {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
342  {"exclude-table-data", required_argument, NULL, 4},
343  {"if-exists", no_argument, &dopt.if_exists, 1},
344  {"include-subscriptions", no_argument, &dopt.include_subscriptions, 1},
345  {"inserts", no_argument, &dopt.dump_inserts, 1},
346  {"lock-wait-timeout", required_argument, NULL, 2},
347  {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
348  {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
349  {"role", required_argument, NULL, 3},
350  {"section", required_argument, NULL, 5},
351  {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
352  {"snapshot", required_argument, NULL, 6},
353  {"strict-names", no_argument, &strict_names, 1},
354  {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
355  {"no-create-subscription-slots", no_argument, &dopt.no_create_subscription_slots, 1},
356  {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
357  {"no-synchronized-snapshots", no_argument, &dopt.no_synchronized_snapshots, 1},
358  {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
359 
360  {NULL, 0, NULL, 0}
361  };
362 
363  set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
364 
365  /*
366  * Initialize what we need for parallel execution, especially for thread
367  * support on Windows.
368  */
370 
371  g_verbose = false;
372 
373  strcpy(g_comment_start, "-- ");
374  g_comment_end[0] = '\0';
375  strcpy(g_opaque_type, "opaque");
376 
377  progname = get_progname(argv[0]);
378 
379  if (argc > 1)
380  {
381  if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
382  {
383  help(progname);
384  exit_nicely(0);
385  }
386  if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
387  {
388  puts("pg_dump (PostgreSQL) " PG_VERSION);
389  exit_nicely(0);
390  }
391  }
392 
393  InitDumpOptions(&dopt);
394 
395  while ((c = getopt_long(argc, argv, "abBcCd:E:f:F:h:j:n:N:oOp:RsS:t:T:U:vwWxZ:",
396  long_options, &optindex)) != -1)
397  {
398  switch (c)
399  {
400  case 'a': /* Dump data only */
401  dopt.dataOnly = true;
402  break;
403 
404  case 'b': /* Dump blobs */
405  dopt.outputBlobs = true;
406  break;
407 
408  case 'B': /* Don't dump blobs */
409  dopt.dontOutputBlobs = true;
410  break;
411 
412  case 'c': /* clean (i.e., drop) schema prior to create */
413  dopt.outputClean = 1;
414  break;
415 
416  case 'C': /* Create DB */
417  dopt.outputCreateDB = 1;
418  break;
419 
420  case 'd': /* database name */
421  dopt.dbname = pg_strdup(optarg);
422  break;
423 
424  case 'E': /* Dump encoding */
425  dumpencoding = pg_strdup(optarg);
426  break;
427 
428  case 'f':
429  filename = pg_strdup(optarg);
430  break;
431 
432  case 'F':
433  format = pg_strdup(optarg);
434  break;
435 
436  case 'h': /* server host */
437  dopt.pghost = pg_strdup(optarg);
438  break;
439 
440  case 'j': /* number of dump jobs */
441  numWorkers = atoi(optarg);
442  break;
443 
444  case 'n': /* include schema(s) */
445  simple_string_list_append(&schema_include_patterns, optarg);
446  dopt.include_everything = false;
447  break;
448 
449  case 'N': /* exclude schema(s) */
450  simple_string_list_append(&schema_exclude_patterns, optarg);
451  break;
452 
453  case 'o': /* Dump oids */
454  dopt.oids = true;
455  break;
456 
457  case 'O': /* Don't reconnect to match owner */
458  dopt.outputNoOwner = 1;
459  break;
460 
461  case 'p': /* server port */
462  dopt.pgport = pg_strdup(optarg);
463  break;
464 
465  case 'R':
466  /* no-op, still accepted for backwards compatibility */
467  break;
468 
469  case 's': /* dump schema only */
470  dopt.schemaOnly = true;
471  break;
472 
473  case 'S': /* Username for superuser in plain text output */
475  break;
476 
477  case 't': /* include table(s) */
478  simple_string_list_append(&table_include_patterns, optarg);
479  dopt.include_everything = false;
480  break;
481 
482  case 'T': /* exclude table(s) */
483  simple_string_list_append(&table_exclude_patterns, optarg);
484  break;
485 
486  case 'U':
487  dopt.username = pg_strdup(optarg);
488  break;
489 
490  case 'v': /* verbose */
491  g_verbose = true;
492  break;
493 
494  case 'w':
495  prompt_password = TRI_NO;
496  break;
497 
498  case 'W':
499  prompt_password = TRI_YES;
500  break;
501 
502  case 'x': /* skip ACL dump */
503  dopt.aclsSkip = true;
504  break;
505 
506  case 'Z': /* Compression Level */
507  compressLevel = atoi(optarg);
508  if (compressLevel < 0 || compressLevel > 9)
509  {
510  write_msg(NULL, "compression level must be in range 0..9\n");
511  exit_nicely(1);
512  }
513  break;
514 
515  case 0:
516  /* This covers the long options. */
517  break;
518 
519  case 2: /* lock-wait-timeout */
521  break;
522 
523  case 3: /* SET ROLE */
524  use_role = pg_strdup(optarg);
525  break;
526 
527  case 4: /* exclude table(s) data */
528  simple_string_list_append(&tabledata_exclude_patterns, optarg);
529  break;
530 
531  case 5: /* section */
533  break;
534 
535  case 6: /* snapshot */
536  dumpsnapshot = pg_strdup(optarg);
537  break;
538 
539  default:
540  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
541  exit_nicely(1);
542  }
543  }
544 
545  /*
546  * Non-option argument specifies database name as long as it wasn't
547  * already specified with -d / --dbname
548  */
549  if (optind < argc && dopt.dbname == NULL)
550  dopt.dbname = argv[optind++];
551 
552  /* Complain if any arguments remain */
553  if (optind < argc)
554  {
555  fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
556  progname, argv[optind]);
557  fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
558  progname);
559  exit_nicely(1);
560  }
561 
562  /* --column-inserts implies --inserts */
563  if (dopt.column_inserts)
564  dopt.dump_inserts = 1;
565 
566  /*
567  * Binary upgrade mode implies dumping sequence data even in schema-only
568  * mode. This is not exposed as a separate option, but kept separate
569  * internally for clarity.
570  */
571  if (dopt.binary_upgrade)
572  dopt.sequence_data = 1;
573 
574  if (dopt.dataOnly && dopt.schemaOnly)
575  {
576  write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
577  exit_nicely(1);
578  }
579 
580  if (dopt.dataOnly && dopt.outputClean)
581  {
582  write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
583  exit_nicely(1);
584  }
585 
586  if (dopt.dump_inserts && dopt.oids)
587  {
588  write_msg(NULL, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
589  write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
590  exit_nicely(1);
591  }
592 
593  if (dopt.if_exists && !dopt.outputClean)
594  exit_horribly(NULL, "option --if-exists requires option -c/--clean\n");
595 
596  /* Identify archive format to emit */
597  archiveFormat = parseArchiveFormat(format, &archiveMode);
598 
599  /* archiveFormat specific setup */
600  if (archiveFormat == archNull)
601  plainText = 1;
602 
603  /* Custom and directory formats are compressed by default, others not */
604  if (compressLevel == -1)
605  {
606 #ifdef HAVE_LIBZ
607  if (archiveFormat == archCustom || archiveFormat == archDirectory)
608  compressLevel = Z_DEFAULT_COMPRESSION;
609  else
610 #endif
611  compressLevel = 0;
612  }
613 
614 #ifndef HAVE_LIBZ
615  if (compressLevel != 0)
616  write_msg(NULL, "WARNING: requested compression not available in this "
617  "installation -- archive will be uncompressed\n");
618  compressLevel = 0;
619 #endif
620 
621  /*
622  * On Windows we can only have at most MAXIMUM_WAIT_OBJECTS (= 64 usually)
623  * parallel jobs because that's the maximum limit for the
624  * WaitForMultipleObjects() call.
625  */
626  if (numWorkers <= 0
627 #ifdef WIN32
628  || numWorkers > MAXIMUM_WAIT_OBJECTS
629 #endif
630  )
631  exit_horribly(NULL, "invalid number of parallel jobs\n");
632 
633  /* Parallel backup only in the directory archive format so far */
634  if (archiveFormat != archDirectory && numWorkers > 1)
635  exit_horribly(NULL, "parallel backup only supported by the directory format\n");
636 
637  /* Open the output file */
638  fout = CreateArchive(filename, archiveFormat, compressLevel, archiveMode,
640 
641  /* Make dump options accessible right away */
642  SetArchiveOptions(fout, &dopt, NULL);
643 
644  /* Register the cleanup hook */
645  on_exit_close_archive(fout);
646 
647  /* Let the archiver know how noisy to be */
648  fout->verbose = g_verbose;
649 
650  /*
651  * We allow the server to be back to 8.0, and up to any minor release of
652  * our own major version. (See also version check in pg_dumpall.c.)
653  */
654  fout->minRemoteVersion = 80000;
655  fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
656 
657  fout->numWorkers = numWorkers;
658 
659  /*
660  * Open the database using the Archiver, so it knows about it. Errors mean
661  * death.
662  */
663  ConnectDatabase(fout, dopt.dbname, dopt.pghost, dopt.pgport, dopt.username, prompt_password);
664  setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
665 
666  /*
667  * Disable security label support if server version < v9.1.x (prevents
668  * access to nonexistent pg_seclabel catalog)
669  */
670  if (fout->remoteVersion < 90100)
671  dopt.no_security_labels = 1;
672 
673  /*
674  * On hot standby slaves, never try to dump unlogged table data, since it
675  * will just throw an error.
676  */
677  if (fout->isStandby)
678  dopt.no_unlogged_table_data = true;
679 
680  /* Select the appropriate subquery to convert user IDs to names */
681  if (fout->remoteVersion >= 80100)
682  username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
683  else
684  username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
685 
686  /* check the version for the synchronized snapshots feature */
687  if (numWorkers > 1 && fout->remoteVersion < 90200
688  && !dopt.no_synchronized_snapshots)
690  "Synchronized snapshots are not supported by this server version.\n"
691  "Run with --no-synchronized-snapshots instead if you do not need\n"
692  "synchronized snapshots.\n");
693 
694  /* check the version when a snapshot is explicitly specified by user */
695  if (dumpsnapshot && fout->remoteVersion < 90200)
697  "Exported snapshots are not supported by this server version.\n");
698 
699  /*
700  * Find the last built-in OID, if needed (prior to 8.1)
701  *
702  * With 8.1 and above, we can just use FirstNormalObjectId - 1.
703  */
704  if (fout->remoteVersion < 80100)
706  PQdb(GetConnection(fout)));
707  else
709 
710  if (g_verbose)
711  write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
712 
713  /* Expand schema selection patterns into OID lists */
714  if (schema_include_patterns.head != NULL)
715  {
716  expand_schema_name_patterns(fout, &schema_include_patterns,
717  &schema_include_oids,
718  strict_names);
719  if (schema_include_oids.head == NULL)
720  exit_horribly(NULL, "no matching schemas were found\n");
721  }
722  expand_schema_name_patterns(fout, &schema_exclude_patterns,
723  &schema_exclude_oids,
724  false);
725  /* non-matching exclusion patterns aren't an error */
726 
727  /* Expand table selection patterns into OID lists */
728  if (table_include_patterns.head != NULL)
729  {
730  expand_table_name_patterns(fout, &table_include_patterns,
731  &table_include_oids,
732  strict_names);
733  if (table_include_oids.head == NULL)
734  exit_horribly(NULL, "no matching tables were found\n");
735  }
736  expand_table_name_patterns(fout, &table_exclude_patterns,
737  &table_exclude_oids,
738  false);
739 
740  expand_table_name_patterns(fout, &tabledata_exclude_patterns,
741  &tabledata_exclude_oids,
742  false);
743 
744  /* non-matching exclusion patterns aren't an error */
745 
746  /*
747  * Dumping blobs is the default for dumps where an inclusion switch is not
748  * used (an "include everything" dump). -B can be used to exclude blobs
749  * from those dumps. -b can be used to include blobs even when an
750  * inclusion switch is used.
751  *
752  * -s means "schema only" and blobs are data, not schema, so we never
753  * include blobs when -s is used.
754  */
755  if (dopt.include_everything && !dopt.schemaOnly && !dopt.dontOutputBlobs)
756  dopt.outputBlobs = true;
757 
758  /*
759  * Now scan the database and create DumpableObject structs for all the
760  * objects we intend to dump.
761  */
762  tblinfo = getSchemaData(fout, &numTables);
763 
764  if (fout->remoteVersion < 80400)
765  guessConstraintInheritance(tblinfo, numTables);
766 
767  if (!dopt.schemaOnly)
768  {
769  getTableData(&dopt, tblinfo, numTables, dopt.oids, 0);
771  if (dopt.dataOnly)
773  }
774 
775  if (dopt.schemaOnly && dopt.sequence_data)
776  getTableData(&dopt, tblinfo, numTables, dopt.oids, RELKIND_SEQUENCE);
777 
778  if (dopt.outputBlobs)
779  getBlobs(fout);
780 
781  /*
782  * Collect dependency data to assist in ordering the objects.
783  */
784  getDependencies(fout);
785 
786  /* Lastly, create dummy objects to represent the section boundaries */
787  boundaryObjs = createBoundaryObjects();
788 
789  /* Get pointers to all the known DumpableObjects */
790  getDumpableObjects(&dobjs, &numObjs);
791 
792  /*
793  * Add dummy dependencies to enforce the dump section ordering.
794  */
795  addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
796 
797  /*
798  * Sort the objects into a safe dump order (no forward references).
799  *
800  * We rely on dependency information to help us determine a safe order, so
801  * the initial sort is mostly for cosmetic purposes: we sort by name to
802  * ensure that logically identical schemas will dump identically.
803  */
804  sortDumpableObjectsByTypeName(dobjs, numObjs);
805 
806  /* If we do a parallel dump, we want the largest tables to go first */
807  if (archiveFormat == archDirectory && numWorkers > 1)
808  sortDataAndIndexObjectsBySize(dobjs, numObjs);
809 
810  sortDumpableObjects(dobjs, numObjs,
811  boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
812 
813  /*
814  * Create archive TOC entries for all the objects to be dumped, in a safe
815  * order.
816  */
817 
818  /* First the special ENCODING and STDSTRINGS entries. */
819  dumpEncoding(fout);
820  dumpStdStrings(fout);
821 
822  /* The database item is always next, unless we don't want it at all */
823  if (dopt.include_everything && !dopt.dataOnly)
824  dumpDatabase(fout);
825 
826  /* Now the rearrangeable objects. */
827  for (i = 0; i < numObjs; i++)
828  dumpDumpableObject(fout, dobjs[i]);
829 
830  /*
831  * Set up options info to ensure we dump what we want.
832  */
833  ropt = NewRestoreOptions();
834  ropt->filename = filename;
835 
836  /* if you change this list, see dumpOptionsFromRestoreOptions */
837  ropt->dropSchema = dopt.outputClean;
838  ropt->dataOnly = dopt.dataOnly;
839  ropt->schemaOnly = dopt.schemaOnly;
840  ropt->if_exists = dopt.if_exists;
841  ropt->column_inserts = dopt.column_inserts;
842  ropt->dumpSections = dopt.dumpSections;
843  ropt->aclsSkip = dopt.aclsSkip;
844  ropt->superuser = dopt.outputSuperuser;
845  ropt->createDB = dopt.outputCreateDB;
846  ropt->noOwner = dopt.outputNoOwner;
847  ropt->noTablespace = dopt.outputNoTablespaces;
848  ropt->disable_triggers = dopt.disable_triggers;
849  ropt->use_setsessauth = dopt.use_setsessauth;
851  ropt->dump_inserts = dopt.dump_inserts;
853  ropt->lockWaitTimeout = dopt.lockWaitTimeout;
856  ropt->sequence_data = dopt.sequence_data;
858 
859  if (compressLevel == -1)
860  ropt->compression = 0;
861  else
862  ropt->compression = compressLevel;
863 
864  ropt->suppressDumpWarnings = true; /* We've already shown them */
865 
866  SetArchiveOptions(fout, &dopt, ropt);
867 
868  /* Mark which entries should be output */
870 
871  /*
872  * The archive's TOC entries are now marked as to which ones will actually
873  * be output, so we can set up their dependency lists properly. This isn't
874  * necessary for plain-text output, though.
875  */
876  if (!plainText)
878 
879  /*
880  * And finally we can do the actual output.
881  *
882  * Note: for non-plain-text output formats, the output file is written
883  * inside CloseArchive(). This is, um, bizarre; but not worth changing
884  * right now.
885  */
886  if (plainText)
887  RestoreArchive(fout);
888 
889  CloseArchive(fout);
890 
891  exit_nicely(0);
892 }
893 
894 
895 static void
896 help(const char *progname)
897 {
898  printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
899  printf(_("Usage:\n"));
900  printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
901 
902  printf(_("\nGeneral options:\n"));
903  printf(_(" -f, --file=FILENAME output file or directory name\n"));
904  printf(_(" -F, --format=c|d|t|p output file format (custom, directory, tar,\n"
905  " plain text (default))\n"));
906  printf(_(" -j, --jobs=NUM use this many parallel jobs to dump\n"));
907  printf(_(" -v, --verbose verbose mode\n"));
908  printf(_(" -V, --version output version information, then exit\n"));
909  printf(_(" -Z, --compress=0-9 compression level for compressed formats\n"));
910  printf(_(" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
911  printf(_(" -?, --help show this help, then exit\n"));
912 
913  printf(_("\nOptions controlling the output content:\n"));
914  printf(_(" -a, --data-only dump only the data, not the schema\n"));
915  printf(_(" -b, --blobs include large objects in dump\n"));
916  printf(_(" -B, --no-blobs exclude large objects in dump\n"));
917  printf(_(" -c, --clean clean (drop) database objects before recreating\n"));
918  printf(_(" -C, --create include commands to create database in dump\n"));
919  printf(_(" -E, --encoding=ENCODING dump the data in encoding ENCODING\n"));
920  printf(_(" -n, --schema=SCHEMA dump the named schema(s) only\n"));
921  printf(_(" -N, --exclude-schema=SCHEMA do NOT dump the named schema(s)\n"));
922  printf(_(" -o, --oids include OIDs in dump\n"));
923  printf(_(" -O, --no-owner skip restoration of object ownership in\n"
924  " plain-text format\n"));
925  printf(_(" -s, --schema-only dump only the schema, no data\n"));
926  printf(_(" -S, --superuser=NAME superuser user name to use in plain-text format\n"));
927  printf(_(" -t, --table=TABLE dump the named table(s) only\n"));
928  printf(_(" -T, --exclude-table=TABLE do NOT dump the named table(s)\n"));
929  printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
930  printf(_(" --binary-upgrade for use by upgrade utilities only\n"));
931  printf(_(" --column-inserts dump data as INSERT commands with column names\n"));
932  printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n"));
933  printf(_(" --disable-triggers disable triggers during data-only restore\n"));
934  printf(_(" --enable-row-security enable row security (dump only content user has\n"
935  " access to)\n"));
936  printf(_(" --exclude-table-data=TABLE do NOT dump data for the named table(s)\n"));
937  printf(_(" --if-exists use IF EXISTS when dropping objects\n"));
938  printf(_(" --include-subscriptions dump logical replication subscriptions\n"));
939  printf(_(" --inserts dump data as INSERT commands, rather than COPY\n"));
940  printf(_(" --no-create-subscription-slots\n"
941  " do not create replication slots for subscriptions\n"));
942  printf(_(" --no-security-labels do not dump security label assignments\n"));
943  printf(_(" --no-synchronized-snapshots do not use synchronized snapshots in parallel jobs\n"));
944  printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
945  printf(_(" --no-unlogged-table-data do not dump unlogged table data\n"));
946  printf(_(" --quote-all-identifiers quote all identifiers, even if not key words\n"));
947  printf(_(" --section=SECTION dump named section (pre-data, data, or post-data)\n"));
948  printf(_(" --serializable-deferrable wait until the dump can run without anomalies\n"));
949  printf(_(" --snapshot=SNAPSHOT use given snapshot for the dump\n"));
950  printf(_(" --strict-names require table and/or schema include patterns to\n"
951  " match at least one entity each\n"));
952  printf(_(" --use-set-session-authorization\n"
953  " use SET SESSION AUTHORIZATION commands instead of\n"
954  " ALTER OWNER commands to set ownership\n"));
955 
956  printf(_("\nConnection options:\n"));
957  printf(_(" -d, --dbname=DBNAME database to dump\n"));
958  printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
959  printf(_(" -p, --port=PORT database server port number\n"));
960  printf(_(" -U, --username=NAME connect as specified database user\n"));
961  printf(_(" -w, --no-password never prompt for password\n"));
962  printf(_(" -W, --password force password prompt (should happen automatically)\n"));
963  printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
964 
965  printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
966  "variable value is used.\n\n"));
967  printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
968 }
969 
970 static void
971 setup_connection(Archive *AH, const char *dumpencoding,
972  const char *dumpsnapshot, char *use_role)
973 {
974  DumpOptions *dopt = AH->dopt;
975  PGconn *conn = GetConnection(AH);
976  const char *std_strings;
977 
978  /*
979  * Set the client encoding if requested.
980  */
981  if (dumpencoding)
982  {
983  if (PQsetClientEncoding(conn, dumpencoding) < 0)
984  exit_horribly(NULL, "invalid client encoding \"%s\" specified\n",
985  dumpencoding);
986  }
987 
988  /*
989  * Get the active encoding and the standard_conforming_strings setting, so
990  * we know how to escape strings.
991  */
992  AH->encoding = PQclientEncoding(conn);
993 
994  std_strings = PQparameterStatus(conn, "standard_conforming_strings");
995  AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
996 
997  /*
998  * Set the role if requested. In a parallel dump worker, we'll be passed
999  * use_role == NULL, but AH->use_role is already set (if user specified it
1000  * originally) and we should use that.
1001  */
1002  if (!use_role && AH->use_role)
1003  use_role = AH->use_role;
1004 
1005  /* Set the role if requested */
1006  if (use_role && AH->remoteVersion >= 80100)
1007  {
1008  PQExpBuffer query = createPQExpBuffer();
1009 
1010  appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
1011  ExecuteSqlStatement(AH, query->data);
1012  destroyPQExpBuffer(query);
1013 
1014  /* save it for possible later use by parallel workers */
1015  if (!AH->use_role)
1016  AH->use_role = pg_strdup(use_role);
1017  }
1018 
1019  /* Set the datestyle to ISO to ensure the dump's portability */
1020  ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
1021 
1022  /* Likewise, avoid using sql_standard intervalstyle */
1023  if (AH->remoteVersion >= 80400)
1024  ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
1025 
1026  /*
1027  * Set extra_float_digits so that we can dump float data exactly (given
1028  * correctly implemented float I/O code, anyway)
1029  */
1030  if (AH->remoteVersion >= 90000)
1031  ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
1032  else
1033  ExecuteSqlStatement(AH, "SET extra_float_digits TO 2");
1034 
1035  /*
1036  * If synchronized scanning is supported, disable it, to prevent
1037  * unpredictable changes in row ordering across a dump and reload.
1038  */
1039  if (AH->remoteVersion >= 80300)
1040  ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
1041 
1042  /*
1043  * Disable timeouts if supported.
1044  */
1045  ExecuteSqlStatement(AH, "SET statement_timeout = 0");
1046  if (AH->remoteVersion >= 90300)
1047  ExecuteSqlStatement(AH, "SET lock_timeout = 0");
1048  if (AH->remoteVersion >= 90600)
1049  ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
1050 
1051  /*
1052  * Quote all identifiers, if requested.
1053  */
1054  if (quote_all_identifiers && AH->remoteVersion >= 90100)
1055  ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1056 
1057  /*
1058  * Adjust row-security mode, if supported.
1059  */
1060  if (AH->remoteVersion >= 90500)
1061  {
1062  if (dopt->enable_row_security)
1063  ExecuteSqlStatement(AH, "SET row_security = on");
1064  else
1065  ExecuteSqlStatement(AH, "SET row_security = off");
1066  }
1067 
1068  /*
1069  * Start transaction-snapshot mode transaction to dump consistent data.
1070  */
1071  ExecuteSqlStatement(AH, "BEGIN");
1072  if (AH->remoteVersion >= 90100)
1073  {
1074  /*
1075  * To support the combination of serializable_deferrable with the jobs
1076  * option we use REPEATABLE READ for the worker connections that are
1077  * passed a snapshot. As long as the snapshot is acquired in a
1078  * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
1079  * REPEATABLE READ transaction provides the appropriate integrity
1080  * guarantees. This is a kluge, but safe for back-patching.
1081  */
1082  if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
1084  "SET TRANSACTION ISOLATION LEVEL "
1085  "SERIALIZABLE, READ ONLY, DEFERRABLE");
1086  else
1088  "SET TRANSACTION ISOLATION LEVEL "
1089  "REPEATABLE READ, READ ONLY");
1090  }
1091  else
1092  {
1094  "SET TRANSACTION ISOLATION LEVEL "
1095  "SERIALIZABLE, READ ONLY");
1096  }
1097 
1098  /*
1099  * If user specified a snapshot to use, select that. In a parallel dump
1100  * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
1101  * is already set (if the server can handle it) and we should use that.
1102  */
1103  if (dumpsnapshot)
1104  AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
1105 
1106  if (AH->sync_snapshot_id)
1107  {
1108  PQExpBuffer query = createPQExpBuffer();
1109 
1110  appendPQExpBuffer(query, "SET TRANSACTION SNAPSHOT ");
1111  appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
1112  ExecuteSqlStatement(AH, query->data);
1113  destroyPQExpBuffer(query);
1114  }
1115  else if (AH->numWorkers > 1 &&
1116  AH->remoteVersion >= 90200 &&
1118  {
1119  if (AH->isStandby)
1121  "Synchronized snapshots are not supported on standby servers.\n"
1122  "Run with --no-synchronized-snapshots instead if you do not need\n"
1123  "synchronized snapshots.\n");
1124 
1125 
1127  }
1128 }
1129 
1130 /* Set up connection for a parallel worker process */
1131 static void
1133 {
1134  /*
1135  * We want to re-select all the same values the master connection is
1136  * using. We'll have inherited directly-usable values in
1137  * AH->sync_snapshot_id and AH->use_role, but we need to translate the
1138  * inherited encoding value back to a string to pass to setup_connection.
1139  */
1140  setup_connection(AH,
1142  NULL,
1143  NULL);
1144 }
1145 
1146 static char *
1148 {
1149  char *query = "SELECT pg_catalog.pg_export_snapshot()";
1150  char *result;
1151  PGresult *res;
1152 
1153  res = ExecuteSqlQueryForSingleRow(fout, query);
1154  result = pg_strdup(PQgetvalue(res, 0, 0));
1155  PQclear(res);
1156 
1157  return result;
1158 }
1159 
1160 static ArchiveFormat
1162 {
1163  ArchiveFormat archiveFormat;
1164 
1165  *mode = archModeWrite;
1166 
1167  if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1168  {
1169  /* This is used by pg_dumpall, and is not documented */
1170  archiveFormat = archNull;
1171  *mode = archModeAppend;
1172  }
1173  else if (pg_strcasecmp(format, "c") == 0)
1174  archiveFormat = archCustom;
1175  else if (pg_strcasecmp(format, "custom") == 0)
1176  archiveFormat = archCustom;
1177  else if (pg_strcasecmp(format, "d") == 0)
1178  archiveFormat = archDirectory;
1179  else if (pg_strcasecmp(format, "directory") == 0)
1180  archiveFormat = archDirectory;
1181  else if (pg_strcasecmp(format, "p") == 0)
1182  archiveFormat = archNull;
1183  else if (pg_strcasecmp(format, "plain") == 0)
1184  archiveFormat = archNull;
1185  else if (pg_strcasecmp(format, "t") == 0)
1186  archiveFormat = archTar;
1187  else if (pg_strcasecmp(format, "tar") == 0)
1188  archiveFormat = archTar;
1189  else
1190  exit_horribly(NULL, "invalid output format \"%s\" specified\n", format);
1191  return archiveFormat;
1192 }
1193 
1194 /*
1195  * Find the OIDs of all schemas matching the given list of patterns,
1196  * and append them to the given OID list.
1197  */
1198 static void
1200  SimpleStringList *patterns,
1201  SimpleOidList *oids,
1202  bool strict_names)
1203 {
1204  PQExpBuffer query;
1205  PGresult *res;
1206  SimpleStringListCell *cell;
1207  int i;
1208 
1209  if (patterns->head == NULL)
1210  return; /* nothing to do */
1211 
1212  query = createPQExpBuffer();
1213 
1214  /*
1215  * The loop below runs multiple SELECTs might sometimes result in
1216  * duplicate entries in the OID list, but we don't care.
1217  */
1218 
1219  for (cell = patterns->head; cell; cell = cell->next)
1220  {
1221  appendPQExpBuffer(query,
1222  "SELECT oid FROM pg_catalog.pg_namespace n\n");
1223  processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1224  false, NULL, "n.nspname", NULL, NULL);
1225 
1226  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1227  if (strict_names && PQntuples(res) == 0)
1228  exit_horribly(NULL, "no matching schemas were found for pattern \"%s\"\n", cell->val);
1229 
1230  for (i = 0; i < PQntuples(res); i++)
1231  {
1232  simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1233  }
1234 
1235  PQclear(res);
1236  resetPQExpBuffer(query);
1237  }
1238 
1239  destroyPQExpBuffer(query);
1240 }
1241 
1242 /*
1243  * Find the OIDs of all tables matching the given list of patterns,
1244  * and append them to the given OID list.
1245  */
1246 static void
1248  SimpleStringList *patterns, SimpleOidList *oids,
1249  bool strict_names)
1250 {
1251  PQExpBuffer query;
1252  PGresult *res;
1253  SimpleStringListCell *cell;
1254  int i;
1255 
1256  if (patterns->head == NULL)
1257  return; /* nothing to do */
1258 
1259  query = createPQExpBuffer();
1260 
1261  /*
1262  * this might sometimes result in duplicate entries in the OID list, but
1263  * we don't care.
1264  */
1265 
1266  for (cell = patterns->head; cell; cell = cell->next)
1267  {
1268  appendPQExpBuffer(query,
1269  "SELECT c.oid"
1270  "\nFROM pg_catalog.pg_class c"
1271  "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
1272  "\nWHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c')\n",
1276  processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1277  false, "n.nspname", "c.relname", NULL,
1278  "pg_catalog.pg_table_is_visible(c.oid)");
1279 
1280  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1281  if (strict_names && PQntuples(res) == 0)
1282  exit_horribly(NULL, "no matching tables were found for pattern \"%s\"\n", cell->val);
1283 
1284  for (i = 0; i < PQntuples(res); i++)
1285  {
1286  simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1287  }
1288 
1289  PQclear(res);
1290  resetPQExpBuffer(query);
1291  }
1292 
1293  destroyPQExpBuffer(query);
1294 }
1295 
1296 /*
1297  * checkExtensionMembership
1298  * Determine whether object is an extension member, and if so,
1299  * record an appropriate dependency and set the object's dump flag.
1300  *
1301  * It's important to call this for each object that could be an extension
1302  * member. Generally, we integrate this with determining the object's
1303  * to-be-dumped-ness, since extension membership overrides other rules for that.
1304  *
1305  * Returns true if object is an extension member, else false.
1306  */
1307 static bool
1309 {
1310  ExtensionInfo *ext = findOwningExtension(dobj->catId);
1311 
1312  if (ext == NULL)
1313  return false;
1314 
1315  dobj->ext_member = true;
1316 
1317  /* Record dependency so that getDependencies needn't deal with that */
1318  addObjectDependency(dobj, ext->dobj.dumpId);
1319 
1320  /*
1321  * In 9.6 and above, mark the member object to have any non-initial ACL,
1322  * policies, and security labels dumped.
1323  *
1324  * Note that any initial ACLs (see pg_init_privs) will be removed when we
1325  * extract the information about the object. We don't provide support for
1326  * initial policies and security labels and it seems unlikely for those to
1327  * ever exist, but we may have to revisit this later.
1328  *
1329  * Prior to 9.6, we do not include any extension member components.
1330  *
1331  * In binary upgrades, we still dump all components of the members
1332  * individually, since the idea is to exactly reproduce the database
1333  * contents rather than replace the extension contents with something
1334  * different.
1335  */
1336  if (fout->dopt->binary_upgrade)
1337  dobj->dump = ext->dobj.dump;
1338  else
1339  {
1340  if (fout->remoteVersion < 90600)
1341  dobj->dump = DUMP_COMPONENT_NONE;
1342  else
1343  dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL |
1346  }
1347 
1348  return true;
1349 }
1350 
1351 /*
1352  * selectDumpableNamespace: policy-setting subroutine
1353  * Mark a namespace as to be dumped or not
1354  */
1355 static void
1357 {
1358  /*
1359  * If specific tables are being dumped, do not dump any complete
1360  * namespaces. If specific namespaces are being dumped, dump just those
1361  * namespaces. Otherwise, dump all non-system namespaces.
1362  */
1363  if (table_include_oids.head != NULL)
1364  nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1365  else if (schema_include_oids.head != NULL)
1366  nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
1367  simple_oid_list_member(&schema_include_oids,
1368  nsinfo->dobj.catId.oid) ?
1370  else if (fout->remoteVersion >= 90600 &&
1371  strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
1372  {
1373  /*
1374  * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
1375  * they are interesting (and not the original ACLs which were set at
1376  * initdb time, see pg_init_privs).
1377  */
1378  nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1379  }
1380  else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1381  strcmp(nsinfo->dobj.name, "information_schema") == 0)
1382  {
1383  /* Other system schemas don't get dumped */
1384  nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1385  }
1386  else
1387  nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
1388 
1389  /*
1390  * In any case, a namespace can be excluded by an exclusion switch
1391  */
1392  if (nsinfo->dobj.dump_contains &&
1393  simple_oid_list_member(&schema_exclude_oids,
1394  nsinfo->dobj.catId.oid))
1395  nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1396 
1397  /*
1398  * If the schema belongs to an extension, allow extension membership to
1399  * override the dump decision for the schema itself. However, this does
1400  * not change dump_contains, so this won't change what we do with objects
1401  * within the schema. (If they belong to the extension, they'll get
1402  * suppressed by it, otherwise not.)
1403  */
1404  (void) checkExtensionMembership(&nsinfo->dobj, fout);
1405 }
1406 
1407 /*
1408  * selectDumpableTable: policy-setting subroutine
1409  * Mark a table as to be dumped or not
1410  */
1411 static void
1413 {
1414  if (checkExtensionMembership(&tbinfo->dobj, fout))
1415  return; /* extension membership overrides all else */
1416 
1417  /*
1418  * If specific tables are being dumped, dump just those tables; else, dump
1419  * according to the parent namespace's dump flag.
1420  */
1421  if (table_include_oids.head != NULL)
1422  tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1423  tbinfo->dobj.catId.oid) ?
1425  else
1426  tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
1427 
1428  /*
1429  * In any case, a table can be excluded by an exclusion switch
1430  */
1431  if (tbinfo->dobj.dump &&
1432  simple_oid_list_member(&table_exclude_oids,
1433  tbinfo->dobj.catId.oid))
1434  tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
1435 }
1436 
1437 /*
1438  * selectDumpableType: policy-setting subroutine
1439  * Mark a type as to be dumped or not
1440  *
1441  * If it's a table's rowtype or an autogenerated array type, we also apply a
1442  * special type code to facilitate sorting into the desired order. (We don't
1443  * want to consider those to be ordinary types because that would bring tables
1444  * up into the datatype part of the dump order.) We still set the object's
1445  * dump flag; that's not going to cause the dummy type to be dumped, but we
1446  * need it so that casts involving such types will be dumped correctly -- see
1447  * dumpCast. This means the flag should be set the same as for the underlying
1448  * object (the table or base type).
1449  */
1450 static void
1452 {
1453  /* skip complex types, except for standalone composite types */
1454  if (OidIsValid(tyinfo->typrelid) &&
1456  {
1457  TableInfo *tytable = findTableByOid(tyinfo->typrelid);
1458 
1459  tyinfo->dobj.objType = DO_DUMMY_TYPE;
1460  if (tytable != NULL)
1461  tyinfo->dobj.dump = tytable->dobj.dump;
1462  else
1463  tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
1464  return;
1465  }
1466 
1467  /* skip auto-generated array types */
1468  if (tyinfo->isArray)
1469  {
1470  tyinfo->dobj.objType = DO_DUMMY_TYPE;
1471 
1472  /*
1473  * Fall through to set the dump flag; we assume that the subsequent
1474  * rules will do the same thing as they would for the array's base
1475  * type. (We cannot reliably look up the base type here, since
1476  * getTypes may not have processed it yet.)
1477  */
1478  }
1479 
1480  if (checkExtensionMembership(&tyinfo->dobj, fout))
1481  return; /* extension membership overrides all else */
1482 
1483  /* Dump based on if the contents of the namespace are being dumped */
1484  tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
1485 }
1486 
1487 /*
1488  * selectDumpableDefaultACL: policy-setting subroutine
1489  * Mark a default ACL as to be dumped or not
1490  *
1491  * For per-schema default ACLs, dump if the schema is to be dumped.
1492  * Otherwise dump if we are dumping "everything". Note that dataOnly
1493  * and aclsSkip are checked separately.
1494  */
1495 static void
1497 {
1498  /* Default ACLs can't be extension members */
1499 
1500  if (dinfo->dobj.namespace)
1501  /* default ACLs are considered part of the namespace */
1502  dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
1503  else
1504  dinfo->dobj.dump = dopt->include_everything ?
1506 }
1507 
1508 /*
1509  * selectDumpableCast: policy-setting subroutine
1510  * Mark a cast as to be dumped or not
1511  *
1512  * Casts do not belong to any particular namespace (since they haven't got
1513  * names), nor do they have identifiable owners. To distinguish user-defined
1514  * casts from built-in ones, we must resort to checking whether the cast's
1515  * OID is in the range reserved for initdb.
1516  */
1517 static void
1519 {
1520  if (checkExtensionMembership(&cast->dobj, fout))
1521  return; /* extension membership overrides all else */
1522 
1523  /*
1524  * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
1525  * support ACLs currently.
1526  */
1527  if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1528  cast->dobj.dump = DUMP_COMPONENT_NONE;
1529  else
1530  cast->dobj.dump = fout->dopt->include_everything ?
1532 }
1533 
1534 /*
1535  * selectDumpableProcLang: policy-setting subroutine
1536  * Mark a procedural language as to be dumped or not
1537  *
1538  * Procedural languages do not belong to any particular namespace. To
1539  * identify built-in languages, we must resort to checking whether the
1540  * language's OID is in the range reserved for initdb.
1541  */
1542 static void
1544 {
1545  if (checkExtensionMembership(&plang->dobj, fout))
1546  return; /* extension membership overrides all else */
1547 
1548  /*
1549  * Only include procedural languages when we are dumping everything.
1550  *
1551  * For from-initdb procedural languages, only include ACLs, as we do for
1552  * the pg_catalog namespace. We need this because procedural languages do
1553  * not live in any namespace.
1554  */
1555  if (!fout->dopt->include_everything)
1556  plang->dobj.dump = DUMP_COMPONENT_NONE;
1557  else
1558  {
1559  if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1560  plang->dobj.dump = fout->remoteVersion < 90600 ?
1562  else
1563  plang->dobj.dump = DUMP_COMPONENT_ALL;
1564  }
1565 }
1566 
1567 /*
1568  * selectDumpableAccessMethod: policy-setting subroutine
1569  * Mark an access method as to be dumped or not
1570  *
1571  * Access methods do not belong to any particular namespace. To identify
1572  * built-in access methods, we must resort to checking whether the
1573  * method's OID is in the range reserved for initdb.
1574  */
1575 static void
1577 {
1578  if (checkExtensionMembership(&method->dobj, fout))
1579  return; /* extension membership overrides all else */
1580 
1581  /*
1582  * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
1583  * they do not support ACLs currently.
1584  */
1585  if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1586  method->dobj.dump = DUMP_COMPONENT_NONE;
1587  else
1588  method->dobj.dump = fout->dopt->include_everything ?
1590 }
1591 
1592 /*
1593  * selectDumpableExtension: policy-setting subroutine
1594  * Mark an extension as to be dumped or not
1595  *
1596  * Normally, we dump all extensions, or none of them if include_everything
1597  * is false (i.e., a --schema or --table switch was given). However, in
1598  * binary-upgrade mode it's necessary to skip built-in extensions, since we
1599  * assume those will already be installed in the target database. We identify
1600  * such extensions by their having OIDs in the range reserved for initdb.
1601  */
1602 static void
1604 {
1605  /*
1606  * Use DUMP_COMPONENT_ACL for from-initdb extensions, to allow users to
1607  * change permissions on those objects, if they wish to, and have those
1608  * changes preserved.
1609  */
1610  if (dopt->binary_upgrade && extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1611  extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
1612  else
1613  extinfo->dobj.dump = extinfo->dobj.dump_contains =
1616 }
1617 
1618 /*
1619  * selectDumpableObject: policy-setting subroutine
1620  * Mark a generic dumpable object as to be dumped or not
1621  *
1622  * Use this only for object types without a special-case routine above.
1623  */
1624 static void
1626 {
1627  if (checkExtensionMembership(dobj, fout))
1628  return; /* extension membership overrides all else */
1629 
1630  /*
1631  * Default policy is to dump if parent namespace is dumpable, or for
1632  * non-namespace-associated items, dump if we're dumping "everything".
1633  */
1634  if (dobj->namespace)
1635  dobj->dump = dobj->namespace->dobj.dump_contains;
1636  else
1637  dobj->dump = fout->dopt->include_everything ?
1639 }
1640 
1641 /*
1642  * Dump a table's contents for loading using the COPY command
1643  * - this routine is called by the Archiver when it wants the table
1644  * to be dumped.
1645  */
1646 
1647 static int
1648 dumpTableData_copy(Archive *fout, void *dcontext)
1649 {
1650  TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1651  TableInfo *tbinfo = tdinfo->tdtable;
1652  const char *classname = tbinfo->dobj.name;
1653  const bool hasoids = tbinfo->hasoids;
1654  const bool oids = tdinfo->oids;
1656 
1657  /*
1658  * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
1659  * which uses it already.
1660  */
1661  PQExpBuffer clistBuf = createPQExpBuffer();
1662  PGconn *conn = GetConnection(fout);
1663  PGresult *res;
1664  int ret;
1665  char *copybuf;
1666  const char *column_list;
1667 
1668  if (g_verbose)
1669  write_msg(NULL, "dumping contents of table \"%s.%s\"\n",
1670  tbinfo->dobj.namespace->dobj.name, classname);
1671 
1672  /*
1673  * Make sure we are in proper schema. We will qualify the table name
1674  * below anyway (in case its name conflicts with a pg_catalog table); but
1675  * this ensures reproducible results in case the table contains regproc,
1676  * regclass, etc columns.
1677  */
1678  selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
1679 
1680  /*
1681  * Specify the column list explicitly so that we have no possibility of
1682  * retrieving data in the wrong column order. (The default column
1683  * ordering of COPY will not be what we want in certain corner cases
1684  * involving ADD COLUMN and inheritance.)
1685  */
1686  column_list = fmtCopyColumnList(tbinfo, clistBuf);
1687 
1688  if (oids && hasoids)
1689  {
1690  appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
1692  tbinfo->dobj.namespace->dobj.name,
1693  classname),
1694  column_list);
1695  }
1696  else if (tdinfo->filtercond)
1697  {
1698  /* Note: this syntax is only supported in 8.2 and up */
1699  appendPQExpBufferStr(q, "COPY (SELECT ");
1700  /* klugery to get rid of parens in column list */
1701  if (strlen(column_list) > 2)
1702  {
1703  appendPQExpBufferStr(q, column_list + 1);
1704  q->data[q->len - 1] = ' ';
1705  }
1706  else
1707  appendPQExpBufferStr(q, "* ");
1708  appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
1710  tbinfo->dobj.namespace->dobj.name,
1711  classname),
1712  tdinfo->filtercond);
1713  }
1714  else
1715  {
1716  appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1718  tbinfo->dobj.namespace->dobj.name,
1719  classname),
1720  column_list);
1721  }
1722  res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
1723  PQclear(res);
1724  destroyPQExpBuffer(clistBuf);
1725 
1726  for (;;)
1727  {
1728  ret = PQgetCopyData(conn, &copybuf, 0);
1729 
1730  if (ret < 0)
1731  break; /* done or error */
1732 
1733  if (copybuf)
1734  {
1735  WriteData(fout, copybuf, ret);
1736  PQfreemem(copybuf);
1737  }
1738 
1739  /* ----------
1740  * THROTTLE:
1741  *
1742  * There was considerable discussion in late July, 2000 regarding
1743  * slowing down pg_dump when backing up large tables. Users with both
1744  * slow & fast (multi-processor) machines experienced performance
1745  * degradation when doing a backup.
1746  *
1747  * Initial attempts based on sleeping for a number of ms for each ms
1748  * of work were deemed too complex, then a simple 'sleep in each loop'
1749  * implementation was suggested. The latter failed because the loop
1750  * was too tight. Finally, the following was implemented:
1751  *
1752  * If throttle is non-zero, then
1753  * See how long since the last sleep.
1754  * Work out how long to sleep (based on ratio).
1755  * If sleep is more than 100ms, then
1756  * sleep
1757  * reset timer
1758  * EndIf
1759  * EndIf
1760  *
1761  * where the throttle value was the number of ms to sleep per ms of
1762  * work. The calculation was done in each loop.
1763  *
1764  * Most of the hard work is done in the backend, and this solution
1765  * still did not work particularly well: on slow machines, the ratio
1766  * was 50:1, and on medium paced machines, 1:1, and on fast
1767  * multi-processor machines, it had little or no effect, for reasons
1768  * that were unclear.
1769  *
1770  * Further discussion ensued, and the proposal was dropped.
1771  *
1772  * For those people who want this feature, it can be implemented using
1773  * gettimeofday in each loop, calculating the time since last sleep,
1774  * multiplying that by the sleep ratio, then if the result is more
1775  * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1776  * function to sleep for a subsecond period ie.
1777  *
1778  * select(0, NULL, NULL, NULL, &tvi);
1779  *
1780  * This will return after the interval specified in the structure tvi.
1781  * Finally, call gettimeofday again to save the 'last sleep time'.
1782  * ----------
1783  */
1784  }
1785  archprintf(fout, "\\.\n\n\n");
1786 
1787  if (ret == -2)
1788  {
1789  /* copy data transfer failed */
1790  write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
1791  write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1792  write_msg(NULL, "The command was: %s\n", q->data);
1793  exit_nicely(1);
1794  }
1795 
1796  /* Check command status and return to normal libpq state */
1797  res = PQgetResult(conn);
1798  if (PQresultStatus(res) != PGRES_COMMAND_OK)
1799  {
1800  write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetResult() failed.\n", classname);
1801  write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1802  write_msg(NULL, "The command was: %s\n", q->data);
1803  exit_nicely(1);
1804  }
1805  PQclear(res);
1806 
1807  /* Do this to ensure we've pumped libpq back to idle state */
1808  if (PQgetResult(conn) != NULL)
1809  write_msg(NULL, "WARNING: unexpected extra results during COPY of table \"%s\"\n",
1810  classname);
1811 
1812  destroyPQExpBuffer(q);
1813  return 1;
1814 }
1815 
1816 /*
1817  * Dump table data using INSERT commands.
1818  *
1819  * Caution: when we restore from an archive file direct to database, the
1820  * INSERT commands emitted by this function have to be parsed by
1821  * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
1822  * E'' strings, or dollar-quoted strings. So don't emit anything like that.
1823  */
1824 static int
1825 dumpTableData_insert(Archive *fout, void *dcontext)
1826 {
1827  TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1828  TableInfo *tbinfo = tdinfo->tdtable;
1829  const char *classname = tbinfo->dobj.name;
1830  DumpOptions *dopt = fout->dopt;
1832  PQExpBuffer insertStmt = NULL;
1833  PGresult *res;
1834  int tuple;
1835  int nfields;
1836  int field;
1837 
1838  /*
1839  * Make sure we are in proper schema. We will qualify the table name
1840  * below anyway (in case its name conflicts with a pg_catalog table); but
1841  * this ensures reproducible results in case the table contains regproc,
1842  * regclass, etc columns.
1843  */
1844  selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
1845 
1846  appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1847  "SELECT * FROM ONLY %s",
1849  tbinfo->dobj.namespace->dobj.name,
1850  classname));
1851  if (tdinfo->filtercond)
1852  appendPQExpBuffer(q, " %s", tdinfo->filtercond);
1853 
1854  ExecuteSqlStatement(fout, q->data);
1855 
1856  while (1)
1857  {
1858  res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
1859  PGRES_TUPLES_OK);
1860  nfields = PQnfields(res);
1861  for (tuple = 0; tuple < PQntuples(res); tuple++)
1862  {
1863  /*
1864  * First time through, we build as much of the INSERT statement as
1865  * possible in "insertStmt", which we can then just print for each
1866  * line. If the table happens to have zero columns then this will
1867  * be a complete statement, otherwise it will end in "VALUES(" and
1868  * be ready to have the row's column values appended.
1869  */
1870  if (insertStmt == NULL)
1871  {
1872  insertStmt = createPQExpBuffer();
1873  appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
1874  fmtId(classname));
1875 
1876  /* corner case for zero-column table */
1877  if (nfields == 0)
1878  {
1879  appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
1880  }
1881  else
1882  {
1883  /* append the list of column names if required */
1884  if (dopt->column_inserts)
1885  {
1886  appendPQExpBufferChar(insertStmt, '(');
1887  for (field = 0; field < nfields; field++)
1888  {
1889  if (field > 0)
1890  appendPQExpBufferStr(insertStmt, ", ");
1891  appendPQExpBufferStr(insertStmt,
1892  fmtId(PQfname(res, field)));
1893  }
1894  appendPQExpBufferStr(insertStmt, ") ");
1895  }
1896 
1897  appendPQExpBufferStr(insertStmt, "VALUES (");
1898  }
1899  }
1900 
1901  archputs(insertStmt->data, fout);
1902 
1903  /* if it is zero-column table then we're done */
1904  if (nfields == 0)
1905  continue;
1906 
1907  for (field = 0; field < nfields; field++)
1908  {
1909  if (field > 0)
1910  archputs(", ", fout);
1911  if (PQgetisnull(res, tuple, field))
1912  {
1913  archputs("NULL", fout);
1914  continue;
1915  }
1916 
1917  /* XXX This code is partially duplicated in ruleutils.c */
1918  switch (PQftype(res, field))
1919  {
1920  case INT2OID:
1921  case INT4OID:
1922  case INT8OID:
1923  case OIDOID:
1924  case FLOAT4OID:
1925  case FLOAT8OID:
1926  case NUMERICOID:
1927  {
1928  /*
1929  * These types are printed without quotes unless
1930  * they contain values that aren't accepted by the
1931  * scanner unquoted (e.g., 'NaN'). Note that
1932  * strtod() and friends might accept NaN, so we
1933  * can't use that to test.
1934  *
1935  * In reality we only need to defend against
1936  * infinity and NaN, so we need not get too crazy
1937  * about pattern matching here.
1938  */
1939  const char *s = PQgetvalue(res, tuple, field);
1940 
1941  if (strspn(s, "0123456789 +-eE.") == strlen(s))
1942  archputs(s, fout);
1943  else
1944  archprintf(fout, "'%s'", s);
1945  }
1946  break;
1947 
1948  case BITOID:
1949  case VARBITOID:
1950  archprintf(fout, "B'%s'",
1951  PQgetvalue(res, tuple, field));
1952  break;
1953 
1954  case BOOLOID:
1955  if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
1956  archputs("true", fout);
1957  else
1958  archputs("false", fout);
1959  break;
1960 
1961  default:
1962  /* All other types are printed as string literals. */
1963  resetPQExpBuffer(q);
1965  PQgetvalue(res, tuple, field),
1966  fout);
1967  archputs(q->data, fout);
1968  break;
1969  }
1970  }
1971  archputs(");\n", fout);
1972  }
1973 
1974  if (PQntuples(res) <= 0)
1975  {
1976  PQclear(res);
1977  break;
1978  }
1979  PQclear(res);
1980  }
1981 
1982  archputs("\n\n", fout);
1983 
1984  ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
1985 
1986  destroyPQExpBuffer(q);
1987  if (insertStmt != NULL)
1988  destroyPQExpBuffer(insertStmt);
1989 
1990  return 1;
1991 }
1992 
1993 
1994 /*
1995  * dumpTableData -
1996  * dump the contents of a single table
1997  *
1998  * Actually, this just makes an ArchiveEntry for the table contents.
1999  */
2000 static void
2002 {
2003  DumpOptions *dopt = fout->dopt;
2004  TableInfo *tbinfo = tdinfo->tdtable;
2005  PQExpBuffer copyBuf = createPQExpBuffer();
2006  PQExpBuffer clistBuf = createPQExpBuffer();
2007  DataDumperPtr dumpFn;
2008  char *copyStmt;
2009 
2010  if (!dopt->dump_inserts)
2011  {
2012  /* Dump/restore using COPY */
2013  dumpFn = dumpTableData_copy;
2014  /* must use 2 steps here 'cause fmtId is nonreentrant */
2015  appendPQExpBuffer(copyBuf, "COPY %s ",
2016  fmtId(tbinfo->dobj.name));
2017  appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
2018  fmtCopyColumnList(tbinfo, clistBuf),
2019  (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
2020  copyStmt = copyBuf->data;
2021  }
2022  else
2023  {
2024  /* Restore using INSERT */
2025  dumpFn = dumpTableData_insert;
2026  copyStmt = NULL;
2027  }
2028 
2029  /*
2030  * Note: although the TableDataInfo is a full DumpableObject, we treat its
2031  * dependency on its table as "special" and pass it to ArchiveEntry now.
2032  * See comments for BuildArchiveDependencies.
2033  */
2034  if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2035  ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
2036  tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
2037  NULL, tbinfo->rolname,
2038  false, "TABLE DATA", SECTION_DATA,
2039  "", "", copyStmt,
2040  &(tbinfo->dobj.dumpId), 1,
2041  dumpFn, tdinfo);
2042 
2043  destroyPQExpBuffer(copyBuf);
2044  destroyPQExpBuffer(clistBuf);
2045 }
2046 
2047 /*
2048  * refreshMatViewData -
2049  * load or refresh the contents of a single materialized view
2050  *
2051  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
2052  * statement.
2053  */
2054 static void
2056 {
2057  TableInfo *tbinfo = tdinfo->tdtable;
2058  PQExpBuffer q;
2059 
2060  /* If the materialized view is not flagged as populated, skip this. */
2061  if (!tbinfo->relispopulated)
2062  return;
2063 
2064  q = createPQExpBuffer();
2065 
2066  appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
2067  fmtId(tbinfo->dobj.name));
2068 
2069  if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2070  ArchiveEntry(fout,
2071  tdinfo->dobj.catId, /* catalog ID */
2072  tdinfo->dobj.dumpId, /* dump ID */
2073  tbinfo->dobj.name, /* Name */
2074  tbinfo->dobj.namespace->dobj.name, /* Namespace */
2075  NULL, /* Tablespace */
2076  tbinfo->rolname, /* Owner */
2077  false, /* with oids */
2078  "MATERIALIZED VIEW DATA", /* Desc */
2079  SECTION_POST_DATA, /* Section */
2080  q->data, /* Create */
2081  "", /* Del */
2082  NULL, /* Copy */
2083  tdinfo->dobj.dependencies, /* Deps */
2084  tdinfo->dobj.nDeps, /* # Deps */
2085  NULL, /* Dumper */
2086  NULL); /* Dumper Arg */
2087 
2088  destroyPQExpBuffer(q);
2089 }
2090 
2091 /*
2092  * getTableData -
2093  * set up dumpable objects representing the contents of tables
2094  */
2095 static void
2096 getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, bool oids, char relkind)
2097 {
2098  int i;
2099 
2100  for (i = 0; i < numTables; i++)
2101  {
2102  if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
2103  (!relkind || tblinfo[i].relkind == relkind))
2104  makeTableDataInfo(dopt, &(tblinfo[i]), oids);
2105  }
2106 }
2107 
2108 /*
2109  * Make a dumpable object for the data of this specific table
2110  *
2111  * Note: we make a TableDataInfo if and only if we are going to dump the
2112  * table data; the "dump" flag in such objects isn't used.
2113  */
2114 static void
2115 makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo, bool oids)
2116 {
2117  TableDataInfo *tdinfo;
2118 
2119  /*
2120  * Nothing to do if we already decided to dump the table. This will
2121  * happen for "config" tables.
2122  */
2123  if (tbinfo->dataObj != NULL)
2124  return;
2125 
2126  /* Skip VIEWs (no data to dump) */
2127  if (tbinfo->relkind == RELKIND_VIEW)
2128  return;
2129  /* Skip FOREIGN TABLEs (no data to dump) */
2130  if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2131  return;
2132  /* Skip partitioned tables (data in partitions) */
2133  if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
2134  return;
2135 
2136  /* Don't dump data in unlogged tables, if so requested */
2137  if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
2138  dopt->no_unlogged_table_data)
2139  return;
2140 
2141  /* Check that the data is not explicitly excluded */
2142  if (simple_oid_list_member(&tabledata_exclude_oids,
2143  tbinfo->dobj.catId.oid))
2144  return;
2145 
2146  /* OK, let's dump it */
2147  tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
2148 
2149  if (tbinfo->relkind == RELKIND_MATVIEW)
2150  tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
2151  else if (tbinfo->relkind == RELKIND_SEQUENCE)
2152  tdinfo->dobj.objType = DO_SEQUENCE_SET;
2153  else
2154  tdinfo->dobj.objType = DO_TABLE_DATA;
2155 
2156  /*
2157  * Note: use tableoid 0 so that this object won't be mistaken for
2158  * something that pg_depend entries apply to.
2159  */
2160  tdinfo->dobj.catId.tableoid = 0;
2161  tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
2162  AssignDumpId(&tdinfo->dobj);
2163  tdinfo->dobj.name = tbinfo->dobj.name;
2164  tdinfo->dobj.namespace = tbinfo->dobj.namespace;
2165  tdinfo->tdtable = tbinfo;
2166  tdinfo->oids = oids;
2167  tdinfo->filtercond = NULL; /* might get set later */
2168  addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
2169 
2170  tbinfo->dataObj = tdinfo;
2171 }
2172 
2173 /*
2174  * The refresh for a materialized view must be dependent on the refresh for
2175  * any materialized view that this one is dependent on.
2176  *
2177  * This must be called after all the objects are created, but before they are
2178  * sorted.
2179  */
2180 static void
2182 {
2183  PQExpBuffer query;
2184  PGresult *res;
2185  int ntups,
2186  i;
2187  int i_classid,
2188  i_objid,
2189  i_refobjid;
2190 
2191  /* No Mat Views before 9.3. */
2192  if (fout->remoteVersion < 90300)
2193  return;
2194 
2195  /* Make sure we are in proper schema */
2196  selectSourceSchema(fout, "pg_catalog");
2197 
2198  query = createPQExpBuffer();
2199 
2200  appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
2201  "( "
2202  "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
2203  "FROM pg_depend d1 "
2204  "JOIN pg_class c1 ON c1.oid = d1.objid "
2205  "AND c1.relkind = 'm' "
2206  "JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
2207  "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
2208  "AND d2.objid = r1.oid "
2209  "AND d2.refobjid <> d1.objid "
2210  "JOIN pg_class c2 ON c2.oid = d2.refobjid "
2211  "AND c2.relkind IN ('m','v') "
2212  "WHERE d1.classid = 'pg_class'::regclass "
2213  "UNION "
2214  "SELECT w.objid, d3.refobjid, c3.relkind "
2215  "FROM w "
2216  "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
2217  "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
2218  "AND d3.objid = r3.oid "
2219  "AND d3.refobjid <> w.refobjid "
2220  "JOIN pg_class c3 ON c3.oid = d3.refobjid "
2221  "AND c3.relkind IN ('m','v') "
2222  ") "
2223  "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
2224  "FROM w "
2225  "WHERE refrelkind = 'm'");
2226 
2227  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2228 
2229  ntups = PQntuples(res);
2230 
2231  i_classid = PQfnumber(res, "classid");
2232  i_objid = PQfnumber(res, "objid");
2233  i_refobjid = PQfnumber(res, "refobjid");
2234 
2235  for (i = 0; i < ntups; i++)
2236  {
2237  CatalogId objId;
2238  CatalogId refobjId;
2239  DumpableObject *dobj;
2240  DumpableObject *refdobj;
2241  TableInfo *tbinfo;
2242  TableInfo *reftbinfo;
2243 
2244  objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
2245  objId.oid = atooid(PQgetvalue(res, i, i_objid));
2246  refobjId.tableoid = objId.tableoid;
2247  refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
2248 
2249  dobj = findObjectByCatalogId(objId);
2250  if (dobj == NULL)
2251  continue;
2252 
2253  Assert(dobj->objType == DO_TABLE);
2254  tbinfo = (TableInfo *) dobj;
2255  Assert(tbinfo->relkind == RELKIND_MATVIEW);
2256  dobj = (DumpableObject *) tbinfo->dataObj;
2257  if (dobj == NULL)
2258  continue;
2259  Assert(dobj->objType == DO_REFRESH_MATVIEW);
2260 
2261  refdobj = findObjectByCatalogId(refobjId);
2262  if (refdobj == NULL)
2263  continue;
2264 
2265  Assert(refdobj->objType == DO_TABLE);
2266  reftbinfo = (TableInfo *) refdobj;
2267  Assert(reftbinfo->relkind == RELKIND_MATVIEW);
2268  refdobj = (DumpableObject *) reftbinfo->dataObj;
2269  if (refdobj == NULL)
2270  continue;
2271  Assert(refdobj->objType == DO_REFRESH_MATVIEW);
2272 
2273  addObjectDependency(dobj, refdobj->dumpId);
2274 
2275  if (!reftbinfo->relispopulated)
2276  tbinfo->relispopulated = false;
2277  }
2278 
2279  PQclear(res);
2280 
2281  destroyPQExpBuffer(query);
2282 }
2283 
2284 /*
2285  * getTableDataFKConstraints -
2286  * add dump-order dependencies reflecting foreign key constraints
2287  *
2288  * This code is executed only in a data-only dump --- in schema+data dumps
2289  * we handle foreign key issues by not creating the FK constraints until
2290  * after the data is loaded. In a data-only dump, however, we want to
2291  * order the table data objects in such a way that a table's referenced
2292  * tables are restored first. (In the presence of circular references or
2293  * self-references this may be impossible; we'll detect and complain about
2294  * that during the dependency sorting step.)
2295  */
2296 static void
2298 {
2299  DumpableObject **dobjs;
2300  int numObjs;
2301  int i;
2302 
2303  /* Search through all the dumpable objects for FK constraints */
2304  getDumpableObjects(&dobjs, &numObjs);
2305  for (i = 0; i < numObjs; i++)
2306  {
2307  if (dobjs[i]->objType == DO_FK_CONSTRAINT)
2308  {
2309  ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
2310  TableInfo *ftable;
2311 
2312  /* Not interesting unless both tables are to be dumped */
2313  if (cinfo->contable == NULL ||
2314  cinfo->contable->dataObj == NULL)
2315  continue;
2316  ftable = findTableByOid(cinfo->confrelid);
2317  if (ftable == NULL ||
2318  ftable->dataObj == NULL)
2319  continue;
2320 
2321  /*
2322  * Okay, make referencing table's TABLE_DATA object depend on the
2323  * referenced table's TABLE_DATA object.
2324  */
2326  ftable->dataObj->dobj.dumpId);
2327  }
2328  }
2329  free(dobjs);
2330 }
2331 
2332 
2333 /*
2334  * guessConstraintInheritance:
2335  * In pre-8.4 databases, we can't tell for certain which constraints
2336  * are inherited. We assume a CHECK constraint is inherited if its name
2337  * matches the name of any constraint in the parent. Originally this code
2338  * tried to compare the expression texts, but that can fail for various
2339  * reasons --- for example, if the parent and child tables are in different
2340  * schemas, reverse-listing of function calls may produce different text
2341  * (schema-qualified or not) depending on search path.
2342  *
2343  * In 8.4 and up we can rely on the conislocal field to decide which
2344  * constraints must be dumped; much safer.
2345  *
2346  * This function assumes all conislocal flags were initialized to TRUE.
2347  * It clears the flag on anything that seems to be inherited.
2348  */
2349 static void
2351 {
2352  int i,
2353  j,
2354  k;
2355 
2356  for (i = 0; i < numTables; i++)
2357  {
2358  TableInfo *tbinfo = &(tblinfo[i]);
2359  int numParents;
2360  TableInfo **parents;
2361  TableInfo *parent;
2362 
2363  /* Sequences and views never have parents */
2364  if (tbinfo->relkind == RELKIND_SEQUENCE ||
2365  tbinfo->relkind == RELKIND_VIEW)
2366  continue;
2367 
2368  /* Don't bother computing anything for non-target tables, either */
2369  if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
2370  continue;
2371 
2372  numParents = tbinfo->numParents;
2373  parents = tbinfo->parents;
2374 
2375  if (numParents == 0)
2376  continue; /* nothing to see here, move along */
2377 
2378  /* scan for inherited CHECK constraints */
2379  for (j = 0; j < tbinfo->ncheck; j++)
2380  {
2381  ConstraintInfo *constr;
2382 
2383  constr = &(tbinfo->checkexprs[j]);
2384 
2385  for (k = 0; k < numParents; k++)
2386  {
2387  int l;
2388 
2389  parent = parents[k];
2390  for (l = 0; l < parent->ncheck; l++)
2391  {
2392  ConstraintInfo *pconstr = &(parent->checkexprs[l]);
2393 
2394  if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
2395  {
2396  constr->conislocal = false;
2397  break;
2398  }
2399  }
2400  if (!constr->conislocal)
2401  break;
2402  }
2403  }
2404  }
2405 }
2406 
2407 
2408 /*
2409  * dumpDatabase:
2410  * dump the database definition
2411  */
2412 static void
2414 {
2415  DumpOptions *dopt = fout->dopt;
2416  PQExpBuffer dbQry = createPQExpBuffer();
2417  PQExpBuffer delQry = createPQExpBuffer();
2418  PQExpBuffer creaQry = createPQExpBuffer();
2419  PGconn *conn = GetConnection(fout);
2420  PGresult *res;
2421  int i_tableoid,
2422  i_oid,
2423  i_dba,
2424  i_encoding,
2425  i_collate,
2426  i_ctype,
2427  i_frozenxid,
2428  i_minmxid,
2429  i_tablespace;
2430  CatalogId dbCatId;
2431  DumpId dbDumpId;
2432  const char *datname,
2433  *dba,
2434  *encoding,
2435  *collate,
2436  *ctype,
2437  *tablespace;
2438  uint32 frozenxid,
2439  minmxid;
2440 
2441  datname = PQdb(conn);
2442 
2443  if (g_verbose)
2444  write_msg(NULL, "saving database definition\n");
2445 
2446  /* Make sure we are in proper schema */
2447  selectSourceSchema(fout, "pg_catalog");
2448 
2449  /* Get the database owner and parameters from pg_database */
2450  if (fout->remoteVersion >= 90300)
2451  {
2452  appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2453  "(%s datdba) AS dba, "
2454  "pg_encoding_to_char(encoding) AS encoding, "
2455  "datcollate, datctype, datfrozenxid, datminmxid, "
2456  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2457  "shobj_description(oid, 'pg_database') AS description "
2458 
2459  "FROM pg_database "
2460  "WHERE datname = ",
2462  appendStringLiteralAH(dbQry, datname, fout);
2463  }
2464  else if (fout->remoteVersion >= 80400)
2465  {
2466  appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2467  "(%s datdba) AS dba, "
2468  "pg_encoding_to_char(encoding) AS encoding, "
2469  "datcollate, datctype, datfrozenxid, 0 AS datminmxid, "
2470  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2471  "shobj_description(oid, 'pg_database') AS description "
2472 
2473  "FROM pg_database "
2474  "WHERE datname = ",
2476  appendStringLiteralAH(dbQry, datname, fout);
2477  }
2478  else if (fout->remoteVersion >= 80200)
2479  {
2480  appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2481  "(%s datdba) AS dba, "
2482  "pg_encoding_to_char(encoding) AS encoding, "
2483  "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2484  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2485  "shobj_description(oid, 'pg_database') AS description "
2486 
2487  "FROM pg_database "
2488  "WHERE datname = ",
2490  appendStringLiteralAH(dbQry, datname, fout);
2491  }
2492  else
2493  {
2494  appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2495  "(%s datdba) AS dba, "
2496  "pg_encoding_to_char(encoding) AS encoding, "
2497  "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2498  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
2499  "FROM pg_database "
2500  "WHERE datname = ",
2502  appendStringLiteralAH(dbQry, datname, fout);
2503  }
2504 
2505  res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
2506 
2507  i_tableoid = PQfnumber(res, "tableoid");
2508  i_oid = PQfnumber(res, "oid");
2509  i_dba = PQfnumber(res, "dba");
2510  i_encoding = PQfnumber(res, "encoding");
2511  i_collate = PQfnumber(res, "datcollate");
2512  i_ctype = PQfnumber(res, "datctype");
2513  i_frozenxid = PQfnumber(res, "datfrozenxid");
2514  i_minmxid = PQfnumber(res, "datminmxid");
2515  i_tablespace = PQfnumber(res, "tablespace");
2516 
2517  dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
2518  dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
2519  dba = PQgetvalue(res, 0, i_dba);
2520  encoding = PQgetvalue(res, 0, i_encoding);
2521  collate = PQgetvalue(res, 0, i_collate);
2522  ctype = PQgetvalue(res, 0, i_ctype);
2523  frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
2524  minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
2525  tablespace = PQgetvalue(res, 0, i_tablespace);
2526 
2527  appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
2528  fmtId(datname));
2529  if (strlen(encoding) > 0)
2530  {
2531  appendPQExpBufferStr(creaQry, " ENCODING = ");
2532  appendStringLiteralAH(creaQry, encoding, fout);
2533  }
2534  if (strlen(collate) > 0)
2535  {
2536  appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
2537  appendStringLiteralAH(creaQry, collate, fout);
2538  }
2539  if (strlen(ctype) > 0)
2540  {
2541  appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
2542  appendStringLiteralAH(creaQry, ctype, fout);
2543  }
2544  if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
2545  !dopt->outputNoTablespaces)
2546  appendPQExpBuffer(creaQry, " TABLESPACE = %s",
2547  fmtId(tablespace));
2548  appendPQExpBufferStr(creaQry, ";\n");
2549 
2550  if (dopt->binary_upgrade)
2551  {
2552  appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
2553  appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
2554  "SET datfrozenxid = '%u', datminmxid = '%u'\n"
2555  "WHERE datname = ",
2556  frozenxid, minmxid);
2557  appendStringLiteralAH(creaQry, datname, fout);
2558  appendPQExpBufferStr(creaQry, ";\n");
2559 
2560  }
2561 
2562  appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
2563  fmtId(datname));
2564 
2565  dbDumpId = createDumpId();
2566 
2567  ArchiveEntry(fout,
2568  dbCatId, /* catalog ID */
2569  dbDumpId, /* dump ID */
2570  datname, /* Name */
2571  NULL, /* Namespace */
2572  NULL, /* Tablespace */
2573  dba, /* Owner */
2574  false, /* with oids */
2575  "DATABASE", /* Desc */
2576  SECTION_PRE_DATA, /* Section */
2577  creaQry->data, /* Create */
2578  delQry->data, /* Del */
2579  NULL, /* Copy */
2580  NULL, /* Deps */
2581  0, /* # Deps */
2582  NULL, /* Dumper */
2583  NULL); /* Dumper Arg */
2584 
2585  /*
2586  * pg_largeobject and pg_largeobject_metadata come from the old system
2587  * intact, so set their relfrozenxids and relminmxids.
2588  */
2589  if (dopt->binary_upgrade)
2590  {
2591  PGresult *lo_res;
2592  PQExpBuffer loFrozenQry = createPQExpBuffer();
2593  PQExpBuffer loOutQry = createPQExpBuffer();
2594  int i_relfrozenxid,
2595  i_relminmxid;
2596 
2597  /*
2598  * pg_largeobject
2599  */
2600  if (fout->remoteVersion >= 90300)
2601  appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
2602  "FROM pg_catalog.pg_class\n"
2603  "WHERE oid = %u;\n",
2605  else
2606  appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
2607  "FROM pg_catalog.pg_class\n"
2608  "WHERE oid = %u;\n",
2610 
2611  lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2612 
2613  i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2614  i_relminmxid = PQfnumber(lo_res, "relminmxid");
2615 
2616  appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
2617  appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2618  "SET relfrozenxid = '%u', relminmxid = '%u'\n"
2619  "WHERE oid = %u;\n",
2620  atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2621  atoi(PQgetvalue(lo_res, 0, i_relminmxid)),
2623  ArchiveEntry(fout, nilCatalogId, createDumpId(),
2624  "pg_largeobject", NULL, NULL, "",
2625  false, "pg_largeobject", SECTION_PRE_DATA,
2626  loOutQry->data, "", NULL,
2627  NULL, 0,
2628  NULL, NULL);
2629 
2630  PQclear(lo_res);
2631 
2632  /*
2633  * pg_largeobject_metadata
2634  */
2635  if (fout->remoteVersion >= 90000)
2636  {
2637  resetPQExpBuffer(loFrozenQry);
2638  resetPQExpBuffer(loOutQry);
2639 
2640  if (fout->remoteVersion >= 90300)
2641  appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
2642  "FROM pg_catalog.pg_class\n"
2643  "WHERE oid = %u;\n",
2645  else
2646  appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
2647  "FROM pg_catalog.pg_class\n"
2648  "WHERE oid = %u;\n",
2650 
2651  lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2652 
2653  i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2654  i_relminmxid = PQfnumber(lo_res, "relminmxid");
2655 
2656  appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject_metadata relfrozenxid and relminmxid\n");
2657  appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2658  "SET relfrozenxid = '%u', relminmxid = '%u'\n"
2659  "WHERE oid = %u;\n",
2660  atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2661  atoi(PQgetvalue(lo_res, 0, i_relminmxid)),
2663  ArchiveEntry(fout, nilCatalogId, createDumpId(),
2664  "pg_largeobject_metadata", NULL, NULL, "",
2665  false, "pg_largeobject_metadata", SECTION_PRE_DATA,
2666  loOutQry->data, "", NULL,
2667  NULL, 0,
2668  NULL, NULL);
2669 
2670  PQclear(lo_res);
2671  }
2672 
2673  destroyPQExpBuffer(loFrozenQry);
2674  destroyPQExpBuffer(loOutQry);
2675  }
2676 
2677  /* Dump DB comment if any */
2678  if (fout->remoteVersion >= 80200)
2679  {
2680  /*
2681  * 8.2 keeps comments on shared objects in a shared table, so we
2682  * cannot use the dumpComment used for other database objects.
2683  */
2684  char *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
2685 
2686  if (comment && strlen(comment))
2687  {
2688  resetPQExpBuffer(dbQry);
2689 
2690  /*
2691  * Generates warning when loaded into a differently-named
2692  * database.
2693  */
2694  appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
2695  appendStringLiteralAH(dbQry, comment, fout);
2696  appendPQExpBufferStr(dbQry, ";\n");
2697 
2698  ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
2699  dba, false, "COMMENT", SECTION_NONE,
2700  dbQry->data, "", NULL,
2701  &dbDumpId, 1, NULL, NULL);
2702  }
2703  }
2704  else
2705  {
2706  resetPQExpBuffer(dbQry);
2707  appendPQExpBuffer(dbQry, "DATABASE %s", fmtId(datname));
2708  dumpComment(fout, dbQry->data, NULL, "",
2709  dbCatId, 0, dbDumpId);
2710  }
2711 
2712  /* Dump shared security label. */
2713  if (!dopt->no_security_labels && fout->remoteVersion >= 90200)
2714  {
2715  PGresult *shres;
2716  PQExpBuffer seclabelQry;
2717 
2718  seclabelQry = createPQExpBuffer();
2719 
2720  buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
2721  shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
2722  resetPQExpBuffer(seclabelQry);
2723  emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
2724  if (strlen(seclabelQry->data))
2725  ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
2726  dba, false, "SECURITY LABEL", SECTION_NONE,
2727  seclabelQry->data, "", NULL,
2728  &dbDumpId, 1, NULL, NULL);
2729  destroyPQExpBuffer(seclabelQry);
2730  PQclear(shres);
2731  }
2732 
2733  PQclear(res);
2734 
2735  destroyPQExpBuffer(dbQry);
2736  destroyPQExpBuffer(delQry);
2737  destroyPQExpBuffer(creaQry);
2738 }
2739 
2740 /*
2741  * dumpEncoding: put the correct encoding into the archive
2742  */
2743 static void
2745 {
2746  const char *encname = pg_encoding_to_char(AH->encoding);
2748 
2749  if (g_verbose)
2750  write_msg(NULL, "saving encoding = %s\n", encname);
2751 
2752  appendPQExpBufferStr(qry, "SET client_encoding = ");
2753  appendStringLiteralAH(qry, encname, AH);
2754  appendPQExpBufferStr(qry, ";\n");
2755 
2756  ArchiveEntry(AH, nilCatalogId, createDumpId(),
2757  "ENCODING", NULL, NULL, "",
2758  false, "ENCODING", SECTION_PRE_DATA,
2759  qry->data, "", NULL,
2760  NULL, 0,
2761  NULL, NULL);
2762 
2763  destroyPQExpBuffer(qry);
2764 }
2765 
2766 
2767 /*
2768  * dumpStdStrings: put the correct escape string behavior into the archive
2769  */
2770 static void
2772 {
2773  const char *stdstrings = AH->std_strings ? "on" : "off";
2775 
2776  if (g_verbose)
2777  write_msg(NULL, "saving standard_conforming_strings = %s\n",
2778  stdstrings);
2779 
2780  appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
2781  stdstrings);
2782 
2783  ArchiveEntry(AH, nilCatalogId, createDumpId(),
2784  "STDSTRINGS", NULL, NULL, "",
2785  false, "STDSTRINGS", SECTION_PRE_DATA,
2786  qry->data, "", NULL,
2787  NULL, 0,
2788  NULL, NULL);
2789 
2790  destroyPQExpBuffer(qry);
2791 }
2792 
2793 
2794 /*
2795  * getBlobs:
2796  * Collect schema-level data about large objects
2797  */
2798 static void
2800 {
2801  DumpOptions *dopt = fout->dopt;
2802  PQExpBuffer blobQry = createPQExpBuffer();
2803  BlobInfo *binfo;
2804  DumpableObject *bdata;
2805  PGresult *res;
2806  int ntups;
2807  int i;
2808  int i_oid;
2809  int i_lomowner;
2810  int i_lomacl;
2811  int i_rlomacl;
2812  int i_initlomacl;
2813  int i_initrlomacl;
2814 
2815  /* Verbose message */
2816  if (g_verbose)
2817  write_msg(NULL, "reading large objects\n");
2818 
2819  /* Make sure we are in proper schema */
2820  selectSourceSchema(fout, "pg_catalog");
2821 
2822  /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
2823  if (fout->remoteVersion >= 90600)
2824  {
2825  PQExpBuffer acl_subquery = createPQExpBuffer();
2826  PQExpBuffer racl_subquery = createPQExpBuffer();
2827  PQExpBuffer init_acl_subquery = createPQExpBuffer();
2828  PQExpBuffer init_racl_subquery = createPQExpBuffer();
2829 
2830  buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
2831  init_racl_subquery, "l.lomacl", "l.lomowner", "'L'",
2832  dopt->binary_upgrade);
2833 
2834  appendPQExpBuffer(blobQry,
2835  "SELECT l.oid, (%s l.lomowner) AS rolname, "
2836  "%s AS lomacl, "
2837  "%s AS rlomacl, "
2838  "%s AS initlomacl, "
2839  "%s AS initrlomacl "
2840  "FROM pg_largeobject_metadata l "
2841  "LEFT JOIN pg_init_privs pip ON "
2842  "(l.oid = pip.objoid "
2843  "AND pip.classoid = 'pg_largeobject'::regclass "
2844  "AND pip.objsubid = 0) ",
2846  acl_subquery->data,
2847  racl_subquery->data,
2848  init_acl_subquery->data,
2849  init_racl_subquery->data);
2850 
2851  destroyPQExpBuffer(acl_subquery);
2852  destroyPQExpBuffer(racl_subquery);
2853  destroyPQExpBuffer(init_acl_subquery);
2854  destroyPQExpBuffer(init_racl_subquery);
2855  }
2856  else if (fout->remoteVersion >= 90000)
2857  appendPQExpBuffer(blobQry,
2858  "SELECT oid, (%s lomowner) AS rolname, lomacl, "
2859  "NULL AS rlomacl, NULL AS initlomacl, "
2860  "NULL AS initrlomacl "
2861  " FROM pg_largeobject_metadata",
2863  else
2864  appendPQExpBufferStr(blobQry,
2865  "SELECT DISTINCT loid AS oid, "
2866  "NULL::name AS rolname, NULL::oid AS lomacl, "
2867  "NULL::oid AS rlomacl, NULL::oid AS initlomacl, "
2868  "NULL::oid AS initrlomacl "
2869  " FROM pg_largeobject");
2870 
2871  res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
2872 
2873  i_oid = PQfnumber(res, "oid");
2874  i_lomowner = PQfnumber(res, "rolname");
2875  i_lomacl = PQfnumber(res, "lomacl");
2876  i_rlomacl = PQfnumber(res, "rlomacl");
2877  i_initlomacl = PQfnumber(res, "initlomacl");
2878  i_initrlomacl = PQfnumber(res, "initrlomacl");
2879 
2880  ntups = PQntuples(res);
2881 
2882  /*
2883  * Each large object has its own BLOB archive entry.
2884  */
2885  binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
2886 
2887  for (i = 0; i < ntups; i++)
2888  {
2889  binfo[i].dobj.objType = DO_BLOB;
2891  binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2892  AssignDumpId(&binfo[i].dobj);
2893 
2894  binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oid));
2895  binfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_lomowner));
2896  binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, i_lomacl));
2897  binfo[i].rblobacl = pg_strdup(PQgetvalue(res, i, i_rlomacl));
2898  binfo[i].initblobacl = pg_strdup(PQgetvalue(res, i, i_initlomacl));
2899  binfo[i].initrblobacl = pg_strdup(PQgetvalue(res, i, i_initrlomacl));
2900 
2901  if (PQgetisnull(res, i, i_lomacl) &&
2902  PQgetisnull(res, i, i_rlomacl) &&
2903  PQgetisnull(res, i, i_initlomacl) &&
2904  PQgetisnull(res, i, i_initrlomacl))
2905  binfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
2906  }
2907 
2908  /*
2909  * If we have any large objects, a "BLOBS" archive entry is needed. This
2910  * is just a placeholder for sorting; it carries no data now.
2911  */
2912  if (ntups > 0)
2913  {
2914  bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
2915  bdata->objType = DO_BLOB_DATA;
2916  bdata->catId = nilCatalogId;
2917  AssignDumpId(bdata);
2918  bdata->name = pg_strdup("BLOBS");
2919  }
2920 
2921  PQclear(res);
2922  destroyPQExpBuffer(blobQry);
2923 }
2924 
2925 /*
2926  * dumpBlob
2927  *
2928  * dump the definition (metadata) of the given large object
2929  */
2930 static void
2931 dumpBlob(Archive *fout, BlobInfo *binfo)
2932 {
2933  PQExpBuffer cquery = createPQExpBuffer();
2934  PQExpBuffer dquery = createPQExpBuffer();
2935 
2936  appendPQExpBuffer(cquery,
2937  "SELECT pg_catalog.lo_create('%s');\n",
2938  binfo->dobj.name);
2939 
2940  appendPQExpBuffer(dquery,
2941  "SELECT pg_catalog.lo_unlink('%s');\n",
2942  binfo->dobj.name);
2943 
2944  if (binfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
2945  ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
2946  binfo->dobj.name,
2947  NULL, NULL,
2948  binfo->rolname, false,
2949  "BLOB", SECTION_PRE_DATA,
2950  cquery->data, dquery->data, NULL,
2951  NULL, 0,
2952  NULL, NULL);
2953 
2954  /* set up tag for comment and/or ACL */
2955  resetPQExpBuffer(cquery);
2956  appendPQExpBuffer(cquery, "LARGE OBJECT %s", binfo->dobj.name);
2957 
2958  /* Dump comment if any */
2959  if (binfo->dobj.dump & DUMP_COMPONENT_COMMENT)
2960  dumpComment(fout, cquery->data,
2961  NULL, binfo->rolname,
2962  binfo->dobj.catId, 0, binfo->dobj.dumpId);
2963 
2964  /* Dump security label if any */
2965  if (binfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
2966  dumpSecLabel(fout, cquery->data,
2967  NULL, binfo->rolname,
2968  binfo->dobj.catId, 0, binfo->dobj.dumpId);
2969 
2970  /* Dump ACL if any */
2971  if (binfo->blobacl && (binfo->dobj.dump & DUMP_COMPONENT_ACL))
2972  dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
2973  binfo->dobj.name, NULL, cquery->data,
2974  NULL, binfo->rolname, binfo->blobacl, binfo->rblobacl,
2975  binfo->initblobacl, binfo->initrblobacl);
2976 
2977  destroyPQExpBuffer(cquery);
2978  destroyPQExpBuffer(dquery);
2979 }
2980 
2981 /*
2982  * dumpBlobs:
2983  * dump the data contents of all large objects
2984  */
2985 static int
2986 dumpBlobs(Archive *fout, void *arg)
2987 {
2988  const char *blobQry;
2989  const char *blobFetchQry;
2990  PGconn *conn = GetConnection(fout);
2991  PGresult *res;
2992  char buf[LOBBUFSIZE];
2993  int ntups;
2994  int i;
2995  int cnt;
2996 
2997  if (g_verbose)
2998  write_msg(NULL, "saving large objects\n");
2999 
3000  /* Make sure we are in proper schema */
3001  selectSourceSchema(fout, "pg_catalog");
3002 
3003  /*
3004  * Currently, we re-fetch all BLOB OIDs using a cursor. Consider scanning
3005  * the already-in-memory dumpable objects instead...
3006  */
3007  if (fout->remoteVersion >= 90000)
3008  blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_largeobject_metadata";
3009  else
3010  blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
3011 
3012  ExecuteSqlStatement(fout, blobQry);
3013 
3014  /* Command to fetch from cursor */
3015  blobFetchQry = "FETCH 1000 IN bloboid";
3016 
3017  do
3018  {
3019  /* Do a fetch */
3020  res = ExecuteSqlQuery(fout, blobFetchQry, PGRES_TUPLES_OK);
3021 
3022  /* Process the tuples, if any */
3023  ntups = PQntuples(res);
3024  for (i = 0; i < ntups; i++)
3025  {
3026  Oid blobOid;
3027  int loFd;
3028 
3029  blobOid = atooid(PQgetvalue(res, i, 0));
3030  /* Open the BLOB */
3031  loFd = lo_open(conn, blobOid, INV_READ);
3032  if (loFd == -1)
3033  exit_horribly(NULL, "could not open large object %u: %s",
3034  blobOid, PQerrorMessage(conn));
3035 
3036  StartBlob(fout, blobOid);
3037 
3038  /* Now read it in chunks, sending data to archive */
3039  do
3040  {
3041  cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
3042  if (cnt < 0)
3043  exit_horribly(NULL, "error reading large object %u: %s",
3044  blobOid, PQerrorMessage(conn));
3045 
3046  WriteData(fout, buf, cnt);
3047  } while (cnt > 0);
3048 
3049  lo_close(conn, loFd);
3050 
3051  EndBlob(fout, blobOid);
3052  }
3053 
3054  PQclear(res);
3055  } while (ntups > 0);
3056 
3057  return 1;
3058 }
3059 
3060 /*
3061  * getPolicies
3062  * get information about policies on a dumpable table.
3063  */
3064 void
3065 getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
3066 {
3067  PQExpBuffer query;
3068  PGresult *res;
3069  PolicyInfo *polinfo;
3070  int i_oid;
3071  int i_tableoid;
3072  int i_polname;
3073  int i_polcmd;
3074  int i_polpermissive;
3075  int i_polroles;
3076  int i_polqual;
3077  int i_polwithcheck;
3078  int i,
3079  j,
3080  ntups;
3081 
3082  if (fout->remoteVersion < 90500)
3083  return;
3084 
3085  query = createPQExpBuffer();
3086 
3087  for (i = 0; i < numTables; i++)
3088  {
3089  TableInfo *tbinfo = &tblinfo[i];
3090 
3091  /* Ignore row security on tables not to be dumped */
3092  if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
3093  continue;
3094 
3095  if (g_verbose)
3096  write_msg(NULL, "reading row security enabled for table \"%s.%s\"\n",
3097  tbinfo->dobj.namespace->dobj.name,
3098  tbinfo->dobj.name);
3099 
3100  /*
3101  * Get row security enabled information for the table. We represent
3102  * RLS enabled on a table by creating PolicyInfo object with an empty
3103  * policy.
3104  */
3105  if (tbinfo->rowsec)
3106  {
3107  /*
3108  * Note: use tableoid 0 so that this object won't be mistaken for
3109  * something that pg_depend entries apply to.
3110  */
3111  polinfo = pg_malloc(sizeof(PolicyInfo));
3112  polinfo->dobj.objType = DO_POLICY;
3113  polinfo->dobj.catId.tableoid = 0;
3114  polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
3115  AssignDumpId(&polinfo->dobj);
3116  polinfo->dobj.namespace = tbinfo->dobj.namespace;
3117  polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
3118  polinfo->poltable = tbinfo;
3119  polinfo->polname = NULL;
3120  polinfo->polcmd = '\0';
3121  polinfo->polpermissive = 0;
3122  polinfo->polroles = NULL;
3123  polinfo->polqual = NULL;
3124  polinfo->polwithcheck = NULL;
3125  }
3126 
3127  if (g_verbose)
3128  write_msg(NULL, "reading policies for table \"%s.%s\"\n",
3129  tbinfo->dobj.namespace->dobj.name,
3130  tbinfo->dobj.name);
3131 
3132  /*
3133  * select table schema to ensure regproc name is qualified if needed
3134  */
3135  selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
3136 
3137  resetPQExpBuffer(query);
3138 
3139  /* Get the policies for the table. */
3140  if (fout->remoteVersion >= 100000)
3141  appendPQExpBuffer(query,
3142  "SELECT oid, tableoid, pol.polname, pol.polcmd, pol.polpermissive, "
3143  "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3144  " 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, "
3145  "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3146  "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3147  "FROM pg_catalog.pg_policy pol "
3148  "WHERE polrelid = '%u'",
3149  tbinfo->dobj.catId.oid);
3150  else
3151  appendPQExpBuffer(query,
3152  "SELECT oid, tableoid, pol.polname, pol.polcmd, 't' as polpermissive, "
3153  "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3154  " 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, "
3155  "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3156  "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3157  "FROM pg_catalog.pg_policy pol "
3158  "WHERE polrelid = '%u'",
3159  tbinfo->dobj.catId.oid);
3160  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3161 
3162  ntups = PQntuples(res);
3163 
3164  if (ntups == 0)
3165  {
3166  /*
3167  * No explicit policies to handle (only the default-deny policy,
3168  * which is handled as part of the table definition). Clean up
3169  * and return.
3170  */
3171  PQclear(res);
3172  continue;
3173  }
3174 
3175  i_oid = PQfnumber(res, "oid");
3176  i_tableoid = PQfnumber(res, "tableoid");
3177  i_polname = PQfnumber(res, "polname");
3178  i_polcmd = PQfnumber(res, "polcmd");
3179  i_polpermissive = PQfnumber(res, "polpermissive");
3180  i_polroles = PQfnumber(res, "polroles");
3181  i_polqual = PQfnumber(res, "polqual");
3182  i_polwithcheck = PQfnumber(res, "polwithcheck");
3183 
3184  polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
3185 
3186  for (j = 0; j < ntups; j++)
3187  {
3188  polinfo[j].dobj.objType = DO_POLICY;
3189  polinfo[j].dobj.catId.tableoid =
3190  atooid(PQgetvalue(res, j, i_tableoid));
3191  polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3192  AssignDumpId(&polinfo[j].dobj);
3193  polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3194  polinfo[j].poltable = tbinfo;
3195  polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
3196  polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
3197 
3198  polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
3199  polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
3200 
3201  if (PQgetisnull(res, j, i_polroles))
3202  polinfo[j].polroles = NULL;
3203  else
3204  polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
3205 
3206  if (PQgetisnull(res, j, i_polqual))
3207  polinfo[j].polqual = NULL;
3208  else
3209  polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
3210 
3211  if (PQgetisnull(res, j, i_polwithcheck))
3212  polinfo[j].polwithcheck = NULL;
3213  else
3214  polinfo[j].polwithcheck
3215  = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
3216  }
3217  PQclear(res);
3218  }
3219  destroyPQExpBuffer(query);
3220 }
3221 
3222 /*
3223  * dumpPolicy
3224  * dump the definition of the given policy
3225  */
3226 static void
3228 {
3229  DumpOptions *dopt = fout->dopt;
3230  TableInfo *tbinfo = polinfo->poltable;
3231  PQExpBuffer query;
3232  PQExpBuffer delqry;
3233  const char *cmd;
3234  char *tag;
3235 
3236  if (dopt->dataOnly)
3237  return;
3238 
3239  /*
3240  * If polname is NULL, then this record is just indicating that ROW LEVEL
3241  * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
3242  * ROW LEVEL SECURITY.
3243  */
3244  if (polinfo->polname == NULL)
3245  {
3246  query = createPQExpBuffer();
3247 
3248  appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
3249  fmtId(polinfo->dobj.name));
3250 
3251  if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3252  ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3253  polinfo->dobj.name,
3254  polinfo->dobj.namespace->dobj.name,
3255  NULL,
3256  tbinfo->rolname, false,
3257  "ROW SECURITY", SECTION_POST_DATA,
3258  query->data, "", NULL,
3259  NULL, 0,
3260  NULL, NULL);
3261 
3262  destroyPQExpBuffer(query);
3263  return;
3264  }
3265 
3266  if (polinfo->polcmd == '*')
3267  cmd = "";
3268  else if (polinfo->polcmd == 'r')
3269  cmd = " FOR SELECT";
3270  else if (polinfo->polcmd == 'a')
3271  cmd = " FOR INSERT";
3272  else if (polinfo->polcmd == 'w')
3273  cmd = " FOR UPDATE";
3274  else if (polinfo->polcmd == 'd')
3275  cmd = " FOR DELETE";
3276  else
3277  {
3278  write_msg(NULL, "unexpected policy command type: %c\n",
3279  polinfo->polcmd);
3280  exit_nicely(1);
3281  }
3282 
3283  query = createPQExpBuffer();
3284  delqry = createPQExpBuffer();
3285 
3286  appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
3287 
3288  appendPQExpBuffer(query, " ON %s%s%s", fmtId(tbinfo->dobj.name),
3289  !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
3290 
3291  if (polinfo->polroles != NULL)
3292  appendPQExpBuffer(query, " TO %s", polinfo->polroles);
3293 
3294  if (polinfo->polqual != NULL)
3295  appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
3296 
3297  if (polinfo->polwithcheck != NULL)
3298  appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
3299 
3300  appendPQExpBuffer(query, ";\n");
3301 
3302  appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
3303  appendPQExpBuffer(delqry, " ON %s;\n", fmtId(tbinfo->dobj.name));
3304 
3305  tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
3306 
3307  if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3308  ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3309  tag,
3310  polinfo->dobj.namespace->dobj.name,
3311  NULL,
3312  tbinfo->rolname, false,
3313  "POLICY", SECTION_POST_DATA,
3314  query->data, delqry->data, NULL,
3315  NULL, 0,
3316  NULL, NULL);
3317 
3318  free(tag);
3319  destroyPQExpBuffer(query);
3320  destroyPQExpBuffer(delqry);
3321 }
3322 
3323 /*
3324  * getPublications
3325  * get information about publications
3326  */
3327 void
3329 {
3330  PQExpBuffer query;
3331  PGresult *res;
3332  PublicationInfo *pubinfo;
3333  int i_tableoid;
3334  int i_oid;
3335  int i_pubname;
3336  int i_rolname;
3337  int i_puballtables;
3338  int i_pubinsert;
3339  int i_pubupdate;
3340  int i_pubdelete;
3341  int i,
3342  ntups;
3343 
3344  if (fout->remoteVersion < 100000)
3345  return;
3346 
3347  query = createPQExpBuffer();
3348 
3349  resetPQExpBuffer(query);
3350 
3351  /* Get the publications. */
3352  appendPQExpBuffer(query,
3353  "SELECT p.tableoid, p.oid, p.pubname, "
3354  "(%s p.pubowner) AS rolname, "
3355  "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete "
3356  "FROM pg_catalog.pg_publication p",
3358 
3359  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3360 
3361  ntups = PQntuples(res);
3362 
3363  i_tableoid = PQfnumber(res, "tableoid");
3364  i_oid = PQfnumber(res, "oid");
3365  i_pubname = PQfnumber(res, "pubname");
3366  i_rolname = PQfnumber(res, "rolname");
3367  i_puballtables = PQfnumber(res, "puballtables");
3368  i_pubinsert = PQfnumber(res, "pubinsert");
3369  i_pubupdate = PQfnumber(res, "pubupdate");
3370  i_pubdelete = PQfnumber(res, "pubdelete");
3371 
3372  pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
3373 
3374  for (i = 0; i < ntups; i++)
3375  {
3376  pubinfo[i].dobj.objType = DO_PUBLICATION;
3377  pubinfo[i].dobj.catId.tableoid =
3378  atooid(PQgetvalue(res, i, i_tableoid));
3379  pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3380  AssignDumpId(&pubinfo[i].dobj);
3381  pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
3382  pubinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3383  pubinfo[i].puballtables =
3384  (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
3385  pubinfo[i].pubinsert =
3386  (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
3387  pubinfo[i].pubupdate =
3388  (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
3389  pubinfo[i].pubdelete =
3390  (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
3391 
3392  if (strlen(pubinfo[i].rolname) == 0)
3393  write_msg(NULL, "WARNING: owner of publication \"%s\" appears to be invalid\n",
3394  pubinfo[i].dobj.name);
3395  }
3396  PQclear(res);
3397 
3398  destroyPQExpBuffer(query);
3399 }
3400 
3401 /*
3402  * dumpPublication
3403  * dump the definition of the given publication
3404  */
3405 static void
3407 {
3408  DumpOptions *dopt = fout->dopt;
3409  PQExpBuffer delq;
3410  PQExpBuffer query;
3411 
3412  if (dopt->dataOnly)
3413  return;
3414 
3415  delq = createPQExpBuffer();
3416  query = createPQExpBuffer();
3417 
3418  appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
3419  fmtId(pubinfo->dobj.name));
3420 
3421  appendPQExpBuffer(query, "CREATE PUBLICATION %s",
3422  fmtId(pubinfo->dobj.name));
3423 
3424  if (pubinfo->puballtables)
3425  appendPQExpBufferStr(query, " FOR ALL TABLES");
3426 
3427  appendPQExpBufferStr(query, " WITH (");
3428  if (pubinfo->pubinsert)
3429  appendPQExpBufferStr(query, "PUBLISH INSERT");
3430  else
3431  appendPQExpBufferStr(query, "NOPUBLISH INSERT");
3432 
3433  if (pubinfo->pubupdate)
3434  appendPQExpBufferStr(query, ", PUBLISH UPDATE");
3435  else
3436  appendPQExpBufferStr(query, ", NOPUBLISH UPDATE");
3437 
3438  if (pubinfo->pubdelete)
3439  appendPQExpBufferStr(query, ", PUBLISH DELETE");
3440  else
3441  appendPQExpBufferStr(query, ", NOPUBLISH DELETE");
3442 
3443  appendPQExpBufferStr(query, ");\n");
3444 
3445  ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
3446  pubinfo->dobj.name,
3447  NULL,
3448  NULL,
3449  pubinfo->rolname, false,
3450  "PUBLICATION", SECTION_POST_DATA,
3451  query->data, delq->data, NULL,
3452  NULL, 0,
3453  NULL, NULL);
3454 
3455  destroyPQExpBuffer(delq);
3456  destroyPQExpBuffer(query);
3457 }
3458 
3459 /*
3460  * getPublicationTables
3461  * get information about publication membership for dumpable tables.
3462  */
3463 void
3465 {
3466  PQExpBuffer query;
3467  PGresult *res;
3468  PublicationRelInfo *pubrinfo;
3469  int i_tableoid;
3470  int i_oid;
3471  int i_pubname;
3472  int i,
3473  j,
3474  ntups;
3475 
3476  if (fout->remoteVersion < 100000)
3477  return;
3478 
3479  query = createPQExpBuffer();
3480 
3481  for (i = 0; i < numTables; i++)
3482  {
3483  TableInfo *tbinfo = &tblinfo[i];
3484 
3485  /* Only plain tables can be aded to publications. */
3486  if (tbinfo->relkind != RELKIND_RELATION)
3487  continue;
3488 
3489  /*
3490  * Ignore publication membership of tables whose definitions are
3491  * not to be dumped.
3492  */
3493  if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3494  continue;
3495 
3496  if (g_verbose)
3497  write_msg(NULL, "reading publication membership for table \"%s.%s\"\n",
3498  tbinfo->dobj.namespace->dobj.name,
3499  tbinfo->dobj.name);
3500 
3501  resetPQExpBuffer(query);
3502 
3503  /* Get the publication membership for the table. */
3504  appendPQExpBuffer(query,
3505  "SELECT pr.tableoid, pr.oid, p.pubname "
3506  "FROM pg_catalog.pg_publication_rel pr,"
3507  " pg_catalog.pg_publication p "
3508  "WHERE pr.prrelid = '%u'"
3509  " AND p.oid = pr.prpubid",
3510  tbinfo->dobj.catId.oid);
3511  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3512 
3513  ntups = PQntuples(res);
3514 
3515  if (ntups == 0)
3516  {
3517  /*
3518  * Table is not member of any publications. Clean up and return.
3519  */
3520  PQclear(res);
3521  continue;
3522  }
3523 
3524  i_tableoid = PQfnumber(res, "tableoid");
3525  i_oid = PQfnumber(res, "oid");
3526  i_pubname = PQfnumber(res, "pubname");
3527 
3528  pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
3529 
3530  for (j = 0; j < ntups; j++)
3531  {
3532  pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
3533  pubrinfo[j].dobj.catId.tableoid =
3534  atooid(PQgetvalue(res, j, i_tableoid));
3535  pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3536  AssignDumpId(&pubrinfo[j].dobj);
3537  pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3538  pubrinfo[j].pubname = pg_strdup(PQgetvalue(res, j, i_pubname));
3539  pubrinfo[j].pubtable = tbinfo;
3540  }
3541  PQclear(res);
3542  }
3543  destroyPQExpBuffer(query);
3544 }
3545 
3546 /*
3547  * dumpPublicationTable
3548  * dump the definition of the given publication table mapping
3549  */
3550 static void
3552 {
3553  DumpOptions *dopt = fout->dopt;
3554  TableInfo *tbinfo = pubrinfo->pubtable;
3555  PQExpBuffer query;
3556  char *tag;
3557 
3558  if (dopt->dataOnly)
3559  return;
3560 
3561  tag = psprintf("%s %s", pubrinfo->pubname, tbinfo->dobj.name);
3562 
3563  query = createPQExpBuffer();
3564 
3565  appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE",
3566  fmtId(pubrinfo->pubname));
3567  appendPQExpBuffer(query, " %s;",
3568  fmtId(tbinfo->dobj.name));
3569 
3570  /*
3571  * There is no point in creating drop query as drop query as the drop
3572  * is done by table drop.
3573  */
3574  ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
3575  tag,
3576  tbinfo->dobj.namespace->dobj.name,
3577  NULL,
3578  "", false,
3579  "PUBLICATION TABLE", SECTION_POST_DATA,
3580  query->data, "", NULL,
3581  NULL, 0,
3582  NULL, NULL);
3583 
3584  free(tag);
3585  destroyPQExpBuffer(query);
3586 }
3587 
3588 
3589 /*
3590  * getSubscriptions
3591  * get information about subscriptions
3592  */
3593 void
3595 {
3596  DumpOptions *dopt = fout->dopt;
3597  PQExpBuffer query;
3598  PGresult *res;
3599  SubscriptionInfo *subinfo;
3600  int i_tableoid;
3601  int i_oid;
3602  int i_subname;
3603  int i_rolname;
3604  int i_subenabled;
3605  int i_subconninfo;
3606  int i_subslotname;
3607  int i_subpublications;
3608  int i,
3609  ntups;
3610 
3611  if (!dopt->include_subscriptions || fout->remoteVersion < 100000)
3612  return;
3613 
3614  query = createPQExpBuffer();
3615 
3616  resetPQExpBuffer(query);
3617 
3618  /* Get the subscriptions in current database. */
3619  appendPQExpBuffer(query,
3620  "SELECT s.tableoid, s.oid, s.subname,"
3621  "(%s s.subowner) AS rolname, s.subenabled, "
3622  " s.subconninfo, s.subslotname, s.subpublications "
3623  "FROM pg_catalog.pg_subscription s "
3624  "WHERE s.subdbid = (SELECT oid FROM pg_catalog.pg_database"
3625  " WHERE datname = current_database())",
3627  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3628 
3629  ntups = PQntuples(res);
3630 
3631  i_tableoid = PQfnumber(res, "tableoid");
3632  i_oid = PQfnumber(res, "oid");
3633  i_subname = PQfnumber(res, "subname");
3634  i_rolname = PQfnumber(res, "rolname");
3635  i_subenabled = PQfnumber(res, "subenabled");
3636  i_subconninfo = PQfnumber(res, "subconninfo");
3637  i_subslotname = PQfnumber(res, "subslotname");
3638  i_subpublications = PQfnumber(res, "subpublications");
3639 
3640  subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
3641 
3642  for (i = 0; i < ntups; i++)
3643  {
3644  subinfo[i].dobj.objType = DO_SUBSCRIPTION;
3645  subinfo[i].dobj.catId.tableoid =
3646  atooid(PQgetvalue(res, i, i_tableoid));
3647  subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3648  AssignDumpId(&subinfo[i].dobj);
3649  subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
3650  subinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3651  subinfo[i].subenabled =
3652  (strcmp(PQgetvalue(res, i, i_subenabled), "t") == 0);
3653  subinfo[i].subconninfo = pg_strdup(PQgetvalue(res, i, i_subconninfo));
3654  subinfo[i].subslotname = pg_strdup(PQgetvalue(res, i, i_subslotname));
3655  subinfo[i].subpublications =
3656  pg_strdup(PQgetvalue(res, i, i_subpublications));
3657 
3658  if (strlen(subinfo[i].rolname) == 0)
3659  write_msg(NULL, "WARNING: owner of subscription \"%s\" appears to be invalid\n",
3660  subinfo[i].dobj.name);
3661  }
3662  PQclear(res);
3663 
3664  destroyPQExpBuffer(query);
3665 }
3666 
3667 /*
3668  * dumpSubscription
3669  * dump the definition of the given subscription
3670  */
3671 static void
3673 {
3674  DumpOptions *dopt = fout->dopt;
3675  PQExpBuffer delq;
3676  PQExpBuffer query;
3677  PQExpBuffer publications;
3678  char **pubnames = NULL;
3679  int npubnames = 0;
3680  int i;
3681 
3682  if (dopt->dataOnly)
3683  return;
3684 
3685  delq = createPQExpBuffer();
3686  query = createPQExpBuffer();
3687 
3688  appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
3689  fmtId(subinfo->dobj.name));
3690 
3691  appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
3692  fmtId(subinfo->dobj.name));
3693  appendStringLiteralAH(query, subinfo->subconninfo, fout);
3694 
3695  /* Build list of quoted publications and append them to query. */
3696  if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
3697  {
3698  write_msg(NULL,
3699  "WARNING: could not parse subpublications array\n");
3700  if (pubnames)
3701  free(pubnames);
3702  pubnames = NULL;
3703  npubnames = 0;
3704  }
3705 
3706  publications = createPQExpBuffer();
3707  for (i = 0; i < npubnames; i++)
3708  {
3709  if (i > 0)
3710  appendPQExpBufferStr(publications, ", ");
3711 
3712  appendPQExpBufferStr(publications, fmtId(pubnames[i]));
3713  }
3714 
3715  appendPQExpBuffer(query, " PUBLICATION %s WITH (", publications->data);
3716 
3717  if (subinfo->subenabled)
3718  appendPQExpBufferStr(query, "ENABLED");
3719  else
3720  appendPQExpBufferStr(query, "DISABLED");
3721 
3722  appendPQExpBufferStr(query, ", SLOT NAME = ");
3723  appendStringLiteralAH(query, subinfo->subslotname, fout);
3724 
3725  if (dopt->no_create_subscription_slots)
3726  appendPQExpBufferStr(query, ", NOCREATE SLOT");
3727 
3728  appendPQExpBufferStr(query, ");\n");
3729 
3730  ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
3731  subinfo->dobj.name,
3732  NULL,
3733  NULL,
3734  subinfo->rolname, false,
3735  "SUBSCRIPTION", SECTION_POST_DATA,
3736  query->data, delq->data, NULL,
3737  NULL, 0,
3738  NULL, NULL);
3739 
3740  destroyPQExpBuffer(publications);
3741  if (pubnames)
3742  free(pubnames);
3743 
3744  destroyPQExpBuffer(delq);
3745  destroyPQExpBuffer(query);
3746 }
3747 
3748 static void
3750  PQExpBuffer upgrade_buffer,
3751  Oid pg_type_oid)
3752 {
3753  PQExpBuffer upgrade_query = createPQExpBuffer();
3754  PGresult *upgrade_res;
3755  Oid pg_type_array_oid;
3756 
3757  appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
3758  appendPQExpBuffer(upgrade_buffer,
3759  "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
3760  pg_type_oid);
3761 
3762  /* we only support old >= 8.3 for binary upgrades */
3763  appendPQExpBuffer(upgrade_query,
3764  "SELECT typarray "
3765  "FROM pg_catalog.pg_type "
3766  "WHERE pg_type.oid = '%u'::pg_catalog.oid;",
3767  pg_type_oid);
3768 
3769  upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
3770 
3771  pg_type_array_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "typarray")));
3772 
3773  if (OidIsValid(pg_type_array_oid))
3774  {
3775  appendPQExpBufferStr(upgrade_buffer,
3776  "\n-- For binary upgrade, must preserve pg_type array oid\n");
3777  appendPQExpBuffer(upgrade_buffer,
3778  "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
3779  pg_type_array_oid);
3780  }
3781 
3782  PQclear(upgrade_res);
3783  destroyPQExpBuffer(upgrade_query);
3784 }
3785 
3786 static bool
3788  PQExpBuffer upgrade_buffer,
3789  Oid pg_rel_oid)
3790 {
3791  PQExpBuffer upgrade_query = createPQExpBuffer();
3792  PGresult *upgrade_res;
3793  Oid pg_type_oid;
3794  bool toast_set = false;
3795 
3796  /* we only support old >= 8.3 for binary upgrades */
3797  appendPQExpBuffer(upgrade_query,
3798  "SELECT c.reltype AS crel, t.reltype AS trel "
3799  "FROM pg_catalog.pg_class c "
3800  "LEFT JOIN pg_catalog.pg_class t ON "
3801  " (c.reltoastrelid = t.oid) "
3802  "WHERE c.oid = '%u'::pg_catalog.oid;",
3803  pg_rel_oid);
3804 
3805  upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
3806 
3807  pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
3808 
3809  binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
3810  pg_type_oid);
3811 
3812  if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
3813  {
3814  /* Toast tables do not have pg_type array rows */
3815  Oid pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
3816  PQfnumber(upgrade_res, "trel")));
3817 
3818  appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
3819  appendPQExpBuffer(upgrade_buffer,
3820  "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
3821  pg_type_toast_oid);
3822 
3823  toast_set = true;
3824  }
3825 
3826  PQclear(upgrade_res);
3827  destroyPQExpBuffer(upgrade_query);
3828 
3829  return toast_set;
3830 }
3831 
3832 static void
3834  PQExpBuffer upgrade_buffer, Oid pg_class_oid,
3835  bool is_index)
3836 {
3837  PQExpBuffer upgrade_query = createPQExpBuffer();
3838  PGresult *upgrade_res;
3839  Oid pg_class_reltoastrelid;
3840  Oid pg_index_indexrelid;
3841 
3842  appendPQExpBuffer(upgrade_query,
3843  "SELECT c.reltoastrelid, i.indexrelid "
3844  "FROM pg_catalog.pg_class c LEFT JOIN "
3845  "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
3846  "WHERE c.oid = '%u'::pg_catalog.oid;",
3847  pg_class_oid);
3848 
3849  upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
3850 
3851  pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
3852  pg_index_indexrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "indexrelid")));
3853 
3854  appendPQExpBufferStr(upgrade_buffer,
3855  "\n-- For binary upgrade, must preserve pg_class oids\n");
3856 
3857  if (!is_index)
3858  {
3859  appendPQExpBuffer(upgrade_buffer,
3860  "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
3861  pg_class_oid);
3862  /* only tables have toast tables, not indexes */
3863  if (OidIsValid(pg_class_reltoastrelid))
3864  {
3865  /*
3866  * One complexity is that the table definition might not require
3867  * the creation of a TOAST table, and the TOAST table might have
3868  * been created long after table creation, when the table was
3869  * loaded with wide data. By setting the TOAST oid we force
3870  * creation of the TOAST heap and TOAST index by the backend so we
3871  * can cleanly copy the files during binary upgrade.
3872  */
3873 
3874  appendPQExpBuffer(upgrade_buffer,
3875  "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
3876  pg_class_reltoastrelid);
3877 
3878  /* every toast table has an index */
3879  appendPQExpBuffer(upgrade_buffer,
3880  "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
3881  pg_index_indexrelid);
3882  }
3883  }
3884  else
3885  appendPQExpBuffer(upgrade_buffer,
3886  "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
3887  pg_class_oid);
3888 
3889  appendPQExpBufferChar(upgrade_buffer, '\n');
3890 
3891  PQclear(upgrade_res);
3892  destroyPQExpBuffer(upgrade_query);
3893 }
3894 
3895 /*
3896  * If the DumpableObject is a member of an extension, add a suitable
3897  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
3898  */
3899 static void
3901  DumpableObject *dobj,
3902  const char *objlabel)
3903 {
3904  DumpableObject *extobj = NULL;
3905  int i;
3906 
3907  if (!dobj->ext_member)
3908  return;
3909 
3910  /*
3911  * Find the parent extension. We could avoid this search if we wanted to
3912  * add a link field to DumpableObject, but the space costs of that would
3913  * be considerable. We assume that member objects could only have a
3914  * direct dependency on their own extension, not any others.
3915  */
3916  for (i = 0; i < dobj->nDeps; i++)
3917  {
3918  extobj = findObjectByDumpId(dobj->dependencies[i]);
3919  if (extobj && extobj->objType == DO_EXTENSION)
3920  break;
3921  extobj = NULL;
3922  }
3923  if (extobj == NULL)
3924  exit_horribly(NULL, "could not find parent extension for %s\n", objlabel);
3925 
3926  appendPQExpBufferStr(upgrade_buffer,
3927  "\n-- For binary upgrade, handle extension membership the hard way\n");
3928  appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s;\n",
3929  fmtId(extobj->name),
3930  objlabel);
3931 }
3932 
3933 /*
3934  * getNamespaces:
3935  * read all namespaces in the system catalogs and return them in the
3936  * NamespaceInfo* structure
3937  *
3938  * numNamespaces is set to the number of namespaces read in
3939  */
3940 NamespaceInfo *
3942 {
3943  DumpOptions *dopt = fout->dopt;
3944  PGresult *res;
3945  int ntups;
3946  int i;
3947  PQExpBuffer query;
3948  NamespaceInfo *nsinfo;
3949  int i_tableoid;
3950  int i_oid;
3951  int i_nspname;
3952  int i_rolname;
3953  int i_nspacl;
3954  int i_rnspacl;
3955  int i_initnspacl;
3956  int i_initrnspacl;
3957 
3958  query = createPQExpBuffer();
3959 
3960  /* Make sure we are in proper schema */
3961  selectSourceSchema(fout, "pg_catalog");
3962 
3963  /*
3964  * we fetch all namespaces including system ones, so that every object we
3965  * read in can be linked to a containing namespace.
3966  */
3967  if (fout->remoteVersion >= 90600)
3968  {
3969  PQExpBuffer acl_subquery = createPQExpBuffer();
3970  PQExpBuffer racl_subquery = createPQExpBuffer();
3971  PQExpBuffer init_acl_subquery = createPQExpBuffer();
3972  PQExpBuffer init_racl_subquery = createPQExpBuffer();
3973 
3974  buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
3975  init_racl_subquery, "n.nspacl", "n.nspowner", "'n'",
3976  dopt->binary_upgrade);
3977 
3978  appendPQExpBuffer(query, "SELECT n.tableoid, n.oid, n.nspname, "
3979  "(%s nspowner) AS rolname, "
3980  "%s as nspacl, "
3981  "%s as rnspacl, "
3982  "%s as initnspacl, "
3983  "%s as initrnspacl "
3984  "FROM pg_namespace n "
3985  "LEFT JOIN pg_init_privs pip "
3986  "ON (n.oid = pip.objoid "
3987  "AND pip.classoid = 'pg_namespace'::regclass "
3988  "AND pip.objsubid = 0) ",
3990  acl_subquery->data,
3991  racl_subquery->data,
3992  init_acl_subquery->data,
3993  init_racl_subquery->data);
3994 
3995  destroyPQExpBuffer(acl_subquery);
3996  destroyPQExpBuffer(racl_subquery);
3997  destroyPQExpBuffer(init_acl_subquery);
3998  destroyPQExpBuffer(init_racl_subquery);
3999  }
4000  else
4001  appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
4002  "(%s nspowner) AS rolname, "
4003  "nspacl, NULL as rnspacl, "
4004  "NULL AS initnspacl, NULL as initrnspacl "
4005  "FROM pg_namespace",
4007 
4008  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4009 
4010  ntups = PQntuples(res);
4011 
4012  nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
4013 
4014  i_tableoid = PQfnumber(res, "tableoid");
4015  i_oid = PQfnumber(res, "oid");
4016  i_nspname = PQfnumber(res, "nspname");
4017  i_rolname = PQfnumber(res, "rolname");
4018  i_nspacl = PQfnumber(res, "nspacl");
4019  i_rnspacl = PQfnumber(res, "rnspacl");
4020  i_initnspacl = PQfnumber(res, "initnspacl");
4021  i_initrnspacl = PQfnumber(res, "initrnspacl");
4022 
4023  for (i = 0; i < ntups; i++)
4024  {
4025  nsinfo[i].dobj.objType = DO_NAMESPACE;
4026  nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4027  nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4028  AssignDumpId(&nsinfo[i].dobj);
4029  nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
4030  nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4031  nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
4032  nsinfo[i].rnspacl = pg_strdup(PQgetvalue(res, i, i_rnspacl));
4033  nsinfo[i].initnspacl = pg_strdup(PQgetvalue(res, i, i_initnspacl));
4034  nsinfo[i].initrnspacl = pg_strdup(PQgetvalue(res, i, i_initrnspacl));
4035 
4036  /* Decide whether to dump this namespace */
4037  selectDumpableNamespace(&nsinfo[i], fout);
4038 
4039  /*
4040  * Do not try to dump ACL if the ACL is empty or the default.
4041  *
4042  * This is useful because, for some schemas/objects, the only
4043  * component we are going to try and dump is the ACL and if we can
4044  * remove that then 'dump' goes to zero/false and we don't consider
4045  * this object for dumping at all later on.
4046  */
4047  if (PQgetisnull(res, i, i_nspacl) && PQgetisnull(res, i, i_rnspacl) &&
4048  PQgetisnull(res, i, i_initnspacl) &&
4049  PQgetisnull(res, i, i_initrnspacl))
4050  nsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4051 
4052  if (strlen(nsinfo[i].rolname) == 0)
4053  write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
4054  nsinfo[i].dobj.name);
4055  }
4056 
4057  PQclear(res);
4058  destroyPQExpBuffer(query);
4059 
4060  *numNamespaces = ntups;
4061 
4062  return nsinfo;
4063 }
4064 
4065 /*
4066  * findNamespace:
4067  * given a namespace OID, look up the info read by getNamespaces
4068  */
4069 static NamespaceInfo *
4071 {
4072  NamespaceInfo *nsinfo;
4073 
4074  nsinfo = findNamespaceByOid(nsoid);
4075  if (nsinfo == NULL)
4076  exit_horribly(NULL, "schema with OID %u does not exist\n", nsoid);
4077  return nsinfo;
4078 }
4079 
4080 /*
4081  * getExtensions:
4082  * read all extensions in the system catalogs and return them in the
4083  * ExtensionInfo* structure
4084  *
4085  * numExtensions is set to the number of extensions read in
4086  */
4087 ExtensionInfo *
4089 {
4090  DumpOptions *dopt = fout->dopt;
4091  PGresult *res;
4092  int ntups;
4093  int i;
4094  PQExpBuffer query;
4095  ExtensionInfo *extinfo;
4096  int i_tableoid;
4097  int i_oid;
4098  int i_extname;
4099  int i_nspname;
4100  int i_extrelocatable;
4101  int i_extversion;
4102  int i_extconfig;
4103  int i_extcondition;
4104 
4105  /*
4106  * Before 9.1, there are no extensions.
4107  */
4108  if (fout->remoteVersion < 90100)
4109  {
4110  *numExtensions = 0;
4111  return NULL;
4112  }
4113 
4114  query = createPQExpBuffer();
4115 
4116  /* Make sure we are in proper schema */
4117  selectSourceSchema(fout, "pg_catalog");
4118 
4119  appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
4120  "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
4121  "FROM pg_extension x "
4122  "JOIN pg_namespace n ON n.oid = x.extnamespace");
4123 
4124  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4125 
4126  ntups = PQntuples(res);
4127 
4128  extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
4129 
4130  i_tableoid = PQfnumber(res, "tableoid");
4131  i_oid = PQfnumber(res, "oid");
4132  i_extname = PQfnumber(res, "extname");
4133  i_nspname = PQfnumber(res, "nspname");
4134  i_extrelocatable = PQfnumber(res, "extrelocatable");
4135  i_extversion = PQfnumber(res, "extversion");
4136  i_extconfig = PQfnumber(res, "extconfig");
4137  i_extcondition = PQfnumber(res, "extcondition");
4138 
4139  for (i = 0; i < ntups; i++)
4140  {
4141  extinfo[i].dobj.objType = DO_EXTENSION;
4142  extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4143  extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4144  AssignDumpId(&extinfo[i].dobj);
4145  extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
4146  extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
4147  extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
4148  extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
4149  extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
4150  extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
4151 
4152  /* Decide whether we want to dump it */
4153  selectDumpableExtension(&(extinfo[i]), dopt);
4154  }
4155 
4156  PQclear(res);
4157  destroyPQExpBuffer(query);
4158 
4159  *numExtensions = ntups;
4160 
4161  return extinfo;
4162 }
4163 
4164 /*
4165  * getTypes:
4166  * read all types in the system catalogs and return them in the
4167  * TypeInfo* structure
4168  *
4169  * numTypes is set to the number of types read in
4170  *
4171  * NB: this must run after getFuncs() because we assume we can do
4172  * findFuncByOid().
4173  */
4174 TypeInfo *
4176 {
4177  DumpOptions *dopt = fout->dopt;
4178  PGresult *res;
4179  int ntups;
4180  int i;
4181  PQExpBuffer query = createPQExpBuffer();
4182  TypeInfo *tyinfo;
4183  ShellTypeInfo *stinfo;
4184  int i_tableoid;
4185  int i_oid;
4186  int i_typname;
4187  int i_typnamespace;
4188  int i_typacl;
4189  int i_rtypacl;
4190  int i_inittypacl;
4191  int i_initrtypacl;
4192  int i_rolname;
4193  int i_typelem;
4194  int i_typrelid;
4195  int i_typrelkind;
4196  int i_typtype;
4197  int i_typisdefined;
4198  int i_isarray;
4199 
4200  /*
4201  * we include even the built-in types because those may be used as array
4202  * elements by user-defined types
4203  *
4204  * we filter out the built-in types when we dump out the types
4205  *
4206  * same approach for undefined (shell) types and array types
4207  *
4208  * Note: as of 8.3 we can reliably detect whether a type is an
4209  * auto-generated array type by checking the element type's typarray.
4210  * (Before that the test is capable of generating false positives.) We
4211  * still check for name beginning with '_', though, so as to avoid the
4212  * cost of the subselect probe for all standard types. This would have to
4213  * be revisited if the backend ever allows renaming of array types.
4214  */
4215 
4216  /* Make sure we are in proper schema */
4217  selectSourceSchema(fout, "pg_catalog");
4218 
4219  if (fout->remoteVersion >= 90600)
4220  {
4221  PQExpBuffer acl_subquery = createPQExpBuffer();
4222  PQExpBuffer racl_subquery = createPQExpBuffer();
4223  PQExpBuffer initacl_subquery = createPQExpBuffer();
4224  PQExpBuffer initracl_subquery = createPQExpBuffer();
4225 
4226  buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
4227  initracl_subquery, "t.typacl", "t.typowner", "'T'",
4228  dopt->binary_upgrade);
4229 
4230  appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, t.typname, "
4231  "t.typnamespace, "
4232  "%s AS typacl, "
4233  "%s AS rtypacl, "
4234  "%s AS inittypacl, "
4235  "%s AS initrtypacl, "
4236  "(%s t.typowner) AS rolname, "
4237  "t.typelem, t.typrelid, "
4238  "CASE WHEN t.typrelid = 0 THEN ' '::\"char\" "
4239  "ELSE (SELECT relkind FROM pg_class WHERE oid = t.typrelid) END AS typrelkind, "
4240  "t.typtype, t.typisdefined, "
4241  "t.typname[0] = '_' AND t.typelem != 0 AND "
4242  "(SELECT typarray FROM pg_type te WHERE oid = t.typelem) = t.oid AS isarray "
4243  "FROM pg_type t "
4244  "LEFT JOIN pg_init_privs pip ON "
4245  "(t.oid = pip.objoid "
4246  "AND pip.classoid = 'pg_type'::regclass "
4247  "AND pip.objsubid = 0) ",
4248  acl_subquery->data,
4249  racl_subquery->data,
4250  initacl_subquery->data,
4251  initracl_subquery->data,
4253 
4254  destroyPQExpBuffer(acl_subquery);
4255  destroyPQExpBuffer(racl_subquery);
4256  destroyPQExpBuffer(initacl_subquery);
4257  destroyPQExpBuffer(initracl_subquery);
4258  }
4259  else if (fout->remoteVersion >= 90200)
4260  {
4261  appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4262  "typnamespace, typacl, NULL as rtypacl, "
4263  "NULL AS inittypacl, NULL AS initrtypacl, "
4264  "(%s typowner) AS rolname, "
4265  "typelem, typrelid, "
4266  "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4267  "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4268  "typtype, typisdefined, "
4269  "typname[0] = '_' AND typelem != 0 AND "
4270  "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4271  "FROM pg_type",
4273  }
4274  else if (fout->remoteVersion >= 80300)
4275  {
4276  appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4277  "typnamespace, NULL AS typacl, NULL as rtypacl, "
4278  "NULL AS inittypacl, NULL AS initrtypacl, "
4279  "(%s typowner) AS rolname, "
4280  "typelem, typrelid, "
4281  "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4282  "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4283  "typtype, typisdefined, "
4284  "typname[0] = '_' AND typelem != 0 AND "
4285  "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4286  "FROM pg_type",
4288  }
4289  else
4290  {
4291  appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4292  "typnamespace, NULL AS typacl, NULL as rtypacl, "
4293  "NULL AS inittypacl, NULL AS initrtypacl, "
4294  "(%s typowner) AS rolname, "
4295  "typelem, typrelid, "
4296  "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4297  "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4298  "typtype, typisdefined, "
4299  "typname[0] = '_' AND typelem != 0 AS isarray "
4300  "FROM pg_type",
4302  }
4303 
4304  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4305 
4306  ntups = PQntuples(res);
4307 
4308  tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
4309 
4310  i_tableoid = PQfnumber(res, "tableoid");
4311  i_oid = PQfnumber(res, "oid");
4312  i_typname = PQfnumber(res, "typname");
4313  i_typnamespace = PQfnumber(res, "typnamespace");
4314  i_typacl = PQfnumber(res, "typacl");
4315  i_rtypacl = PQfnumber(res, "rtypacl");
4316  i_inittypacl = PQfnumber(res, "inittypacl");
4317  i_initrtypacl = PQfnumber(res, "initrtypacl");
4318  i_rolname = PQfnumber(res, "rolname");
4319  i_typelem = PQfnumber(res, "typelem");
4320  i_typrelid = PQfnumber(res, "typrelid");
4321  i_typrelkind = PQfnumber(res, "typrelkind");
4322  i_typtype = PQfnumber(res, "typtype");
4323  i_typisdefined = PQfnumber(res, "typisdefined");
4324  i_isarray = PQfnumber(res, "isarray");
4325 
4326  for (i = 0; i < ntups; i++)
4327  {
4328  tyinfo[i].dobj.objType = DO_TYPE;
4329  tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4330  tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4331  AssignDumpId(&tyinfo[i].dobj);
4332  tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
4333  tyinfo[i].dobj.namespace =
4334  findNamespace(fout,
4335  atooid(PQgetvalue(res, i, i_typnamespace)));
4336  tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4337  tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
4338  tyinfo[i].rtypacl = pg_strdup(PQgetvalue(res, i, i_rtypacl));
4339  tyinfo[i].inittypacl = pg_strdup(PQgetvalue(res, i, i_inittypacl));
4340  tyinfo[i].initrtypacl = pg_strdup(PQgetvalue(res, i, i_initrtypacl));
4341  tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
4342  tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
4343  tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
4344  tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
4345  tyinfo[i].shellType = NULL;
4346 
4347  if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
4348  tyinfo[i].isDefined = true;
4349  else
4350  tyinfo[i].isDefined = false;
4351 
4352  if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
4353  tyinfo[i].isArray = true;
4354  else
4355  tyinfo[i].isArray = false;
4356 
4357  /* Decide whether we want to dump it */
4358  selectDumpableType(&tyinfo[i], fout);
4359 
4360  /* Do not try to dump ACL if no ACL exists. */
4361  if (PQgetisnull(res, i, i_typacl) && PQgetisnull(res, i, i_rtypacl) &&
4362  PQgetisnull(res, i, i_inittypacl) &&
4363  PQgetisnull(res, i, i_initrtypacl))
4364  tyinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4365 
4366  /*
4367  * If it's a domain, fetch info about its constraints, if any
4368  */
4369  tyinfo[i].nDomChecks = 0;
4370  tyinfo[i].domChecks = NULL;
4371  if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4372  tyinfo[i].typtype == TYPTYPE_DOMAIN)
4373  getDomainConstraints(fout, &(tyinfo[i]));
4374 
4375  /*
4376  * If it's a base type, make a DumpableObject representing a shell
4377  * definition of the type. We will need to dump that ahead of the I/O
4378  * functions for the type. Similarly, range types need a shell
4379  * definition in case they have a canonicalize function.
4380  *
4381  * Note: the shell type doesn't have a catId. You might think it
4382  * should copy the base type's catId, but then it might capture the
4383  * pg_depend entries for the type, which we don't want.
4384  */
4385  if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4386  (tyinfo[i].typtype == TYPTYPE_BASE ||
4387  tyinfo[i].typtype == TYPTYPE_RANGE))
4388  {
4389  stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
4390  stinfo->dobj.objType = DO_SHELL_TYPE;
4391  stinfo->dobj.catId = nilCatalogId;
4392  AssignDumpId(&stinfo->dobj);
4393  stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
4394  stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
4395  stinfo->baseType = &(tyinfo[i]);
4396  tyinfo[i].shellType = stinfo;
4397 
4398  /*
4399  * Initially mark the shell type as not to be dumped. We'll only
4400  * dump it if the I/O or canonicalize functions need to be dumped;
4401  * this is taken care of while sorting dependencies.
4402  */
4403  stinfo->dobj.dump = DUMP_COMPONENT_NONE;
4404  }
4405 
4406  if (strlen(tyinfo[i].rolname) == 0)
4407  write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
4408  tyinfo[i].dobj.name);
4409  }
4410 
4411  *numTypes = ntups;
4412 
4413  PQclear(res);
4414 
4415  destroyPQExpBuffer(query);
4416 
4417  return tyinfo;
4418 }
4419 
4420 /*
4421  * getOperators:
4422  * read all operators in the system catalogs and return them in the
4423  * OprInfo* structure
4424  *
4425  * numOprs is set to the number of operators read in
4426  */
4427 OprInfo *
4428 getOperators(Archive *fout, int *numOprs)
4429 {
4430  PGresult *res;
4431  int ntups;
4432  int i;
4433  PQExpBuffer query = createPQExpBuffer();
4434  OprInfo *oprinfo;
4435  int i_tableoid;
4436  int i_oid;
4437  int i_oprname;
4438  int i_oprnamespace;
4439  int i_rolname;
4440  int i_oprkind;
4441  int i_oprcode;
4442 
4443  /*
4444  * find all operators, including builtin operators; we filter out
4445  * system-defined operators at dump-out time.
4446  */
4447 
4448  /* Make sure we are in proper schema */
4449  selectSourceSchema(fout, "pg_catalog");
4450 
4451  appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
4452  "oprnamespace, "
4453  "(%s oprowner) AS rolname, "
4454  "oprkind, "
4455  "oprcode::oid AS oprcode "
4456  "FROM pg_operator",
4458 
4459  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4460 
4461  ntups = PQntuples(res);
4462  *numOprs = ntups;
4463 
4464  oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
4465 
4466  i_tableoid = PQfnumber(res, "tableoid");
4467  i_oid = PQfnumber(res, "oid");
4468  i_oprname = PQfnumber(res, "oprname");
4469  i_oprnamespace = PQfnumber(res, "oprnamespace");
4470  i_rolname = PQfnumber(res, "rolname");
4471  i_oprkind = PQfnumber(res, "oprkind");
4472  i_oprcode = PQfnumber(res, "oprcode");
4473 
4474  for (i = 0; i < ntups; i++)
4475  {
4476  oprinfo[i].dobj.objType = DO_OPERATOR;
4477  oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4478  oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4479  AssignDumpId(&oprinfo[i].dobj);
4480  oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
4481  oprinfo[i].dobj.namespace =
4482  findNamespace(fout,
4483  atooid(PQgetvalue(res, i, i_oprnamespace)));
4484  oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4485  oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
4486  oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
4487 
4488  /* Decide whether we want to dump it */
4489  selectDumpableObject(&(oprinfo[i].dobj), fout);
4490 
4491  /* Operators do not currently have ACLs. */
4492  oprinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4493 
4494  if (strlen(oprinfo[i].rolname) == 0)
4495  write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
4496  oprinfo[i].dobj.name);
4497  }
4498 
4499  PQclear(res);
4500 
4501  destroyPQExpBuffer(query);
4502 
4503  return oprinfo;
4504 }
4505 
4506 /*
4507  * getCollations:
4508  * read all collations in the system catalogs and return them in the
4509  * CollInfo* structure
4510  *
4511  * numCollations is set to the number of collations read in
4512  */
4513 CollInfo *
4515 {
4516  PGresult *res;
4517  int ntups;
4518  int i;
4519  PQExpBuffer query;
4520  CollInfo *collinfo;
4521  int i_tableoid;
4522  int i_oid;
4523  int i_collname;
4524  int i_collnamespace;
4525  int i_rolname;
4526 
4527  /* Collations didn't exist pre-9.1 */
4528  if (fout->remoteVersion < 90100)
4529  {
4530  *numCollations = 0;
4531  return NULL;
4532  }
4533 
4534  query = createPQExpBuffer();
4535 
4536  /*
4537  * find all collations, including builtin collations; we filter out
4538  * system-defined collations at dump-out time.
4539  */
4540 
4541  /* Make sure we are in proper schema */
4542  selectSourceSchema(fout, "pg_catalog");
4543 
4544  appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
4545  "collnamespace, "
4546  "(%s collowner) AS rolname "
4547  "FROM pg_collation",
4549 
4550  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4551 
4552  ntups = PQntuples(res);
4553  *numCollations = ntups;
4554 
4555  collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
4556 
4557  i_tableoid = PQfnumber(res, "tableoid");
4558  i_oid = PQfnumber(res, "oid");
4559  i_collname = PQfnumber(res, "collname");
4560  i_collnamespace = PQfnumber(res, "collnamespace");
4561  i_rolname = PQfnumber(res, "rolname");
4562 
4563  for (i = 0; i < ntups; i++)
4564  {
4565  collinfo[i].dobj.objType = DO_COLLATION;
4566  collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4567  collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4568  AssignDumpId(&collinfo[i].dobj);
4569  collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
4570  collinfo[i].dobj.namespace =
4571  findNamespace(fout,
4572  atooid(PQgetvalue(res, i, i_collnamespace)));
4573  collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4574 
4575  /* Decide whether we want to dump it */
4576  selectDumpableObject(&(collinfo[i].dobj), fout);
4577 
4578  /* Collations do not currently have ACLs. */
4579  collinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4580  }
4581 
4582  PQclear(res);
4583 
4584  destroyPQExpBuffer(query);
4585 
4586  return collinfo;
4587 }
4588 
4589 /*
4590  * getConversions:
4591  * read all conversions in the system catalogs and return them in the
4592  * ConvInfo* structure
4593  *
4594  * numConversions is set to the number of conversions read in
4595  */
4596 ConvInfo *
4597 getConversions(Archive *fout, int *numConversions)
4598 {
4599  PGresult *res;
4600  int ntups;
4601  int i;
4602  PQExpBuffer query;
4603  ConvInfo *convinfo;
4604  int i_tableoid;
4605  int i_oid;
4606  int i_conname;
4607  int i_connamespace;
4608  int i_rolname;
4609 
4610  query = createPQExpBuffer();
4611 
4612  /*
4613  * find all conversions, including builtin conversions; we filter out
4614  * system-defined conversions at dump-out time.
4615  */
4616 
4617  /* Make sure we are in proper schema */
4618  selectSourceSchema(fout, "pg_catalog");
4619 
4620  appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
4621  "connamespace, "
4622  "(%s conowner) AS rolname "
4623  "FROM pg_conversion",
4625 
4626  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4627 
4628  ntups = PQntuples(res);
4629  *numConversions = ntups;
4630 
4631  convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
4632 
4633  i_tableoid = PQfnumber(res, "tableoid");
4634  i_oid = PQfnumber(res, "oid");
4635  i_conname = PQfnumber(res, "conname");
4636  i_connamespace = PQfnumber(res, "connamespace");
4637  i_rolname = PQfnumber(res, "rolname");
4638 
4639  for (i = 0; i < ntups; i++)
4640  {
4641  convinfo[i].dobj.objType = DO_CONVERSION;
4642  convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4643  convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4644  AssignDumpId(&convinfo[i].dobj);
4645  convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
4646  convinfo[i].dobj.namespace =
4647  findNamespace(fout,
4648  atooid(PQgetvalue(res, i, i_connamespace)));
4649  convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4650 
4651  /* Decide whether we want to dump it */
4652  selectDumpableObject(&(convinfo[i].dobj), fout);
4653 
4654  /* Conversions do not currently have ACLs. */
4655  convinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4656  }
4657 
4658  PQclear(res);
4659 
4660  destroyPQExpBuffer(query);
4661 
4662  return convinfo;
4663 }
4664 
4665 /*
4666  * getAccessMethods:
4667  * read all user-defined access methods in the system catalogs and return
4668  * them in the AccessMethodInfo* structure
4669  *
4670  * numAccessMethods is set to the number of access methods read in
4671  */
4673 getAccessMethods(Archive *fout, int *numAccessMethods)
4674 {
4675  PGresult *res;
4676  int ntups;
4677  int i;
4678  PQExpBuffer query;
4679  AccessMethodInfo *aminfo;
4680  int i_tableoid;
4681  int i_oid;
4682  int i_amname;
4683  int i_amhandler;
4684  int i_amtype;
4685 
4686  /* Before 9.6, there are no user-defined access methods */
4687  if (fout->remoteVersion < 90600)
4688  {
4689  *numAccessMethods = 0;
4690  return NULL;
4691  }
4692 
4693  query = createPQExpBuffer();
4694 
4695  /* Make sure we are in proper schema */
4696  selectSourceSchema(fout, "pg_catalog");
4697 
4698  /* Select all access methods from pg_am table */
4699  appendPQExpBuffer(query, "SELECT tableoid, oid, amname, amtype, "
4700  "amhandler::pg_catalog.regproc AS amhandler "
4701  "FROM pg_am");
4702 
4703  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4704 
4705  ntups = PQntuples(res);
4706  *numAccessMethods = ntups;
4707 
4708  aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
4709 
4710  i_tableoid = PQfnumber(res, "tableoid");
4711  i_oid = PQfnumber(res, "oid");
4712  i_amname = PQfnumber(res, "amname");
4713  i_amhandler = PQfnumber(res, "amhandler");
4714  i_amtype = PQfnumber(res, "amtype");
4715 
4716  for (i = 0; i < ntups; i++)
4717  {
4718  aminfo[i].dobj.objType = DO_ACCESS_METHOD;
4719  aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4720  aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4721  AssignDumpId(&aminfo[i].dobj);
4722  aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
4723  aminfo[i].dobj.namespace = NULL;
4724  aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
4725  aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
4726 
4727  /* Decide whether we want to dump it */
4728  selectDumpableAccessMethod(&(aminfo[i]), fout);
4729 
4730  /* Access methods do not currently have ACLs. */
4731  aminfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4732  }
4733 
4734  PQclear(res);
4735 
4736  destroyPQExpBuffer(query);
4737 
4738  return aminfo;
4739 }
4740 
4741 
4742 /*
4743  * getOpclasses:
4744  * read all opclasses in the system catalogs and return them in the
4745  * OpclassInfo* structure
4746  *
4747  * numOpclasses is set to the number of opclasses read in
4748  */
4749 OpclassInfo *
4750 getOpclasses(Archive *fout, int *numOpclasses)
4751 {
4752  PGresult *res;
4753  int ntups;
4754  int i;
4755  PQExpBuffer query = createPQExpBuffer();
4756  OpclassInfo *opcinfo;
4757  int i_tableoid;
4758  int i_oid;
4759  int i_opcname;
4760  int i_opcnamespace;
4761  int i_rolname;
4762 
4763  /*
4764  * find all opclasses, including builtin opclasses; we filter out
4765  * system-defined opclasses at dump-out time.
4766  */
4767 
4768  /* Make sure we are in proper schema */
4769  selectSourceSchema(fout, "pg_catalog");
4770 
4771  appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
4772  "opcnamespace, "
4773  "(%s opcowner) AS rolname "
4774  "FROM pg_opclass",
4776 
4777  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4778 
4779  ntups = PQntuples(res);
4780  *numOpclasses = ntups;
4781 
4782  opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
4783 
4784  i_tableoid = PQfnumber(res, "tableoid");
4785  i_oid = PQfnumber(res, "oid");
4786  i_opcname = PQfnumber(res, "opcname");
4787  i_opcnamespace = PQfnumber(res, "opcnamespace");
4788  i_rolname = PQfnumber(res, "rolname");
4789 
4790  for (i = 0; i < ntups; i++)
4791  {
4792  opcinfo[i].dobj.objType = DO_OPCLASS;
4793  opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4794  opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4795  AssignDumpId(&opcinfo[i].dobj);
4796  opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
4797  opcinfo[i].dobj.namespace =
4798  findNamespace(fout,
4799  atooid(PQgetvalue(res, i, i_opcnamespace)));
4800  opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4801 
4802  /* Decide whether we want to dump it */
4803  selectDumpableObject(&(opcinfo[i].dobj), fout);
4804 
4805  /* Op Classes do not currently have ACLs. */
4806  opcinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4807 
4808  if (strlen(opcinfo[i].rolname) == 0)
4809  write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
4810  opcinfo[i].dobj.name);
4811  }
4812 
4813  PQclear(res);
4814 
4815  destroyPQExpBuffer(query);
4816 
4817  return opcinfo;
4818 }
4819 
4820 /*
4821  * getOpfamilies:
4822  * read all opfamilies in the system catalogs and return them in the
4823  * OpfamilyInfo* structure
4824  *
4825  * numOpfamilies is set to the number of opfamilies read in
4826  */
4827 OpfamilyInfo *
4828 getOpfamilies(Archive *fout, int *numOpfamilies)
4829 {
4830  PGresult *res;
4831  int ntups;
4832  int i;
4833  PQExpBuffer query;
4834  OpfamilyInfo *opfinfo;
4835  int i_tableoid;
4836  int i_oid;
4837  int i_opfname;
4838  int i_opfnamespace;
4839  int i_rolname;
4840 
4841  /* Before 8.3, there is no separate concept of opfamilies */
4842  if (fout->remoteVersion < 80300)
4843  {
4844  *numOpfamilies = 0;
4845  return NULL;
4846  }
4847 
4848  query = createPQExpBuffer();
4849 
4850  /*
4851  * find all opfamilies, including builtin opfamilies; we filter out
4852  * system-defined opfamilies at dump-out time.
4853  */
4854 
4855  /* Make sure we are in proper schema */
4856  selectSourceSchema(fout, "pg_catalog");
4857 
4858  appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
4859  "opfnamespace, "
4860  "(%s opfowner) AS rolname "
4861  "FROM pg_opfamily",
4863 
4864  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4865 
4866  ntups = PQntuples(res);
4867  *numOpfamilies = ntups;
4868 
4869  opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
4870 
4871  i_tableoid = PQfnumber(res, "tableoid");
4872  i_oid = PQfnumber(res, "oid");
4873  i_opfname = PQfnumber(res, "opfname");
4874  i_opfnamespace = PQfnumber(res, "opfnamespace");
4875  i_rolname = PQfnumber(res, "rolname");
4876 
4877  for (i = 0; i < ntups; i++)
4878  {
4879  opfinfo[i].dobj.objType = DO_OPFAMILY;
4880  opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4881  opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4882  AssignDumpId(&opfinfo[i].dobj);
4883  opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
4884  opfinfo[i].dobj.namespace =
4885  findNamespace(fout,
4886  atooid(PQgetvalue(res, i, i_opfnamespace)));
4887  opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4888 
4889  /* Decide whether we want to dump it */
4890  selectDumpableObject(&(opfinfo[i].dobj), fout);
4891 
4892  /* Extensions do not currently have ACLs. */
4893  opfinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4894 
4895  if (strlen(opfinfo[i].rolname) == 0)
4896  write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
4897  opfinfo[i].dobj.name);
4898  }
4899 
4900  PQclear(res);
4901 
4902  destroyPQExpBuffer(query);
4903 
4904  return opfinfo;
4905 }
4906 
4907 /*
4908  * getAggregates:
4909  * read all the user-defined aggregates in the system catalogs and
4910  * return them in the AggInfo* structure
4911  *
4912  * numAggs is set to the number of aggregates read in
4913  */
4914 AggInfo *
4915 getAggregates(Archive *fout, int *numAggs)
4916 {
4917  DumpOptions *dopt = fout->dopt;
4918  PGresult *res;
4919  int ntups;
4920  int i;
4921  PQExpBuffer query = createPQExpBuffer();
4922  AggInfo *agginfo;
4923  int i_tableoid;
4924  int i_oid;
4925  int i_aggname;
4926  int i_aggnamespace;
4927  int i_pronargs;
4928  int i_proargtypes;
4929  int i_rolname;
4930  int i_aggacl;
4931  int i_raggacl;
4932  int i_initaggacl;
4933  int i_initraggacl;
4934 
4935  /* Make sure we are in proper schema */
4936  selectSourceSchema(fout, "pg_catalog");
4937 
4938  /*
4939  * Find all interesting aggregates. See comment in getFuncs() for the
4940  * rationale behind the filtering logic.
4941  */
4942  if (fout->remoteVersion >= 90600)
4943  {
4944  PQExpBuffer acl_subquery = createPQExpBuffer();
4945  PQExpBuffer racl_subquery = createPQExpBuffer();
4946  PQExpBuffer initacl_subquery = createPQExpBuffer();
4947  PQExpBuffer initracl_subquery = createPQExpBuffer();
4948 
4949  buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
4950  initracl_subquery, "p.proacl", "p.proowner", "'f'",
4951  dopt->binary_upgrade);
4952 
4953  appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
4954  "p.proname AS aggname, "
4955  "p.pronamespace AS aggnamespace, "
4956  "p.pronargs, p.proargtypes, "
4957  "(%s p.proowner) AS rolname, "
4958  "%s AS aggacl, "
4959  "%s AS raggacl, "
4960  "%s AS initaggacl, "
4961  "%s AS initraggacl "
4962  "FROM pg_proc p "
4963  "LEFT JOIN pg_init_privs pip ON "
4964  "(p.oid = pip.objoid "
4965  "AND pip.classoid = 'pg_proc'::regclass "
4966  "AND pip.objsubid = 0) "
4967  "WHERE p.proisagg AND ("
4968  "p.pronamespace != "
4969  "(SELECT oid FROM pg_namespace "
4970  "WHERE nspname = 'pg_catalog') OR "
4971  "p.proacl IS DISTINCT FROM pip.initprivs",
4973  acl_subquery->data,
4974  racl_subquery->data,
4975  initacl_subquery->data,
4976  initracl_subquery->data);
4977  if (dopt->binary_upgrade)
4978  appendPQExpBufferStr(query,
4979  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
4980  "classid = 'pg_proc'::regclass AND "
4981  "objid = p.oid AND "
4982  "refclassid = 'pg_extension'::regclass AND "
4983  "deptype = 'e')");
4984  appendPQExpBufferChar(query, ')');
4985 
4986  destroyPQExpBuffer(acl_subquery);
4987  destroyPQExpBuffer(racl_subquery);
4988  destroyPQExpBuffer(initacl_subquery);
4989  destroyPQExpBuffer(initracl_subquery);
4990  }
4991  else if (fout->remoteVersion >= 80200)
4992  {
4993  appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
4994  "pronamespace AS aggnamespace, "
4995  "pronargs, proargtypes, "
4996  "(%s proowner) AS rolname, "
4997  "proacl AS aggacl, "
4998  "NULL AS raggacl, "
4999  "NULL AS initaggacl, NULL AS initraggacl "
5000  "FROM pg_proc p "
5001  "WHERE proisagg AND ("
5002  "pronamespace != "
5003  "(SELECT oid FROM pg_namespace "
5004  "WHERE nspname = 'pg_catalog')",
5006  if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
5007  appendPQExpBufferStr(query,
5008  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5009  "classid = 'pg_proc'::regclass AND "
5010  "objid = p.oid AND "
5011  "refclassid = 'pg_extension'::regclass AND "
5012  "deptype = 'e')");
5013  appendPQExpBufferChar(query, ')');
5014  }
5015  else
5016  {
5017  appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
5018  "pronamespace AS aggnamespace, "
5019  "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
5020  "proargtypes, "
5021  "(%s proowner) AS rolname, "
5022  "proacl AS aggacl, "
5023  "NULL AS raggacl, "
5024  "NULL AS initaggacl, NULL AS initraggacl "
5025  "FROM pg_proc "
5026  "WHERE proisagg "
5027  "AND pronamespace != "
5028  "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
5030  }
5031 
5032  res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5033 
5034  ntups = PQntuples(res);
5035  *numAggs = ntups;
5036 
5037  agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
5038 
5039  i_tableoid = PQfnumber(res, "tableoid");
5040  i_oid = PQfnumber(res, "oid");
5041  i_aggname = PQfnumber(res, "aggname");
5042  i_aggnamespace = PQfnumber(res, "aggnamespace");
5043  i_pronargs = PQfnumber(res, "pronargs");
5044  i_proargtypes = PQfnumber(res, "proargtypes");
5045  i_rolname = PQfnumber(res, "rolname");
5046  i_aggacl = PQfnumber(res, "aggacl");
5047  i_raggacl = PQfnumber(res, "raggacl");
5048  i_initaggacl = PQfnumber(res, "initaggacl");
5049  i_initraggacl = PQfnumber(res, "initraggacl");
5050 
5051  for (i = 0; i < ntups; i++)
5052  {
5053  agginfo[i].aggfn.dobj.objType = DO_AGG;
5054  agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5055  agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5056  AssignDumpId(&agginfo[i].aggfn.dobj);
5057  agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
5058  agginfo[i].aggfn.dobj.namespace =
5059  findNamespace(fout,
5060  atooid(PQgetvalue(res, i, i_aggnamespace)));
5061  agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5062  if (strlen(agginfo[i].aggfn.rolname) == 0)
5063  write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
5064  agginfo[i].aggfn.dobj.name);
5065  agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
5066  agginfo[i].aggfn.prorettype = InvalidOid; /* not saved */
5067  agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
5068  agginfo[i].aggfn.rproacl = pg_strdup(PQgetvalue(res, i, i_raggacl));
5069  agginfo[i].aggfn.initproacl = pg_strdup(PQgetvalue(res, i, i_initaggacl));
5070  agginfo[i].aggfn.initrproacl = pg_strdup(PQgetvalue(res, i, i_initraggacl));
5071  agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
5072  if (agginfo[i].aggfn.nargs == 0)
5073  agginfo[i].aggfn.argtypes = NULL;
5074  else
5075  {
5076  agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
5077  parseOidArray(PQgetvalue(res, i, i_proargtypes),
5078  agginfo[i].aggfn.argtypes,
5079  agginfo[i].aggfn.nargs);
5080  }
5081 
5082  /* Decide whether we want to dump it */
5083  selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
5084 
5085  /* Do not try to dump ACL if no ACL exists. */
5086  if (PQgetisnull(res, i, i_aggacl) && PQgetisnull(res, i, i_raggacl) &&
5087  PQgetisnull(res, i, i_initaggacl) &&
5088  PQgetisnull(res, i, i_initraggacl))
5089  agginfo[i].aggfn.dobj.dump &= ~DUMP_COMPONENT_ACL;
5090  }
5091 
5092  PQclear(res);
5093 
5094  destroyPQExpBuffer(query);
5095 
5096  return agginfo;
5097 }
5098 
5099 /*
5100  * getFuncs:
5101  * read all the user-defined functions in the system catalogs and
5102  * return them in the FuncInfo* structure
5103  *
5104  * numFuncs is set to the number of functions read in
5105  */
5106 FuncInfo *
5108 {
5109  DumpOptions *dopt = fout->dopt;
5110  PGresult *res;
5111  int ntups;
5112  int i;
5113  PQExpBuffer query = createPQExpBuffer();
5114  FuncInfo *finfo;
5115  int i_tableoid;
5116  int i_oid;
5117  int i_proname;
5118  int i_pronamespace;
5119  int i_rolname;
5120  int i_prolang;
5121  int i_pronargs;
5122  int i_proargtypes;
5123  int i_prorettype;
5124  int i_proacl;
5125  int i_rproacl;
5126  int i_initproacl;
5127  int i_initrproacl;
5128 
5129  /* Make sure we are in proper schema */
5130  selectSourceSchema(fout, "pg_catalog");
5131 
5132  /*
5133  * Find all interesting functions. This is a bit complicated:
5134  *
5135  * 1. Always exclude aggregates; those are handled elsewhere.
5136  *
5137  * 2. Always exclude functions that are internally dependent on something
5138  * else, since presumably those will be created as a result of creating
5139  * the something else. This currently acts only to suppress constructor
5140  * functions for range types (so we only need it in 9.2 and up). Note
5141  * this is OK only because the constructors don't have any dependencies
5142  * the range type doesn't have; otherwise we might not get creation
5143  * ordering correct.
5144  *
5145  * 3. Otherwise, we normally exclude functions in pg_catalog. However, if
5146  * they're members of extensions and we are in binary-upgrade mode then
5147  * include them, since we want to dump extension members individually in
5148  * that mode. Also, if they are used by casts or transforms then we need