]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_dump.c
Move logging.h and logging.c from src/fe_utils/ to src/common/.
[postgresql] / src / bin / pg_dump / pg_dump.c
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-2019, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *      pg_dump will read the system catalogs in a database and dump out a
11  *      script that reproduces the schema in terms of SQL that is understood
12  *      by PostgreSQL
13  *
14  *      Note that pg_dump runs in a transaction-snapshot mode transaction,
15  *      so it sees a consistent snapshot of the database including system
16  *      catalogs. However, it relies in part on various specialized backend
17  *      functions like pg_get_indexdef(), and those things tend to look at
18  *      the currently committed state.  So it is possible to get 'cache
19  *      lookup failed' error if someone performs DDL changes while a dump is
20  *      happening. The window for this sort of thing is from the acquisition
21  *      of the transaction snapshot to getSchemaData() (when pg_dump acquires
22  *      AccessShareLock on every table it intends to dump). It isn't very large,
23  *      but it can happen.
24  *
25  *      http://archives.postgresql.org/pgsql-bugs/2010-02/msg00187.php
26  *
27  * IDENTIFICATION
28  *        src/bin/pg_dump/pg_dump.c
29  *
30  *-------------------------------------------------------------------------
31  */
32 #include "postgres_fe.h"
33
34 #include <unistd.h>
35 #include <ctype.h>
36 #include <limits.h>
37 #ifdef HAVE_TERMIOS_H
38 #include <termios.h>
39 #endif
40
41 #include "getopt_long.h"
42
43 #include "access/attnum.h"
44 #include "access/sysattr.h"
45 #include "access/transam.h"
46 #include "catalog/pg_aggregate_d.h"
47 #include "catalog/pg_am_d.h"
48 #include "catalog/pg_attribute_d.h"
49 #include "catalog/pg_cast_d.h"
50 #include "catalog/pg_class_d.h"
51 #include "catalog/pg_default_acl_d.h"
52 #include "catalog/pg_largeobject_d.h"
53 #include "catalog/pg_largeobject_metadata_d.h"
54 #include "catalog/pg_proc_d.h"
55 #include "catalog/pg_trigger_d.h"
56 #include "catalog/pg_type_d.h"
57 #include "libpq/libpq-fs.h"
58 #include "storage/block.h"
59
60 #include "dumputils.h"
61 #include "parallel.h"
62 #include "pg_backup_db.h"
63 #include "pg_backup_utils.h"
64 #include "pg_dump.h"
65 #include "fe_utils/connect.h"
66 #include "fe_utils/string_utils.h"
67
68
69 typedef struct
70 {
71         const char *descr;                      /* comment for an object */
72         Oid                     classoid;               /* object class (catalog OID) */
73         Oid                     objoid;                 /* object OID */
74         int                     objsubid;               /* subobject (table column #) */
75 } CommentItem;
76
77 typedef struct
78 {
79         const char *provider;           /* label provider of this security label */
80         const char *label;                      /* security label for an object */
81         Oid                     classoid;               /* object class (catalog OID) */
82         Oid                     objoid;                 /* object OID */
83         int                     objsubid;               /* subobject (table column #) */
84 } SecLabelItem;
85
86 typedef enum OidOptions
87 {
88         zeroAsOpaque = 1,
89         zeroAsAny = 2,
90         zeroAsStar = 4,
91         zeroAsNone = 8
92 } OidOptions;
93
94 /* global decls */
95 static bool dosync = true;              /* Issue fsync() to make dump durable on disk. */
96
97 /* subquery used to convert user ID (eg, datdba) to user name */
98 static const char *username_subquery;
99
100 /*
101  * For 8.0 and earlier servers, pulled from pg_database, for 8.1+ we use
102  * FirstNormalObjectId - 1.
103  */
104 static Oid      g_last_builtin_oid; /* value of the last builtin oid */
105
106 /* The specified names/patterns should to match at least one entity */
107 static int      strict_names = 0;
108
109 /*
110  * Object inclusion/exclusion lists
111  *
112  * The string lists record the patterns given by command-line switches,
113  * which we then convert to lists of OIDs of matching objects.
114  */
115 static SimpleStringList schema_include_patterns = {NULL, NULL};
116 static SimpleOidList schema_include_oids = {NULL, NULL};
117 static SimpleStringList schema_exclude_patterns = {NULL, NULL};
118 static SimpleOidList schema_exclude_oids = {NULL, NULL};
119
120 static SimpleStringList table_include_patterns = {NULL, NULL};
121 static SimpleOidList table_include_oids = {NULL, NULL};
122 static SimpleStringList table_exclude_patterns = {NULL, NULL};
123 static SimpleOidList table_exclude_oids = {NULL, NULL};
124 static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
125 static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
126
127
128 char            g_opaque_type[10];      /* name for the opaque type */
129
130 /* placeholders for the delimiters for comments */
131 char            g_comment_start[10];
132 char            g_comment_end[10];
133
134 static const CatalogId nilCatalogId = {0, 0};
135
136 /* override for standard extra_float_digits setting */
137 static bool have_extra_float_digits = false;
138 static int extra_float_digits;
139
140 /*
141  * The default number of rows per INSERT when
142  * --inserts is specified without --rows-per-insert
143  */
144 #define DUMP_DEFAULT_ROWS_PER_INSERT 1
145
146 /*
147  * Macro for producing quoted, schema-qualified name of a dumpable object.
148  */
149 #define fmtQualifiedDumpable(obj) \
150         fmtQualifiedId((obj)->dobj.namespace->dobj.name, \
151                                    (obj)->dobj.name)
152
153 static void help(const char *progname);
154 static void setup_connection(Archive *AH,
155                                  const char *dumpencoding, const char *dumpsnapshot,
156                                  char *use_role);
157 static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
158 static void expand_schema_name_patterns(Archive *fout,
159                                                         SimpleStringList *patterns,
160                                                         SimpleOidList *oids,
161                                                         bool strict_names);
162 static void expand_table_name_patterns(Archive *fout,
163                                                    SimpleStringList *patterns,
164                                                    SimpleOidList *oids,
165                                                    bool strict_names);
166 static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid);
167 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
168 static void refreshMatViewData(Archive *fout, TableDataInfo *tdinfo);
169 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
170 static void dumpComment(Archive *fout, const char *type, const char *name,
171                         const char *namespace, const char *owner,
172                         CatalogId catalogId, int subid, DumpId dumpId);
173 static int findComments(Archive *fout, Oid classoid, Oid objoid,
174                          CommentItem **items);
175 static int      collectComments(Archive *fout, CommentItem **items);
176 static void dumpSecLabel(Archive *fout, const char *type, const char *name,
177                          const char *namespace, const char *owner,
178                          CatalogId catalogId, int subid, DumpId dumpId);
179 static int findSecLabels(Archive *fout, Oid classoid, Oid objoid,
180                           SecLabelItem **items);
181 static int      collectSecLabels(Archive *fout, SecLabelItem **items);
182 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
183 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
184 static void dumpExtension(Archive *fout, ExtensionInfo *extinfo);
185 static void dumpType(Archive *fout, TypeInfo *tyinfo);
186 static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
187 static void dumpEnumType(Archive *fout, TypeInfo *tyinfo);
188 static void dumpRangeType(Archive *fout, TypeInfo *tyinfo);
189 static void dumpUndefinedType(Archive *fout, TypeInfo *tyinfo);
190 static void dumpDomain(Archive *fout, TypeInfo *tyinfo);
191 static void dumpCompositeType(Archive *fout, TypeInfo *tyinfo);
192 static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
193 static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
194 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
195 static void dumpFunc(Archive *fout, FuncInfo *finfo);
196 static void dumpCast(Archive *fout, CastInfo *cast);
197 static void dumpTransform(Archive *fout, TransformInfo *transform);
198 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
199 static void dumpAccessMethod(Archive *fout, AccessMethodInfo *oprinfo);
200 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
201 static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
202 static void dumpCollation(Archive *fout, CollInfo *collinfo);
203 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
204 static void dumpRule(Archive *fout, RuleInfo *rinfo);
205 static void dumpAgg(Archive *fout, AggInfo *agginfo);
206 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
207 static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
208 static void dumpTable(Archive *fout, TableInfo *tbinfo);
209 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
210 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
211 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
212 static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo);
213 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
214 static void dumpIndexAttach(Archive *fout, IndexAttachInfo *attachinfo);
215 static void dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo);
216 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
217 static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
218 static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
219 static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
220 static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
221 static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
222 static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
223 static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
224 static void dumpUserMappings(Archive *fout,
225                                  const char *servername, const char *namespace,
226                                  const char *owner, CatalogId catalogId, DumpId dumpId);
227 static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
228
229 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
230                 const char *type, const char *name, const char *subname,
231                 const char *nspname, const char *owner,
232                 const char *acls, const char *racls,
233                 const char *initacls, const char *initracls);
234
235 static void getDependencies(Archive *fout);
236 static void BuildArchiveDependencies(Archive *fout);
237 static void findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
238                                                  DumpId **dependencies, int *nDeps, int *allocDeps);
239
240 static DumpableObject *createBoundaryObjects(void);
241 static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
242                                                 DumpableObject *boundaryObjs);
243
244 static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
245 static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind);
246 static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo);
247 static void buildMatViewRefreshDependencies(Archive *fout);
248 static void getTableDataFKConstraints(void);
249 static char *format_function_arguments(FuncInfo *finfo, char *funcargs,
250                                                   bool is_agg);
251 static char *format_function_arguments_old(Archive *fout,
252                                                           FuncInfo *finfo, int nallargs,
253                                                           char **allargtypes,
254                                                           char **argmodes,
255                                                           char **argnames);
256 static char *format_function_signature(Archive *fout,
257                                                   FuncInfo *finfo, bool honor_quotes);
258 static char *convertRegProcReference(Archive *fout,
259                                                 const char *proc);
260 static char *getFormattedOperatorName(Archive *fout, const char *oproid);
261 static char *convertTSFunction(Archive *fout, Oid funcOid);
262 static Oid      findLastBuiltinOid_V71(Archive *fout);
263 static char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
264 static void getBlobs(Archive *fout);
265 static void dumpBlob(Archive *fout, BlobInfo *binfo);
266 static int      dumpBlobs(Archive *fout, void *arg);
267 static void dumpPolicy(Archive *fout, PolicyInfo *polinfo);
268 static void dumpPublication(Archive *fout, PublicationInfo *pubinfo);
269 static void dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo);
270 static void dumpSubscription(Archive *fout, SubscriptionInfo *subinfo);
271 static void dumpDatabase(Archive *AH);
272 static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
273                                    const char *dbname, Oid dboid);
274 static void dumpEncoding(Archive *AH);
275 static void dumpStdStrings(Archive *AH);
276 static void dumpSearchPath(Archive *AH);
277 static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
278                                                                                  PQExpBuffer upgrade_buffer,
279                                                                                  Oid pg_type_oid,
280                                                                                  bool force_array_type);
281 static bool binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
282                                                                                 PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
283 static void binary_upgrade_set_pg_class_oids(Archive *fout,
284                                                                  PQExpBuffer upgrade_buffer,
285                                                                  Oid pg_class_oid, bool is_index);
286 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
287                                                                 DumpableObject *dobj,
288                                                                 const char *objtype,
289                                                                 const char *objname,
290                                                                 const char *objnamespace);
291 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
292 static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
293 static bool nonemptyReloptions(const char *reloptions);
294 static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
295                                                 const char *prefix, Archive *fout);
296 static char *get_synchronized_snapshot(Archive *fout);
297 static void setupDumpWorker(Archive *AHX);
298 static TableInfo *getRootTableInfo(TableInfo *tbinfo);
299
300
301 int
302 main(int argc, char **argv)
303 {
304         int                     c;
305         const char *filename = NULL;
306         const char *format = "p";
307         TableInfo  *tblinfo;
308         int                     numTables;
309         DumpableObject **dobjs;
310         int                     numObjs;
311         DumpableObject *boundaryObjs;
312         int                     i;
313         int                     optindex;
314         char       *endptr;
315         RestoreOptions *ropt;
316         Archive    *fout;                       /* the script file */
317         bool            g_verbose = false;
318         const char *dumpencoding = NULL;
319         const char *dumpsnapshot = NULL;
320         char       *use_role = NULL;
321         long            rowsPerInsert;
322         int                     numWorkers = 1;
323         trivalue        prompt_password = TRI_DEFAULT;
324         int                     compressLevel = -1;
325         int                     plainText = 0;
326         ArchiveFormat archiveFormat = archUnknown;
327         ArchiveMode archiveMode;
328
329         static DumpOptions dopt;
330
331         static struct option long_options[] = {
332                 {"data-only", no_argument, NULL, 'a'},
333                 {"blobs", no_argument, NULL, 'b'},
334                 {"no-blobs", no_argument, NULL, 'B'},
335                 {"clean", no_argument, NULL, 'c'},
336                 {"create", no_argument, NULL, 'C'},
337                 {"dbname", required_argument, NULL, 'd'},
338                 {"file", required_argument, NULL, 'f'},
339                 {"format", required_argument, NULL, 'F'},
340                 {"host", required_argument, NULL, 'h'},
341                 {"jobs", 1, NULL, 'j'},
342                 {"no-reconnect", no_argument, NULL, 'R'},
343                 {"no-owner", no_argument, NULL, 'O'},
344                 {"port", required_argument, NULL, 'p'},
345                 {"schema", required_argument, NULL, 'n'},
346                 {"exclude-schema", required_argument, NULL, 'N'},
347                 {"schema-only", no_argument, NULL, 's'},
348                 {"superuser", required_argument, NULL, 'S'},
349                 {"table", required_argument, NULL, 't'},
350                 {"exclude-table", required_argument, NULL, 'T'},
351                 {"no-password", no_argument, NULL, 'w'},
352                 {"password", no_argument, NULL, 'W'},
353                 {"username", required_argument, NULL, 'U'},
354                 {"verbose", no_argument, NULL, 'v'},
355                 {"no-privileges", no_argument, NULL, 'x'},
356                 {"no-acl", no_argument, NULL, 'x'},
357                 {"compress", required_argument, NULL, 'Z'},
358                 {"encoding", required_argument, NULL, 'E'},
359                 {"help", no_argument, NULL, '?'},
360                 {"version", no_argument, NULL, 'V'},
361
362                 /*
363                  * the following options don't have an equivalent short option letter
364                  */
365                 {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
366                 {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
367                 {"column-inserts", no_argument, &dopt.column_inserts, 1},
368                 {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
369                 {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
370                 {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
371                 {"exclude-table-data", required_argument, NULL, 4},
372                 {"extra-float-digits", required_argument, NULL, 8},
373                 {"if-exists", no_argument, &dopt.if_exists, 1},
374                 {"inserts", no_argument, NULL, 9},
375                 {"lock-wait-timeout", required_argument, NULL, 2},
376                 {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
377                 {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
378                 {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
379                 {"role", required_argument, NULL, 3},
380                 {"section", required_argument, NULL, 5},
381                 {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
382                 {"snapshot", required_argument, NULL, 6},
383                 {"strict-names", no_argument, &strict_names, 1},
384                 {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
385                 {"no-comments", no_argument, &dopt.no_comments, 1},
386                 {"no-publications", no_argument, &dopt.no_publications, 1},
387                 {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
388                 {"no-synchronized-snapshots", no_argument, &dopt.no_synchronized_snapshots, 1},
389                 {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
390                 {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
391                 {"no-sync", no_argument, NULL, 7},
392                 {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
393                 {"rows-per-insert", required_argument, NULL, 10},
394
395                 {NULL, 0, NULL, 0}
396         };
397
398         pg_logging_init(argv[0]);
399         pg_logging_set_level(PG_LOG_WARNING);
400         set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
401
402         /*
403          * Initialize what we need for parallel execution, especially for thread
404          * support on Windows.
405          */
406         init_parallel_dump_utils();
407
408         strcpy(g_comment_start, "-- ");
409         g_comment_end[0] = '\0';
410         strcpy(g_opaque_type, "opaque");
411
412         progname = get_progname(argv[0]);
413
414         if (argc > 1)
415         {
416                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
417                 {
418                         help(progname);
419                         exit_nicely(0);
420                 }
421                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
422                 {
423                         puts("pg_dump (PostgreSQL) " PG_VERSION);
424                         exit_nicely(0);
425                 }
426         }
427
428         InitDumpOptions(&dopt);
429
430         while ((c = getopt_long(argc, argv, "abBcCd:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxZ:",
431                                                         long_options, &optindex)) != -1)
432         {
433                 switch (c)
434                 {
435                         case 'a':                       /* Dump data only */
436                                 dopt.dataOnly = true;
437                                 break;
438
439                         case 'b':                       /* Dump blobs */
440                                 dopt.outputBlobs = true;
441                                 break;
442
443                         case 'B':                       /* Don't dump blobs */
444                                 dopt.dontOutputBlobs = true;
445                                 break;
446
447                         case 'c':                       /* clean (i.e., drop) schema prior to create */
448                                 dopt.outputClean = 1;
449                                 break;
450
451                         case 'C':                       /* Create DB */
452                                 dopt.outputCreateDB = 1;
453                                 break;
454
455                         case 'd':                       /* database name */
456                                 dopt.dbname = pg_strdup(optarg);
457                                 break;
458
459                         case 'E':                       /* Dump encoding */
460                                 dumpencoding = pg_strdup(optarg);
461                                 break;
462
463                         case 'f':
464                                 filename = pg_strdup(optarg);
465                                 break;
466
467                         case 'F':
468                                 format = pg_strdup(optarg);
469                                 break;
470
471                         case 'h':                       /* server host */
472                                 dopt.pghost = pg_strdup(optarg);
473                                 break;
474
475                         case 'j':                       /* number of dump jobs */
476                                 numWorkers = atoi(optarg);
477                                 break;
478
479                         case 'n':                       /* include schema(s) */
480                                 simple_string_list_append(&schema_include_patterns, optarg);
481                                 dopt.include_everything = false;
482                                 break;
483
484                         case 'N':                       /* exclude schema(s) */
485                                 simple_string_list_append(&schema_exclude_patterns, optarg);
486                                 break;
487
488                         case 'O':                       /* Don't reconnect to match owner */
489                                 dopt.outputNoOwner = 1;
490                                 break;
491
492                         case 'p':                       /* server port */
493                                 dopt.pgport = pg_strdup(optarg);
494                                 break;
495
496                         case 'R':
497                                 /* no-op, still accepted for backwards compatibility */
498                                 break;
499
500                         case 's':                       /* dump schema only */
501                                 dopt.schemaOnly = true;
502                                 break;
503
504                         case 'S':                       /* Username for superuser in plain text output */
505                                 dopt.outputSuperuser = pg_strdup(optarg);
506                                 break;
507
508                         case 't':                       /* include table(s) */
509                                 simple_string_list_append(&table_include_patterns, optarg);
510                                 dopt.include_everything = false;
511                                 break;
512
513                         case 'T':                       /* exclude table(s) */
514                                 simple_string_list_append(&table_exclude_patterns, optarg);
515                                 break;
516
517                         case 'U':
518                                 dopt.username = pg_strdup(optarg);
519                                 break;
520
521                         case 'v':                       /* verbose */
522                                 g_verbose = true;
523                                 pg_logging_set_level(PG_LOG_INFO);
524                                 break;
525
526                         case 'w':
527                                 prompt_password = TRI_NO;
528                                 break;
529
530                         case 'W':
531                                 prompt_password = TRI_YES;
532                                 break;
533
534                         case 'x':                       /* skip ACL dump */
535                                 dopt.aclsSkip = true;
536                                 break;
537
538                         case 'Z':                       /* Compression Level */
539                                 compressLevel = atoi(optarg);
540                                 if (compressLevel < 0 || compressLevel > 9)
541                                 {
542                                         pg_log_error("compression level must be in range 0..9");
543                                         exit_nicely(1);
544                                 }
545                                 break;
546
547                         case 0:
548                                 /* This covers the long options. */
549                                 break;
550
551                         case 2:                         /* lock-wait-timeout */
552                                 dopt.lockWaitTimeout = pg_strdup(optarg);
553                                 break;
554
555                         case 3:                         /* SET ROLE */
556                                 use_role = pg_strdup(optarg);
557                                 break;
558
559                         case 4:                         /* exclude table(s) data */
560                                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
561                                 break;
562
563                         case 5:                         /* section */
564                                 set_dump_section(optarg, &dopt.dumpSections);
565                                 break;
566
567                         case 6:                         /* snapshot */
568                                 dumpsnapshot = pg_strdup(optarg);
569                                 break;
570
571                         case 7:                         /* no-sync */
572                                 dosync = false;
573                                 break;
574
575                         case 8:
576                                 have_extra_float_digits = true;
577                                 extra_float_digits = atoi(optarg);
578                                 if (extra_float_digits < -15 || extra_float_digits > 3)
579                                 {
580                                         pg_log_error("extra_float_digits must be in range -15..3");
581                                         exit_nicely(1);
582                                 }
583                                 break;
584
585                         case 9:                         /* inserts */
586
587                                 /*
588                                  * dump_inserts also stores --rows-per-insert, careful not to
589                                  * overwrite that.
590                                  */
591                                 if (dopt.dump_inserts == 0)
592                                         dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
593                                 break;
594
595                         case 10:                        /* rows per insert */
596                                 errno = 0;
597                                 rowsPerInsert = strtol(optarg, &endptr, 10);
598
599                                 if (endptr == optarg || *endptr != '\0' ||
600                                         rowsPerInsert <= 0 || rowsPerInsert > INT_MAX ||
601                                         errno == ERANGE)
602                                 {
603                                         pg_log_error("rows-per-insert must be in range %d..%d",
604                                                           1, INT_MAX);
605                                         exit_nicely(1);
606                                 }
607                                 dopt.dump_inserts = (int) rowsPerInsert;
608                                 break;
609
610                         default:
611                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
612                                 exit_nicely(1);
613                 }
614         }
615
616         /*
617          * Non-option argument specifies database name as long as it wasn't
618          * already specified with -d / --dbname
619          */
620         if (optind < argc && dopt.dbname == NULL)
621                 dopt.dbname = argv[optind++];
622
623         /* Complain if any arguments remain */
624         if (optind < argc)
625         {
626                 pg_log_error("too many command-line arguments (first is \"%s\")",
627                                          argv[optind]);
628                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
629                                 progname);
630                 exit_nicely(1);
631         }
632
633         /* --column-inserts implies --inserts */
634         if (dopt.column_inserts && dopt.dump_inserts == 0)
635                 dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
636
637         /*
638          * Binary upgrade mode implies dumping sequence data even in schema-only
639          * mode.  This is not exposed as a separate option, but kept separate
640          * internally for clarity.
641          */
642         if (dopt.binary_upgrade)
643                 dopt.sequence_data = 1;
644
645         if (dopt.dataOnly && dopt.schemaOnly)
646         {
647                 pg_log_error("options -s/--schema-only and -a/--data-only cannot be used together");
648                 exit_nicely(1);
649         }
650
651         if (dopt.dataOnly && dopt.outputClean)
652         {
653                 pg_log_error("options -c/--clean and -a/--data-only cannot be used together");
654                 exit_nicely(1);
655         }
656
657         if (dopt.if_exists && !dopt.outputClean)
658                 fatal("option --if-exists requires option -c/--clean");
659
660         /*
661          * --inserts are already implied above if --column-inserts or
662          * --rows-per-insert were specified.
663          */
664         if (dopt.do_nothing && dopt.dump_inserts == 0)
665                 fatal("option --on-conflict-do-nothing requires option --inserts, --rows-per-insert or --column-inserts");
666
667         /* Identify archive format to emit */
668         archiveFormat = parseArchiveFormat(format, &archiveMode);
669
670         /* archiveFormat specific setup */
671         if (archiveFormat == archNull)
672                 plainText = 1;
673
674         /* Custom and directory formats are compressed by default, others not */
675         if (compressLevel == -1)
676         {
677 #ifdef HAVE_LIBZ
678                 if (archiveFormat == archCustom || archiveFormat == archDirectory)
679                         compressLevel = Z_DEFAULT_COMPRESSION;
680                 else
681 #endif
682                         compressLevel = 0;
683         }
684
685 #ifndef HAVE_LIBZ
686         if (compressLevel != 0)
687                 pg_log_warning("requested compression not available in this installation -- archive will be uncompressed");
688         compressLevel = 0;
689 #endif
690
691         /*
692          * If emitting an archive format, we always want to emit a DATABASE item,
693          * in case --create is specified at pg_restore time.
694          */
695         if (!plainText)
696                 dopt.outputCreateDB = 1;
697
698         /*
699          * On Windows we can only have at most MAXIMUM_WAIT_OBJECTS (= 64 usually)
700          * parallel jobs because that's the maximum limit for the
701          * WaitForMultipleObjects() call.
702          */
703         if (numWorkers <= 0
704 #ifdef WIN32
705                 || numWorkers > MAXIMUM_WAIT_OBJECTS
706 #endif
707                 )
708                 fatal("invalid number of parallel jobs");
709
710         /* Parallel backup only in the directory archive format so far */
711         if (archiveFormat != archDirectory && numWorkers > 1)
712                 fatal("parallel backup only supported by the directory format");
713
714         /* Open the output file */
715         fout = CreateArchive(filename, archiveFormat, compressLevel, dosync,
716                                                  archiveMode, setupDumpWorker);
717
718         /* Make dump options accessible right away */
719         SetArchiveOptions(fout, &dopt, NULL);
720
721         /* Register the cleanup hook */
722         on_exit_close_archive(fout);
723
724         /* Let the archiver know how noisy to be */
725         fout->verbose = g_verbose;
726
727
728         /*
729          * We allow the server to be back to 8.0, and up to any minor release of
730          * our own major version.  (See also version check in pg_dumpall.c.)
731          */
732         fout->minRemoteVersion = 80000;
733         fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
734
735         fout->numWorkers = numWorkers;
736
737         /*
738          * Open the database using the Archiver, so it knows about it. Errors mean
739          * death.
740          */
741         ConnectDatabase(fout, dopt.dbname, dopt.pghost, dopt.pgport, dopt.username, prompt_password);
742         setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
743
744         /*
745          * Disable security label support if server version < v9.1.x (prevents
746          * access to nonexistent pg_seclabel catalog)
747          */
748         if (fout->remoteVersion < 90100)
749                 dopt.no_security_labels = 1;
750
751         /*
752          * On hot standbys, never try to dump unlogged table data, since it will
753          * just throw an error.
754          */
755         if (fout->isStandby)
756                 dopt.no_unlogged_table_data = true;
757
758         /* Select the appropriate subquery to convert user IDs to names */
759         if (fout->remoteVersion >= 80100)
760                 username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
761         else
762                 username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
763
764         /* check the version for the synchronized snapshots feature */
765         if (numWorkers > 1 && fout->remoteVersion < 90200
766                 && !dopt.no_synchronized_snapshots)
767                 fatal("Synchronized snapshots are not supported by this server version.\n"
768                           "Run with --no-synchronized-snapshots instead if you do not need\n"
769                           "synchronized snapshots.");
770
771         /* check the version when a snapshot is explicitly specified by user */
772         if (dumpsnapshot && fout->remoteVersion < 90200)
773                 fatal("Exported snapshots are not supported by this server version.");
774
775         /*
776          * Find the last built-in OID, if needed (prior to 8.1)
777          *
778          * With 8.1 and above, we can just use FirstNormalObjectId - 1.
779          */
780         if (fout->remoteVersion < 80100)
781                 g_last_builtin_oid = findLastBuiltinOid_V71(fout);
782         else
783                 g_last_builtin_oid = FirstNormalObjectId - 1;
784
785         pg_log_info("last built-in OID is %u", g_last_builtin_oid);
786
787         /* Expand schema selection patterns into OID lists */
788         if (schema_include_patterns.head != NULL)
789         {
790                 expand_schema_name_patterns(fout, &schema_include_patterns,
791                                                                         &schema_include_oids,
792                                                                         strict_names);
793                 if (schema_include_oids.head == NULL)
794                         fatal("no matching schemas were found");
795         }
796         expand_schema_name_patterns(fout, &schema_exclude_patterns,
797                                                                 &schema_exclude_oids,
798                                                                 false);
799         /* non-matching exclusion patterns aren't an error */
800
801         /* Expand table selection patterns into OID lists */
802         if (table_include_patterns.head != NULL)
803         {
804                 expand_table_name_patterns(fout, &table_include_patterns,
805                                                                    &table_include_oids,
806                                                                    strict_names);
807                 if (table_include_oids.head == NULL)
808                         fatal("no matching tables were found");
809         }
810         expand_table_name_patterns(fout, &table_exclude_patterns,
811                                                            &table_exclude_oids,
812                                                            false);
813
814         expand_table_name_patterns(fout, &tabledata_exclude_patterns,
815                                                            &tabledata_exclude_oids,
816                                                            false);
817
818         /* non-matching exclusion patterns aren't an error */
819
820         /*
821          * Dumping blobs is the default for dumps where an inclusion switch is not
822          * used (an "include everything" dump).  -B can be used to exclude blobs
823          * from those dumps.  -b can be used to include blobs even when an
824          * inclusion switch is used.
825          *
826          * -s means "schema only" and blobs are data, not schema, so we never
827          * include blobs when -s is used.
828          */
829         if (dopt.include_everything && !dopt.schemaOnly && !dopt.dontOutputBlobs)
830                 dopt.outputBlobs = true;
831
832         /*
833          * Now scan the database and create DumpableObject structs for all the
834          * objects we intend to dump.
835          */
836         tblinfo = getSchemaData(fout, &numTables);
837
838         if (fout->remoteVersion < 80400)
839                 guessConstraintInheritance(tblinfo, numTables);
840
841         if (!dopt.schemaOnly)
842         {
843                 getTableData(&dopt, tblinfo, numTables, 0);
844                 buildMatViewRefreshDependencies(fout);
845                 if (dopt.dataOnly)
846                         getTableDataFKConstraints();
847         }
848
849         if (dopt.schemaOnly && dopt.sequence_data)
850                 getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
851
852         /*
853          * In binary-upgrade mode, we do not have to worry about the actual blob
854          * data or the associated metadata that resides in the pg_largeobject and
855          * pg_largeobject_metadata tables, respectively.
856          *
857          * However, we do need to collect blob information as there may be
858          * comments or other information on blobs that we do need to dump out.
859          */
860         if (dopt.outputBlobs || dopt.binary_upgrade)
861                 getBlobs(fout);
862
863         /*
864          * Collect dependency data to assist in ordering the objects.
865          */
866         getDependencies(fout);
867
868         /* Lastly, create dummy objects to represent the section boundaries */
869         boundaryObjs = createBoundaryObjects();
870
871         /* Get pointers to all the known DumpableObjects */
872         getDumpableObjects(&dobjs, &numObjs);
873
874         /*
875          * Add dummy dependencies to enforce the dump section ordering.
876          */
877         addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
878
879         /*
880          * Sort the objects into a safe dump order (no forward references).
881          *
882          * We rely on dependency information to help us determine a safe order, so
883          * the initial sort is mostly for cosmetic purposes: we sort by name to
884          * ensure that logically identical schemas will dump identically.
885          */
886         sortDumpableObjectsByTypeName(dobjs, numObjs);
887
888         sortDumpableObjects(dobjs, numObjs,
889                                                 boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
890
891         /*
892          * Create archive TOC entries for all the objects to be dumped, in a safe
893          * order.
894          */
895
896         /* First the special ENCODING, STDSTRINGS, and SEARCHPATH entries. */
897         dumpEncoding(fout);
898         dumpStdStrings(fout);
899         dumpSearchPath(fout);
900
901         /* The database items are always next, unless we don't want them at all */
902         if (dopt.outputCreateDB)
903                 dumpDatabase(fout);
904
905         /* Now the rearrangeable objects. */
906         for (i = 0; i < numObjs; i++)
907                 dumpDumpableObject(fout, dobjs[i]);
908
909         /*
910          * Set up options info to ensure we dump what we want.
911          */
912         ropt = NewRestoreOptions();
913         ropt->filename = filename;
914
915         /* if you change this list, see dumpOptionsFromRestoreOptions */
916         ropt->dropSchema = dopt.outputClean;
917         ropt->dataOnly = dopt.dataOnly;
918         ropt->schemaOnly = dopt.schemaOnly;
919         ropt->if_exists = dopt.if_exists;
920         ropt->column_inserts = dopt.column_inserts;
921         ropt->dumpSections = dopt.dumpSections;
922         ropt->aclsSkip = dopt.aclsSkip;
923         ropt->superuser = dopt.outputSuperuser;
924         ropt->createDB = dopt.outputCreateDB;
925         ropt->noOwner = dopt.outputNoOwner;
926         ropt->noTablespace = dopt.outputNoTablespaces;
927         ropt->disable_triggers = dopt.disable_triggers;
928         ropt->use_setsessauth = dopt.use_setsessauth;
929         ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
930         ropt->dump_inserts = dopt.dump_inserts;
931         ropt->no_comments = dopt.no_comments;
932         ropt->no_publications = dopt.no_publications;
933         ropt->no_security_labels = dopt.no_security_labels;
934         ropt->no_subscriptions = dopt.no_subscriptions;
935         ropt->lockWaitTimeout = dopt.lockWaitTimeout;
936         ropt->include_everything = dopt.include_everything;
937         ropt->enable_row_security = dopt.enable_row_security;
938         ropt->sequence_data = dopt.sequence_data;
939         ropt->binary_upgrade = dopt.binary_upgrade;
940
941         if (compressLevel == -1)
942                 ropt->compression = 0;
943         else
944                 ropt->compression = compressLevel;
945
946         ropt->suppressDumpWarnings = true;      /* We've already shown them */
947
948         SetArchiveOptions(fout, &dopt, ropt);
949
950         /* Mark which entries should be output */
951         ProcessArchiveRestoreOptions(fout);
952
953         /*
954          * The archive's TOC entries are now marked as to which ones will actually
955          * be output, so we can set up their dependency lists properly. This isn't
956          * necessary for plain-text output, though.
957          */
958         if (!plainText)
959                 BuildArchiveDependencies(fout);
960
961         /*
962          * And finally we can do the actual output.
963          *
964          * Note: for non-plain-text output formats, the output file is written
965          * inside CloseArchive().  This is, um, bizarre; but not worth changing
966          * right now.
967          */
968         if (plainText)
969                 RestoreArchive(fout);
970
971         CloseArchive(fout);
972
973         exit_nicely(0);
974 }
975
976
977 static void
978 help(const char *progname)
979 {
980         printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
981         printf(_("Usage:\n"));
982         printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
983
984         printf(_("\nGeneral options:\n"));
985         printf(_("  -f, --file=FILENAME          output file or directory name\n"));
986         printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
987                          "                               plain text (default))\n"));
988         printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
989         printf(_("  -v, --verbose                verbose mode\n"));
990         printf(_("  -V, --version                output version information, then exit\n"));
991         printf(_("  -Z, --compress=0-9           compression level for compressed formats\n"));
992         printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
993         printf(_("  --no-sync                    do not wait for changes to be written safely to disk\n"));
994         printf(_("  -?, --help                   show this help, then exit\n"));
995
996         printf(_("\nOptions controlling the output content:\n"));
997         printf(_("  -a, --data-only              dump only the data, not the schema\n"));
998         printf(_("  -b, --blobs                  include large objects in dump\n"));
999         printf(_("  -B, --no-blobs               exclude large objects in dump\n"));
1000         printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
1001         printf(_("  -C, --create                 include commands to create database in dump\n"));
1002         printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
1003         printf(_("  -n, --schema=SCHEMA          dump the named schema(s) only\n"));
1004         printf(_("  -N, --exclude-schema=SCHEMA  do NOT dump the named schema(s)\n"));
1005         printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
1006                          "                               plain-text format\n"));
1007         printf(_("  -s, --schema-only            dump only the schema, no data\n"));
1008         printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
1009         printf(_("  -t, --table=TABLE            dump the named table(s) only\n"));
1010         printf(_("  -T, --exclude-table=TABLE    do NOT dump the named table(s)\n"));
1011         printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
1012         printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
1013         printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
1014         printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
1015         printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
1016         printf(_("  --enable-row-security        enable row security (dump only content user has\n"
1017                          "                               access to)\n"));
1018         printf(_("  --exclude-table-data=TABLE   do NOT dump data for the named table(s)\n"));
1019         printf(_("  --extra-float-digits=NUM     override default setting for extra_float_digits\n"));
1020         printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
1021         printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
1022         printf(_("  --load-via-partition-root    load partitions via the root table\n"));
1023         printf(_("  --no-comments                do not dump comments\n"));
1024         printf(_("  --no-publications            do not dump publications\n"));
1025         printf(_("  --no-security-labels         do not dump security label assignments\n"));
1026         printf(_("  --no-subscriptions           do not dump subscriptions\n"));
1027         printf(_("  --no-synchronized-snapshots  do not use synchronized snapshots in parallel jobs\n"));
1028         printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
1029         printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
1030         printf(_("  --on-conflict-do-nothing     add ON CONFLICT DO NOTHING to INSERT commands\n"));
1031         printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
1032         printf(_("  --rows-per-insert=NROWS      number of rows per INSERT; implies --inserts\n"));
1033         printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
1034         printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
1035         printf(_("  --snapshot=SNAPSHOT          use given snapshot for the dump\n"));
1036         printf(_("  --strict-names               require table and/or schema include patterns to\n"
1037                          "                               match at least one entity each\n"));
1038         printf(_("  --use-set-session-authorization\n"
1039                          "                               use SET SESSION AUTHORIZATION commands instead of\n"
1040                          "                               ALTER OWNER commands to set ownership\n"));
1041
1042         printf(_("\nConnection options:\n"));
1043         printf(_("  -d, --dbname=DBNAME      database to dump\n"));
1044         printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
1045         printf(_("  -p, --port=PORT          database server port number\n"));
1046         printf(_("  -U, --username=NAME      connect as specified database user\n"));
1047         printf(_("  -w, --no-password        never prompt for password\n"));
1048         printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
1049         printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
1050
1051         printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
1052                          "variable value is used.\n\n"));
1053         printf(_("Report bugs to <pgsql-bugs@lists.postgresql.org>.\n"));
1054 }
1055
1056 static void
1057 setup_connection(Archive *AH, const char *dumpencoding,
1058                                  const char *dumpsnapshot, char *use_role)
1059 {
1060         DumpOptions *dopt = AH->dopt;
1061         PGconn     *conn = GetConnection(AH);
1062         const char *std_strings;
1063
1064         PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
1065
1066         /*
1067          * Set the client encoding if requested.
1068          */
1069         if (dumpencoding)
1070         {
1071                 if (PQsetClientEncoding(conn, dumpencoding) < 0)
1072                         fatal("invalid client encoding \"%s\" specified",
1073                                   dumpencoding);
1074         }
1075
1076         /*
1077          * Get the active encoding and the standard_conforming_strings setting, so
1078          * we know how to escape strings.
1079          */
1080         AH->encoding = PQclientEncoding(conn);
1081
1082         std_strings = PQparameterStatus(conn, "standard_conforming_strings");
1083         AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
1084
1085         /*
1086          * Set the role if requested.  In a parallel dump worker, we'll be passed
1087          * use_role == NULL, but AH->use_role is already set (if user specified it
1088          * originally) and we should use that.
1089          */
1090         if (!use_role && AH->use_role)
1091                 use_role = AH->use_role;
1092
1093         /* Set the role if requested */
1094         if (use_role && AH->remoteVersion >= 80100)
1095         {
1096                 PQExpBuffer query = createPQExpBuffer();
1097
1098                 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
1099                 ExecuteSqlStatement(AH, query->data);
1100                 destroyPQExpBuffer(query);
1101
1102                 /* save it for possible later use by parallel workers */
1103                 if (!AH->use_role)
1104                         AH->use_role = pg_strdup(use_role);
1105         }
1106
1107         /* Set the datestyle to ISO to ensure the dump's portability */
1108         ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
1109
1110         /* Likewise, avoid using sql_standard intervalstyle */
1111         if (AH->remoteVersion >= 80400)
1112                 ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
1113
1114         /*
1115          * Use an explicitly specified extra_float_digits if it has been
1116          * provided. Otherwise, set extra_float_digits so that we can dump float
1117          * data exactly (given correctly implemented float I/O code, anyway).
1118          */
1119         if (have_extra_float_digits)
1120         {
1121                 PQExpBuffer q = createPQExpBuffer();
1122                 appendPQExpBuffer(q, "SET extra_float_digits TO %d",
1123                                                   extra_float_digits);
1124                 ExecuteSqlStatement(AH, q->data);
1125                 destroyPQExpBuffer(q);
1126         }
1127         else if (AH->remoteVersion >= 90000)
1128                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
1129         else
1130                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 2");
1131
1132         /*
1133          * If synchronized scanning is supported, disable it, to prevent
1134          * unpredictable changes in row ordering across a dump and reload.
1135          */
1136         if (AH->remoteVersion >= 80300)
1137                 ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
1138
1139         /*
1140          * Disable timeouts if supported.
1141          */
1142         ExecuteSqlStatement(AH, "SET statement_timeout = 0");
1143         if (AH->remoteVersion >= 90300)
1144                 ExecuteSqlStatement(AH, "SET lock_timeout = 0");
1145         if (AH->remoteVersion >= 90600)
1146                 ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
1147
1148         /*
1149          * Quote all identifiers, if requested.
1150          */
1151         if (quote_all_identifiers && AH->remoteVersion >= 90100)
1152                 ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1153
1154         /*
1155          * Adjust row-security mode, if supported.
1156          */
1157         if (AH->remoteVersion >= 90500)
1158         {
1159                 if (dopt->enable_row_security)
1160                         ExecuteSqlStatement(AH, "SET row_security = on");
1161                 else
1162                         ExecuteSqlStatement(AH, "SET row_security = off");
1163         }
1164
1165         /*
1166          * Start transaction-snapshot mode transaction to dump consistent data.
1167          */
1168         ExecuteSqlStatement(AH, "BEGIN");
1169         if (AH->remoteVersion >= 90100)
1170         {
1171                 /*
1172                  * To support the combination of serializable_deferrable with the jobs
1173                  * option we use REPEATABLE READ for the worker connections that are
1174                  * passed a snapshot.  As long as the snapshot is acquired in a
1175                  * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
1176                  * REPEATABLE READ transaction provides the appropriate integrity
1177                  * guarantees.  This is a kluge, but safe for back-patching.
1178                  */
1179                 if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
1180                         ExecuteSqlStatement(AH,
1181                                                                 "SET TRANSACTION ISOLATION LEVEL "
1182                                                                 "SERIALIZABLE, READ ONLY, DEFERRABLE");
1183                 else
1184                         ExecuteSqlStatement(AH,
1185                                                                 "SET TRANSACTION ISOLATION LEVEL "
1186                                                                 "REPEATABLE READ, READ ONLY");
1187         }
1188         else
1189         {
1190                 ExecuteSqlStatement(AH,
1191                                                         "SET TRANSACTION ISOLATION LEVEL "
1192                                                         "SERIALIZABLE, READ ONLY");
1193         }
1194
1195         /*
1196          * If user specified a snapshot to use, select that.  In a parallel dump
1197          * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
1198          * is already set (if the server can handle it) and we should use that.
1199          */
1200         if (dumpsnapshot)
1201                 AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
1202
1203         if (AH->sync_snapshot_id)
1204         {
1205                 PQExpBuffer query = createPQExpBuffer();
1206
1207                 appendPQExpBuffer(query, "SET TRANSACTION SNAPSHOT ");
1208                 appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
1209                 ExecuteSqlStatement(AH, query->data);
1210                 destroyPQExpBuffer(query);
1211         }
1212         else if (AH->numWorkers > 1 &&
1213                          AH->remoteVersion >= 90200 &&
1214                          !dopt->no_synchronized_snapshots)
1215         {
1216                 if (AH->isStandby && AH->remoteVersion < 100000)
1217                         fatal("Synchronized snapshots on standby servers are not supported by this server version.\n"
1218                                   "Run with --no-synchronized-snapshots instead if you do not need\n"
1219                                   "synchronized snapshots.");
1220
1221
1222                 AH->sync_snapshot_id = get_synchronized_snapshot(AH);
1223         }
1224 }
1225
1226 /* Set up connection for a parallel worker process */
1227 static void
1228 setupDumpWorker(Archive *AH)
1229 {
1230         /*
1231          * We want to re-select all the same values the master connection is
1232          * using.  We'll have inherited directly-usable values in
1233          * AH->sync_snapshot_id and AH->use_role, but we need to translate the
1234          * inherited encoding value back to a string to pass to setup_connection.
1235          */
1236         setup_connection(AH,
1237                                          pg_encoding_to_char(AH->encoding),
1238                                          NULL,
1239                                          NULL);
1240 }
1241
1242 static char *
1243 get_synchronized_snapshot(Archive *fout)
1244 {
1245         char       *query = "SELECT pg_catalog.pg_export_snapshot()";
1246         char       *result;
1247         PGresult   *res;
1248
1249         res = ExecuteSqlQueryForSingleRow(fout, query);
1250         result = pg_strdup(PQgetvalue(res, 0, 0));
1251         PQclear(res);
1252
1253         return result;
1254 }
1255
1256 static ArchiveFormat
1257 parseArchiveFormat(const char *format, ArchiveMode *mode)
1258 {
1259         ArchiveFormat archiveFormat;
1260
1261         *mode = archModeWrite;
1262
1263         if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1264         {
1265                 /* This is used by pg_dumpall, and is not documented */
1266                 archiveFormat = archNull;
1267                 *mode = archModeAppend;
1268         }
1269         else if (pg_strcasecmp(format, "c") == 0)
1270                 archiveFormat = archCustom;
1271         else if (pg_strcasecmp(format, "custom") == 0)
1272                 archiveFormat = archCustom;
1273         else if (pg_strcasecmp(format, "d") == 0)
1274                 archiveFormat = archDirectory;
1275         else if (pg_strcasecmp(format, "directory") == 0)
1276                 archiveFormat = archDirectory;
1277         else if (pg_strcasecmp(format, "p") == 0)
1278                 archiveFormat = archNull;
1279         else if (pg_strcasecmp(format, "plain") == 0)
1280                 archiveFormat = archNull;
1281         else if (pg_strcasecmp(format, "t") == 0)
1282                 archiveFormat = archTar;
1283         else if (pg_strcasecmp(format, "tar") == 0)
1284                 archiveFormat = archTar;
1285         else
1286                 fatal("invalid output format \"%s\" specified", format);
1287         return archiveFormat;
1288 }
1289
1290 /*
1291  * Find the OIDs of all schemas matching the given list of patterns,
1292  * and append them to the given OID list.
1293  */
1294 static void
1295 expand_schema_name_patterns(Archive *fout,
1296                                                         SimpleStringList *patterns,
1297                                                         SimpleOidList *oids,
1298                                                         bool strict_names)
1299 {
1300         PQExpBuffer query;
1301         PGresult   *res;
1302         SimpleStringListCell *cell;
1303         int                     i;
1304
1305         if (patterns->head == NULL)
1306                 return;                                 /* nothing to do */
1307
1308         query = createPQExpBuffer();
1309
1310         /*
1311          * The loop below runs multiple SELECTs might sometimes result in
1312          * duplicate entries in the OID list, but we don't care.
1313          */
1314
1315         for (cell = patterns->head; cell; cell = cell->next)
1316         {
1317                 appendPQExpBuffer(query,
1318                                                   "SELECT oid FROM pg_catalog.pg_namespace n\n");
1319                 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1320                                                           false, NULL, "n.nspname", NULL, NULL);
1321
1322                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1323                 if (strict_names && PQntuples(res) == 0)
1324                         fatal("no matching schemas were found for pattern \"%s\"", cell->val);
1325
1326                 for (i = 0; i < PQntuples(res); i++)
1327                 {
1328                         simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1329                 }
1330
1331                 PQclear(res);
1332                 resetPQExpBuffer(query);
1333         }
1334
1335         destroyPQExpBuffer(query);
1336 }
1337
1338 /*
1339  * Find the OIDs of all tables matching the given list of patterns,
1340  * and append them to the given OID list. See also expand_dbname_patterns()
1341  * in pg_dumpall.c
1342  */
1343 static void
1344 expand_table_name_patterns(Archive *fout,
1345                                                    SimpleStringList *patterns, SimpleOidList *oids,
1346                                                    bool strict_names)
1347 {
1348         PQExpBuffer query;
1349         PGresult   *res;
1350         SimpleStringListCell *cell;
1351         int                     i;
1352
1353         if (patterns->head == NULL)
1354                 return;                                 /* nothing to do */
1355
1356         query = createPQExpBuffer();
1357
1358         /*
1359          * this might sometimes result in duplicate entries in the OID list, but
1360          * we don't care.
1361          */
1362
1363         for (cell = patterns->head; cell; cell = cell->next)
1364         {
1365                 /*
1366                  * Query must remain ABSOLUTELY devoid of unqualified names.  This
1367                  * would be unnecessary given a pg_table_is_visible() variant taking a
1368                  * search_path argument.
1369                  */
1370                 appendPQExpBuffer(query,
1371                                                   "SELECT c.oid"
1372                                                   "\nFROM pg_catalog.pg_class c"
1373                                                   "\n     LEFT JOIN pg_catalog.pg_namespace n"
1374                                                   "\n     ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
1375                                                   "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
1376                                                   "\n    (array['%c', '%c', '%c', '%c', '%c', '%c'])\n",
1377                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1378                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
1379                                                   RELKIND_PARTITIONED_TABLE);
1380                 processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1381                                                           false, "n.nspname", "c.relname", NULL,
1382                                                           "pg_catalog.pg_table_is_visible(c.oid)");
1383
1384                 ExecuteSqlStatement(fout, "RESET search_path");
1385                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1386                 PQclear(ExecuteSqlQueryForSingleRow(fout,
1387                                                                                         ALWAYS_SECURE_SEARCH_PATH_SQL));
1388                 if (strict_names && PQntuples(res) == 0)
1389                         fatal("no matching tables were found for pattern \"%s\"", cell->val);
1390
1391                 for (i = 0; i < PQntuples(res); i++)
1392                 {
1393                         simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1394                 }
1395
1396                 PQclear(res);
1397                 resetPQExpBuffer(query);
1398         }
1399
1400         destroyPQExpBuffer(query);
1401 }
1402
1403 /*
1404  * checkExtensionMembership
1405  *              Determine whether object is an extension member, and if so,
1406  *              record an appropriate dependency and set the object's dump flag.
1407  *
1408  * It's important to call this for each object that could be an extension
1409  * member.  Generally, we integrate this with determining the object's
1410  * to-be-dumped-ness, since extension membership overrides other rules for that.
1411  *
1412  * Returns true if object is an extension member, else false.
1413  */
1414 static bool
1415 checkExtensionMembership(DumpableObject *dobj, Archive *fout)
1416 {
1417         ExtensionInfo *ext = findOwningExtension(dobj->catId);
1418
1419         if (ext == NULL)
1420                 return false;
1421
1422         dobj->ext_member = true;
1423
1424         /* Record dependency so that getDependencies needn't deal with that */
1425         addObjectDependency(dobj, ext->dobj.dumpId);
1426
1427         /*
1428          * In 9.6 and above, mark the member object to have any non-initial ACL,
1429          * policies, and security labels dumped.
1430          *
1431          * Note that any initial ACLs (see pg_init_privs) will be removed when we
1432          * extract the information about the object.  We don't provide support for
1433          * initial policies and security labels and it seems unlikely for those to
1434          * ever exist, but we may have to revisit this later.
1435          *
1436          * Prior to 9.6, we do not include any extension member components.
1437          *
1438          * In binary upgrades, we still dump all components of the members
1439          * individually, since the idea is to exactly reproduce the database
1440          * contents rather than replace the extension contents with something
1441          * different.
1442          */
1443         if (fout->dopt->binary_upgrade)
1444                 dobj->dump = ext->dobj.dump;
1445         else
1446         {
1447                 if (fout->remoteVersion < 90600)
1448                         dobj->dump = DUMP_COMPONENT_NONE;
1449                 else
1450                         dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL |
1451                                                                                                         DUMP_COMPONENT_SECLABEL |
1452                                                                                                         DUMP_COMPONENT_POLICY);
1453         }
1454
1455         return true;
1456 }
1457
1458 /*
1459  * selectDumpableNamespace: policy-setting subroutine
1460  *              Mark a namespace as to be dumped or not
1461  */
1462 static void
1463 selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
1464 {
1465         /*
1466          * If specific tables are being dumped, do not dump any complete
1467          * namespaces. If specific namespaces are being dumped, dump just those
1468          * namespaces. Otherwise, dump all non-system namespaces.
1469          */
1470         if (table_include_oids.head != NULL)
1471                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1472         else if (schema_include_oids.head != NULL)
1473                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
1474                         simple_oid_list_member(&schema_include_oids,
1475                                                                    nsinfo->dobj.catId.oid) ?
1476                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1477         else if (fout->remoteVersion >= 90600 &&
1478                          strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
1479         {
1480                 /*
1481                  * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
1482                  * they are interesting (and not the original ACLs which were set at
1483                  * initdb time, see pg_init_privs).
1484                  */
1485                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1486         }
1487         else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1488                          strcmp(nsinfo->dobj.name, "information_schema") == 0)
1489         {
1490                 /* Other system schemas don't get dumped */
1491                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1492         }
1493         else if (strcmp(nsinfo->dobj.name, "public") == 0)
1494         {
1495                 /*
1496                  * The public schema is a strange beast that sits in a sort of
1497                  * no-mans-land between being a system object and a user object.  We
1498                  * don't want to dump creation or comment commands for it, because
1499                  * that complicates matters for non-superuser use of pg_dump.  But we
1500                  * should dump any ACL changes that have occurred for it, and of
1501                  * course we should dump contained objects.
1502                  */
1503                 nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1504                 nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
1505         }
1506         else
1507                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
1508
1509         /*
1510          * In any case, a namespace can be excluded by an exclusion switch
1511          */
1512         if (nsinfo->dobj.dump_contains &&
1513                 simple_oid_list_member(&schema_exclude_oids,
1514                                                            nsinfo->dobj.catId.oid))
1515                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1516
1517         /*
1518          * If the schema belongs to an extension, allow extension membership to
1519          * override the dump decision for the schema itself.  However, this does
1520          * not change dump_contains, so this won't change what we do with objects
1521          * within the schema.  (If they belong to the extension, they'll get
1522          * suppressed by it, otherwise not.)
1523          */
1524         (void) checkExtensionMembership(&nsinfo->dobj, fout);
1525 }
1526
1527 /*
1528  * selectDumpableTable: policy-setting subroutine
1529  *              Mark a table as to be dumped or not
1530  */
1531 static void
1532 selectDumpableTable(TableInfo *tbinfo, Archive *fout)
1533 {
1534         if (checkExtensionMembership(&tbinfo->dobj, fout))
1535                 return;                                 /* extension membership overrides all else */
1536
1537         /*
1538          * If specific tables are being dumped, dump just those tables; else, dump
1539          * according to the parent namespace's dump flag.
1540          */
1541         if (table_include_oids.head != NULL)
1542                 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1543                                                                                                    tbinfo->dobj.catId.oid) ?
1544                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1545         else
1546                 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
1547
1548         /*
1549          * In any case, a table can be excluded by an exclusion switch
1550          */
1551         if (tbinfo->dobj.dump &&
1552                 simple_oid_list_member(&table_exclude_oids,
1553                                                            tbinfo->dobj.catId.oid))
1554                 tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
1555 }
1556
1557 /*
1558  * selectDumpableType: policy-setting subroutine
1559  *              Mark a type as to be dumped or not
1560  *
1561  * If it's a table's rowtype or an autogenerated array type, we also apply a
1562  * special type code to facilitate sorting into the desired order.  (We don't
1563  * want to consider those to be ordinary types because that would bring tables
1564  * up into the datatype part of the dump order.)  We still set the object's
1565  * dump flag; that's not going to cause the dummy type to be dumped, but we
1566  * need it so that casts involving such types will be dumped correctly -- see
1567  * dumpCast.  This means the flag should be set the same as for the underlying
1568  * object (the table or base type).
1569  */
1570 static void
1571 selectDumpableType(TypeInfo *tyinfo, Archive *fout)
1572 {
1573         /* skip complex types, except for standalone composite types */
1574         if (OidIsValid(tyinfo->typrelid) &&
1575                 tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1576         {
1577                 TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
1578
1579                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1580                 if (tytable != NULL)
1581                         tyinfo->dobj.dump = tytable->dobj.dump;
1582                 else
1583                         tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
1584                 return;
1585         }
1586
1587         /* skip auto-generated array types */
1588         if (tyinfo->isArray)
1589         {
1590                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1591
1592                 /*
1593                  * Fall through to set the dump flag; we assume that the subsequent
1594                  * rules will do the same thing as they would for the array's base
1595                  * type.  (We cannot reliably look up the base type here, since
1596                  * getTypes may not have processed it yet.)
1597                  */
1598         }
1599
1600         if (checkExtensionMembership(&tyinfo->dobj, fout))
1601                 return;                                 /* extension membership overrides all else */
1602
1603         /* Dump based on if the contents of the namespace are being dumped */
1604         tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
1605 }
1606
1607 /*
1608  * selectDumpableDefaultACL: policy-setting subroutine
1609  *              Mark a default ACL as to be dumped or not
1610  *
1611  * For per-schema default ACLs, dump if the schema is to be dumped.
1612  * Otherwise dump if we are dumping "everything".  Note that dataOnly
1613  * and aclsSkip are checked separately.
1614  */
1615 static void
1616 selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
1617 {
1618         /* Default ACLs can't be extension members */
1619
1620         if (dinfo->dobj.namespace)
1621                 /* default ACLs are considered part of the namespace */
1622                 dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
1623         else
1624                 dinfo->dobj.dump = dopt->include_everything ?
1625                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1626 }
1627
1628 /*
1629  * selectDumpableCast: policy-setting subroutine
1630  *              Mark a cast as to be dumped or not
1631  *
1632  * Casts do not belong to any particular namespace (since they haven't got
1633  * names), nor do they have identifiable owners.  To distinguish user-defined
1634  * casts from built-in ones, we must resort to checking whether the cast's
1635  * OID is in the range reserved for initdb.
1636  */
1637 static void
1638 selectDumpableCast(CastInfo *cast, Archive *fout)
1639 {
1640         if (checkExtensionMembership(&cast->dobj, fout))
1641                 return;                                 /* extension membership overrides all else */
1642
1643         /*
1644          * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
1645          * support ACLs currently.
1646          */
1647         if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1648                 cast->dobj.dump = DUMP_COMPONENT_NONE;
1649         else
1650                 cast->dobj.dump = fout->dopt->include_everything ?
1651                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1652 }
1653
1654 /*
1655  * selectDumpableProcLang: policy-setting subroutine
1656  *              Mark a procedural language as to be dumped or not
1657  *
1658  * Procedural languages do not belong to any particular namespace.  To
1659  * identify built-in languages, we must resort to checking whether the
1660  * language's OID is in the range reserved for initdb.
1661  */
1662 static void
1663 selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
1664 {
1665         if (checkExtensionMembership(&plang->dobj, fout))
1666                 return;                                 /* extension membership overrides all else */
1667
1668         /*
1669          * Only include procedural languages when we are dumping everything.
1670          *
1671          * For from-initdb procedural languages, only include ACLs, as we do for
1672          * the pg_catalog namespace.  We need this because procedural languages do
1673          * not live in any namespace.
1674          */
1675         if (!fout->dopt->include_everything)
1676                 plang->dobj.dump = DUMP_COMPONENT_NONE;
1677         else
1678         {
1679                 if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1680                         plang->dobj.dump = fout->remoteVersion < 90600 ?
1681                                 DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
1682                 else
1683                         plang->dobj.dump = DUMP_COMPONENT_ALL;
1684         }
1685 }
1686
1687 /*
1688  * selectDumpableAccessMethod: policy-setting subroutine
1689  *              Mark an access method as to be dumped or not
1690  *
1691  * Access methods do not belong to any particular namespace.  To identify
1692  * built-in access methods, we must resort to checking whether the
1693  * method's OID is in the range reserved for initdb.
1694  */
1695 static void
1696 selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
1697 {
1698         if (checkExtensionMembership(&method->dobj, fout))
1699                 return;                                 /* extension membership overrides all else */
1700
1701         /*
1702          * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
1703          * they do not support ACLs currently.
1704          */
1705         if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1706                 method->dobj.dump = DUMP_COMPONENT_NONE;
1707         else
1708                 method->dobj.dump = fout->dopt->include_everything ?
1709                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1710 }
1711
1712 /*
1713  * selectDumpableExtension: policy-setting subroutine
1714  *              Mark an extension as to be dumped or not
1715  *
1716  * Built-in extensions should be skipped except for checking ACLs, since we
1717  * assume those will already be installed in the target database.  We identify
1718  * such extensions by their having OIDs in the range reserved for initdb.
1719  * We dump all user-added extensions by default, or none of them if
1720  * include_everything is false (i.e., a --schema or --table switch was given).
1721  */
1722 static void
1723 selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
1724 {
1725         /*
1726          * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
1727          * change permissions on their member objects, if they wish to, and have
1728          * those changes preserved.
1729          */
1730         if (extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1731                 extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
1732         else
1733                 extinfo->dobj.dump = extinfo->dobj.dump_contains =
1734                         dopt->include_everything ? DUMP_COMPONENT_ALL :
1735                         DUMP_COMPONENT_NONE;
1736 }
1737
1738 /*
1739  * selectDumpablePublicationTable: policy-setting subroutine
1740  *              Mark a publication table as to be dumped or not
1741  *
1742  * Publication tables have schemas, but those are ignored in decision making,
1743  * because publications are only dumped when we are dumping everything.
1744  */
1745 static void
1746 selectDumpablePublicationTable(DumpableObject *dobj, Archive *fout)
1747 {
1748         if (checkExtensionMembership(dobj, fout))
1749                 return;                                 /* extension membership overrides all else */
1750
1751         dobj->dump = fout->dopt->include_everything ?
1752                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1753 }
1754
1755 /*
1756  * selectDumpableObject: policy-setting subroutine
1757  *              Mark a generic dumpable object as to be dumped or not
1758  *
1759  * Use this only for object types without a special-case routine above.
1760  */
1761 static void
1762 selectDumpableObject(DumpableObject *dobj, Archive *fout)
1763 {
1764         if (checkExtensionMembership(dobj, fout))
1765                 return;                                 /* extension membership overrides all else */
1766
1767         /*
1768          * Default policy is to dump if parent namespace is dumpable, or for
1769          * non-namespace-associated items, dump if we're dumping "everything".
1770          */
1771         if (dobj->namespace)
1772                 dobj->dump = dobj->namespace->dobj.dump_contains;
1773         else
1774                 dobj->dump = fout->dopt->include_everything ?
1775                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1776 }
1777
1778 /*
1779  *      Dump a table's contents for loading using the COPY command
1780  *      - this routine is called by the Archiver when it wants the table
1781  *        to be dumped.
1782  */
1783
1784 static int
1785 dumpTableData_copy(Archive *fout, void *dcontext)
1786 {
1787         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1788         TableInfo  *tbinfo = tdinfo->tdtable;
1789         const char *classname = tbinfo->dobj.name;
1790         PQExpBuffer q = createPQExpBuffer();
1791
1792         /*
1793          * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
1794          * which uses it already.
1795          */
1796         PQExpBuffer clistBuf = createPQExpBuffer();
1797         PGconn     *conn = GetConnection(fout);
1798         PGresult   *res;
1799         int                     ret;
1800         char       *copybuf;
1801         const char *column_list;
1802
1803         pg_log_info("dumping contents of table \"%s.%s\"",
1804                                 tbinfo->dobj.namespace->dobj.name, classname);
1805
1806         /*
1807          * Specify the column list explicitly so that we have no possibility of
1808          * retrieving data in the wrong column order.  (The default column
1809          * ordering of COPY will not be what we want in certain corner cases
1810          * involving ADD COLUMN and inheritance.)
1811          */
1812         column_list = fmtCopyColumnList(tbinfo, clistBuf);
1813
1814         if (tdinfo->filtercond)
1815         {
1816                 /* Note: this syntax is only supported in 8.2 and up */
1817                 appendPQExpBufferStr(q, "COPY (SELECT ");
1818                 /* klugery to get rid of parens in column list */
1819                 if (strlen(column_list) > 2)
1820                 {
1821                         appendPQExpBufferStr(q, column_list + 1);
1822                         q->data[q->len - 1] = ' ';
1823                 }
1824                 else
1825                         appendPQExpBufferStr(q, "* ");
1826                 appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
1827                                                   fmtQualifiedDumpable(tbinfo),
1828                                                   tdinfo->filtercond);
1829         }
1830         else
1831         {
1832                 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1833                                                   fmtQualifiedDumpable(tbinfo),
1834                                                   column_list);
1835         }
1836         res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
1837         PQclear(res);
1838         destroyPQExpBuffer(clistBuf);
1839
1840         for (;;)
1841         {
1842                 ret = PQgetCopyData(conn, &copybuf, 0);
1843
1844                 if (ret < 0)
1845                         break;                          /* done or error */
1846
1847                 if (copybuf)
1848                 {
1849                         WriteData(fout, copybuf, ret);
1850                         PQfreemem(copybuf);
1851                 }
1852
1853                 /* ----------
1854                  * THROTTLE:
1855                  *
1856                  * There was considerable discussion in late July, 2000 regarding
1857                  * slowing down pg_dump when backing up large tables. Users with both
1858                  * slow & fast (multi-processor) machines experienced performance
1859                  * degradation when doing a backup.
1860                  *
1861                  * Initial attempts based on sleeping for a number of ms for each ms
1862                  * of work were deemed too complex, then a simple 'sleep in each loop'
1863                  * implementation was suggested. The latter failed because the loop
1864                  * was too tight. Finally, the following was implemented:
1865                  *
1866                  * If throttle is non-zero, then
1867                  *              See how long since the last sleep.
1868                  *              Work out how long to sleep (based on ratio).
1869                  *              If sleep is more than 100ms, then
1870                  *                      sleep
1871                  *                      reset timer
1872                  *              EndIf
1873                  * EndIf
1874                  *
1875                  * where the throttle value was the number of ms to sleep per ms of
1876                  * work. The calculation was done in each loop.
1877                  *
1878                  * Most of the hard work is done in the backend, and this solution
1879                  * still did not work particularly well: on slow machines, the ratio
1880                  * was 50:1, and on medium paced machines, 1:1, and on fast
1881                  * multi-processor machines, it had little or no effect, for reasons
1882                  * that were unclear.
1883                  *
1884                  * Further discussion ensued, and the proposal was dropped.
1885                  *
1886                  * For those people who want this feature, it can be implemented using
1887                  * gettimeofday in each loop, calculating the time since last sleep,
1888                  * multiplying that by the sleep ratio, then if the result is more
1889                  * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1890                  * function to sleep for a subsecond period ie.
1891                  *
1892                  * select(0, NULL, NULL, NULL, &tvi);
1893                  *
1894                  * This will return after the interval specified in the structure tvi.
1895                  * Finally, call gettimeofday again to save the 'last sleep time'.
1896                  * ----------
1897                  */
1898         }
1899         archprintf(fout, "\\.\n\n\n");
1900
1901         if (ret == -2)
1902         {
1903                 /* copy data transfer failed */
1904                 pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
1905                 pg_log_error("Error message from server: %s", PQerrorMessage(conn));
1906                 pg_log_error("The command was: %s", q->data);
1907                 exit_nicely(1);
1908         }
1909
1910         /* Check command status and return to normal libpq state */
1911         res = PQgetResult(conn);
1912         if (PQresultStatus(res) != PGRES_COMMAND_OK)
1913         {
1914                 pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
1915                 pg_log_error("Error message from server: %s", PQerrorMessage(conn));
1916                 pg_log_error("The command was: %s", q->data);
1917                 exit_nicely(1);
1918         }
1919         PQclear(res);
1920
1921         /* Do this to ensure we've pumped libpq back to idle state */
1922         if (PQgetResult(conn) != NULL)
1923                 pg_log_warning("unexpected extra results during COPY of table \"%s\"",
1924                                   classname);
1925
1926         destroyPQExpBuffer(q);
1927         return 1;
1928 }
1929
1930 /*
1931  * Dump table data using INSERT commands.
1932  *
1933  * Caution: when we restore from an archive file direct to database, the
1934  * INSERT commands emitted by this function have to be parsed by
1935  * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
1936  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
1937  */
1938 static int
1939 dumpTableData_insert(Archive *fout, void *dcontext)
1940 {
1941         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1942         TableInfo  *tbinfo = tdinfo->tdtable;
1943         DumpOptions *dopt = fout->dopt;
1944         PQExpBuffer q = createPQExpBuffer();
1945         PQExpBuffer insertStmt = NULL;
1946         PGresult   *res;
1947         int                     nfields;
1948         int                     rows_per_statement = dopt->dump_inserts;
1949         int                     rows_this_statement = 0;
1950
1951         appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1952                                           "SELECT * FROM ONLY %s",
1953                                           fmtQualifiedDumpable(tbinfo));
1954         if (tdinfo->filtercond)
1955                 appendPQExpBuffer(q, " %s", tdinfo->filtercond);
1956
1957         ExecuteSqlStatement(fout, q->data);
1958
1959         while (1)
1960         {
1961                 res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
1962                                                           PGRES_TUPLES_OK);
1963                 nfields = PQnfields(res);
1964
1965                 /*
1966                  * First time through, we build as much of the INSERT statement as
1967                  * possible in "insertStmt", which we can then just print for each
1968                  * statement. If the table happens to have zero columns then this will
1969                  * be a complete statement, otherwise it will end in "VALUES" and be
1970                  * ready to have the row's column values printed.
1971                  */
1972                 if (insertStmt == NULL)
1973                 {
1974                         TableInfo  *targettab;
1975
1976                         insertStmt = createPQExpBuffer();
1977
1978                         /*
1979                          * When load-via-partition-root is set, get the root table name
1980                          * for the partition table, so that we can reload data through the
1981                          * root table.
1982                          */
1983                         if (dopt->load_via_partition_root && tbinfo->ispartition)
1984                                 targettab = getRootTableInfo(tbinfo);
1985                         else
1986                                 targettab = tbinfo;
1987
1988                         appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
1989                                                           fmtQualifiedDumpable(targettab));
1990
1991                         /* corner case for zero-column table */
1992                         if (nfields == 0)
1993                         {
1994                                 appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
1995                         }
1996                         else
1997                         {
1998                                 /* append the list of column names if required */
1999                                 if (dopt->column_inserts)
2000                                 {
2001                                         appendPQExpBufferChar(insertStmt, '(');
2002                                         for (int field = 0; field < nfields; field++)
2003                                         {
2004                                                 if (field > 0)
2005                                                         appendPQExpBufferStr(insertStmt, ", ");
2006                                                 appendPQExpBufferStr(insertStmt,
2007                                                                                          fmtId(PQfname(res, field)));
2008                                         }
2009                                         appendPQExpBufferStr(insertStmt, ") ");
2010                                 }
2011
2012                                 if (tbinfo->needs_override)
2013                                         appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
2014
2015                                 appendPQExpBufferStr(insertStmt, "VALUES");
2016                         }
2017                 }
2018
2019                 for (int tuple = 0; tuple < PQntuples(res); tuple++)
2020                 {
2021                         /* Write the INSERT if not in the middle of a multi-row INSERT. */
2022                         if (rows_this_statement == 0)
2023                                 archputs(insertStmt->data, fout);
2024
2025                         /*
2026                          * If it is zero-column table then we've already written the
2027                          * complete statement, which will mean we've disobeyed
2028                          * --rows-per-insert when it's set greater than 1.  We do support
2029                          * a way to make this multi-row with: SELECT UNION ALL SELECT
2030                          * UNION ALL ... but that's non-standard so we should avoid it
2031                          * given that using INSERTs is mostly only ever needed for
2032                          * cross-database exports.
2033                          */
2034                         if (nfields == 0)
2035                                 continue;
2036
2037                         /* Emit a row heading */
2038                         if (rows_per_statement == 1)
2039                                 archputs(" (", fout);
2040                         else if (rows_this_statement > 0)
2041                                 archputs(",\n\t(", fout);
2042                         else
2043                                 archputs("\n\t(", fout);
2044
2045                         for (int field = 0; field < nfields; field++)
2046                         {
2047                                 if (field > 0)
2048                                         archputs(", ", fout);
2049                                 if (tbinfo->attgenerated[field])
2050                                 {
2051                                         archputs("DEFAULT", fout);
2052                                         continue;
2053                                 }
2054                                 if (PQgetisnull(res, tuple, field))
2055                                 {
2056                                         archputs("NULL", fout);
2057                                         continue;
2058                                 }
2059
2060                                 /* XXX This code is partially duplicated in ruleutils.c */
2061                                 switch (PQftype(res, field))
2062                                 {
2063                                         case INT2OID:
2064                                         case INT4OID:
2065                                         case INT8OID:
2066                                         case OIDOID:
2067                                         case FLOAT4OID:
2068                                         case FLOAT8OID:
2069                                         case NUMERICOID:
2070                                                 {
2071                                                         /*
2072                                                          * These types are printed without quotes unless
2073                                                          * they contain values that aren't accepted by the
2074                                                          * scanner unquoted (e.g., 'NaN').  Note that
2075                                                          * strtod() and friends might accept NaN, so we
2076                                                          * can't use that to test.
2077                                                          *
2078                                                          * In reality we only need to defend against
2079                                                          * infinity and NaN, so we need not get too crazy
2080                                                          * about pattern matching here.
2081                                                          */
2082                                                         const char *s = PQgetvalue(res, tuple, field);
2083
2084                                                         if (strspn(s, "0123456789 +-eE.") == strlen(s))
2085                                                                 archputs(s, fout);
2086                                                         else
2087                                                                 archprintf(fout, "'%s'", s);
2088                                                 }
2089                                                 break;
2090
2091                                         case BITOID:
2092                                         case VARBITOID:
2093                                                 archprintf(fout, "B'%s'",
2094                                                                    PQgetvalue(res, tuple, field));
2095                                                 break;
2096
2097                                         case BOOLOID:
2098                                                 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
2099                                                         archputs("true", fout);
2100                                                 else
2101                                                         archputs("false", fout);
2102                                                 break;
2103
2104                                         default:
2105                                                 /* All other types are printed as string literals. */
2106                                                 resetPQExpBuffer(q);
2107                                                 appendStringLiteralAH(q,
2108                                                                                           PQgetvalue(res, tuple, field),
2109                                                                                           fout);
2110                                                 archputs(q->data, fout);
2111                                                 break;
2112                                 }
2113                         }
2114
2115                         /* Terminate the row ... */
2116                         archputs(")", fout);
2117
2118                         /* ... and the statement, if the target no. of rows is reached */
2119                         if (++rows_this_statement >= rows_per_statement)
2120                         {
2121                                 if (dopt->do_nothing)
2122                                         archputs(" ON CONFLICT DO NOTHING;\n", fout);
2123                                 else
2124                                         archputs(";\n", fout);
2125                                 /* Reset the row counter */
2126                                 rows_this_statement = 0;
2127                         }
2128                 }
2129
2130                 if (PQntuples(res) <= 0)
2131                 {
2132                         PQclear(res);
2133                         break;
2134                 }
2135                 PQclear(res);
2136         }
2137
2138         /* Terminate any statements that didn't make the row count. */
2139         if (rows_this_statement > 0)
2140         {
2141                 if (dopt->do_nothing)
2142                         archputs(" ON CONFLICT DO NOTHING;\n", fout);
2143                 else
2144                         archputs(";\n", fout);
2145         }
2146
2147         archputs("\n\n", fout);
2148
2149         ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
2150
2151         destroyPQExpBuffer(q);
2152         if (insertStmt != NULL)
2153                 destroyPQExpBuffer(insertStmt);
2154
2155         return 1;
2156 }
2157
2158 /*
2159  * getRootTableInfo:
2160  *     get the root TableInfo for the given partition table.
2161  */
2162 static TableInfo *
2163 getRootTableInfo(TableInfo *tbinfo)
2164 {
2165         TableInfo  *parentTbinfo;
2166
2167         Assert(tbinfo->ispartition);
2168         Assert(tbinfo->numParents == 1);
2169
2170         parentTbinfo = tbinfo->parents[0];
2171         while (parentTbinfo->ispartition)
2172         {
2173                 Assert(parentTbinfo->numParents == 1);
2174                 parentTbinfo = parentTbinfo->parents[0];
2175         }
2176
2177         return parentTbinfo;
2178 }
2179
2180 /*
2181  * dumpTableData -
2182  *        dump the contents of a single table
2183  *
2184  * Actually, this just makes an ArchiveEntry for the table contents.
2185  */
2186 static void
2187 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
2188 {
2189         DumpOptions *dopt = fout->dopt;
2190         TableInfo  *tbinfo = tdinfo->tdtable;
2191         PQExpBuffer copyBuf = createPQExpBuffer();
2192         PQExpBuffer clistBuf = createPQExpBuffer();
2193         DataDumperPtr dumpFn;
2194         char       *copyStmt;
2195         const char *copyFrom;
2196
2197         if (!dopt->dump_inserts)
2198         {
2199                 /* Dump/restore using COPY */
2200                 dumpFn = dumpTableData_copy;
2201
2202                 /*
2203                  * When load-via-partition-root is set, get the root table name for
2204                  * the partition table, so that we can reload data through the root
2205                  * table.
2206                  */
2207                 if (dopt->load_via_partition_root && tbinfo->ispartition)
2208                 {
2209                         TableInfo  *parentTbinfo;
2210
2211                         parentTbinfo = getRootTableInfo(tbinfo);
2212                         copyFrom = fmtQualifiedDumpable(parentTbinfo);
2213                 }
2214                 else
2215                         copyFrom = fmtQualifiedDumpable(tbinfo);
2216
2217                 /* must use 2 steps here 'cause fmtId is nonreentrant */
2218                 appendPQExpBuffer(copyBuf, "COPY %s ",
2219                                                   copyFrom);
2220                 appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
2221                                                   fmtCopyColumnList(tbinfo, clistBuf));
2222                 copyStmt = copyBuf->data;
2223         }
2224         else
2225         {
2226                 /* Restore using INSERT */
2227                 dumpFn = dumpTableData_insert;
2228                 copyStmt = NULL;
2229         }
2230
2231         /*
2232          * Note: although the TableDataInfo is a full DumpableObject, we treat its
2233          * dependency on its table as "special" and pass it to ArchiveEntry now.
2234          * See comments for BuildArchiveDependencies.
2235          */
2236         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2237         {
2238                 TocEntry   *te;
2239
2240                 te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
2241                                                   ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
2242                                                                            .namespace = tbinfo->dobj.namespace->dobj.name,
2243                                                                            .owner = tbinfo->rolname,
2244                                                                            .description = "TABLE DATA",
2245                                                                            .section = SECTION_DATA,
2246                                                                            .copyStmt = copyStmt,
2247                                                                            .deps = &(tbinfo->dobj.dumpId),
2248                                                                            .nDeps = 1,
2249                                                                            .dumpFn = dumpFn,
2250                                                                            .dumpArg = tdinfo));
2251
2252                 /*
2253                  * Set the TocEntry's dataLength in case we are doing a parallel dump
2254                  * and want to order dump jobs by table size.  We choose to measure
2255                  * dataLength in table pages during dump, so no scaling is needed.
2256                  * However, relpages is declared as "integer" in pg_class, and hence
2257                  * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
2258                  * Cast so that we get the right interpretation of table sizes
2259                  * exceeding INT_MAX pages.
2260                  */
2261                 te->dataLength = (BlockNumber) tbinfo->relpages;
2262         }
2263
2264         destroyPQExpBuffer(copyBuf);
2265         destroyPQExpBuffer(clistBuf);
2266 }
2267
2268 /*
2269  * refreshMatViewData -
2270  *        load or refresh the contents of a single materialized view
2271  *
2272  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
2273  * statement.
2274  */
2275 static void
2276 refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
2277 {
2278         TableInfo  *tbinfo = tdinfo->tdtable;
2279         PQExpBuffer q;
2280
2281         /* If the materialized view is not flagged as populated, skip this. */
2282         if (!tbinfo->relispopulated)
2283                 return;
2284
2285         q = createPQExpBuffer();
2286
2287         appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
2288                                           fmtQualifiedDumpable(tbinfo));
2289
2290         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2291                 ArchiveEntry(fout,
2292                                          tdinfo->dobj.catId,    /* catalog ID */
2293                                          tdinfo->dobj.dumpId,   /* dump ID */
2294                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
2295                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
2296                                                                   .owner = tbinfo->rolname,
2297                                                                   .description = "MATERIALIZED VIEW DATA",
2298                                                                   .section = SECTION_POST_DATA,
2299                                                                   .createStmt = q->data,
2300                                                                   .deps = tdinfo->dobj.dependencies,
2301                                                                   .nDeps = tdinfo->dobj.nDeps));
2302
2303         destroyPQExpBuffer(q);
2304 }
2305
2306 /*
2307  * getTableData -
2308  *        set up dumpable objects representing the contents of tables
2309  */
2310 static void
2311 getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
2312 {
2313         int                     i;
2314
2315         for (i = 0; i < numTables; i++)
2316         {
2317                 if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
2318                         (!relkind || tblinfo[i].relkind == relkind))
2319                         makeTableDataInfo(dopt, &(tblinfo[i]));
2320         }
2321 }
2322
2323 /*
2324  * Make a dumpable object for the data of this specific table
2325  *
2326  * Note: we make a TableDataInfo if and only if we are going to dump the
2327  * table data; the "dump" flag in such objects isn't used.
2328  */
2329 static void
2330 makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
2331 {
2332         TableDataInfo *tdinfo;
2333
2334         /*
2335          * Nothing to do if we already decided to dump the table.  This will
2336          * happen for "config" tables.
2337          */
2338         if (tbinfo->dataObj != NULL)
2339                 return;
2340
2341         /* Skip VIEWs (no data to dump) */
2342         if (tbinfo->relkind == RELKIND_VIEW)
2343                 return;
2344         /* Skip FOREIGN TABLEs (no data to dump) */
2345         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2346                 return;
2347         /* Skip partitioned tables (data in partitions) */
2348         if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
2349                 return;
2350
2351         /* Don't dump data in unlogged tables, if so requested */
2352         if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
2353                 dopt->no_unlogged_table_data)
2354                 return;
2355
2356         /* Check that the data is not explicitly excluded */
2357         if (simple_oid_list_member(&tabledata_exclude_oids,
2358                                                            tbinfo->dobj.catId.oid))
2359                 return;
2360
2361         /* OK, let's dump it */
2362         tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
2363
2364         if (tbinfo->relkind == RELKIND_MATVIEW)
2365                 tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
2366         else if (tbinfo->relkind == RELKIND_SEQUENCE)
2367                 tdinfo->dobj.objType = DO_SEQUENCE_SET;
2368         else
2369                 tdinfo->dobj.objType = DO_TABLE_DATA;
2370
2371         /*
2372          * Note: use tableoid 0 so that this object won't be mistaken for
2373          * something that pg_depend entries apply to.
2374          */
2375         tdinfo->dobj.catId.tableoid = 0;
2376         tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
2377         AssignDumpId(&tdinfo->dobj);
2378         tdinfo->dobj.name = tbinfo->dobj.name;
2379         tdinfo->dobj.namespace = tbinfo->dobj.namespace;
2380         tdinfo->tdtable = tbinfo;
2381         tdinfo->filtercond = NULL;      /* might get set later */
2382         addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
2383
2384         tbinfo->dataObj = tdinfo;
2385 }
2386
2387 /*
2388  * The refresh for a materialized view must be dependent on the refresh for
2389  * any materialized view that this one is dependent on.
2390  *
2391  * This must be called after all the objects are created, but before they are
2392  * sorted.
2393  */
2394 static void
2395 buildMatViewRefreshDependencies(Archive *fout)
2396 {
2397         PQExpBuffer query;
2398         PGresult   *res;
2399         int                     ntups,
2400                                 i;
2401         int                     i_classid,
2402                                 i_objid,
2403                                 i_refobjid;
2404
2405         /* No Mat Views before 9.3. */
2406         if (fout->remoteVersion < 90300)
2407                 return;
2408
2409         query = createPQExpBuffer();
2410
2411         appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
2412                                                  "( "
2413                                                  "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
2414                                                  "FROM pg_depend d1 "
2415                                                  "JOIN pg_class c1 ON c1.oid = d1.objid "
2416                                                  "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
2417                                                  " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
2418                                                  "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
2419                                                  "AND d2.objid = r1.oid "
2420                                                  "AND d2.refobjid <> d1.objid "
2421                                                  "JOIN pg_class c2 ON c2.oid = d2.refobjid "
2422                                                  "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2423                                                  CppAsString2(RELKIND_VIEW) ") "
2424                                                  "WHERE d1.classid = 'pg_class'::regclass "
2425                                                  "UNION "
2426                                                  "SELECT w.objid, d3.refobjid, c3.relkind "
2427                                                  "FROM w "
2428                                                  "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
2429                                                  "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
2430                                                  "AND d3.objid = r3.oid "
2431                                                  "AND d3.refobjid <> w.refobjid "
2432                                                  "JOIN pg_class c3 ON c3.oid = d3.refobjid "
2433                                                  "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2434                                                  CppAsString2(RELKIND_VIEW) ") "
2435                                                  ") "
2436                                                  "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
2437                                                  "FROM w "
2438                                                  "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
2439
2440         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2441
2442         ntups = PQntuples(res);
2443
2444         i_classid = PQfnumber(res, "classid");
2445         i_objid = PQfnumber(res, "objid");
2446         i_refobjid = PQfnumber(res, "refobjid");
2447
2448         for (i = 0; i < ntups; i++)
2449         {
2450                 CatalogId       objId;
2451                 CatalogId       refobjId;
2452                 DumpableObject *dobj;
2453                 DumpableObject *refdobj;
2454                 TableInfo  *tbinfo;
2455                 TableInfo  *reftbinfo;
2456
2457                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
2458                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
2459                 refobjId.tableoid = objId.tableoid;
2460                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
2461
2462                 dobj = findObjectByCatalogId(objId);
2463                 if (dobj == NULL)
2464                         continue;
2465
2466                 Assert(dobj->objType == DO_TABLE);
2467                 tbinfo = (TableInfo *) dobj;
2468                 Assert(tbinfo->relkind == RELKIND_MATVIEW);
2469                 dobj = (DumpableObject *) tbinfo->dataObj;
2470                 if (dobj == NULL)
2471                         continue;
2472                 Assert(dobj->objType == DO_REFRESH_MATVIEW);
2473
2474                 refdobj = findObjectByCatalogId(refobjId);
2475                 if (refdobj == NULL)
2476                         continue;
2477
2478                 Assert(refdobj->objType == DO_TABLE);
2479                 reftbinfo = (TableInfo *) refdobj;
2480                 Assert(reftbinfo->relkind == RELKIND_MATVIEW);
2481                 refdobj = (DumpableObject *) reftbinfo->dataObj;
2482                 if (refdobj == NULL)
2483                         continue;
2484                 Assert(refdobj->objType == DO_REFRESH_MATVIEW);
2485
2486                 addObjectDependency(dobj, refdobj->dumpId);
2487
2488                 if (!reftbinfo->relispopulated)
2489                         tbinfo->relispopulated = false;
2490         }
2491
2492         PQclear(res);
2493
2494         destroyPQExpBuffer(query);
2495 }
2496
2497 /*
2498  * getTableDataFKConstraints -
2499  *        add dump-order dependencies reflecting foreign key constraints
2500  *
2501  * This code is executed only in a data-only dump --- in schema+data dumps
2502  * we handle foreign key issues by not creating the FK constraints until
2503  * after the data is loaded.  In a data-only dump, however, we want to
2504  * order the table data objects in such a way that a table's referenced
2505  * tables are restored first.  (In the presence of circular references or
2506  * self-references this may be impossible; we'll detect and complain about
2507  * that during the dependency sorting step.)
2508  */
2509 static void
2510 getTableDataFKConstraints(void)
2511 {
2512         DumpableObject **dobjs;
2513         int                     numObjs;
2514         int                     i;
2515
2516         /* Search through all the dumpable objects for FK constraints */
2517         getDumpableObjects(&dobjs, &numObjs);
2518         for (i = 0; i < numObjs; i++)
2519         {
2520                 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
2521                 {
2522                         ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
2523                         TableInfo  *ftable;
2524
2525                         /* Not interesting unless both tables are to be dumped */
2526                         if (cinfo->contable == NULL ||
2527                                 cinfo->contable->dataObj == NULL)
2528                                 continue;
2529                         ftable = findTableByOid(cinfo->confrelid);
2530                         if (ftable == NULL ||
2531                                 ftable->dataObj == NULL)
2532                                 continue;
2533
2534                         /*
2535                          * Okay, make referencing table's TABLE_DATA object depend on the
2536                          * referenced table's TABLE_DATA object.
2537                          */
2538                         addObjectDependency(&cinfo->contable->dataObj->dobj,
2539                                                                 ftable->dataObj->dobj.dumpId);
2540                 }
2541         }
2542         free(dobjs);
2543 }
2544
2545
2546 /*
2547  * guessConstraintInheritance:
2548  *      In pre-8.4 databases, we can't tell for certain which constraints
2549  *      are inherited.  We assume a CHECK constraint is inherited if its name
2550  *      matches the name of any constraint in the parent.  Originally this code
2551  *      tried to compare the expression texts, but that can fail for various
2552  *      reasons --- for example, if the parent and child tables are in different
2553  *      schemas, reverse-listing of function calls may produce different text
2554  *      (schema-qualified or not) depending on search path.
2555  *
2556  *      In 8.4 and up we can rely on the conislocal field to decide which
2557  *      constraints must be dumped; much safer.
2558  *
2559  *      This function assumes all conislocal flags were initialized to true.
2560  *      It clears the flag on anything that seems to be inherited.
2561  */
2562 static void
2563 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
2564 {
2565         int                     i,
2566                                 j,
2567                                 k;
2568
2569         for (i = 0; i < numTables; i++)
2570         {
2571                 TableInfo  *tbinfo = &(tblinfo[i]);
2572                 int                     numParents;
2573                 TableInfo **parents;
2574                 TableInfo  *parent;
2575
2576                 /* Sequences and views never have parents */
2577                 if (tbinfo->relkind == RELKIND_SEQUENCE ||
2578                         tbinfo->relkind == RELKIND_VIEW)
2579                         continue;
2580
2581                 /* Don't bother computing anything for non-target tables, either */
2582                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
2583                         continue;
2584
2585                 numParents = tbinfo->numParents;
2586                 parents = tbinfo->parents;
2587
2588                 if (numParents == 0)
2589                         continue;                       /* nothing to see here, move along */
2590
2591                 /* scan for inherited CHECK constraints */
2592                 for (j = 0; j < tbinfo->ncheck; j++)
2593                 {
2594                         ConstraintInfo *constr;
2595
2596                         constr = &(tbinfo->checkexprs[j]);
2597
2598                         for (k = 0; k < numParents; k++)
2599                         {
2600                                 int                     l;
2601
2602                                 parent = parents[k];
2603                                 for (l = 0; l < parent->ncheck; l++)
2604                                 {
2605                                         ConstraintInfo *pconstr = &(parent->checkexprs[l]);
2606
2607                                         if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
2608                                         {
2609                                                 constr->conislocal = false;
2610                                                 break;
2611                                         }
2612                                 }
2613                                 if (!constr->conislocal)
2614                                         break;
2615                         }
2616                 }
2617         }
2618 }
2619
2620
2621 /*
2622  * dumpDatabase:
2623  *      dump the database definition
2624  */
2625 static void
2626 dumpDatabase(Archive *fout)
2627 {
2628         DumpOptions *dopt = fout->dopt;
2629         PQExpBuffer dbQry = createPQExpBuffer();
2630         PQExpBuffer delQry = createPQExpBuffer();
2631         PQExpBuffer creaQry = createPQExpBuffer();
2632         PQExpBuffer labelq = createPQExpBuffer();
2633         PGconn     *conn = GetConnection(fout);
2634         PGresult   *res;
2635         int                     i_tableoid,
2636                                 i_oid,
2637                                 i_datname,
2638                                 i_dba,
2639                                 i_encoding,
2640                                 i_collate,
2641                                 i_ctype,
2642                                 i_frozenxid,
2643                                 i_minmxid,
2644                                 i_datacl,
2645                                 i_rdatacl,
2646                                 i_datistemplate,
2647                                 i_datconnlimit,
2648                                 i_tablespace;
2649         CatalogId       dbCatId;
2650         DumpId          dbDumpId;
2651         const char *datname,
2652                            *dba,
2653                            *encoding,
2654                            *collate,
2655                            *ctype,
2656                            *datacl,
2657                            *rdatacl,
2658                            *datistemplate,
2659                            *datconnlimit,
2660                            *tablespace;
2661         uint32          frozenxid,
2662                                 minmxid;
2663         char       *qdatname;
2664
2665         pg_log_info("saving database definition");
2666
2667         /* Fetch the database-level properties for this database */
2668         if (fout->remoteVersion >= 90600)
2669         {
2670                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2671                                                   "(%s datdba) AS dba, "
2672                                                   "pg_encoding_to_char(encoding) AS encoding, "
2673                                                   "datcollate, datctype, datfrozenxid, datminmxid, "
2674                                                   "(SELECT array_agg(acl ORDER BY acl::text COLLATE \"C\") FROM ( "
2675                                                   "  SELECT unnest(coalesce(datacl,acldefault('d',datdba))) AS acl "
2676                                                   "  EXCEPT SELECT unnest(acldefault('d',datdba))) as datacls)"
2677                                                   " AS datacl, "
2678                                                   "(SELECT array_agg(acl ORDER BY acl::text COLLATE \"C\") FROM ( "
2679                                                   "  SELECT unnest(acldefault('d',datdba)) AS acl "
2680                                                   "  EXCEPT SELECT unnest(coalesce(datacl,acldefault('d',datdba)))) as rdatacls)"
2681                                                   " AS rdatacl, "
2682                                                   "datistemplate, datconnlimit, "
2683                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2684                                                   "shobj_description(oid, 'pg_database') AS description "
2685
2686                                                   "FROM pg_database "
2687                                                   "WHERE datname = current_database()",
2688                                                   username_subquery);
2689         }
2690         else if (fout->remoteVersion >= 90300)
2691         {
2692                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2693                                                   "(%s datdba) AS dba, "
2694                                                   "pg_encoding_to_char(encoding) AS encoding, "
2695                                                   "datcollate, datctype, datfrozenxid, datminmxid, "
2696                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2697                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2698                                                   "shobj_description(oid, 'pg_database') AS description "
2699
2700                                                   "FROM pg_database "
2701                                                   "WHERE datname = current_database()",
2702                                                   username_subquery);
2703         }
2704         else if (fout->remoteVersion >= 80400)
2705         {
2706                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2707                                                   "(%s datdba) AS dba, "
2708                                                   "pg_encoding_to_char(encoding) AS encoding, "
2709                                                   "datcollate, datctype, datfrozenxid, 0 AS datminmxid, "
2710                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2711                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2712                                                   "shobj_description(oid, 'pg_database') AS description "
2713
2714                                                   "FROM pg_database "
2715                                                   "WHERE datname = current_database()",
2716                                                   username_subquery);
2717         }
2718         else if (fout->remoteVersion >= 80200)
2719         {
2720                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2721                                                   "(%s datdba) AS dba, "
2722                                                   "pg_encoding_to_char(encoding) AS encoding, "
2723                                                   "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2724                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2725                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2726                                                   "shobj_description(oid, 'pg_database') AS description "
2727
2728                                                   "FROM pg_database "
2729                                                   "WHERE datname = current_database()",
2730                                                   username_subquery);
2731         }
2732         else
2733         {
2734                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2735                                                   "(%s datdba) AS dba, "
2736                                                   "pg_encoding_to_char(encoding) AS encoding, "
2737                                                   "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2738                                                   "datacl, '' as rdatacl, datistemplate, "
2739                                                   "-1 as datconnlimit, "
2740                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
2741                                                   "FROM pg_database "
2742                                                   "WHERE datname = current_database()",
2743                                                   username_subquery);
2744         }
2745
2746         res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
2747
2748         i_tableoid = PQfnumber(res, "tableoid");
2749         i_oid = PQfnumber(res, "oid");
2750         i_datname = PQfnumber(res, "datname");
2751         i_dba = PQfnumber(res, "dba");
2752         i_encoding = PQfnumber(res, "encoding");
2753         i_collate = PQfnumber(res, "datcollate");
2754         i_ctype = PQfnumber(res, "datctype");
2755         i_frozenxid = PQfnumber(res, "datfrozenxid");
2756         i_minmxid = PQfnumber(res, "datminmxid");
2757         i_datacl = PQfnumber(res, "datacl");
2758         i_rdatacl = PQfnumber(res, "rdatacl");
2759         i_datistemplate = PQfnumber(res, "datistemplate");
2760         i_datconnlimit = PQfnumber(res, "datconnlimit");
2761         i_tablespace = PQfnumber(res, "tablespace");
2762
2763         dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
2764         dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
2765         datname = PQgetvalue(res, 0, i_datname);
2766         dba = PQgetvalue(res, 0, i_dba);
2767         encoding = PQgetvalue(res, 0, i_encoding);
2768         collate = PQgetvalue(res, 0, i_collate);
2769         ctype = PQgetvalue(res, 0, i_ctype);
2770         frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
2771         minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
2772         datacl = PQgetvalue(res, 0, i_datacl);
2773         rdatacl = PQgetvalue(res, 0, i_rdatacl);
2774         datistemplate = PQgetvalue(res, 0, i_datistemplate);
2775         datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
2776         tablespace = PQgetvalue(res, 0, i_tablespace);
2777
2778         qdatname = pg_strdup(fmtId(datname));
2779
2780         /*
2781          * Prepare the CREATE DATABASE command.  We must specify encoding, locale,
2782          * and tablespace since those can't be altered later.  Other DB properties
2783          * are left to the DATABASE PROPERTIES entry, so that they can be applied
2784          * after reconnecting to the target DB.
2785          */
2786         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
2787                                           qdatname);
2788         if (strlen(encoding) > 0)
2789         {
2790                 appendPQExpBufferStr(creaQry, " ENCODING = ");
2791                 appendStringLiteralAH(creaQry, encoding, fout);
2792         }
2793         if (strlen(collate) > 0)
2794         {
2795                 appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
2796                 appendStringLiteralAH(creaQry, collate, fout);
2797         }
2798         if (strlen(ctype) > 0)
2799         {
2800                 appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
2801                 appendStringLiteralAH(creaQry, ctype, fout);
2802         }
2803
2804         /*
2805          * Note: looking at dopt->outputNoTablespaces here is completely the wrong
2806          * thing; the decision whether to specify a tablespace should be left till
2807          * pg_restore, so that pg_restore --no-tablespaces applies.  Ideally we'd
2808          * label the DATABASE entry with the tablespace and let the normal
2809          * tablespace selection logic work ... but CREATE DATABASE doesn't pay
2810          * attention to default_tablespace, so that won't work.
2811          */
2812         if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
2813                 !dopt->outputNoTablespaces)
2814                 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
2815                                                   fmtId(tablespace));
2816         appendPQExpBufferStr(creaQry, ";\n");
2817
2818         appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
2819                                           qdatname);
2820
2821         dbDumpId = createDumpId();
2822
2823         ArchiveEntry(fout,
2824                                  dbCatId,               /* catalog ID */
2825                                  dbDumpId,              /* dump ID */
2826                                  ARCHIVE_OPTS(.tag = datname,
2827                                                           .owner = dba,
2828                                                           .description = "DATABASE",
2829                                                           .section = SECTION_PRE_DATA,
2830                                                           .createStmt = creaQry->data,
2831                                                           .dropStmt = delQry->data));
2832
2833         /* Compute correct tag for archive entry */
2834         appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
2835
2836         /* Dump DB comment if any */
2837         if (fout->remoteVersion >= 80200)
2838         {
2839                 /*
2840                  * 8.2 and up keep comments on shared objects in a shared table, so we
2841                  * cannot use the dumpComment() code used for other database objects.
2842                  * Be careful that the ArchiveEntry parameters match that function.
2843                  */
2844                 char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
2845
2846                 if (comment && *comment && !dopt->no_comments)
2847                 {
2848                         resetPQExpBuffer(dbQry);
2849
2850                         /*
2851                          * Generates warning when loaded into a differently-named
2852                          * database.
2853                          */
2854                         appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
2855                         appendStringLiteralAH(dbQry, comment, fout);
2856                         appendPQExpBufferStr(dbQry, ";\n");
2857
2858                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2859                                                  ARCHIVE_OPTS(.tag = labelq->data,
2860                                                                           .owner = dba,
2861                                                                           .description = "COMMENT",
2862                                                                           .section = SECTION_NONE,
2863                                                                           .createStmt = dbQry->data,
2864                                                                           .deps = &dbDumpId,
2865                                                                           .nDeps = 1));
2866                 }
2867         }
2868         else
2869         {
2870                 dumpComment(fout, "DATABASE", qdatname, NULL, dba,
2871                                         dbCatId, 0, dbDumpId);
2872         }
2873
2874         /* Dump DB security label, if enabled */
2875         if (!dopt->no_security_labels && fout->remoteVersion >= 90200)
2876         {
2877                 PGresult   *shres;
2878                 PQExpBuffer seclabelQry;
2879
2880                 seclabelQry = createPQExpBuffer();
2881
2882                 buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
2883                 shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
2884                 resetPQExpBuffer(seclabelQry);
2885                 emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
2886                 if (seclabelQry->len > 0)
2887                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2888                                                  ARCHIVE_OPTS(.tag = labelq->data,
2889                                                                           .owner = dba,
2890                                                                           .description = "SECURITY LABEL",
2891                                                                           .section = SECTION_NONE,
2892                                                                           .createStmt = seclabelQry->data,
2893                                                                           .deps = &dbDumpId,
2894                                                                           .nDeps = 1));
2895                 destroyPQExpBuffer(seclabelQry);
2896                 PQclear(shres);
2897         }
2898
2899         /*
2900          * Dump ACL if any.  Note that we do not support initial privileges
2901          * (pg_init_privs) on databases.
2902          */
2903         dumpACL(fout, dbCatId, dbDumpId, "DATABASE",
2904                         qdatname, NULL, NULL,
2905                         dba, datacl, rdatacl, "", "");
2906
2907         /*
2908          * Now construct a DATABASE PROPERTIES archive entry to restore any
2909          * non-default database-level properties.  (The reason this must be
2910          * separate is that we cannot put any additional commands into the TOC
2911          * entry that has CREATE DATABASE.  pg_restore would execute such a group
2912          * in an implicit transaction block, and the backend won't allow CREATE
2913          * DATABASE in that context.)
2914          */
2915         resetPQExpBuffer(creaQry);
2916         resetPQExpBuffer(delQry);
2917
2918         if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
2919                 appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
2920                                                   qdatname, datconnlimit);
2921
2922         if (strcmp(datistemplate, "t") == 0)
2923         {
2924                 appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
2925                                                   qdatname);
2926
2927                 /*
2928                  * The backend won't accept DROP DATABASE on a template database.  We
2929                  * can deal with that by removing the template marking before the DROP
2930                  * gets issued.  We'd prefer to use ALTER DATABASE IF EXISTS here, but
2931                  * since no such command is currently supported, fake it with a direct
2932                  * UPDATE on pg_database.
2933                  */
2934                 appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
2935                                                          "SET datistemplate = false WHERE datname = ");
2936                 appendStringLiteralAH(delQry, datname, fout);
2937                 appendPQExpBufferStr(delQry, ";\n");
2938         }
2939
2940         /* Add database-specific SET options */
2941         dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
2942
2943         /*
2944          * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
2945          * entry, too, for lack of a better place.
2946          */
2947         if (dopt->binary_upgrade)
2948         {
2949                 appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
2950                 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
2951                                                   "SET datfrozenxid = '%u', datminmxid = '%u'\n"
2952                                                   "WHERE datname = ",
2953                                                   frozenxid, minmxid);
2954                 appendStringLiteralAH(creaQry, datname, fout);
2955                 appendPQExpBufferStr(creaQry, ";\n");
2956         }
2957
2958         if (creaQry->len > 0)
2959                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
2960                                          ARCHIVE_OPTS(.tag = datname,
2961                                                                   .owner = dba,
2962                                                                   .description = "DATABASE PROPERTIES",
2963                                                                   .section = SECTION_PRE_DATA,
2964                                                                   .createStmt = creaQry->data,
2965                                                                   .dropStmt = delQry->data,
2966                                                                   .deps = &dbDumpId));
2967
2968         /*
2969          * pg_largeobject comes from the old system intact, so set its
2970          * relfrozenxids and relminmxids.
2971          */
2972         if (dopt->binary_upgrade)
2973         {
2974                 PGresult   *lo_res;
2975                 PQExpBuffer loFrozenQry = createPQExpBuffer();
2976                 PQExpBuffer loOutQry = createPQExpBuffer();
2977                 int                     i_relfrozenxid,
2978                                         i_relminmxid;
2979
2980                 /*
2981                  * pg_largeobject
2982                  */
2983                 if (fout->remoteVersion >= 90300)
2984                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
2985                                                           "FROM pg_catalog.pg_class\n"
2986                                                           "WHERE oid = %u;\n",
2987                                                           LargeObjectRelationId);
2988                 else
2989                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
2990                                                           "FROM pg_catalog.pg_class\n"
2991                                                           "WHERE oid = %u;\n",
2992                                                           LargeObjectRelationId);
2993
2994                 lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2995
2996                 i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2997                 i_relminmxid = PQfnumber(lo_res, "relminmxid");
2998
2999                 appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
3000                 appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
3001                                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
3002                                                   "WHERE oid = %u;\n",
3003                                                   atooid(PQgetvalue(lo_res, 0, i_relfrozenxid)),
3004                                                   atooid(PQgetvalue(lo_res, 0, i_relminmxid)),
3005                                                   LargeObjectRelationId);
3006                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
3007                                          ARCHIVE_OPTS(.tag = "pg_largeobject",
3008                                                                   .description = "pg_largeobject",
3009                                                                   .section = SECTION_PRE_DATA,
3010                                                                   .createStmt = loOutQry->data));
3011
3012                 PQclear(lo_res);
3013
3014                 destroyPQExpBuffer(loFrozenQry);
3015                 destroyPQExpBuffer(loOutQry);
3016         }
3017
3018         PQclear(res);
3019
3020         free(qdatname);
3021         destroyPQExpBuffer(dbQry);
3022         destroyPQExpBuffer(delQry);
3023         destroyPQExpBuffer(creaQry);
3024         destroyPQExpBuffer(labelq);
3025 }
3026
3027 /*
3028  * Collect any database-specific or role-and-database-specific SET options
3029  * for this database, and append them to outbuf.
3030  */
3031 static void
3032 dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
3033                                    const char *dbname, Oid dboid)
3034 {
3035         PGconn     *conn = GetConnection(AH);
3036         PQExpBuffer buf = createPQExpBuffer();
3037         PGresult   *res;
3038         int                     count = 1;
3039
3040         /*
3041          * First collect database-specific options.  Pre-8.4 server versions lack
3042          * unnest(), so we do this the hard way by querying once per subscript.
3043          */
3044         for (;;)
3045         {
3046                 if (AH->remoteVersion >= 90000)
3047                         printfPQExpBuffer(buf, "SELECT setconfig[%d] FROM pg_db_role_setting "
3048                                                           "WHERE setrole = 0 AND setdatabase = '%u'::oid",
3049                                                           count, dboid);
3050                 else
3051                         printfPQExpBuffer(buf, "SELECT datconfig[%d] FROM pg_database WHERE oid = '%u'::oid", count, dboid);
3052
3053                 res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3054
3055                 if (PQntuples(res) == 1 &&
3056                         !PQgetisnull(res, 0, 0))
3057                 {
3058                         makeAlterConfigCommand(conn, PQgetvalue(res, 0, 0),
3059                                                                    "DATABASE", dbname, NULL, NULL,
3060                                                                    outbuf);
3061                         PQclear(res);
3062                         count++;
3063                 }
3064                 else
3065                 {
3066                         PQclear(res);
3067                         break;
3068                 }
3069         }
3070
3071         /* Now look for role-and-database-specific options */
3072         if (AH->remoteVersion >= 90000)
3073         {
3074                 /* Here we can assume we have unnest() */
3075                 printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
3076                                                   "FROM pg_db_role_setting s, pg_roles r "
3077                                                   "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
3078                                                   dboid);
3079
3080                 res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3081
3082                 if (PQntuples(res) > 0)
3083                 {
3084                         int                     i;
3085
3086                         for (i = 0; i < PQntuples(res); i++)
3087                                 makeAlterConfigCommand(conn, PQgetvalue(res, i, 1),
3088                                                                            "ROLE", PQgetvalue(res, i, 0),
3089                                                                            "DATABASE", dbname,
3090                                                                            outbuf);
3091                 }
3092
3093                 PQclear(res);
3094         }
3095
3096         destroyPQExpBuffer(buf);
3097 }
3098
3099 /*
3100  * dumpEncoding: put the correct encoding into the archive
3101  */
3102 static void
3103 dumpEncoding(Archive *AH)
3104 {
3105         const char *encname = pg_encoding_to_char(AH->encoding);
3106         PQExpBuffer qry = createPQExpBuffer();
3107
3108         pg_log_info("saving encoding = %s", encname);
3109
3110         appendPQExpBufferStr(qry, "SET client_encoding = ");
3111         appendStringLiteralAH(qry, encname, AH);
3112         appendPQExpBufferStr(qry, ";\n");
3113
3114         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3115                                  ARCHIVE_OPTS(.tag = "ENCODING",
3116                                                           .description = "ENCODING",
3117                                                           .section = SECTION_PRE_DATA,
3118                                                           .createStmt = qry->data));
3119
3120         destroyPQExpBuffer(qry);
3121 }
3122
3123
3124 /*
3125  * dumpStdStrings: put the correct escape string behavior into the archive
3126  */
3127 static void
3128 dumpStdStrings(Archive *AH)
3129 {
3130         const char *stdstrings = AH->std_strings ? "on" : "off";
3131         PQExpBuffer qry = createPQExpBuffer();
3132
3133         pg_log_info("saving standard_conforming_strings = %s",
3134                                 stdstrings);
3135
3136         appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
3137                                           stdstrings);
3138
3139         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3140                                  ARCHIVE_OPTS(.tag = "STDSTRINGS",
3141                                                           .description = "STDSTRINGS",
3142                                                           .section = SECTION_PRE_DATA,
3143                                                           .createStmt = qry->data));
3144
3145         destroyPQExpBuffer(qry);
3146 }
3147
3148 /*
3149  * dumpSearchPath: record the active search_path in the archive
3150  */
3151 static void
3152 dumpSearchPath(Archive *AH)
3153 {
3154         PQExpBuffer qry = createPQExpBuffer();
3155         PQExpBuffer path = createPQExpBuffer();
3156         PGresult   *res;
3157         char      **schemanames = NULL;
3158         int                     nschemanames = 0;
3159         int                     i;
3160
3161         /*
3162          * We use the result of current_schemas(), not the search_path GUC,
3163          * because that might contain wildcards such as "$user", which won't
3164          * necessarily have the same value during restore.  Also, this way avoids
3165          * listing schemas that may appear in search_path but not actually exist,
3166          * which seems like a prudent exclusion.
3167          */
3168         res = ExecuteSqlQueryForSingleRow(AH,
3169                                                                           "SELECT pg_catalog.current_schemas(false)");
3170
3171         if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
3172                 fatal("could not parse result of current_schemas()");
3173
3174         /*
3175          * We use set_config(), not a simple "SET search_path" command, because
3176          * the latter has less-clean behavior if the search path is empty.  While
3177          * that's likely to get fixed at some point, it seems like a good idea to
3178          * be as backwards-compatible as possible in what we put into archives.
3179          */
3180         for (i = 0; i < nschemanames; i++)
3181         {
3182                 if (i > 0)
3183                         appendPQExpBufferStr(path, ", ");
3184                 appendPQExpBufferStr(path, fmtId(schemanames[i]));
3185         }
3186
3187         appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
3188         appendStringLiteralAH(qry, path->data, AH);
3189         appendPQExpBufferStr(qry, ", false);\n");
3190
3191         pg_log_info("saving search_path = %s", path->data);
3192
3193         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3194                                  ARCHIVE_OPTS(.tag = "SEARCHPATH",
3195                                                           .description = "SEARCHPATH",
3196                                                           .section = SECTION_PRE_DATA,
3197                                                           .createStmt = qry->data));
3198
3199         /* Also save it in AH->searchpath, in case we're doing plain text dump */
3200         AH->searchpath = pg_strdup(qry->data);
3201
3202         if (schemanames)
3203                 free(schemanames);
3204         PQclear(res);
3205         destroyPQExpBuffer(qry);
3206         destroyPQExpBuffer(path);
3207 }
3208
3209
3210 /*
3211  * getBlobs:
3212  *      Collect schema-level data about large objects
3213  */
3214 static void
3215 getBlobs(Archive *fout)
3216 {
3217         DumpOptions *dopt = fout->dopt;
3218         PQExpBuffer blobQry = createPQExpBuffer();
3219         BlobInfo   *binfo;
3220         DumpableObject *bdata;
3221         PGresult   *res;
3222         int                     ntups;
3223         int                     i;
3224         int                     i_oid;
3225         int                     i_lomowner;
3226         int                     i_lomacl;
3227         int                     i_rlomacl;
3228         int                     i_initlomacl;
3229         int                     i_initrlomacl;
3230
3231         pg_log_info("reading large objects");
3232
3233         /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
3234         if (fout->remoteVersion >= 90600)
3235         {
3236                 PQExpBuffer acl_subquery = createPQExpBuffer();
3237                 PQExpBuffer racl_subquery = createPQExpBuffer();
3238                 PQExpBuffer init_acl_subquery = createPQExpBuffer();
3239                 PQExpBuffer init_racl_subquery = createPQExpBuffer();
3240
3241                 buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
3242                                                 init_racl_subquery, "l.lomacl", "l.lomowner", "'L'",
3243                                                 dopt->binary_upgrade);
3244
3245                 appendPQExpBuffer(blobQry,
3246                                                   "SELECT l.oid, (%s l.lomowner) AS rolname, "
3247                                                   "%s AS lomacl, "
3248                                                   "%s AS rlomacl, "
3249                                                   "%s AS initlomacl, "
3250                                                   "%s AS initrlomacl "
3251                                                   "FROM pg_largeobject_metadata l "
3252                                                   "LEFT JOIN pg_init_privs pip ON "
3253                                                   "(l.oid = pip.objoid "
3254                                                   "AND pip.classoid = 'pg_largeobject'::regclass "
3255                                                   "AND pip.objsubid = 0) ",
3256                                                   username_subquery,
3257                                                   acl_subquery->data,
3258                                                   racl_subquery->data,
3259                                                   init_acl_subquery->data,
3260                                                   init_racl_subquery->data);
3261
3262                 destroyPQExpBuffer(acl_subquery);
3263                 destroyPQExpBuffer(racl_subquery);
3264                 destroyPQExpBuffer(init_acl_subquery);
3265                 destroyPQExpBuffer(init_racl_subquery);
3266         }
3267         else if (fout->remoteVersion >= 90000)
3268                 appendPQExpBuffer(blobQry,
3269                                                   "SELECT oid, (%s lomowner) AS rolname, lomacl, "
3270                                                   "NULL AS rlomacl, NULL AS initlomacl, "
3271                                                   "NULL AS initrlomacl "
3272                                                   " FROM pg_largeobject_metadata",
3273                                                   username_subquery);
3274         else
3275                 appendPQExpBufferStr(blobQry,
3276                                                          "SELECT DISTINCT loid AS oid, "
3277                                                          "NULL::name AS rolname, NULL::oid AS lomacl, "
3278                                                          "NULL::oid AS rlomacl, NULL::oid AS initlomacl, "
3279                                                          "NULL::oid AS initrlomacl "
3280                                                          " FROM pg_largeobject");
3281
3282         res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
3283
3284         i_oid = PQfnumber(res, "oid");
3285         i_lomowner = PQfnumber(res, "rolname");
3286         i_lomacl = PQfnumber(res, "lomacl");
3287         i_rlomacl = PQfnumber(res, "rlomacl");
3288         i_initlomacl = PQfnumber(res, "initlomacl");
3289         i_initrlomacl = PQfnumber(res, "initrlomacl");
3290
3291         ntups = PQntuples(res);
3292
3293         /*
3294          * Each large object has its own BLOB archive entry.
3295          */
3296         binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
3297
3298         for (i = 0; i < ntups; i++)
3299         {
3300                 binfo[i].dobj.objType = DO_BLOB;
3301                 binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
3302                 binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3303                 AssignDumpId(&binfo[i].dobj);
3304
3305                 binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oid));
3306                 binfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_lomowner));
3307                 binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, i_lomacl));
3308                 binfo[i].rblobacl = pg_strdup(PQgetvalue(res, i, i_rlomacl));
3309                 binfo[i].initblobacl = pg_strdup(PQgetvalue(res, i, i_initlomacl));
3310                 binfo[i].initrblobacl = pg_strdup(PQgetvalue(res, i, i_initrlomacl));
3311
3312                 if (PQgetisnull(res, i, i_lomacl) &&
3313                         PQgetisnull(res, i, i_rlomacl) &&
3314                         PQgetisnull(res, i, i_initlomacl) &&
3315                         PQgetisnull(res, i, i_initrlomacl))
3316                         binfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
3317
3318                 /*
3319                  * In binary-upgrade mode for blobs, we do *not* dump out the blob
3320                  * data, as it will be copied by pg_upgrade, which simply copies the
3321                  * pg_largeobject table. We *do* however dump out anything but the
3322                  * data, as pg_upgrade copies just pg_largeobject, but not
3323                  * pg_largeobject_metadata, after the dump is restored.
3324                  */
3325                 if (dopt->binary_upgrade)
3326                         binfo[i].dobj.dump &= ~DUMP_COMPONENT_DATA;
3327         }
3328
3329         /*
3330          * If we have any large objects, a "BLOBS" archive entry is needed. This
3331          * is just a placeholder for sorting; it carries no data now.
3332          */
3333         if (ntups > 0)
3334         {
3335                 bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
3336                 bdata->objType = DO_BLOB_DATA;
3337                 bdata->catId = nilCatalogId;
3338                 AssignDumpId(bdata);
3339                 bdata->name = pg_strdup("BLOBS");
3340         }
3341
3342         PQclear(res);
3343         destroyPQExpBuffer(blobQry);
3344 }
3345
3346 /*
3347  * dumpBlob
3348  *
3349  * dump the definition (metadata) of the given large object
3350  */
3351 static void
3352 dumpBlob(Archive *fout, BlobInfo *binfo)
3353 {
3354         PQExpBuffer cquery = createPQExpBuffer();
3355         PQExpBuffer dquery = createPQExpBuffer();
3356
3357         appendPQExpBuffer(cquery,
3358                                           "SELECT pg_catalog.lo_create('%s');\n",
3359                                           binfo->dobj.name);
3360
3361         appendPQExpBuffer(dquery,
3362                                           "SELECT pg_catalog.lo_unlink('%s');\n",
3363                                           binfo->dobj.name);
3364
3365         if (binfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
3366                 ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
3367                                          ARCHIVE_OPTS(.tag = binfo->dobj.name,
3368                                                                   .owner = binfo->rolname,
3369                                                                   .description = "BLOB",
3370                                                                   .section = SECTION_PRE_DATA,
3371                                                                   .createStmt = cquery->data,
3372                                                                   .dropStmt = dquery->data));
3373
3374         /* Dump comment if any */
3375         if (binfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3376                 dumpComment(fout, "LARGE OBJECT", binfo->dobj.name,
3377                                         NULL, binfo->rolname,
3378                                         binfo->dobj.catId, 0, binfo->dobj.dumpId);
3379
3380         /* Dump security label if any */
3381         if (binfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3382                 dumpSecLabel(fout, "LARGE OBJECT", binfo->dobj.name,
3383                                          NULL, binfo->rolname,
3384                                          binfo->dobj.catId, 0, binfo->dobj.dumpId);
3385
3386         /* Dump ACL if any */
3387         if (binfo->blobacl && (binfo->dobj.dump & DUMP_COMPONENT_ACL))
3388                 dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
3389                                 binfo->dobj.name, NULL,
3390                                 NULL, binfo->rolname, binfo->blobacl, binfo->rblobacl,
3391                                 binfo->initblobacl, binfo->initrblobacl);
3392
3393         destroyPQExpBuffer(cquery);
3394         destroyPQExpBuffer(dquery);
3395 }
3396
3397 /*
3398  * dumpBlobs:
3399  *      dump the data contents of all large objects
3400  */
3401 static int
3402 dumpBlobs(Archive *fout, void *arg)
3403 {
3404         const char *blobQry;
3405         const char *blobFetchQry;
3406         PGconn     *conn = GetConnection(fout);
3407         PGresult   *res;
3408         char            buf[LOBBUFSIZE];
3409         int                     ntups;
3410         int                     i;
3411         int                     cnt;
3412
3413         pg_log_info("saving large objects");
3414
3415         /*
3416          * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
3417          * the already-in-memory dumpable objects instead...
3418          */
3419         if (fout->remoteVersion >= 90000)
3420                 blobQry =
3421                         "DECLARE bloboid CURSOR FOR "
3422                         "SELECT oid FROM pg_largeobject_metadata ORDER BY 1";
3423         else
3424                 blobQry =
3425                         "DECLARE bloboid CURSOR FOR "
3426                         "SELECT DISTINCT loid FROM pg_largeobject ORDER BY 1";
3427
3428         ExecuteSqlStatement(fout, blobQry);
3429
3430         /* Command to fetch from cursor */
3431         blobFetchQry = "FETCH 1000 IN bloboid";
3432
3433         do
3434         {
3435                 /* Do a fetch */
3436                 res = ExecuteSqlQuery(fout, blobFetchQry, PGRES_TUPLES_OK);
3437
3438                 /* Process the tuples, if any */
3439                 ntups = PQntuples(res);
3440                 for (i = 0; i < ntups; i++)
3441                 {
3442                         Oid                     blobOid;
3443                         int                     loFd;
3444
3445                         blobOid = atooid(PQgetvalue(res, i, 0));
3446                         /* Open the BLOB */
3447                         loFd = lo_open(conn, blobOid, INV_READ);
3448                         if (loFd == -1)
3449                                 fatal("could not open large object %u: %s",
3450                                                           blobOid, PQerrorMessage(conn));
3451
3452                         StartBlob(fout, blobOid);
3453
3454                         /* Now read it in chunks, sending data to archive */
3455                         do
3456                         {
3457                                 cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
3458                                 if (cnt < 0)
3459                                         fatal("error reading large object %u: %s",
3460                                                                   blobOid, PQerrorMessage(conn));
3461
3462                                 WriteData(fout, buf, cnt);
3463                         } while (cnt > 0);
3464
3465                         lo_close(conn, loFd);
3466
3467                         EndBlob(fout, blobOid);
3468                 }
3469
3470                 PQclear(res);
3471         } while (ntups > 0);
3472
3473         return 1;
3474 }
3475
3476 /*
3477  * getPolicies
3478  *        get information about policies on a dumpable table.
3479  */
3480 void
3481 getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
3482 {
3483         PQExpBuffer query;
3484         PGresult   *res;
3485         PolicyInfo *polinfo;
3486         int                     i_oid;
3487         int                     i_tableoid;
3488         int                     i_polname;
3489         int                     i_polcmd;
3490         int                     i_polpermissive;
3491         int                     i_polroles;
3492         int                     i_polqual;
3493         int                     i_polwithcheck;
3494         int                     i,
3495                                 j,
3496                                 ntups;
3497
3498         if (fout->remoteVersion < 90500)
3499                 return;
3500
3501         query = createPQExpBuffer();
3502
3503         for (i = 0; i < numTables; i++)
3504         {
3505                 TableInfo  *tbinfo = &tblinfo[i];
3506
3507                 /* Ignore row security on tables not to be dumped */
3508                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
3509                         continue;
3510
3511                 pg_log_info("reading row security enabled for table \"%s.%s\"",
3512                                         tbinfo->dobj.namespace->dobj.name,
3513                                         tbinfo->dobj.name);
3514
3515                 /*
3516                  * Get row security enabled information for the table. We represent
3517                  * RLS being enabled on a table by creating a PolicyInfo object with
3518                  * null polname.
3519                  */
3520                 if (tbinfo->rowsec)
3521                 {
3522                         /*
3523                          * Note: use tableoid 0 so that this object won't be mistaken for
3524                          * something that pg_depend entries apply to.
3525                          */
3526                         polinfo = pg_malloc(sizeof(PolicyInfo));
3527                         polinfo->dobj.objType = DO_POLICY;
3528                         polinfo->dobj.catId.tableoid = 0;
3529                         polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
3530                         AssignDumpId(&polinfo->dobj);
3531                         polinfo->dobj.namespace = tbinfo->dobj.namespace;
3532                         polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
3533                         polinfo->poltable = tbinfo;
3534                         polinfo->polname = NULL;
3535                         polinfo->polcmd = '\0';
3536                         polinfo->polpermissive = 0;
3537                         polinfo->polroles = NULL;
3538                         polinfo->polqual = NULL;
3539                         polinfo->polwithcheck = NULL;
3540                 }
3541
3542                 pg_log_info("reading policies for table \"%s.%s\"",
3543                                         tbinfo->dobj.namespace->dobj.name,
3544                                         tbinfo->dobj.name);
3545
3546                 resetPQExpBuffer(query);
3547
3548                 /* Get the policies for the table. */
3549                 if (fout->remoteVersion >= 100000)
3550                         appendPQExpBuffer(query,
3551                                                           "SELECT oid, tableoid, pol.polname, pol.polcmd, pol.polpermissive, "
3552                                                           "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3553                                                           "   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, "
3554                                                           "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3555                                                           "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3556                                                           "FROM pg_catalog.pg_policy pol "
3557                                                           "WHERE polrelid = '%u'",
3558                                                           tbinfo->dobj.catId.oid);
3559                 else
3560                         appendPQExpBuffer(query,
3561                                                           "SELECT oid, tableoid, pol.polname, pol.polcmd, 't' as polpermissive, "
3562                                                           "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3563                                                           "   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, "
3564                                                           "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3565                                                           "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3566                                                           "FROM pg_catalog.pg_policy pol "
3567                                                           "WHERE polrelid = '%u'",
3568                                                           tbinfo->dobj.catId.oid);
3569                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3570
3571                 ntups = PQntuples(res);
3572
3573                 if (ntups == 0)
3574                 {
3575                         /*
3576                          * No explicit policies to handle (only the default-deny policy,
3577                          * which is handled as part of the table definition).  Clean up
3578                          * and return.
3579                          */
3580                         PQclear(res);
3581                         continue;
3582                 }
3583
3584                 i_oid = PQfnumber(res, "oid");
3585                 i_tableoid = PQfnumber(res, "tableoid");
3586                 i_polname = PQfnumber(res, "polname");
3587                 i_polcmd = PQfnumber(res, "polcmd");
3588                 i_polpermissive = PQfnumber(res, "polpermissive");
3589                 i_polroles = PQfnumber(res, "polroles");
3590                 i_polqual = PQfnumber(res, "polqual");
3591                 i_polwithcheck = PQfnumber(res, "polwithcheck");
3592
3593                 polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
3594
3595                 for (j = 0; j < ntups; j++)
3596                 {
3597                         polinfo[j].dobj.objType = DO_POLICY;
3598                         polinfo[j].dobj.catId.tableoid =
3599                                 atooid(PQgetvalue(res, j, i_tableoid));
3600                         polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3601                         AssignDumpId(&polinfo[j].dobj);
3602                         polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3603                         polinfo[j].poltable = tbinfo;
3604                         polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
3605                         polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
3606
3607                         polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
3608                         polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
3609
3610                         if (PQgetisnull(res, j, i_polroles))
3611                                 polinfo[j].polroles = NULL;
3612                         else
3613                                 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
3614
3615                         if (PQgetisnull(res, j, i_polqual))
3616                                 polinfo[j].polqual = NULL;
3617                         else
3618                                 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
3619
3620                         if (PQgetisnull(res, j, i_polwithcheck))
3621                                 polinfo[j].polwithcheck = NULL;
3622                         else
3623                                 polinfo[j].polwithcheck
3624                                         = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
3625                 }
3626                 PQclear(res);
3627         }
3628         destroyPQExpBuffer(query);
3629 }
3630
3631 /*
3632  * dumpPolicy
3633  *        dump the definition of the given policy
3634  */
3635 static void
3636 dumpPolicy(Archive *fout, PolicyInfo *polinfo)
3637 {
3638         DumpOptions *dopt = fout->dopt;
3639         TableInfo  *tbinfo = polinfo->poltable;
3640         PQExpBuffer query;
3641         PQExpBuffer delqry;
3642         const char *cmd;
3643         char       *tag;
3644
3645         if (dopt->dataOnly)
3646                 return;
3647
3648         /*
3649          * If polname is NULL, then this record is just indicating that ROW LEVEL
3650          * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
3651          * ROW LEVEL SECURITY.
3652          */
3653         if (polinfo->polname == NULL)
3654         {
3655                 query = createPQExpBuffer();
3656
3657                 appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
3658                                                   fmtQualifiedDumpable(tbinfo));
3659
3660                 /*
3661                  * We must emit the ROW SECURITY object's dependency on its table
3662                  * explicitly, because it will not match anything in pg_depend (unlike
3663                  * the case for other PolicyInfo objects).
3664                  */
3665                 if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3666                         ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3667                                                  ARCHIVE_OPTS(.tag = polinfo->dobj.name,
3668                                                                           .namespace = polinfo->dobj.namespace->dobj.name,
3669                                                                           .owner = tbinfo->rolname,
3670                                                                           .description = "ROW SECURITY",
3671                                                                           .section = SECTION_POST_DATA,
3672                                                                           .createStmt = query->data,
3673                                                                           .deps = &(tbinfo->dobj.dumpId),
3674                                                                           .nDeps = 1));
3675
3676                 destroyPQExpBuffer(query);
3677                 return;
3678         }
3679
3680         if (polinfo->polcmd == '*')
3681                 cmd = "";
3682         else if (polinfo->polcmd == 'r')
3683                 cmd = " FOR SELECT";
3684         else if (polinfo->polcmd == 'a')
3685                 cmd = " FOR INSERT";
3686         else if (polinfo->polcmd == 'w')
3687                 cmd = " FOR UPDATE";
3688         else if (polinfo->polcmd == 'd')
3689                 cmd = " FOR DELETE";
3690         else
3691         {
3692                 pg_log_error("unexpected policy command type: %c",
3693                                   polinfo->polcmd);
3694                 exit_nicely(1);
3695         }
3696
3697         query = createPQExpBuffer();
3698         delqry = createPQExpBuffer();
3699
3700         appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
3701
3702         appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
3703                                           !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
3704
3705         if (polinfo->polroles != NULL)
3706                 appendPQExpBuffer(query, " TO %s", polinfo->polroles);
3707
3708         if (polinfo->polqual != NULL)
3709                 appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
3710
3711         if (polinfo->polwithcheck != NULL)
3712                 appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
3713
3714         appendPQExpBuffer(query, ";\n");
3715
3716         appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
3717         appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
3718
3719         tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
3720
3721         if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3722                 ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3723                                          ARCHIVE_OPTS(.tag = tag,
3724                                                                   .namespace = polinfo->dobj.namespace->dobj.name,
3725                                                                   .owner = tbinfo->rolname,
3726                                                                   .description = "POLICY",
3727                                                                   .section = SECTION_POST_DATA,
3728                                                                   .createStmt = query->data,
3729                                                                   .dropStmt = delqry->data));
3730
3731         free(tag);
3732         destroyPQExpBuffer(query);
3733         destroyPQExpBuffer(delqry);
3734 }
3735
3736 /*
3737  * getPublications
3738  *        get information about publications
3739  */
3740 void
3741 getPublications(Archive *fout)
3742 {
3743         DumpOptions *dopt = fout->dopt;
3744         PQExpBuffer query;
3745         PGresult   *res;
3746         PublicationInfo *pubinfo;
3747         int                     i_tableoid;
3748         int                     i_oid;
3749         int                     i_pubname;
3750         int                     i_rolname;
3751         int                     i_puballtables;
3752         int                     i_pubinsert;
3753         int                     i_pubupdate;
3754         int                     i_pubdelete;
3755         int                     i_pubtruncate;
3756         int                     i,
3757                                 ntups;
3758
3759         if (dopt->no_publications || fout->remoteVersion < 100000)
3760                 return;
3761
3762         query = createPQExpBuffer();
3763
3764         resetPQExpBuffer(query);
3765
3766         /* Get the publications. */
3767         if (fout->remoteVersion >= 110000)
3768                 appendPQExpBuffer(query,
3769                                                   "SELECT p.tableoid, p.oid, p.pubname, "
3770                                                   "(%s p.pubowner) AS rolname, "
3771                                                   "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, p.pubtruncate "
3772                                                   "FROM pg_publication p",
3773                                                   username_subquery);
3774         else
3775                 appendPQExpBuffer(query,
3776                                                   "SELECT p.tableoid, p.oid, p.pubname, "
3777                                                   "(%s p.pubowner) AS rolname, "
3778                                                   "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, false AS pubtruncate "
3779                                                   "FROM pg_publication p",
3780                                                   username_subquery);
3781
3782         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3783
3784         ntups = PQntuples(res);
3785
3786         i_tableoid = PQfnumber(res, "tableoid");
3787         i_oid = PQfnumber(res, "oid");
3788         i_pubname = PQfnumber(res, "pubname");
3789         i_rolname = PQfnumber(res, "rolname");
3790         i_puballtables = PQfnumber(res, "puballtables");
3791         i_pubinsert = PQfnumber(res, "pubinsert");
3792         i_pubupdate = PQfnumber(res, "pubupdate");
3793         i_pubdelete = PQfnumber(res, "pubdelete");
3794         i_pubtruncate = PQfnumber(res, "pubtruncate");
3795
3796         pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
3797
3798         for (i = 0; i < ntups; i++)
3799         {
3800                 pubinfo[i].dobj.objType = DO_PUBLICATION;
3801                 pubinfo[i].dobj.catId.tableoid =
3802                         atooid(PQgetvalue(res, i, i_tableoid));
3803                 pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3804                 AssignDumpId(&pubinfo[i].dobj);
3805                 pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
3806                 pubinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3807                 pubinfo[i].puballtables =
3808                         (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
3809                 pubinfo[i].pubinsert =
3810                         (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
3811                 pubinfo[i].pubupdate =
3812                         (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
3813                 pubinfo[i].pubdelete =
3814                         (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
3815                 pubinfo[i].pubtruncate =
3816                         (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
3817
3818                 if (strlen(pubinfo[i].rolname) == 0)
3819                         pg_log_warning("owner of publication \"%s\" appears to be invalid",
3820                                           pubinfo[i].dobj.name);
3821
3822                 /* Decide whether we want to dump it */
3823                 selectDumpableObject(&(pubinfo[i].dobj), fout);
3824         }
3825         PQclear(res);
3826
3827         destroyPQExpBuffer(query);
3828 }
3829
3830 /*
3831  * dumpPublication
3832  *        dump the definition of the given publication
3833  */
3834 static void
3835 dumpPublication(Archive *fout, PublicationInfo *pubinfo)
3836 {
3837         PQExpBuffer delq;
3838         PQExpBuffer query;
3839         char       *qpubname;
3840         bool            first = true;
3841
3842         if (!(pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3843                 return;
3844
3845         delq = createPQExpBuffer();
3846         query = createPQExpBuffer();
3847
3848         qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
3849
3850         appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
3851                                           qpubname);
3852
3853         appendPQExpBuffer(query, "CREATE PUBLICATION %s",
3854                                           qpubname);
3855
3856         if (pubinfo->puballtables)
3857                 appendPQExpBufferStr(query, " FOR ALL TABLES");
3858
3859         appendPQExpBufferStr(query, " WITH (publish = '");
3860         if (pubinfo->pubinsert)
3861         {
3862                 appendPQExpBufferStr(query, "insert");
3863                 first = false;
3864         }
3865
3866         if (pubinfo->pubupdate)
3867         {
3868                 if (!first)
3869                         appendPQExpBufferStr(query, ", ");
3870
3871                 appendPQExpBufferStr(query, "update");
3872                 first = false;
3873         }
3874
3875         if (pubinfo->pubdelete)
3876         {
3877                 if (!first)
3878                         appendPQExpBufferStr(query, ", ");
3879
3880                 appendPQExpBufferStr(query, "delete");
3881                 first = false;
3882         }
3883
3884         if (pubinfo->pubtruncate)
3885         {
3886                 if (!first)
3887                         appendPQExpBufferStr(query, ", ");
3888
3889                 appendPQExpBufferStr(query, "truncate");
3890                 first = false;
3891         }
3892
3893         appendPQExpBufferStr(query, "');\n");
3894
3895         ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
3896                                  ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
3897                                                           .owner = pubinfo->rolname,
3898                                                           .description = "PUBLICATION",
3899                                                           .section = SECTION_POST_DATA,
3900                                                           .createStmt = query->data,
3901                                                           .dropStmt = delq->data));
3902
3903         if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3904                 dumpComment(fout, "PUBLICATION", qpubname,
3905                                         NULL, pubinfo->rolname,
3906                                         pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
3907
3908         if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3909                 dumpSecLabel(fout, "PUBLICATION", qpubname,
3910                                          NULL, pubinfo->rolname,
3911                                          pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
3912
3913         destroyPQExpBuffer(delq);
3914         destroyPQExpBuffer(query);
3915         free(qpubname);
3916 }
3917
3918 /*
3919  * getPublicationTables
3920  *        get information about publication membership for dumpable tables.
3921  */
3922 void
3923 getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
3924 {
3925         PQExpBuffer query;
3926         PGresult   *res;
3927         PublicationRelInfo *pubrinfo;
3928         DumpOptions *dopt = fout->dopt;
3929         int                     i_tableoid;
3930         int                     i_oid;
3931         int                     i_pubname;
3932         int                     i,
3933                                 j,
3934                                 ntups;
3935
3936         if (dopt->no_publications || fout->remoteVersion < 100000)
3937                 return;
3938
3939         query = createPQExpBuffer();
3940
3941         for (i = 0; i < numTables; i++)
3942         {
3943                 TableInfo  *tbinfo = &tblinfo[i];
3944
3945                 /* Only plain tables can be aded to publications. */
3946                 if (tbinfo->relkind != RELKIND_RELATION)
3947                         continue;
3948
3949                 /*
3950                  * Ignore publication membership of tables whose definitions are not
3951                  * to be dumped.
3952                  */
3953                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3954                         continue;
3955
3956                 pg_log_info("reading publication membership for table \"%s.%s\"",
3957                                         tbinfo->dobj.namespace->dobj.name,
3958                                         tbinfo->dobj.name);
3959
3960                 resetPQExpBuffer(query);
3961
3962                 /* Get the publication membership for the table. */
3963                 appendPQExpBuffer(query,
3964                                                   "SELECT pr.tableoid, pr.oid, p.pubname "
3965                                                   "FROM pg_publication_rel pr, pg_publication p "
3966                                                   "WHERE pr.prrelid = '%u'"
3967                                                   "  AND p.oid = pr.prpubid",
3968                                                   tbinfo->dobj.catId.oid);
3969                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3970
3971                 ntups = PQntuples(res);
3972
3973                 if (ntups == 0)
3974                 {
3975                         /*
3976                          * Table is not member of any publications. Clean up and return.
3977                          */
3978                         PQclear(res);
3979                         continue;
3980                 }
3981
3982                 i_tableoid = PQfnumber(res, "tableoid");
3983                 i_oid = PQfnumber(res, "oid");
3984                 i_pubname = PQfnumber(res, "pubname");
3985
3986                 pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
3987
3988                 for (j = 0; j < ntups; j++)
3989                 {
3990                         pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
3991                         pubrinfo[j].dobj.catId.tableoid =
3992                                 atooid(PQgetvalue(res, j, i_tableoid));
3993                         pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3994                         AssignDumpId(&pubrinfo[j].dobj);
3995                         pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3996                         pubrinfo[j].dobj.name = tbinfo->dobj.name;
3997                         pubrinfo[j].pubname = pg_strdup(PQgetvalue(res, j, i_pubname));
3998                         pubrinfo[j].pubtable = tbinfo;
3999
4000                         /* Decide whether we want to dump it */
4001                         selectDumpablePublicationTable(&(pubrinfo[j].dobj), fout);
4002                 }
4003                 PQclear(res);
4004         }
4005         destroyPQExpBuffer(query);
4006 }
4007
4008 /*
4009  * dumpPublicationTable
4010  *        dump the definition of the given publication table mapping
4011  */
4012 static void
4013 dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo)
4014 {
4015         TableInfo  *tbinfo = pubrinfo->pubtable;
4016         PQExpBuffer query;
4017         char       *tag;
4018
4019         if (!(pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
4020                 return;
4021
4022         tag = psprintf("%s %s", pubrinfo->pubname, tbinfo->dobj.name);
4023
4024         query = createPQExpBuffer();
4025
4026         appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
4027                                           fmtId(pubrinfo->pubname));
4028         appendPQExpBuffer(query, " %s;\n",
4029                                           fmtQualifiedDumpable(tbinfo));
4030
4031         /*
4032          * There is no point in creating drop query as drop query as the drop is
4033          * done by table drop.
4034          */
4035         ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
4036                                  ARCHIVE_OPTS(.tag = tag,
4037                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
4038                                                           .description = "PUBLICATION TABLE",
4039                                                           .section = SECTION_POST_DATA,
4040                                                           .createStmt = query->data));
4041
4042         free(tag);
4043         destroyPQExpBuffer(query);
4044 }
4045
4046 /*
4047  * Is the currently connected user a superuser?
4048  */
4049 static bool
4050 is_superuser(Archive *fout)
4051 {
4052         ArchiveHandle *AH = (ArchiveHandle *) fout;
4053         const char *val;
4054
4055         val = PQparameterStatus(AH->connection, "is_superuser");
4056
4057         if (val && strcmp(val, "on") == 0)
4058                 return true;
4059
4060         return false;
4061 }
4062
4063 /*
4064  * getSubscriptions
4065  *        get information about subscriptions
4066  */
4067 void
4068 getSubscriptions(Archive *fout)
4069 {
4070         DumpOptions *dopt = fout->dopt;
4071         PQExpBuffer query;
4072         PGresult   *res;
4073         SubscriptionInfo *subinfo;
4074         int                     i_tableoid;
4075         int                     i_oid;
4076         int                     i_subname;
4077         int                     i_rolname;
4078         int                     i_subconninfo;
4079         int                     i_subslotname;
4080         int                     i_subsynccommit;
4081         int                     i_subpublications;
4082         int                     i,
4083                                 ntups;
4084
4085         if (dopt->no_subscriptions || fout->remoteVersion < 100000)
4086                 return;
4087
4088         if (!is_superuser(fout))
4089         {
4090                 int                     n;
4091
4092                 res = ExecuteSqlQuery(fout,
4093                                                           "SELECT count(*) FROM pg_subscription "
4094                                                           "WHERE subdbid = (SELECT oid FROM pg_database"
4095                                                           "                 WHERE datname = current_database())",
4096                                                           PGRES_TUPLES_OK);
4097                 n = atoi(PQgetvalue(res, 0, 0));
4098                 if (n > 0)
4099                         pg_log_warning("subscriptions not dumped because current user is not a superuser");
4100                 PQclear(res);
4101                 return;
4102         }
4103
4104         query = createPQExpBuffer();
4105
4106         resetPQExpBuffer(query);
4107
4108         /* Get the subscriptions in current database. */
4109         appendPQExpBuffer(query,
4110                                           "SELECT s.tableoid, s.oid, s.subname,"
4111                                           "(%s s.subowner) AS rolname, "
4112                                           " s.subconninfo, s.subslotname, s.subsynccommit, "
4113                                           " s.subpublications "
4114                                           "FROM pg_subscription s "
4115                                           "WHERE s.subdbid = (SELECT oid FROM pg_database"
4116                                           "                   WHERE datname = current_database())",
4117                                           username_subquery);
4118         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4119
4120         ntups = PQntuples(res);
4121
4122         i_tableoid = PQfnumber(res, "tableoid");
4123         i_oid = PQfnumber(res, "oid");
4124         i_subname = PQfnumber(res, "subname");
4125         i_rolname = PQfnumber(res, "rolname");
4126         i_subconninfo = PQfnumber(res, "subconninfo");
4127         i_subslotname = PQfnumber(res, "subslotname");
4128         i_subsynccommit = PQfnumber(res, "subsynccommit");
4129         i_subpublications = PQfnumber(res, "subpublications");
4130
4131         subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
4132
4133         for (i = 0; i < ntups; i++)
4134         {
4135                 subinfo[i].dobj.objType = DO_SUBSCRIPTION;
4136                 subinfo[i].dobj.catId.tableoid =
4137                         atooid(PQgetvalue(res, i, i_tableoid));
4138                 subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4139                 AssignDumpId(&subinfo[i].dobj);
4140                 subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
4141                 subinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4142                 subinfo[i].subconninfo = pg_strdup(PQgetvalue(res, i, i_subconninfo));
4143                 if (PQgetisnull(res, i, i_subslotname))
4144                         subinfo[i].subslotname = NULL;
4145                 else
4146                         subinfo[i].subslotname = pg_strdup(PQgetvalue(res, i, i_subslotname));
4147                 subinfo[i].subsynccommit =
4148                         pg_strdup(PQgetvalue(res, i, i_subsynccommit));
4149                 subinfo[i].subpublications =
4150                         pg_strdup(PQgetvalue(res, i, i_subpublications));
4151
4152                 if (strlen(subinfo[i].rolname) == 0)
4153                         pg_log_warning("owner of subscription \"%s\" appears to be invalid",
4154                                           subinfo[i].dobj.name);
4155
4156                 /* Decide whether we want to dump it */
4157                 selectDumpableObject(&(subinfo[i].dobj), fout);
4158         }
4159         PQclear(res);
4160
4161         destroyPQExpBuffer(query);
4162 }
4163
4164 /*
4165  * dumpSubscription
4166  *        dump the definition of the given subscription
4167  */
4168 static void
4169 dumpSubscription(Archive *fout, SubscriptionInfo *subinfo)
4170 {
4171         PQExpBuffer delq;
4172         PQExpBuffer query;
4173         PQExpBuffer publications;
4174         char       *qsubname;
4175         char      **pubnames = NULL;
4176         int                     npubnames = 0;
4177         int                     i;
4178
4179         if (!(subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
4180                 return;
4181
4182         delq = createPQExpBuffer();
4183         query = createPQExpBuffer();
4184
4185         qsubname = pg_strdup(fmtId(subinfo->dobj.name));
4186
4187         appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
4188                                           qsubname);
4189
4190         appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
4191                                           qsubname);
4192         appendStringLiteralAH(query, subinfo->subconninfo, fout);
4193
4194         /* Build list of quoted publications and append them to query. */
4195         if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
4196         {
4197                 pg_log_warning("could not parse subpublications array");
4198                 if (pubnames)
4199                         free(pubnames);
4200                 pubnames = NULL;
4201                 npubnames = 0;
4202         }
4203
4204         publications = createPQExpBuffer();
4205         for (i = 0; i < npubnames; i++)
4206         {
4207                 if (i > 0)
4208                         appendPQExpBufferStr(publications, ", ");
4209
4210                 appendPQExpBufferStr(publications, fmtId(pubnames[i]));
4211         }
4212
4213         appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
4214         if (subinfo->subslotname)
4215                 appendStringLiteralAH(query, subinfo->subslotname, fout);
4216         else
4217                 appendPQExpBufferStr(query, "NONE");
4218
4219         if (strcmp(subinfo->subsynccommit, "off") != 0)
4220                 appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
4221
4222         appendPQExpBufferStr(query, ");\n");
4223
4224         ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
4225                                  ARCHIVE_OPTS(.tag = subinfo->dobj.name,
4226                                                           .owner = subinfo->rolname,
4227                                                           .description = "SUBSCRIPTION",
4228                                                           .section = SECTION_POST_DATA,
4229                                                           .createStmt = query->data,
4230                                                           .dropStmt = delq->data));
4231
4232         if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4233                 dumpComment(fout, "SUBSCRIPTION", qsubname,
4234                                         NULL, subinfo->rolname,
4235                                         subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
4236
4237         if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
4238                 dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
4239                                          NULL, subinfo->rolname,
4240                                          subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
4241
4242         destroyPQExpBuffer(publications);
4243         if (pubnames)
4244                 free(pubnames);
4245
4246         destroyPQExpBuffer(delq);
4247         destroyPQExpBuffer(query);
4248         free(qsubname);
4249 }
4250
4251 static void
4252 binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
4253                                                                                  PQExpBuffer upgrade_buffer,
4254                                                                                  Oid pg_type_oid,
4255                                                                                  bool force_array_type)
4256 {
4257         PQExpBuffer upgrade_query = createPQExpBuffer();
4258         PGresult   *res;
4259         Oid                     pg_type_array_oid;
4260
4261         appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
4262         appendPQExpBuffer(upgrade_buffer,
4263                                           "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4264                                           pg_type_oid);
4265
4266         /* we only support old >= 8.3 for binary upgrades */
4267         appendPQExpBuffer(upgrade_query,
4268                                           "SELECT typarray "
4269                                           "FROM pg_catalog.pg_type "
4270                                           "WHERE oid = '%u'::pg_catalog.oid;",
4271                                           pg_type_oid);
4272
4273         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4274
4275         pg_type_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
4276
4277         PQclear(res);
4278
4279         if (!OidIsValid(pg_type_array_oid) && force_array_type)
4280         {
4281                 /*
4282                  * If the old version didn't assign an array type, but the new version
4283                  * does, we must select an unused type OID to assign.  This currently
4284                  * only happens for domains, when upgrading pre-v11 to v11 and up.
4285                  *
4286                  * Note: local state here is kind of ugly, but we must have some,
4287                  * since we mustn't choose the same unused OID more than once.
4288                  */
4289                 static Oid      next_possible_free_oid = FirstNormalObjectId;
4290                 bool            is_dup;
4291
4292                 do
4293                 {
4294                         ++next_possible_free_oid;
4295                         printfPQExpBuffer(upgrade_query,
4296                                                           "SELECT EXISTS(SELECT 1 "
4297                                                           "FROM pg_catalog.pg_type "
4298                                                           "WHERE oid = '%u'::pg_catalog.oid);",
4299                                                           next_possible_free_oid);
4300                         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4301                         is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
4302                         PQclear(res);
4303                 } while (is_dup);
4304
4305                 pg_type_array_oid = next_possible_free_oid;
4306         }
4307
4308         if (OidIsValid(pg_type_array_oid))
4309         {
4310                 appendPQExpBufferStr(upgrade_buffer,
4311                                                          "\n-- For binary upgrade, must preserve pg_type array oid\n");
4312                 appendPQExpBuffer(upgrade_buffer,
4313                                                   "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4314                                                   pg_type_array_oid);
4315         }
4316
4317         destroyPQExpBuffer(upgrade_query);
4318 }
4319
4320 static bool
4321 binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
4322                                                                                 PQExpBuffer upgrade_buffer,
4323                                                                                 Oid pg_rel_oid)
4324 {
4325         PQExpBuffer upgrade_query = createPQExpBuffer();
4326         PGresult   *upgrade_res;
4327         Oid                     pg_type_oid;
4328         bool            toast_set = false;
4329
4330         /*
4331          * We only support old >= 8.3 for binary upgrades.
4332          *
4333          * We purposefully ignore toast OIDs for partitioned tables; the reason is
4334          * that versions 10 and 11 have them, but 12 does not, so emitting them
4335          * causes the upgrade to fail.
4336          */
4337         appendPQExpBuffer(upgrade_query,
4338                                           "SELECT c.reltype AS crel, t.reltype AS trel "
4339                                           "FROM pg_catalog.pg_class c "
4340                                           "LEFT JOIN pg_catalog.pg_class t ON "
4341                                           "  (c.reltoastrelid = t.oid AND c.relkind <> '%c') "
4342                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
4343                                           RELKIND_PARTITIONED_TABLE, pg_rel_oid);
4344
4345         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4346
4347         pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
4348
4349         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
4350                                                                                          pg_type_oid, false);
4351
4352         if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
4353         {
4354                 /* Toast tables do not have pg_type array rows */
4355                 Oid                     pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
4356                                                                                                                   PQfnumber(upgrade_res, "trel")));
4357
4358                 appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
4359                 appendPQExpBuffer(upgrade_buffer,
4360                                                   "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4361                                                   pg_type_toast_oid);
4362
4363                 toast_set = true;
4364         }
4365
4366         PQclear(upgrade_res);
4367         destroyPQExpBuffer(upgrade_query);
4368
4369         return toast_set;
4370 }
4371
4372 static void
4373 binary_upgrade_set_pg_class_oids(Archive *fout,
4374                                                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid,
4375                                                                  bool is_index)
4376 {
4377         PQExpBuffer upgrade_query = createPQExpBuffer();
4378         PGresult   *upgrade_res;
4379         Oid                     pg_class_reltoastrelid;
4380         Oid                     pg_index_indexrelid;
4381
4382         appendPQExpBuffer(upgrade_query,
4383                                           "SELECT c.reltoastrelid, i.indexrelid "
4384                                           "FROM pg_catalog.pg_class c LEFT JOIN "
4385                                           "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
4386                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
4387                                           pg_class_oid);
4388
4389         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4390
4391         pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
4392         pg_index_indexrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "indexrelid")));
4393
4394         appendPQExpBufferStr(upgrade_buffer,
4395                                                  "\n-- For binary upgrade, must preserve pg_class oids\n");
4396
4397         if (!is_index)
4398         {
4399                 appendPQExpBuffer(upgrade_buffer,
4400                                                   "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
4401                                                   pg_class_oid);
4402                 /* only tables have toast tables, not indexes */
4403                 if (OidIsValid(pg_class_reltoastrelid))
4404                 {
4405                         /*
4406                          * One complexity is that the table definition might not require
4407                          * the creation of a TOAST table, and the TOAST table might have
4408                          * been created long after table creation, when the table was
4409                          * loaded with wide data.  By setting the TOAST oid we force
4410                          * creation of the TOAST heap and TOAST index by the backend so we
4411                          * can cleanly copy the files during binary upgrade.
4412                          */
4413
4414                         appendPQExpBuffer(upgrade_buffer,
4415                                                           "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
4416                                                           pg_class_reltoastrelid);
4417
4418                         /* every toast table has an index */
4419                         appendPQExpBuffer(upgrade_buffer,
4420                                                           "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
4421                                                           pg_index_indexrelid);
4422                 }
4423         }
4424         else
4425                 appendPQExpBuffer(upgrade_buffer,
4426                                                   "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
4427                                                   pg_class_oid);
4428
4429         appendPQExpBufferChar(upgrade_buffer, '\n');
4430
4431         PQclear(upgrade_res);
4432         destroyPQExpBuffer(upgrade_query);
4433 }
4434
4435 /*
4436  * If the DumpableObject is a member of an extension, add a suitable
4437  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
4438  *
4439  * For somewhat historical reasons, objname should already be quoted,
4440  * but not objnamespace (if any).
4441  */
4442 static void
4443 binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
4444                                                                 DumpableObject *dobj,
4445                                                                 const char *objtype,
4446                                                                 const char *objname,
4447                                                                 const char *objnamespace)
4448 {
4449         DumpableObject *extobj = NULL;
4450         int                     i;
4451
4452         if (!dobj->ext_member)
4453                 return;
4454
4455         /*
4456          * Find the parent extension.  We could avoid this search if we wanted to
4457          * add a link field to DumpableObject, but the space costs of that would
4458          * be considerable.  We assume that member objects could only have a
4459          * direct dependency on their own extension, not any others.
4460          */
4461         for (i = 0; i < dobj->nDeps; i++)
4462         {
4463                 extobj = findObjectByDumpId(dobj->dependencies[i]);
4464                 if (extobj && extobj->objType == DO_EXTENSION)
4465                         break;
4466                 extobj = NULL;
4467         }
4468         if (extobj == NULL)
4469                 fatal("could not find parent extension for %s %s",
4470                                           objtype, objname);
4471
4472         appendPQExpBufferStr(upgrade_buffer,
4473                                                  "\n-- For binary upgrade, handle extension membership the hard way\n");
4474         appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
4475                                           fmtId(extobj->name),
4476                                           objtype);
4477         if (objnamespace && *objnamespace)
4478                 appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
4479         appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
4480 }
4481
4482 /*
4483  * getNamespaces:
4484  *        read all namespaces in the system catalogs and return them in the
4485  * NamespaceInfo* structure
4486  *
4487  *      numNamespaces is set to the number of namespaces read in
4488  */
4489 NamespaceInfo *
4490 getNamespaces(Archive *fout, int *numNamespaces)
4491 {
4492         DumpOptions *dopt = fout->dopt;
4493         PGresult   *res;
4494         int                     ntups;
4495         int                     i;
4496         PQExpBuffer query;
4497         NamespaceInfo *nsinfo;
4498         int                     i_tableoid;
4499         int                     i_oid;
4500         int                     i_nspname;
4501         int                     i_rolname;
4502         int                     i_nspacl;
4503         int                     i_rnspacl;
4504         int                     i_initnspacl;
4505         int                     i_initrnspacl;
4506
4507         query = createPQExpBuffer();
4508
4509         /*
4510          * we fetch all namespaces including system ones, so that every object we
4511          * read in can be linked to a containing namespace.
4512          */
4513         if (fout->remoteVersion >= 90600)
4514         {
4515                 PQExpBuffer acl_subquery = createPQExpBuffer();
4516                 PQExpBuffer racl_subquery = createPQExpBuffer();
4517                 PQExpBuffer init_acl_subquery = createPQExpBuffer();
4518                 PQExpBuffer init_racl_subquery = createPQExpBuffer();
4519
4520                 buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
4521                                                 init_racl_subquery, "n.nspacl", "n.nspowner", "'n'",
4522                                                 dopt->binary_upgrade);
4523
4524                 appendPQExpBuffer(query, "SELECT n.tableoid, n.oid, n.nspname, "
4525                                                   "(%s nspowner) AS rolname, "
4526                                                   "%s as nspacl, "
4527                                                   "%s as rnspacl, "
4528                                                   "%s as initnspacl, "
4529                                                   "%s as initrnspacl "
4530                                                   "FROM pg_namespace n "
4531                                                   "LEFT JOIN pg_init_privs pip "
4532                                                   "ON (n.oid = pip.objoid "
4533                                                   "AND pip.classoid = 'pg_namespace'::regclass "
4534                                                   "AND pip.objsubid = 0",
4535                                                   username_subquery,
4536                                                   acl_subquery->data,
4537                                                   racl_subquery->data,
4538                                                   init_acl_subquery->data,
4539                                                   init_racl_subquery->data);
4540
4541                 appendPQExpBuffer(query, ") ");
4542
4543                 destroyPQExpBuffer(acl_subquery);
4544                 destroyPQExpBuffer(racl_subquery);
4545                 destroyPQExpBuffer(init_acl_subquery);
4546                 destroyPQExpBuffer(init_racl_subquery);
4547         }
4548         else
4549                 appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
4550                                                   "(%s nspowner) AS rolname, "
4551                                                   "nspacl, NULL as rnspacl, "
4552                                                   "NULL AS initnspacl, NULL as initrnspacl "
4553                                                   "FROM pg_namespace",
4554                                                   username_subquery);
4555
4556         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4557
4558         ntups = PQntuples(res);
4559
4560         nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
4561
4562         i_tableoid = PQfnumber(res, "tableoid");
4563         i_oid = PQfnumber(res, "oid");
4564         i_nspname = PQfnumber(res, "nspname");
4565         i_rolname = PQfnumber(res, "rolname");
4566         i_nspacl = PQfnumber(res, "nspacl");
4567         i_rnspacl = PQfnumber(res, "rnspacl");
4568         i_initnspacl = PQfnumber(res, "initnspacl");
4569         i_initrnspacl = PQfnumber(res, "initrnspacl");
4570
4571         for (i = 0; i < ntups; i++)
4572         {
4573                 nsinfo[i].dobj.objType = DO_NAMESPACE;
4574                 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4575                 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4576                 AssignDumpId(&nsinfo[i].dobj);
4577                 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
4578                 nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4579                 nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
4580                 nsinfo[i].rnspacl = pg_strdup(PQgetvalue(res, i, i_rnspacl));
4581                 nsinfo[i].initnspacl = pg_strdup(PQgetvalue(res, i, i_initnspacl));
4582                 nsinfo[i].initrnspacl = pg_strdup(PQgetvalue(res, i, i_initrnspacl));
4583
4584                 /* Decide whether to dump this namespace */
4585                 selectDumpableNamespace(&nsinfo[i], fout);
4586
4587                 /*
4588                  * Do not try to dump ACL if the ACL is empty or the default.
4589                  *
4590                  * This is useful because, for some schemas/objects, the only
4591                  * component we are going to try and dump is the ACL and if we can
4592                  * remove that then 'dump' goes to zero/false and we don't consider
4593                  * this object for dumping at all later on.
4594                  */
4595                 if (PQgetisnull(res, i, i_nspacl) && PQgetisnull(res, i, i_rnspacl) &&
4596                         PQgetisnull(res, i, i_initnspacl) &&
4597                         PQgetisnull(res, i, i_initrnspacl))
4598                         nsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4599
4600                 if (strlen(nsinfo[i].rolname) == 0)
4601                         pg_log_warning("owner of schema \"%s\" appears to be invalid",
4602                                           nsinfo[i].dobj.name);
4603         }
4604
4605         PQclear(res);
4606         destroyPQExpBuffer(query);
4607
4608         *numNamespaces = ntups;
4609
4610         return nsinfo;
4611 }
4612
4613 /*
4614  * findNamespace:
4615  *              given a namespace OID, look up the info read by getNamespaces
4616  */
4617 static NamespaceInfo *
4618 findNamespace(Archive *fout, Oid nsoid)
4619 {
4620         NamespaceInfo *nsinfo;
4621
4622         nsinfo = findNamespaceByOid(nsoid);
4623         if (nsinfo == NULL)
4624                 fatal("schema with OID %u does not exist", nsoid);
4625         return nsinfo;
4626 }
4627
4628 /*
4629  * getExtensions:
4630  *        read all extensions in the system catalogs and return them in the
4631  * ExtensionInfo* structure
4632  *
4633  *      numExtensions is set to the number of extensions read in
4634  */
4635 ExtensionInfo *
4636 getExtensions(Archive *fout, int *numExtensions)
4637 {
4638         DumpOptions *dopt = fout->dopt;
4639         PGresult   *res;
4640         int                     ntups;
4641         int                     i;
4642         PQExpBuffer query;
4643         ExtensionInfo *extinfo;
4644         int                     i_tableoid;
4645         int                     i_oid;
4646         int                     i_extname;
4647         int                     i_nspname;
4648         int                     i_extrelocatable;
4649         int                     i_extversion;
4650         int                     i_extconfig;
4651         int                     i_extcondition;
4652
4653         /*
4654          * Before 9.1, there are no extensions.
4655          */
4656         if (fout->remoteVersion < 90100)
4657         {
4658                 *numExtensions = 0;
4659                 return NULL;
4660         }
4661
4662         query = createPQExpBuffer();
4663
4664         appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
4665                                                  "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
4666                                                  "FROM pg_extension x "
4667                                                  "JOIN pg_namespace n ON n.oid = x.extnamespace");
4668
4669         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4670
4671         ntups = PQntuples(res);
4672
4673         extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
4674
4675         i_tableoid = PQfnumber(res, "tableoid");
4676         i_oid = PQfnumber(res, "oid");
4677         i_extname = PQfnumber(res, "extname");
4678         i_nspname = PQfnumber(res, "nspname");
4679         i_extrelocatable = PQfnumber(res, "extrelocatable");
4680         i_extversion = PQfnumber(res, "extversion");
4681         i_extconfig = PQfnumber(res, "extconfig");
4682         i_extcondition = PQfnumber(res, "extcondition");
4683
4684         for (i = 0; i < ntups; i++)
4685         {
4686                 extinfo[i].dobj.objType = DO_EXTENSION;
4687                 extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4688                 extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4689                 AssignDumpId(&extinfo[i].dobj);
4690                 extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
4691                 extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
4692                 extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
4693                 extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
4694                 extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
4695                 extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
4696
4697                 /* Decide whether we want to dump it */
4698                 selectDumpableExtension(&(extinfo[i]), dopt);
4699         }
4700
4701         PQclear(res);
4702         destroyPQExpBuffer(query);
4703
4704         *numExtensions = ntups;
4705
4706         return extinfo;
4707 }
4708
4709 /*
4710  * getTypes:
4711  *        read all types in the system catalogs and return them in the
4712  * TypeInfo* structure
4713  *
4714  *      numTypes is set to the number of types read in
4715  *
4716  * NB: this must run after getFuncs() because we assume we can do
4717  * findFuncByOid().
4718  */
4719 TypeInfo *
4720 getTypes(Archive *fout, int *numTypes)
4721 {
4722         DumpOptions *dopt = fout->dopt;
4723         PGresult   *res;
4724         int                     ntups;
4725         int                     i;
4726         PQExpBuffer query = createPQExpBuffer();
4727         TypeInfo   *tyinfo;
4728         ShellTypeInfo *stinfo;
4729         int                     i_tableoid;
4730         int                     i_oid;
4731         int                     i_typname;
4732         int                     i_typnamespace;
4733         int                     i_typacl;
4734         int                     i_rtypacl;
4735         int                     i_inittypacl;
4736         int                     i_initrtypacl;
4737         int                     i_rolname;
4738         int                     i_typelem;
4739         int                     i_typrelid;
4740         int                     i_typrelkind;
4741         int                     i_typtype;
4742         int                     i_typisdefined;
4743         int                     i_isarray;
4744
4745         /*
4746          * we include even the built-in types because those may be used as array
4747          * elements by user-defined types
4748          *
4749          * we filter out the built-in types when we dump out the types
4750          *
4751          * same approach for undefined (shell) types and array types
4752          *
4753          * Note: as of 8.3 we can reliably detect whether a type is an
4754          * auto-generated array type by checking the element type's typarray.
4755          * (Before that the test is capable of generating false positives.) We
4756          * still check for name beginning with '_', though, so as to avoid the
4757          * cost of the subselect probe for all standard types.  This would have to
4758          * be revisited if the backend ever allows renaming of array types.
4759          */
4760
4761         if (fout->remoteVersion >= 90600)
4762         {
4763                 PQExpBuffer acl_subquery = createPQExpBuffer();
4764                 PQExpBuffer racl_subquery = createPQExpBuffer();
4765                 PQExpBuffer initacl_subquery = createPQExpBuffer();
4766                 PQExpBuffer initracl_subquery = createPQExpBuffer();
4767
4768                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
4769                                                 initracl_subquery, "t.typacl", "t.typowner", "'T'",
4770                                                 dopt->binary_upgrade);
4771
4772                 appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, t.typname, "
4773                                                   "t.typnamespace, "
4774                                                   "%s AS typacl, "
4775                                                   "%s AS rtypacl, "
4776                                                   "%s AS inittypacl, "
4777                                                   "%s AS initrtypacl, "
4778                                                   "(%s t.typowner) AS rolname, "
4779                                                   "t.typelem, t.typrelid, "
4780                                                   "CASE WHEN t.typrelid = 0 THEN ' '::\"char\" "
4781                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = t.typrelid) END AS typrelkind, "
4782                                                   "t.typtype, t.typisdefined, "
4783                                                   "t.typname[0] = '_' AND t.typelem != 0 AND "
4784                                                   "(SELECT typarray FROM pg_type te WHERE oid = t.typelem) = t.oid AS isarray "
4785                                                   "FROM pg_type t "
4786                                                   "LEFT JOIN pg_init_privs pip ON "
4787                                                   "(t.oid = pip.objoid "
4788                                                   "AND pip.classoid = 'pg_type'::regclass "
4789                                                   "AND pip.objsubid = 0) ",
4790                                                   acl_subquery->data,
4791                                                   racl_subquery->data,
4792                                                   initacl_subquery->data,
4793                                                   initracl_subquery->data,
4794                                                   username_subquery);
4795
4796                 destroyPQExpBuffer(acl_subquery);
4797                 destroyPQExpBuffer(racl_subquery);
4798                 destroyPQExpBuffer(initacl_subquery);
4799                 destroyPQExpBuffer(initracl_subquery);
4800         }
4801         else if (fout->remoteVersion >= 90200)
4802         {
4803                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4804                                                   "typnamespace, typacl, NULL as rtypacl, "
4805                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4806                                                   "(%s typowner) AS rolname, "
4807                                                   "typelem, typrelid, "
4808                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4809                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4810                                                   "typtype, typisdefined, "
4811                                                   "typname[0] = '_' AND typelem != 0 AND "
4812                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4813                                                   "FROM pg_type",
4814                                                   username_subquery);
4815         }
4816         else if (fout->remoteVersion >= 80300)
4817         {
4818                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4819                                                   "typnamespace, NULL AS typacl, NULL as rtypacl, "
4820                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4821                                                   "(%s typowner) AS rolname, "
4822                                                   "typelem, typrelid, "
4823                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4824                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4825                                                   "typtype, typisdefined, "
4826                                                   "typname[0] = '_' AND typelem != 0 AND "
4827                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4828                                                   "FROM pg_type",
4829                                                   username_subquery);
4830         }
4831         else
4832         {
4833                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4834                                                   "typnamespace, NULL AS typacl, NULL as rtypacl, "
4835                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4836                                                   "(%s typowner) AS rolname, "
4837                                                   "typelem, typrelid, "
4838                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4839                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4840                                                   "typtype, typisdefined, "
4841                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
4842                                                   "FROM pg_type",
4843                                                   username_subquery);
4844         }
4845
4846         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4847
4848         ntups = PQntuples(res);
4849
4850         tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
4851
4852         i_tableoid = PQfnumber(res, "tableoid");
4853         i_oid = PQfnumber(res, "oid");
4854         i_typname = PQfnumber(res, "typname");
4855         i_typnamespace = PQfnumber(res, "typnamespace");
4856         i_typacl = PQfnumber(res, "typacl");
4857         i_rtypacl = PQfnumber(res, "rtypacl");
4858         i_inittypacl = PQfnumber(res, "inittypacl");
4859         i_initrtypacl = PQfnumber(res, "initrtypacl");
4860         i_rolname = PQfnumber(res, "rolname");
4861         i_typelem = PQfnumber(res, "typelem");
4862         i_typrelid = PQfnumber(res, "typrelid");
4863         i_typrelkind = PQfnumber(res, "typrelkind");
4864         i_typtype = PQfnumber(res, "typtype");
4865         i_typisdefined = PQfnumber(res, "typisdefined");
4866         i_isarray = PQfnumber(res, "isarray");
4867
4868         for (i = 0; i < ntups; i++)
4869         {
4870                 tyinfo[i].dobj.objType = DO_TYPE;
4871                 tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4872                 tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4873                 AssignDumpId(&tyinfo[i].dobj);
4874                 tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
4875                 tyinfo[i].dobj.namespace =
4876                         findNamespace(fout,
4877                                                   atooid(PQgetvalue(res, i, i_typnamespace)));
4878                 tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4879                 tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
4880                 tyinfo[i].rtypacl = pg_strdup(PQgetvalue(res, i, i_rtypacl));
4881                 tyinfo[i].inittypacl = pg_strdup(PQgetvalue(res, i, i_inittypacl));
4882                 tyinfo[i].initrtypacl = pg_strdup(PQgetvalue(res, i, i_initrtypacl));
4883                 tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
4884                 tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
4885                 tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
4886                 tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
4887                 tyinfo[i].shellType = NULL;
4888
4889                 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
4890                         tyinfo[i].isDefined = true;
4891                 else
4892                         tyinfo[i].isDefined = false;
4893
4894                 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
4895                         tyinfo[i].isArray = true;
4896                 else
4897                         tyinfo[i].isArray = false;
4898
4899                 /* Decide whether we want to dump it */
4900                 selectDumpableType(&tyinfo[i], fout);
4901
4902                 /* Do not try to dump ACL if no ACL exists. */
4903                 if (PQgetisnull(res, i, i_typacl) && PQgetisnull(res, i, i_rtypacl) &&
4904                         PQgetisnull(res, i, i_inittypacl) &&
4905                         PQgetisnull(res, i, i_initrtypacl))
4906                         tyinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4907
4908                 /*
4909                  * If it's a domain, fetch info about its constraints, if any
4910                  */
4911                 tyinfo[i].nDomChecks = 0;
4912                 tyinfo[i].domChecks = NULL;
4913                 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4914                         tyinfo[i].typtype == TYPTYPE_DOMAIN)
4915                         getDomainConstraints(fout, &(tyinfo[i]));
4916
4917                 /*
4918                  * If it's a base type, make a DumpableObject representing a shell
4919                  * definition of the type.  We will need to dump that ahead of the I/O
4920                  * functions for the type.  Similarly, range types need a shell
4921                  * definition in case they have a canonicalize function.
4922                  *
4923                  * Note: the shell type doesn't have a catId.  You might think it
4924                  * should copy the base type's catId, but then it might capture the
4925                  * pg_depend entries for the type, which we don't want.
4926                  */
4927                 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4928                         (tyinfo[i].typtype == TYPTYPE_BASE ||
4929                          tyinfo[i].typtype == TYPTYPE_RANGE))
4930                 {
4931                         stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
4932                         stinfo->dobj.objType = DO_SHELL_TYPE;
4933                         stinfo->dobj.catId = nilCatalogId;
4934                         AssignDumpId(&stinfo->dobj);
4935                         stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
4936                         stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
4937                         stinfo->baseType = &(tyinfo[i]);
4938                         tyinfo[i].shellType = stinfo;
4939
4940                         /*
4941                          * Initially mark the shell type as not to be dumped.  We'll only
4942                          * dump it if the I/O or canonicalize functions need to be dumped;
4943                          * this is taken care of while sorting dependencies.
4944                          */
4945                         stinfo->dobj.dump = DUMP_COMPONENT_NONE;
4946                 }
4947
4948                 if (strlen(tyinfo[i].rolname) == 0)
4949                         pg_log_warning("owner of data type \"%s\" appears to be invalid",
4950                                           tyinfo[i].dobj.name);
4951         }
4952
4953         *numTypes = ntups;
4954
4955         PQclear(res);
4956
4957         destroyPQExpBuffer(query);
4958
4959         return tyinfo;
4960 }
4961
4962 /*
4963  * getOperators:
4964  *        read all operators in the system catalogs and return them in the
4965  * OprInfo* structure
4966  *
4967  *      numOprs is set to the number of operators read in
4968  */
4969 OprInfo *
4970 getOperators(Archive *fout, int *numOprs)
4971 {
4972         PGresult   *res;
4973         int                     ntups;
4974         int                     i;
4975         PQExpBuffer query = createPQExpBuffer();
4976         OprInfo    *oprinfo;
4977         int                     i_tableoid;
4978         int                     i_oid;
4979         int                     i_oprname;
4980         int                     i_oprnamespace;
4981         int                     i_rolname;
4982         int                     i_oprkind;
4983         int                     i_oprcode;
4984
4985         /*
4986          * find all operators, including builtin operators; we filter out
4987          * system-defined operators at dump-out time.
4988          */
4989
4990         appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
4991                                           "oprnamespace, "
4992                                           "(%s oprowner) AS rolname, "
4993                                           "oprkind, "
4994                                           "oprcode::oid AS oprcode "
4995                                           "FROM pg_operator",
4996                                           username_subquery);
4997
4998         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4999
5000         ntups = PQntuples(res);
5001         *numOprs = ntups;
5002
5003         oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
5004
5005         i_tableoid = PQfnumber(res, "tableoid");
5006         i_oid = PQfnumber(res, "oid");
5007         i_oprname = PQfnumber(res, "oprname");
5008         i_oprnamespace = PQfnumber(res, "oprnamespace");
5009         i_rolname = PQfnumber(res, "rolname");
5010         i_oprkind = PQfnumber(res, "oprkind");
5011         i_oprcode = PQfnumber(res, "oprcode");
5012
5013         for (i = 0; i < ntups; i++)
5014         {
5015                 oprinfo[i].dobj.objType = DO_OPERATOR;
5016                 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5017                 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5018                 AssignDumpId(&oprinfo[i].dobj);
5019                 oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
5020                 oprinfo[i].dobj.namespace =
5021                         findNamespace(fout,
5022                                                   atooid(PQgetvalue(res, i, i_oprnamespace)));
5023                 oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5024                 oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
5025                 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
5026
5027                 /* Decide whether we want to dump it */
5028                 selectDumpableObject(&(oprinfo[i].dobj), fout);
5029
5030                 /* Operators do not currently have ACLs. */
5031                 oprinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5032
5033                 if (strlen(oprinfo[i].rolname) == 0)
5034                         pg_log_warning("owner of operator \"%s\" appears to be invalid",
5035                                           oprinfo[i].dobj.name);
5036         }
5037
5038         PQclear(res);
5039
5040         destroyPQExpBuffer(query);
5041
5042         return oprinfo;
5043 }
5044
5045 /*
5046  * getCollations:
5047  *        read all collations in the system catalogs and return them in the
5048  * CollInfo* structure
5049  *
5050  *      numCollations is set to the number of collations read in
5051  */
5052 CollInfo *
5053 getCollations(Archive *fout, int *numCollations)
5054 {
5055         PGresult   *res;
5056         int                     ntups;
5057         int                     i;
5058         PQExpBuffer query;
5059         CollInfo   *collinfo;
5060         int                     i_tableoid;
5061         int                     i_oid;
5062         int                     i_collname;
5063         int                     i_collnamespace;
5064         int                     i_rolname;
5065
5066         /* Collations didn't exist pre-9.1 */
5067         if (fout->remoteVersion < 90100)
5068         {
5069                 *numCollations = 0;
5070                 return NULL;
5071         }
5072
5073         query = createPQExpBuffer();
5074
5075         /*
5076          * find all collations, including builtin collations; we filter out
5077          * system-defined collations at dump-out time.
5078          */
5079
5080         appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
5081                                           "collnamespace, "
5082                                           "(%s collowner) AS rolname "
5083                                           "FROM pg_collation",
5084                                           username_subquery);
5085
5086         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5087
5088         ntups = PQntuples(res);
5089         *numCollations = ntups;
5090
5091         collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
5092
5093         i_tableoid = PQfnumber(res, "tableoid");
5094         i_oid = PQfnumber(res, "oid");
5095         i_collname = PQfnumber(res, "collname");
5096         i_collnamespace = PQfnumber(res, "collnamespace");
5097         i_rolname = PQfnumber(res, "rolname");
5098
5099         for (i = 0; i < ntups; i++)
5100         {
5101                 collinfo[i].dobj.objType = DO_COLLATION;
5102                 collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5103                 collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5104                 AssignDumpId(&collinfo[i].dobj);
5105                 collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
5106                 collinfo[i].dobj.namespace =
5107                         findNamespace(fout,
5108                                                   atooid(PQgetvalue(res, i, i_collnamespace)));
5109                 collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5110
5111                 /* Decide whether we want to dump it */
5112                 selectDumpableObject(&(collinfo[i].dobj), fout);
5113
5114                 /* Collations do not currently have ACLs. */
5115                 collinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5116         }
5117
5118         PQclear(res);
5119
5120         destroyPQExpBuffer(query);
5121
5122         return collinfo;
5123 }
5124
5125 /*
5126  * getConversions:
5127  *        read all conversions in the system catalogs and return them in the
5128  * ConvInfo* structure
5129  *
5130  *      numConversions is set to the number of conversions read in
5131  */
5132 ConvInfo *
5133 getConversions(Archive *fout, int *numConversions)
5134 {
5135         PGresult   *res;
5136         int                     ntups;
5137         int                     i;
5138         PQExpBuffer query;
5139         ConvInfo   *convinfo;
5140         int                     i_tableoid;
5141         int                     i_oid;
5142         int                     i_conname;
5143         int                     i_connamespace;
5144         int                     i_rolname;
5145
5146         query = createPQExpBuffer();
5147
5148         /*
5149          * find all conversions, including builtin conversions; we filter out
5150          * system-defined conversions at dump-out time.
5151          */
5152
5153         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5154                                           "connamespace, "
5155                                           "(%s conowner) AS rolname "
5156                                           "FROM pg_conversion",
5157                                           username_subquery);
5158
5159         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5160
5161         ntups = PQntuples(res);
5162         *numConversions = ntups;
5163
5164         convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
5165
5166         i_tableoid = PQfnumber(res, "tableoid");
5167         i_oid = PQfnumber(res, "oid");
5168         i_conname = PQfnumber(res, "conname");
5169         i_connamespace = PQfnumber(res, "connamespace");
5170         i_rolname = PQfnumber(res, "rolname");
5171
5172         for (i = 0; i < ntups; i++)
5173         {
5174                 convinfo[i].dobj.objType = DO_CONVERSION;
5175                 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5176                 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5177                 AssignDumpId(&convinfo[i].dobj);
5178                 convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
5179                 convinfo[i].dobj.namespace =
5180                         findNamespace(fout,
5181                                                   atooid(PQgetvalue(res, i, i_connamespace)));
5182                 convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5183
5184                 /* Decide whether we want to dump it */
5185                 selectDumpableObject(&(convinfo[i].dobj), fout);
5186
5187                 /* Conversions do not currently have ACLs. */
5188                 convinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5189         }
5190
5191         PQclear(res);
5192
5193         destroyPQExpBuffer(query);
5194
5195         return convinfo;
5196 }
5197
5198 /*
5199  * getAccessMethods:
5200  *        read all user-defined access methods in the system catalogs and return
5201  *        them in the AccessMethodInfo* structure
5202  *
5203  *      numAccessMethods is set to the number of access methods read in
5204  */
5205 AccessMethodInfo *
5206 getAccessMethods(Archive *fout, int *numAccessMethods)
5207 {
5208         PGresult   *res;
5209         int                     ntups;
5210         int                     i;
5211         PQExpBuffer query;
5212         AccessMethodInfo *aminfo;
5213         int                     i_tableoid;
5214         int                     i_oid;
5215         int                     i_amname;
5216         int                     i_amhandler;
5217         int                     i_amtype;
5218
5219         /* Before 9.6, there are no user-defined access methods */
5220         if (fout->remoteVersion < 90600)
5221         {
5222                 *numAccessMethods = 0;
5223                 return NULL;
5224         }
5225
5226         query = createPQExpBuffer();
5227
5228         /* Select all access methods from pg_am table */
5229         appendPQExpBuffer(query, "SELECT tableoid, oid, amname, amtype, "
5230                                           "amhandler::pg_catalog.regproc AS amhandler "
5231                                           "FROM pg_am");
5232
5233         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5234
5235         ntups = PQntuples(res);
5236         *numAccessMethods = ntups;
5237
5238         aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
5239
5240         i_tableoid = PQfnumber(res, "tableoid");
5241         i_oid = PQfnumber(res, "oid");
5242         i_amname = PQfnumber(res, "amname");
5243         i_amhandler = PQfnumber(res, "amhandler");
5244         i_amtype = PQfnumber(res, "amtype");
5245
5246         for (i = 0; i < ntups; i++)
5247         {
5248                 aminfo[i].dobj.objType = DO_ACCESS_METHOD;
5249                 aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5250                 aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5251                 AssignDumpId(&aminfo[i].dobj);
5252                 aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
5253                 aminfo[i].dobj.namespace = NULL;
5254                 aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
5255                 aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
5256
5257                 /* Decide whether we want to dump it */
5258                 selectDumpableAccessMethod(&(aminfo[i]), fout);
5259
5260                 /* Access methods do not currently have ACLs. */
5261                 aminfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5262         }
5263
5264         PQclear(res);
5265
5266         destroyPQExpBuffer(query);
5267
5268         return aminfo;
5269 }
5270
5271
5272 /*
5273  * getOpclasses:
5274  *        read all opclasses in the system catalogs and return them in the
5275  * OpclassInfo* structure
5276  *
5277  *      numOpclasses is set to the number of opclasses read in
5278  */
5279 OpclassInfo *
5280 getOpclasses(Archive *fout, int *numOpclasses)
5281 {
5282         PGresult   *res;
5283         int                     ntups;
5284         int                     i;
5285         PQExpBuffer query = createPQExpBuffer();
5286         OpclassInfo *opcinfo;
5287         int                     i_tableoid;
5288         int                     i_oid;
5289         int                     i_opcname;
5290         int                     i_opcnamespace;
5291         int                     i_rolname;
5292
5293         /*
5294          * find all opclasses, including builtin opclasses; we filter out
5295          * system-defined opclasses at dump-out time.
5296          */
5297
5298         appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
5299                                           "opcnamespace, "
5300                                           "(%s opcowner) AS rolname "
5301                                           "FROM pg_opclass",
5302                                           username_subquery);
5303
5304         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5305
5306         ntups = PQntuples(res);
5307         *numOpclasses = ntups;
5308
5309         opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
5310
5311         i_tableoid = PQfnumber(res, "tableoid");
5312         i_oid = PQfnumber(res, "oid");
5313         i_opcname = PQfnumber(res, "opcname");
5314         i_opcnamespace = PQfnumber(res, "opcnamespace");
5315         i_rolname = PQfnumber(res, "rolname");
5316
5317         for (i = 0; i < ntups; i++)
5318         {
5319                 opcinfo[i].dobj.objType = DO_OPCLASS;
5320                 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5321                 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5322                 AssignDumpId(&opcinfo[i].dobj);
5323                 opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
5324                 opcinfo[i].dobj.namespace =
5325                         findNamespace(fout,
5326                                                   atooid(PQgetvalue(res, i, i_opcnamespace)));
5327                 opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5328
5329                 /* Decide whether we want to dump it */
5330                 selectDumpableObject(&(opcinfo[i].dobj), fout);
5331
5332                 /* Op Classes do not currently have ACLs. */
5333                 opcinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5334
5335                 if (strlen(opcinfo[i].rolname) == 0)
5336                         pg_log_warning("owner of operator class \"%s\" appears to be invalid",
5337                                           opcinfo[i].dobj.name);
5338         }
5339
5340         PQclear(res);
5341
5342         destroyPQExpBuffer(query);
5343
5344         return opcinfo;
5345 }
5346
5347 /*
5348  * getOpfamilies:
5349  *        read all opfamilies in the system catalogs and return them in the
5350  * OpfamilyInfo* structure
5351  *
5352  *      numOpfamilies is set to the number of opfamilies read in
5353  */
5354 OpfamilyInfo *
5355 getOpfamilies(Archive *fout, int *numOpfamilies)
5356 {
5357         PGresult   *res;
5358         int                     ntups;
5359         int                     i;
5360         PQExpBuffer query;
5361         OpfamilyInfo *opfinfo;
5362         int                     i_tableoid;
5363         int                     i_oid;
5364         int                     i_opfname;
5365         int                     i_opfnamespace;
5366         int                     i_rolname;
5367
5368         /* Before 8.3, there is no separate concept of opfamilies */
5369         if (fout->remoteVersion < 80300)
5370         {
5371                 *numOpfamilies = 0;
5372                 return NULL;
5373         }
5374
5375         query = createPQExpBuffer();
5376
5377         /*
5378          * find all opfamilies, including builtin opfamilies; we filter out
5379          * system-defined opfamilies at dump-out time.
5380          */
5381
5382         appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
5383                                           "opfnamespace, "
5384                                           "(%s opfowner) AS rolname "
5385                                           "FROM pg_opfamily",
5386                                           username_subquery);
5387
5388         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5389
5390         ntups = PQntuples(res);
5391         *numOpfamilies = ntups;
5392
5393         opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
5394
5395         i_tableoid = PQfnumber(res, "tableoid");
5396         i_oid = PQfnumber(res, "oid");
5397         i_opfname = PQfnumber(res, "opfname");
5398         i_opfnamespace = PQfnumber(res, "opfnamespace");
5399         i_rolname = PQfnumber(res, "rolname");
5400
5401         for (i = 0; i < ntups; i++)
5402         {
5403                 opfinfo[i].dobj.objType = DO_OPFAMILY;
5404                 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5405                 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5406                 AssignDumpId(&opfinfo[i].dobj);
5407                 opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
5408                 opfinfo[i].dobj.namespace =
5409                         findNamespace(fout,
5410                                                   atooid(PQgetvalue(res, i, i_opfnamespace)));
5411                 opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5412
5413                 /* Decide whether we want to dump it */
5414                 selectDumpableObject(&(opfinfo[i].dobj), fout);
5415
5416                 /* Extensions do not currently have ACLs. */
5417                 opfinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5418
5419                 if (strlen(opfinfo[i].rolname) == 0)
5420                         pg_log_warning("owner of operator family \"%s\" appears to be invalid",
5421                                           opfinfo[i].dobj.name);
5422         }
5423
5424         PQclear(res);
5425
5426         destroyPQExpBuffer(query);
5427
5428         return opfinfo;
5429 }
5430
5431 /*
5432  * getAggregates:
5433  *        read all the user-defined aggregates in the system catalogs and
5434  * return them in the AggInfo* structure
5435  *
5436  * numAggs is set to the number of aggregates read in
5437  */
5438 AggInfo *
5439 getAggregates(Archive *fout, int *numAggs)
5440 {
5441         DumpOptions *dopt = fout->dopt;
5442         PGresult   *res;
5443         int                     ntups;
5444         int                     i;
5445         PQExpBuffer query = createPQExpBuffer();
5446         AggInfo    *agginfo;
5447         int                     i_tableoid;
5448         int                     i_oid;
5449         int                     i_aggname;
5450         int                     i_aggnamespace;
5451         int                     i_pronargs;
5452         int                     i_proargtypes;
5453         int                     i_rolname;
5454         int                     i_aggacl;
5455         int                     i_raggacl;
5456         int                     i_initaggacl;
5457         int                     i_initraggacl;
5458
5459         /*
5460          * Find all interesting aggregates.  See comment in getFuncs() for the
5461          * rationale behind the filtering logic.
5462          */
5463         if (fout->remoteVersion >= 90600)
5464         {
5465                 PQExpBuffer acl_subquery = createPQExpBuffer();
5466                 PQExpBuffer racl_subquery = createPQExpBuffer();
5467                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5468                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5469                 const char *agg_check;
5470
5471                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5472                                                 initracl_subquery, "p.proacl", "p.proowner", "'f'",
5473                                                 dopt->binary_upgrade);
5474
5475                 agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
5476                                          : "p.proisagg");
5477
5478                 appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
5479                                                   "p.proname AS aggname, "
5480                                                   "p.pronamespace AS aggnamespace, "
5481                                                   "p.pronargs, p.proargtypes, "
5482                                                   "(%s p.proowner) AS rolname, "
5483                                                   "%s AS aggacl, "
5484                                                   "%s AS raggacl, "
5485                                                   "%s AS initaggacl, "
5486                                                   "%s AS initraggacl "
5487                                                   "FROM pg_proc p "
5488                                                   "LEFT JOIN pg_init_privs pip ON "
5489                                                   "(p.oid = pip.objoid "
5490                                                   "AND pip.classoid = 'pg_proc'::regclass "
5491                                                   "AND pip.objsubid = 0) "
5492                                                   "WHERE %s AND ("
5493                                                   "p.pronamespace != "
5494                                                   "(SELECT oid FROM pg_namespace "
5495                                                   "WHERE nspname = 'pg_catalog') OR "
5496                                                   "p.proacl IS DISTINCT FROM pip.initprivs",
5497                                                   username_subquery,
5498                                                   acl_subquery->data,
5499                                                   racl_subquery->data,
5500                                                   initacl_subquery->data,
5501                                                   initracl_subquery->data,
5502                                                   agg_check);
5503                 if (dopt->binary_upgrade)
5504                         appendPQExpBufferStr(query,
5505                                                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5506                                                                  "classid = 'pg_proc'::regclass AND "
5507                                                                  "objid = p.oid AND "
5508                                                                  "refclassid = 'pg_extension'::regclass AND "
5509                                                                  "deptype = 'e')");
5510                 appendPQExpBufferChar(query, ')');
5511
5512                 destroyPQExpBuffer(acl_subquery);
5513                 destroyPQExpBuffer(racl_subquery);
5514                 destroyPQExpBuffer(initacl_subquery);
5515                 destroyPQExpBuffer(initracl_subquery);
5516         }
5517         else if (fout->remoteVersion >= 80200)
5518         {
5519                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
5520                                                   "pronamespace AS aggnamespace, "
5521                                                   "pronargs, proargtypes, "
5522                                                   "(%s proowner) AS rolname, "
5523                                                   "proacl AS aggacl, "
5524                                                   "NULL AS raggacl, "
5525                                                   "NULL AS initaggacl, NULL AS initraggacl "
5526                                                   "FROM pg_proc p "
5527                                                   "WHERE proisagg AND ("
5528                                                   "pronamespace != "
5529                                                   "(SELECT oid FROM pg_namespace "
5530                                                   "WHERE nspname = 'pg_catalog')",
5531                                                   username_subquery);
5532                 if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
5533                         appendPQExpBufferStr(query,
5534                                                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5535                                                                  "classid = 'pg_proc'::regclass AND "
5536                                                                  "objid = p.oid AND "
5537                                                                  "refclassid = 'pg_extension'::regclass AND "
5538                                                                  "deptype = 'e')");
5539                 appendPQExpBufferChar(query, ')');
5540         }
5541         else
5542         {
5543                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
5544                                                   "pronamespace AS aggnamespace, "
5545                                                   "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
5546                                                   "proargtypes, "
5547                                                   "(%s proowner) AS rolname, "
5548                                                   "proacl AS aggacl, "
5549                                                   "NULL AS raggacl, "
5550                                                   "NULL AS initaggacl, NULL AS initraggacl "
5551                                                   "FROM pg_proc "
5552                                                   "WHERE proisagg "
5553                                                   "AND pronamespace != "
5554                                                   "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
5555                                                   username_subquery);
5556         }
5557
5558         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5559
5560         ntups = PQntuples(res);
5561         *numAggs = ntups;
5562
5563         agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
5564
5565         i_tableoid = PQfnumber(res, "tableoid");
5566         i_oid = PQfnumber(res, "oid");
5567         i_aggname = PQfnumber(res, "aggname");
5568         i_aggnamespace = PQfnumber(res, "aggnamespace");
5569         i_pronargs = PQfnumber(res, "pronargs");
5570         i_proargtypes = PQfnumber(res, "proargtypes");
5571         i_rolname = PQfnumber(res, "rolname");
5572         i_aggacl = PQfnumber(res, "aggacl");
5573         i_raggacl = PQfnumber(res, "raggacl");
5574         i_initaggacl = PQfnumber(res, "initaggacl");
5575         i_initraggacl = PQfnumber(res, "initraggacl");
5576
5577         for (i = 0; i < ntups; i++)
5578         {
5579                 agginfo[i].aggfn.dobj.objType = DO_AGG;
5580                 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5581                 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5582                 AssignDumpId(&agginfo[i].aggfn.dobj);
5583                 agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
5584                 agginfo[i].aggfn.dobj.namespace =
5585                         findNamespace(fout,
5586                                                   atooid(PQgetvalue(res, i, i_aggnamespace)));
5587                 agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5588                 if (strlen(agginfo[i].aggfn.rolname) == 0)
5589                         pg_log_warning("owner of aggregate function \"%s\" appears to be invalid",
5590                                           agginfo[i].aggfn.dobj.name);
5591                 agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
5592                 agginfo[i].aggfn.prorettype = InvalidOid;       /* not saved */
5593                 agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
5594                 agginfo[i].aggfn.rproacl = pg_strdup(PQgetvalue(res, i, i_raggacl));
5595                 agginfo[i].aggfn.initproacl = pg_strdup(PQgetvalue(res, i, i_initaggacl));
5596                 agginfo[i].aggfn.initrproacl = pg_strdup(PQgetvalue(res, i, i_initraggacl));
5597                 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
5598                 if (agginfo[i].aggfn.nargs == 0)
5599                         agginfo[i].aggfn.argtypes = NULL;
5600                 else
5601                 {
5602                         agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
5603                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
5604                                                   agginfo[i].aggfn.argtypes,
5605                                                   agginfo[i].aggfn.nargs);
5606                 }
5607
5608                 /* Decide whether we want to dump it */
5609                 selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
5610
5611                 /* Do not try to dump ACL if no ACL exists. */
5612                 if (PQgetisnull(res, i, i_aggacl) && PQgetisnull(res, i, i_raggacl) &&
5613                         PQgetisnull(res, i, i_initaggacl) &&
5614                         PQgetisnull(res, i, i_initraggacl))
5615                         agginfo[i].aggfn.dobj.dump &= ~DUMP_COMPONENT_ACL;
5616         }
5617
5618         PQclear(res);
5619
5620         destroyPQExpBuffer(query);
5621
5622         return agginfo;
5623 }
5624
5625 /*
5626  * getFuncs:
5627  *        read all the user-defined functions in the system catalogs and
5628  * return them in the FuncInfo* structure
5629  *
5630  * numFuncs is set to the number of functions read in
5631  */
5632 FuncInfo *
5633 getFuncs(Archive *fout, int *numFuncs)
5634 {
5635         DumpOptions *dopt = fout->dopt;
5636         PGresult   *res;
5637         int                     ntups;
5638         int                     i;
5639         PQExpBuffer query = createPQExpBuffer();
5640         FuncInfo   *finfo;
5641         int                     i_tableoid;
5642         int                     i_oid;
5643         int                     i_proname;
5644         int                     i_pronamespace;
5645         int                     i_rolname;
5646         int                     i_prolang;
5647         int                     i_pronargs;
5648         int                     i_proargtypes;
5649         int                     i_prorettype;
5650         int                     i_proacl;
5651         int                     i_rproacl;
5652         int                     i_initproacl;
5653         int                     i_initrproacl;
5654
5655         /*
5656          * Find all interesting functions.  This is a bit complicated:
5657          *
5658          * 1. Always exclude aggregates; those are handled elsewhere.
5659          *
5660          * 2. Always exclude functions that are internally dependent on something
5661          * else, since presumably those will be created as a result of creating
5662          * the something else.  This currently acts only to suppress constructor
5663          * functions for range types (so we only need it in 9.2 and up).  Note
5664          * this is OK only because the constructors don't have any dependencies
5665          * the range type doesn't have; otherwise we might not get creation
5666          * ordering correct.
5667          *
5668          * 3. Otherwise, we normally exclude functions in pg_catalog.  However, if
5669          * they're members of extensions and we are in binary-upgrade mode then
5670          * include them, since we want to dump extension members individually in
5671          * that mode.  Also, if they are used by casts or transforms then we need
5672          * to gather the information about them, though they won't be dumped if
5673          * they are built-in.  Also, in 9.6 and up, include functions in
5674          * pg_catalog if they have an ACL different from what's shown in
5675          * pg_init_privs.
5676          */
5677         if (fout->remoteVersion >= 90600)
5678         {
5679                 PQExpBuffer acl_subquery = createPQExpBuffer();
5680                 PQExpBuffer racl_subquery = createPQExpBuffer();
5681                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5682                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5683                 const char *not_agg_check;
5684
5685                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5686                                                 initracl_subquery, "p.proacl", "p.proowner", "'f'",
5687                                                 dopt->binary_upgrade);
5688
5689                 not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
5690                                                  : "NOT p.proisagg");
5691
5692                 appendPQExpBuffer(query,
5693                                                   "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
5694                                                   "p.pronargs, p.proargtypes, p.prorettype, "
5695                                                   "%s AS proacl, "
5696                                                   "%s AS rproacl, "
5697                                                   "%s AS initproacl, "
5698                                                   "%s AS initrproacl, "
5699                                                   "p.pronamespace, "
5700                                                   "(%s p.proowner) AS rolname "
5701                                                   "FROM pg_proc p "
5702                                                   "LEFT JOIN pg_init_privs pip ON "
5703                                                   "(p.oid = pip.objoid "
5704                                                   "AND pip.classoid = 'pg_proc'::regclass "
5705                                                   "AND pip.objsubid = 0) "
5706                                                   "WHERE %s"
5707                                                   "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
5708                                                   "WHERE classid = 'pg_proc'::regclass AND "
5709                                                   "objid = p.oid AND deptype = 'i')"
5710                                                   "\n  AND ("
5711                                                   "\n  pronamespace != "
5712                                                   "(SELECT oid FROM pg_namespace "
5713                                                   "WHERE nspname = 'pg_catalog')"
5714                                                   "\n  OR EXISTS (SELECT 1 FROM pg_cast"
5715                                                   "\n  WHERE pg_cast.oid > %u "
5716                                                   "\n  AND p.oid = pg_cast.castfunc)"
5717                                                   "\n  OR EXISTS (SELECT 1 FROM pg_transform"
5718                                                   "\n  WHERE pg_transform.oid > %u AND "
5719                                                   "\n  (p.oid = pg_transform.trffromsql"
5720                                                   "\n  OR p.oid = pg_transform.trftosql))",
5721                                                   acl_subquery->data,
5722                                                   racl_subquery->data,
5723                                                   initacl_subquery->data,
5724                                                   initracl_subquery->data,
5725                                                   username_subquery,
5726                                                   not_agg_check,
5727                                                   g_last_builtin_oid,
5728                                                   g_last_builtin_oid);
5729                 if (dopt->binary_upgrade)
5730                         appendPQExpBufferStr(query,
5731                                                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5732                                                                  "classid = 'pg_proc'::regclass AND "
5733                                                                  "objid = p.oid AND "
5734                                                                  "refclassid = 'pg_extension'::regclass AND "
5735                                                                  "deptype = 'e')");
5736                 appendPQExpBufferStr(query,
5737                                                          "\n  OR p.proacl IS DISTINCT FROM pip.initprivs");
5738                 appendPQExpBufferChar(query, ')');
5739
5740                 destroyPQExpBuffer(acl_subquery);
5741                 destroyPQExpBuffer(racl_subquery);
5742                 destroyPQExpBuffer(initacl_subquery);
5743                 destroyPQExpBuffer(initracl_subquery);
5744         }
5745         else
5746         {
5747                 appendPQExpBuffer(query,
5748                                                   "SELECT tableoid, oid, proname, prolang, "
5749                                                   "pronargs, proargtypes, prorettype, proacl, "
5750                                                   "NULL as rproacl, "
5751                                                   "NULL as initproacl, NULL AS initrproacl, "
5752                                                   "pronamespace, "
5753                                                   "(%s proowner) AS rolname "
5754                                                   "FROM pg_proc p "
5755                                                   "WHERE NOT proisagg",
5756                                                   username_subquery);
5757                 if (fout->remoteVersion >= 90200)
5758                         appendPQExpBufferStr(query,
5759                                                                  "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
5760                                                                  "WHERE classid = 'pg_proc'::regclass AND "
5761                                                                  "objid = p.oid AND deptype = 'i')");
5762                 appendPQExpBuffer(query,
5763                                                   "\n  AND ("
5764                                                   "\n  pronamespace != "
5765                                                   "(SELECT oid FROM pg_namespace "
5766                                                   "WHERE nspname = 'pg_catalog')"
5767                                                   "\n  OR EXISTS (SELECT 1 FROM pg_cast"
5768                                                   "\n  WHERE pg_cast.oid > '%u'::oid"
5769                                                   "\n  AND p.oid = pg_cast.castfunc)",
5770                                                   g_last_builtin_oid);
5771
5772                 if (fout->remoteVersion >= 90500)
5773                         appendPQExpBuffer(query,
5774                                                           "\n  OR EXISTS (SELECT 1 FROM pg_transform"
5775                                                           "\n  WHERE pg_transform.oid > '%u'::oid"
5776                                                           "\n  AND (p.oid = pg_transform.trffromsql"
5777                                                           "\n  OR p.oid = pg_transform.trftosql))",
5778                                                           g_last_builtin_oid);
5779
5780                 if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
5781                         appendPQExpBufferStr(query,
5782                                                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5783                                                                  "classid = 'pg_proc'::regclass AND "
5784                                                                  "objid = p.oid AND "
5785                                                                  "refclassid = 'pg_extension'::regclass AND "
5786                                                                  "deptype = 'e')");
5787                 appendPQExpBufferChar(query, ')');
5788         }
5789
5790         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5791
5792         ntups = PQntuples(res);
5793
5794         *numFuncs = ntups;
5795
5796         finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
5797
5798         i_tableoid = PQfnumber(res, "tableoid");
5799         i_oid = PQfnumber(res, "oid");
5800         i_proname = PQfnumber(res, "proname");
5801         i_pronamespace = PQfnumber(res, "pronamespace");
5802         i_rolname = PQfnumber(res, "rolname");
5803         i_prolang = PQfnumber(res, "prolang");
5804         i_pronargs = PQfnumber(res, "pronargs");
5805         i_proargtypes = PQfnumber(res, "proargtypes");
5806         i_prorettype = PQfnumber(res, "prorettype");
5807         i_proacl = PQfnumber(res, "proacl");
5808         i_rproacl = PQfnumber(res, "rproacl");
5809         i_initproacl = PQfnumber(res, "initproacl");
5810         i_initrproacl = PQfnumber(res, "initrproacl");
5811
5812         for (i = 0; i < ntups; i++)
5813         {
5814                 finfo[i].dobj.objType = DO_FUNC;
5815                 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5816                 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5817                 AssignDumpId(&finfo[i].dobj);
5818                 finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
5819                 finfo[i].dobj.namespace =
5820                         findNamespace(fout,
5821                                                   atooid(PQgetvalue(res, i, i_pronamespace)));
5822                 finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5823                 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
5824                 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
5825                 finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
5826                 finfo[i].rproacl = pg_strdup(PQgetvalue(res, i, i_rproacl));
5827                 finfo[i].initproacl = pg_strdup(PQgetvalue(res, i, i_initproacl));
5828                 finfo[i].initrproacl = pg_strdup(PQgetvalue(res, i, i_initrproacl));
5829                 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
5830                 if (finfo[i].nargs == 0)
5831                         finfo[i].argtypes = NULL;
5832                 else
5833                 {
5834                         finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
5835                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
5836                                                   finfo[i].argtypes, finfo[i].nargs);
5837                 }
5838
5839                 /* Decide whether we want to dump it */
5840                 selectDumpableObject(&(finfo[i].dobj), fout);
5841
5842                 /* Do not try to dump ACL if no ACL exists. */
5843                 if (PQgetisnull(res, i, i_proacl) && PQgetisnull(res, i, i_rproacl) &&
5844                         PQgetisnull(res, i, i_initproacl) &&
5845                         PQgetisnull(res, i, i_initrproacl))
5846                         finfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5847
5848                 if (strlen(finfo[i].rolname) == 0)
5849                         pg_log_warning("owner of function \"%s\" appears to be invalid",
5850                                           finfo[i].dobj.name);
5851         }
5852
5853         PQclear(res);
5854
5855         destroyPQExpBuffer(query);
5856
5857         return finfo;
5858 }
5859
5860 /*
5861  * getTables
5862  *        read all the tables (no indexes)
5863  * in the system catalogs return them in the TableInfo* structure
5864  *
5865  * numTables is set to the number of tables read in
5866  */
5867 TableInfo *
5868 getTables(Archive *fout, int *numTables)
5869 {
5870         DumpOptions *dopt = fout->dopt;
5871         PGresult   *res;
5872         int                     ntups;
5873         int                     i;
5874         PQExpBuffer query = createPQExpBuffer();
5875         TableInfo  *tblinfo;
5876         int                     i_reltableoid;
5877         int                     i_reloid;
5878         int                     i_relname;
5879         int                     i_relnamespace;
5880         int                     i_relkind;
5881         int                     i_relacl;
5882         int                     i_rrelacl;
5883         int                     i_initrelacl;
5884         int                     i_initrrelacl;
5885         int                     i_rolname;
5886         int                     i_relchecks;
5887         int                     i_relhastriggers;
5888         int                     i_relhasindex;
5889         int                     i_relhasrules;
5890         int                     i_relrowsec;
5891         int                     i_relforcerowsec;
5892         int                     i_relhasoids;
5893         int                     i_relfrozenxid;
5894         int                     i_relminmxid;
5895         int                     i_toastoid;
5896         int                     i_toastfrozenxid;
5897         int                     i_toastminmxid;
5898         int                     i_relpersistence;
5899         int                     i_relispopulated;
5900         int                     i_relreplident;
5901         int                     i_owning_tab;
5902         int                     i_owning_col;
5903         int                     i_reltablespace;
5904         int                     i_reloptions;
5905         int                     i_checkoption;
5906         int                     i_toastreloptions;
5907         int                     i_reloftype;
5908         int                     i_relpages;
5909         int                     i_is_identity_sequence;
5910         int                     i_changed_acl;
5911         int                     i_partkeydef;
5912         int                     i_ispartition;
5913         int                     i_partbound;
5914         int                     i_amname;
5915
5916         /*
5917          * Find all the tables and table-like objects.
5918          *
5919          * We include system catalogs, so that we can work if a user table is
5920          * defined to inherit from a system catalog (pretty weird, but...)
5921          *
5922          * We ignore relations that are not ordinary tables, sequences, views,
5923          * materialized views, composite types, or foreign tables.
5924          *
5925          * Composite-type table entries won't be dumped as such, but we have to
5926          * make a DumpableObject for them so that we can track dependencies of the
5927          * composite type (pg_depend entries for columns of the composite type
5928          * link to the pg_class entry not the pg_type entry).
5929          *
5930          * Note: in this phase we should collect only a minimal amount of
5931          * information about each table, basically just enough to decide if it is
5932          * interesting. We must fetch all tables in this phase because otherwise
5933          * we cannot correctly identify inherited columns, owned sequences, etc.
5934          *
5935          * We purposefully ignore toast OIDs for partitioned tables; the reason is
5936          * that versions 10 and 11 have them, but 12 does not, so emitting them
5937          * causes the upgrade to fail.
5938          */
5939
5940         if (fout->remoteVersion >= 90600)
5941         {
5942                 char       *partkeydef = "NULL";
5943                 char       *ispartition = "false";
5944                 char       *partbound = "NULL";
5945                 char       *relhasoids = "c.relhasoids";
5946
5947                 PQExpBuffer acl_subquery = createPQExpBuffer();
5948                 PQExpBuffer racl_subquery = createPQExpBuffer();
5949                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5950                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5951
5952                 PQExpBuffer attacl_subquery = createPQExpBuffer();
5953                 PQExpBuffer attracl_subquery = createPQExpBuffer();
5954                 PQExpBuffer attinitacl_subquery = createPQExpBuffer();
5955                 PQExpBuffer attinitracl_subquery = createPQExpBuffer();
5956
5957                 /*
5958                  * Collect the information about any partitioned tables, which were
5959                  * added in PG10.
5960                  */
5961
5962                 if (fout->remoteVersion >= 100000)
5963                 {
5964                         partkeydef = "pg_get_partkeydef(c.oid)";
5965                         ispartition = "c.relispartition";
5966                         partbound = "pg_get_expr(c.relpartbound, c.oid)";
5967                 }
5968
5969                 /* In PG12 upwards WITH OIDS does not exist anymore. */
5970                 if (fout->remoteVersion >= 120000)
5971                         relhasoids = "'f'::bool";
5972
5973                 /*
5974                  * Left join to pick up dependency info linking sequences to their
5975                  * owning column, if any (note this dependency is AUTO as of 8.2)
5976                  *
5977                  * Left join to detect if any privileges are still as-set-at-init, in
5978                  * which case we won't dump out ACL commands for those.
5979                  */
5980
5981                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5982                                                 initracl_subquery, "c.relacl", "c.relowner",
5983                                                 "CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
5984                                                 " THEN 's' ELSE 'r' END::\"char\"",
5985                                                 dopt->binary_upgrade);
5986
5987                 buildACLQueries(attacl_subquery, attracl_subquery, attinitacl_subquery,
5988                                                 attinitracl_subquery, "at.attacl", "c.relowner", "'c'",
5989                                                 dopt->binary_upgrade);
5990
5991                 appendPQExpBuffer(query,
5992                                                   "SELECT c.tableoid, c.oid, c.relname, "
5993                                                   "%s AS relacl, %s as rrelacl, "
5994                                                   "%s AS initrelacl, %s as initrrelacl, "
5995                                                   "c.relkind, c.relnamespace, "
5996                                                   "(%s c.relowner) AS rolname, "
5997                                                   "c.relchecks, c.relhastriggers, "
5998                                                   "c.relhasindex, c.relhasrules, %s AS relhasoids, "
5999                                                   "c.relrowsecurity, c.relforcerowsecurity, "
6000                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6001                                                   "tc.relfrozenxid AS tfrozenxid, "
6002                                                   "tc.relminmxid AS tminmxid, "
6003                                                   "c.relpersistence, c.relispopulated, "
6004                                                   "c.relreplident, c.relpages, am.amname, "
6005                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6006                                                   "d.refobjid AS owning_tab, "
6007                                                   "d.refobjsubid AS owning_col, "
6008                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6009                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6010                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6011                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6012                                                   "tc.reloptions AS toast_reloptions, "
6013                                                   "c.relkind = '%c' AND EXISTS (SELECT 1 FROM pg_depend WHERE classid = 'pg_class'::regclass AND objid = c.oid AND objsubid = 0 AND refclassid = 'pg_class'::regclass AND deptype = 'i') AS is_identity_sequence, "
6014                                                   "EXISTS (SELECT 1 FROM pg_attribute at LEFT JOIN pg_init_privs pip ON "
6015                                                   "(c.oid = pip.objoid "
6016                                                   "AND pip.classoid = 'pg_class'::regclass "
6017                                                   "AND pip.objsubid = at.attnum)"
6018                                                   "WHERE at.attrelid = c.oid AND ("
6019                                                   "%s IS NOT NULL "
6020                                                   "OR %s IS NOT NULL "
6021                                                   "OR %s IS NOT NULL "
6022                                                   "OR %s IS NOT NULL"
6023                                                   "))"
6024                                                   "AS changed_acl, "
6025                                                   "%s AS partkeydef, "
6026                                                   "%s AS ispartition, "
6027                                                   "%s AS partbound "
6028                                                   "FROM pg_class c "
6029                                                   "LEFT JOIN pg_depend d ON "
6030                                                   "(c.relkind = '%c' AND "
6031                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6032                                                   "d.objsubid = 0 AND "
6033                                                   "d.refclassid = c.tableoid AND d.deptype IN ('a', 'i')) "
6034                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid AND c.relkind <> '%c') "
6035                                                   "LEFT JOIN pg_am am ON (c.relam = am.oid) "
6036                                                   "LEFT JOIN pg_init_privs pip ON "
6037                                                   "(c.oid = pip.objoid "
6038                                                   "AND pip.classoid = 'pg_class'::regclass "
6039                                                   "AND pip.objsubid = 0) "
6040                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c', '%c') "
6041                                                   "ORDER BY c.oid",
6042                                                   acl_subquery->data,
6043                                                   racl_subquery->data,
6044                                                   initacl_subquery->data,
6045                                                   initracl_subquery->data,
6046                                                   username_subquery,
6047                                                   relhasoids,
6048                                                   RELKIND_SEQUENCE,
6049                                                   attacl_subquery->data,
6050                                                   attracl_subquery->data,
6051                                                   attinitacl_subquery->data,
6052                                                   attinitracl_subquery->data,
6053                                                   partkeydef,
6054                                                   ispartition,
6055                                                   partbound,
6056                                                   RELKIND_SEQUENCE,
6057                                                   RELKIND_PARTITIONED_TABLE,
6058                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6059                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6060                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
6061                                                   RELKIND_PARTITIONED_TABLE);
6062
6063                 destroyPQExpBuffer(acl_subquery);
6064                 destroyPQExpBuffer(racl_subquery);
6065                 destroyPQExpBuffer(initacl_subquery);
6066                 destroyPQExpBuffer(initracl_subquery);
6067
6068                 destroyPQExpBuffer(attacl_subquery);
6069                 destroyPQExpBuffer(attracl_subquery);
6070                 destroyPQExpBuffer(attinitacl_subquery);
6071                 destroyPQExpBuffer(attinitracl_subquery);
6072         }
6073         else if (fout->remoteVersion >= 90500)
6074         {
6075                 /*
6076                  * Left join to pick up dependency info linking sequences to their
6077                  * owning column, if any (note this dependency is AUTO as of 8.2)
6078                  */
6079                 appendPQExpBuffer(query,
6080                                                   "SELECT c.tableoid, c.oid, c.relname, "
6081                                                   "c.relacl, NULL as rrelacl, "
6082                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6083                                                   "c.relkind, "
6084                                                   "c.relnamespace, "
6085                                                   "(%s c.relowner) AS rolname, "
6086                                                   "c.relchecks, c.relhastriggers, "
6087                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6088                                                   "c.relrowsecurity, c.relforcerowsecurity, "
6089                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6090                                                   "tc.relfrozenxid AS tfrozenxid, "
6091                                                   "tc.relminmxid AS tminmxid, "
6092                                                   "c.relpersistence, c.relispopulated, "
6093                                                   "c.relreplident, c.relpages, "
6094                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6095                                                   "d.refobjid AS owning_tab, "
6096                                                   "d.refobjsubid AS owning_col, "
6097                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6098                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6099                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6100                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6101                                                   "tc.reloptions AS toast_reloptions, "
6102                                                   "NULL AS changed_acl, "
6103                                                   "NULL AS partkeydef, "
6104                                                   "false AS ispartition, "
6105                                                   "NULL AS partbound "
6106                                                   "FROM pg_class c "
6107                                                   "LEFT JOIN pg_depend d ON "
6108                                                   "(c.relkind = '%c' AND "
6109                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6110                                                   "d.objsubid = 0 AND "
6111                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6112                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6113                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6114                                                   "ORDER BY c.oid",
6115                                                   username_subquery,
6116                                                   RELKIND_SEQUENCE,
6117                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6118                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6119                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6120         }
6121         else if (fout->remoteVersion >= 90400)
6122         {
6123                 /*
6124                  * Left join to pick up dependency info linking sequences to their
6125                  * owning column, if any (note this dependency is AUTO as of 8.2)
6126                  */
6127                 appendPQExpBuffer(query,
6128                                                   "SELECT c.tableoid, c.oid, c.relname, "
6129                                                   "c.relacl, NULL as rrelacl, "
6130                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6131                                                   "c.relkind, "
6132                                                   "c.relnamespace, "
6133                                                   "(%s c.relowner) AS rolname, "
6134                                                   "c.relchecks, c.relhastriggers, "
6135                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6136                                                   "'f'::bool AS relrowsecurity, "
6137                                                   "'f'::bool AS relforcerowsecurity, "
6138                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6139                                                   "tc.relfrozenxid AS tfrozenxid, "
6140                                                   "tc.relminmxid AS tminmxid, "
6141                                                   "c.relpersistence, c.relispopulated, "
6142                                                   "c.relreplident, c.relpages, "
6143                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6144                                                   "d.refobjid AS owning_tab, "
6145                                                   "d.refobjsubid AS owning_col, "
6146                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6147                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6148                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6149                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6150                                                   "tc.reloptions AS toast_reloptions, "
6151                                                   "NULL AS changed_acl, "
6152                                                   "NULL AS partkeydef, "
6153                                                   "false AS ispartition, "
6154                                                   "NULL AS partbound "
6155                                                   "FROM pg_class c "
6156                                                   "LEFT JOIN pg_depend d ON "
6157                                                   "(c.relkind = '%c' AND "
6158                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6159                                                   "d.objsubid = 0 AND "
6160                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6161                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6162                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6163                                                   "ORDER BY c.oid",
6164                                                   username_subquery,
6165                                                   RELKIND_SEQUENCE,
6166                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6167                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6168                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6169         }
6170         else if (fout->remoteVersion >= 90300)
6171         {
6172                 /*
6173                  * Left join to pick up dependency info linking sequences to their
6174                  * owning column, if any (note this dependency is AUTO as of 8.2)
6175                  */
6176                 appendPQExpBuffer(query,
6177                                                   "SELECT c.tableoid, c.oid, c.relname, "
6178                                                   "c.relacl, NULL as rrelacl, "
6179                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6180                                                   "c.relkind, "
6181                                                   "c.relnamespace, "
6182                                                   "(%s c.relowner) AS rolname, "
6183                                                   "c.relchecks, c.relhastriggers, "
6184                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6185                                                   "'f'::bool AS relrowsecurity, "
6186                                                   "'f'::bool AS relforcerowsecurity, "
6187                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6188                                                   "tc.relfrozenxid AS tfrozenxid, "
6189                                                   "tc.relminmxid AS tminmxid, "
6190                                                   "c.relpersistence, c.relispopulated, "
6191                                                   "'d' AS relreplident, c.relpages, "
6192                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6193                                                   "d.refobjid AS owning_tab, "
6194                                                   "d.refobjsubid AS owning_col, "
6195                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6196                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6197                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6198                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6199                                                   "tc.reloptions AS toast_reloptions, "
6200                                                   "NULL AS changed_acl, "
6201                                                   "NULL AS partkeydef, "
6202                                                   "false AS ispartition, "
6203                                                   "NULL AS partbound "
6204                                                   "FROM pg_class c "
6205                                                   "LEFT JOIN pg_depend d ON "
6206                                                   "(c.relkind = '%c' AND "
6207                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6208                                                   "d.objsubid = 0 AND "
6209                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6210                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6211                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6212                                                   "ORDER BY c.oid",
6213                                                   username_subquery,
6214                                                   RELKIND_SEQUENCE,
6215                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6216                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6217                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6218         }
6219         else if (fout->remoteVersion >= 90100)
6220         {
6221                 /*
6222                  * Left join to pick up dependency info linking sequences to their
6223                  * owning column, if any (note this dependency is AUTO as of 8.2)
6224                  */
6225                 appendPQExpBuffer(query,
6226                                                   "SELECT c.tableoid, c.oid, c.relname, "
6227                                                   "c.relacl, NULL as rrelacl, "
6228                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6229                                                   "c.relkind, "
6230                                                   "c.relnamespace, "
6231                                                   "(%s c.relowner) AS rolname, "
6232                                                   "c.relchecks, c.relhastriggers, "
6233                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6234                                                   "'f'::bool AS relrowsecurity, "
6235                                                   "'f'::bool AS relforcerowsecurity, "
6236                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6237                                                   "tc.relfrozenxid AS tfrozenxid, "
6238                                                   "0 AS tminmxid, "
6239                                                   "c.relpersistence, 't' as relispopulated, "
6240                                                   "'d' AS relreplident, c.relpages, "
6241                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6242                                                   "d.refobjid AS owning_tab, "
6243                                                   "d.refobjsubid AS owning_col, "
6244                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6245                                                   "c.reloptions AS reloptions, "
6246                                                   "tc.reloptions AS toast_reloptions, "
6247                                                   "NULL AS changed_acl, "
6248                                                   "NULL AS partkeydef, "
6249                                                   "false AS ispartition, "
6250                                                   "NULL AS partbound "
6251                                                   "FROM pg_class c "
6252                                                   "LEFT JOIN pg_depend d ON "
6253                                                   "(c.relkind = '%c' AND "
6254                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6255                                                   "d.objsubid = 0 AND "
6256                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6257                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6258                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6259                                                   "ORDER BY c.oid",
6260                                                   username_subquery,
6261                                                   RELKIND_SEQUENCE,
6262                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6263                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6264                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6265         }
6266         else if (fout->remoteVersion >= 90000)
6267         {
6268                 /*
6269                  * Left join to pick up dependency info linking sequences to their
6270                  * owning column, if any (note this dependency is AUTO as of 8.2)
6271                  */
6272                 appendPQExpBuffer(query,
6273                                                   "SELECT c.tableoid, c.oid, c.relname, "
6274                                                   "c.relacl, NULL as rrelacl, "
6275                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6276                                                   "c.relkind, "
6277                                                   "c.relnamespace, "
6278                                                   "(%s c.relowner) AS rolname, "
6279                                                   "c.relchecks, c.relhastriggers, "
6280                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6281                                                   "'f'::bool AS relrowsecurity, "
6282                                                   "'f'::bool AS relforcerowsecurity, "
6283                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6284                                                   "tc.relfrozenxid AS tfrozenxid, "
6285                                                   "0 AS tminmxid, "
6286                                                   "'p' AS relpersistence, 't' as relispopulated, "
6287                                                   "'d' AS relreplident, c.relpages, "
6288                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6289                                                   "d.refobjid AS owning_tab, "
6290                                                   "d.refobjsubid AS owning_col, "
6291                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6292                                                   "c.reloptions AS reloptions, "
6293                                                   "tc.reloptions AS toast_reloptions, "
6294                                                   "NULL AS changed_acl, "
6295                                                   "NULL AS partkeydef, "
6296                                                   "false AS ispartition, "
6297                                                   "NULL AS partbound "
6298                                                   "FROM pg_class c "
6299                                                   "LEFT JOIN pg_depend d ON "
6300                                                   "(c.relkind = '%c' AND "
6301                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6302                                                   "d.objsubid = 0 AND "
6303                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6304                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6305                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6306                                                   "ORDER BY c.oid",
6307                                                   username_subquery,
6308                                                   RELKIND_SEQUENCE,
6309                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6310                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6311         }
6312         else if (fout->remoteVersion >= 80400)
6313         {
6314                 /*
6315                  * Left join to pick up dependency info linking sequences to their
6316                  * owning column, if any (note this dependency is AUTO as of 8.2)
6317                  */
6318                 appendPQExpBuffer(query,
6319                                                   "SELECT c.tableoid, c.oid, c.relname, "
6320                                                   "c.relacl, NULL as rrelacl, "
6321                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6322                                                   "c.relkind, "
6323                                                   "c.relnamespace, "
6324                                                   "(%s c.relowner) AS rolname, "
6325                                                   "c.relchecks, c.relhastriggers, "
6326                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6327                                                   "'f'::bool AS relrowsecurity, "
6328                                                   "'f'::bool AS relforcerowsecurity, "
6329                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6330                                                   "tc.relfrozenxid AS tfrozenxid, "
6331                                                   "0 AS tminmxid, "
6332                                                   "'p' AS relpersistence, 't' as relispopulated, "
6333                                                   "'d' AS relreplident, c.relpages, "
6334                                                   "NULL AS reloftype, "
6335                                                   "d.refobjid AS owning_tab, "
6336                                                   "d.refobjsubid AS owning_col, "
6337                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6338                                                   "c.reloptions AS reloptions, "
6339                                                   "tc.reloptions AS toast_reloptions, "
6340                                                   "NULL AS changed_acl, "
6341                                                   "NULL AS partkeydef, "
6342                                                   "false AS ispartition, "
6343                                                   "NULL AS partbound "
6344                                                   "FROM pg_class c "
6345                                                   "LEFT JOIN pg_depend d ON "
6346                                                   "(c.relkind = '%c' AND "
6347                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6348                                                   "d.objsubid = 0 AND "
6349                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6350                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6351                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6352                                                   "ORDER BY c.oid",
6353                                                   username_subquery,
6354                                                   RELKIND_SEQUENCE,
6355                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6356                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6357         }
6358         else if (fout->remoteVersion >= 80200)
6359         {
6360                 /*
6361                  * Left join to pick up dependency info linking sequences to their
6362                  * owning column, if any (note this dependency is AUTO as of 8.2)
6363                  */
6364                 appendPQExpBuffer(query,
6365                                                   "SELECT c.tableoid, c.oid, c.relname, "
6366                                                   "c.relacl, NULL as rrelacl, "
6367                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6368                                                   "c.relkind, "
6369                                                   "c.relnamespace, "
6370                                                   "(%s c.relowner) AS rolname, "
6371                                                   "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
6372                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6373                                                   "'f'::bool AS relrowsecurity, "
6374                                                   "'f'::bool AS relforcerowsecurity, "
6375                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6376                                                   "tc.relfrozenxid AS tfrozenxid, "
6377                                                   "0 AS tminmxid, "
6378                                                   "'p' AS relpersistence, 't' as relispopulated, "
6379                                                   "'d' AS relreplident, c.relpages, "
6380                                                   "NULL AS reloftype, "
6381                                                   "d.refobjid AS owning_tab, "
6382                                                   "d.refobjsubid AS owning_col, "
6383                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6384                                                   "c.reloptions AS reloptions, "
6385                                                   "NULL AS toast_reloptions, "
6386                                                   "NULL AS changed_acl, "
6387                                                   "NULL AS partkeydef, "
6388                                                   "false AS ispartition, "
6389                                                   "NULL AS partbound "
6390                                                   "FROM pg_class c "
6391                                                   "LEFT JOIN pg_depend d ON "
6392                                                   "(c.relkind = '%c' AND "
6393                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6394                                                   "d.objsubid = 0 AND "
6395                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6396                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6397                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6398                                                   "ORDER BY c.oid",
6399                                                   username_subquery,
6400                                                   RELKIND_SEQUENCE,
6401                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6402                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6403         }
6404         else
6405         {
6406                 /*
6407                  * Left join to pick up dependency info linking sequences to their
6408                  * owning column, if any
6409                  */
6410                 appendPQExpBuffer(query,
6411                                                   "SELECT c.tableoid, c.oid, relname, "
6412                                                   "relacl, NULL as rrelacl, "
6413                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6414                                                   "relkind, relnamespace, "
6415                                                   "(%s relowner) AS rolname, "
6416                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
6417                                                   "relhasindex, relhasrules, relhasoids, "
6418                                                   "'f'::bool AS relrowsecurity, "
6419                                                   "'f'::bool AS relforcerowsecurity, "
6420                                                   "0 AS relfrozenxid, 0 AS relminmxid,"
6421                                                   "0 AS toid, "
6422                                                   "0 AS tfrozenxid, 0 AS tminmxid,"
6423                                                   "'p' AS relpersistence, 't' as relispopulated, "
6424                                                   "'d' AS relreplident, relpages, "
6425                                                   "NULL AS reloftype, "
6426                                                   "d.refobjid AS owning_tab, "
6427                                                   "d.refobjsubid AS owning_col, "
6428                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6429                                                   "NULL AS reloptions, "
6430                                                   "NULL AS toast_reloptions, "
6431                                                   "NULL AS changed_acl, "
6432                                                   "NULL AS partkeydef, "
6433                                                   "false AS ispartition, "
6434                                                   "NULL AS partbound "
6435                                                   "FROM pg_class c "
6436                                                   "LEFT JOIN pg_depend d ON "
6437                                                   "(c.relkind = '%c' AND "
6438                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6439                                                   "d.objsubid = 0 AND "
6440                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
6441                                                   "WHERE relkind in ('%c', '%c', '%c', '%c') "
6442                                                   "ORDER BY c.oid",
6443                                                   username_subquery,
6444                                                   RELKIND_SEQUENCE,
6445                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6446                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6447         }
6448
6449         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6450
6451         ntups = PQntuples(res);
6452
6453         *numTables = ntups;
6454
6455         /*
6456          * Extract data from result and lock dumpable tables.  We do the locking
6457          * before anything else, to minimize the window wherein a table could
6458          * disappear under us.
6459          *
6460          * Note that we have to save info about all tables here, even when dumping
6461          * only one, because we don't yet know which tables might be inheritance
6462          * ancestors of the target table.
6463          */
6464         tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
6465
6466         i_reltableoid = PQfnumber(res, "tableoid");
6467         i_reloid = PQfnumber(res, "oid");
6468         i_relname = PQfnumber(res, "relname");
6469         i_relnamespace = PQfnumber(res, "relnamespace");
6470         i_relacl = PQfnumber(res, "relacl");
6471         i_rrelacl = PQfnumber(res, "rrelacl");
6472         i_initrelacl = PQfnumber(res, "initrelacl");
6473         i_initrrelacl = PQfnumber(res, "initrrelacl");
6474         i_relkind = PQfnumber(res, "relkind");
6475         i_rolname = PQfnumber(res, "rolname");
6476         i_relchecks = PQfnumber(res, "relchecks");
6477         i_relhastriggers = PQfnumber(res, "relhastriggers");
6478         i_relhasindex = PQfnumber(res, "relhasindex");
6479         i_relhasrules = PQfnumber(res, "relhasrules");
6480         i_relrowsec = PQfnumber(res, "relrowsecurity");
6481         i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
6482         i_relhasoids = PQfnumber(res, "relhasoids");
6483         i_relfrozenxid = PQfnumber(res, "relfrozenxid");
6484         i_relminmxid = PQfnumber(res, "relminmxid");
6485         i_toastoid = PQfnumber(res, "toid");
6486         i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
6487         i_toastminmxid = PQfnumber(res, "tminmxid");
6488         i_relpersistence = PQfnumber(res, "relpersistence");
6489         i_relispopulated = PQfnumber(res, "relispopulated");
6490         i_relreplident = PQfnumber(res, "relreplident");
6491         i_relpages = PQfnumber(res, "relpages");
6492         i_owning_tab = PQfnumber(res, "owning_tab");
6493         i_owning_col = PQfnumber(res, "owning_col");
6494         i_reltablespace = PQfnumber(res, "reltablespace");
6495         i_reloptions = PQfnumber(res, "reloptions");
6496         i_checkoption = PQfnumber(res, "checkoption");
6497         i_toastreloptions = PQfnumber(res, "toast_reloptions");
6498         i_reloftype = PQfnumber(res, "reloftype");
6499         i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
6500         i_changed_acl = PQfnumber(res, "changed_acl");
6501         i_partkeydef = PQfnumber(res, "partkeydef");
6502         i_ispartition = PQfnumber(res, "ispartition");
6503         i_partbound = PQfnumber(res, "partbound");
6504         i_amname = PQfnumber(res, "amname");
6505
6506         if (dopt->lockWaitTimeout)
6507         {
6508                 /*
6509                  * Arrange to fail instead of waiting forever for a table lock.
6510                  *
6511                  * NB: this coding assumes that the only queries issued within the
6512                  * following loop are LOCK TABLEs; else the timeout may be undesirably
6513                  * applied to other things too.
6514                  */
6515                 resetPQExpBuffer(query);
6516                 appendPQExpBufferStr(query, "SET statement_timeout = ");
6517                 appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
6518                 ExecuteSqlStatement(fout, query->data);
6519         }
6520
6521         for (i = 0; i < ntups; i++)
6522         {
6523                 tblinfo[i].dobj.objType = DO_TABLE;
6524                 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
6525                 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
6526                 AssignDumpId(&tblinfo[i].dobj);
6527                 tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
6528                 tblinfo[i].dobj.namespace =
6529                         findNamespace(fout,
6530                                                   atooid(PQgetvalue(res, i, i_relnamespace)));
6531                 tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6532                 tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
6533                 tblinfo[i].rrelacl = pg_strdup(PQgetvalue(res, i, i_rrelacl));
6534                 tblinfo[i].initrelacl = pg_strdup(PQgetvalue(res, i, i_initrelacl));
6535                 tblinfo[i].initrrelacl = pg_strdup(PQgetvalue(res, i, i_initrrelacl));
6536                 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
6537                 tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
6538                 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
6539                 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
6540                 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
6541                 tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
6542                 tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
6543                 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
6544                 tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
6545                 tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
6546                 tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
6547                 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
6548                 tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
6549                 tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
6550                 tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
6551                 tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
6552                 if (PQgetisnull(res, i, i_reloftype))
6553                         tblinfo[i].reloftype = NULL;
6554                 else
6555                         tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
6556                 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
6557                 if (PQgetisnull(res, i, i_owning_tab))
6558                 {
6559                         tblinfo[i].owning_tab = InvalidOid;
6560                         tblinfo[i].owning_col = 0;
6561                 }
6562                 else
6563                 {
6564                         tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
6565                         tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
6566                 }
6567                 tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
6568                 tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
6569                 if (i_checkoption == -1 || PQgetisnull(res, i, i_checkoption))
6570                         tblinfo[i].checkoption = NULL;
6571                 else
6572                         tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
6573                 tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
6574                 if (PQgetisnull(res, i, i_amname))
6575                         tblinfo[i].amname = NULL;
6576                 else
6577                         tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
6578
6579                 /* other fields were zeroed above */
6580
6581                 /*
6582                  * Decide whether we want to dump this table.
6583                  */
6584                 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
6585                         tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
6586                 else
6587                         selectDumpableTable(&tblinfo[i], fout);
6588
6589                 /*
6590                  * If the table-level and all column-level ACLs for this table are
6591                  * unchanged, then we don't need to worry about including the ACLs for
6592                  * this table.  If any column-level ACLs have been changed, the
6593                  * 'changed_acl' column from the query will indicate that.
6594                  *
6595                  * This can result in a significant performance improvement in cases
6596                  * where we are only looking to dump out the ACL (eg: pg_catalog).
6597                  */
6598                 if (PQgetisnull(res, i, i_relacl) && PQgetisnull(res, i, i_rrelacl) &&
6599                         PQgetisnull(res, i, i_initrelacl) &&
6600                         PQgetisnull(res, i, i_initrrelacl) &&
6601                         strcmp(PQgetvalue(res, i, i_changed_acl), "f") == 0)
6602                         tblinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
6603
6604                 tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
6605                 tblinfo[i].dummy_view = false;  /* might get set during sort */
6606                 tblinfo[i].postponed_def = false;       /* might get set during sort */
6607
6608                 tblinfo[i].is_identity_sequence = (i_is_identity_sequence >= 0 &&
6609                                                                                    strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
6610
6611                 /* Partition key string or NULL */
6612                 tblinfo[i].partkeydef = pg_strdup(PQgetvalue(res, i, i_partkeydef));
6613                 tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
6614                 tblinfo[i].partbound = pg_strdup(PQgetvalue(res, i, i_partbound));
6615
6616                 /*
6617                  * Read-lock target tables to make sure they aren't DROPPED or altered
6618                  * in schema before we get around to dumping them.
6619                  *
6620                  * Note that we don't explicitly lock parents of the target tables; we
6621                  * assume our lock on the child is enough to prevent schema
6622                  * alterations to parent tables.
6623                  *
6624                  * NOTE: it'd be kinda nice to lock other relations too, not only
6625                  * plain or partitioned tables, but the backend doesn't presently
6626                  * allow that.
6627                  *
6628                  * We only need to lock the table for certain components; see
6629                  * pg_dump.h
6630                  */
6631                 if (tblinfo[i].dobj.dump &&
6632                         (tblinfo[i].relkind == RELKIND_RELATION ||
6633                          tblinfo->relkind == RELKIND_PARTITIONED_TABLE) &&
6634                         (tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK))
6635                 {
6636                         resetPQExpBuffer(query);
6637                         appendPQExpBuffer(query,
6638                                                           "LOCK TABLE %s IN ACCESS SHARE MODE",
6639                                                           fmtQualifiedDumpable(&tblinfo[i]));
6640                         ExecuteSqlStatement(fout, query->data);
6641                 }
6642
6643                 /* Emit notice if join for owner failed */
6644                 if (strlen(tblinfo[i].rolname) == 0)
6645                         pg_log_warning("owner of table \"%s\" appears to be invalid",
6646                                           tblinfo[i].dobj.name);
6647         }
6648
6649         if (dopt->lockWaitTimeout)
6650         {
6651                 ExecuteSqlStatement(fout, "SET statement_timeout = 0");
6652         }
6653
6654         PQclear(res);
6655
6656         destroyPQExpBuffer(query);
6657
6658         return tblinfo;
6659 }
6660
6661 /*
6662  * getOwnedSeqs
6663  *        identify owned sequences and mark them as dumpable if owning table is
6664  *
6665  * We used to do this in getTables(), but it's better to do it after the
6666  * index used by findTableByOid() has been set up.
6667  */
6668 void
6669 getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
6670 {
6671         int                     i;
6672
6673         /*
6674          * Force sequences that are "owned" by table columns to be dumped whenever
6675          * their owning table is being dumped.
6676          */
6677         for (i = 0; i < numTables; i++)
6678         {
6679                 TableInfo  *seqinfo = &tblinfo[i];
6680                 TableInfo  *owning_tab;
6681
6682                 if (!OidIsValid(seqinfo->owning_tab))
6683                         continue;                       /* not an owned sequence */
6684
6685                 owning_tab = findTableByOid(seqinfo->owning_tab);
6686                 if (owning_tab == NULL)
6687                         fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
6688                                                   seqinfo->owning_tab, seqinfo->dobj.catId.oid);
6689
6690                 /*
6691                  * Only dump identity sequences if we're going to dump the table that
6692                  * it belongs to.
6693                  */
6694                 if (owning_tab->dobj.dump == DUMP_COMPONENT_NONE &&
6695                         seqinfo->is_identity_sequence)
6696                 {
6697                         seqinfo->dobj.dump = DUMP_COMPONENT_NONE;
6698                         continue;
6699                 }
6700
6701                 /*
6702                  * Otherwise we need to dump the components that are being dumped for
6703                  * the table and any components which the sequence is explicitly
6704                  * marked with.
6705                  *
6706                  * We can't simply use the set of components which are being dumped
6707                  * for the table as the table might be in an extension (and only the
6708                  * non-extension components, eg: ACLs if changed, security labels, and
6709                  * policies, are being dumped) while the sequence is not (and
6710                  * therefore the definition and other components should also be
6711                  * dumped).
6712                  *
6713                  * If the sequence is part of the extension then it should be properly
6714                  * marked by checkExtensionMembership() and this will be a no-op as
6715                  * the table will be equivalently marked.
6716                  */
6717                 seqinfo->dobj.dump = seqinfo->dobj.dump | owning_tab->dobj.dump;
6718
6719                 if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
6720                         seqinfo->interesting = true;
6721         }
6722 }
6723
6724 /*
6725  * getInherits
6726  *        read all the inheritance information
6727  * from the system catalogs return them in the InhInfo* structure
6728  *
6729  * numInherits is set to the number of pairs read in
6730  */
6731 InhInfo *
6732 getInherits(Archive *fout, int *numInherits)
6733 {
6734         PGresult   *res;
6735         int                     ntups;
6736         int                     i;
6737         PQExpBuffer query = createPQExpBuffer();
6738         InhInfo    *inhinfo;
6739
6740         int                     i_inhrelid;
6741         int                     i_inhparent;
6742
6743         /*
6744          * Find all the inheritance information, excluding implicit inheritance
6745          * via partitioning.  We handle that case using getPartitions(), because
6746          * we want more information about partitions than just the parent-child
6747          * relationship.
6748          */
6749         appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
6750
6751         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6752
6753         ntups = PQntuples(res);
6754
6755         *numInherits = ntups;
6756
6757         inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
6758
6759         i_inhrelid = PQfnumber(res, "inhrelid");
6760         i_inhparent = PQfnumber(res, "inhparent");
6761
6762         for (i = 0; i < ntups; i++)
6763         {
6764                 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
6765                 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
6766         }
6767
6768         PQclear(res);
6769
6770         destroyPQExpBuffer(query);
6771
6772         return inhinfo;
6773 }
6774
6775 /*
6776  * getIndexes
6777  *        get information about every index on a dumpable table
6778  *
6779  * Note: index data is not returned directly to the caller, but it
6780  * does get entered into the DumpableObject tables.
6781  */
6782 void
6783 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
6784 {
6785         int                     i,
6786                                 j;
6787         PQExpBuffer query = createPQExpBuffer();
6788         PGresult   *res;
6789         IndxInfo   *indxinfo;
6790         ConstraintInfo *constrinfo;
6791         int                     i_tableoid,
6792                                 i_oid,
6793                                 i_indexname,
6794                                 i_parentidx,
6795                                 i_indexdef,
6796                                 i_indnkeyatts,
6797                                 i_indnatts,
6798                                 i_indkey,
6799                                 i_indisclustered,
6800                                 i_indisreplident,
6801                                 i_contype,
6802                                 i_conname,
6803                                 i_condeferrable,
6804                                 i_condeferred,
6805                                 i_contableoid,
6806                                 i_conoid,
6807                                 i_condef,
6808                                 i_tablespace,
6809                                 i_indreloptions,
6810                                 i_indstatcols,
6811                                 i_indstatvals;
6812         int                     ntups;
6813
6814         for (i = 0; i < numTables; i++)
6815         {
6816                 TableInfo  *tbinfo = &tblinfo[i];
6817
6818                 if (!tbinfo->hasindex)
6819                         continue;
6820
6821                 /*
6822                  * Ignore indexes of tables whose definitions are not to be dumped.
6823                  *
6824                  * We also need indexes on partitioned tables which have partitions to
6825                  * be dumped, in order to dump the indexes on the partitions.
6826                  */
6827                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION) &&
6828                         !tbinfo->interesting)
6829                         continue;
6830
6831                 pg_log_info("reading indexes for table \"%s.%s\"",
6832                                         tbinfo->dobj.namespace->dobj.name,
6833                                         tbinfo->dobj.name);
6834
6835                 /*
6836                  * The point of the messy-looking outer join is to find a constraint
6837                  * that is related by an internal dependency link to the index. If we
6838                  * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
6839                  * assume an index won't have more than one internal dependency.
6840                  *
6841                  * As of 9.0 we don't need to look at pg_depend but can check for a
6842                  * match to pg_constraint.conindid.  The check on conrelid is
6843                  * redundant but useful because that column is indexed while conindid
6844                  * is not.
6845                  */
6846                 resetPQExpBuffer(query);
6847                 if (fout->remoteVersion >= 110000)
6848                 {
6849                         appendPQExpBuffer(query,
6850                                                           "SELECT t.tableoid, t.oid, "
6851                                                           "t.relname AS indexname, "
6852                                                           "inh.inhparent AS parentidx, "
6853                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6854                                                           "i.indnkeyatts AS indnkeyatts, "
6855                                                           "i.indnatts AS indnatts, "
6856                                                           "i.indkey, i.indisclustered, "
6857                                                           "i.indisreplident, "
6858                                                           "c.contype, c.conname, "
6859                                                           "c.condeferrable, c.condeferred, "
6860                                                           "c.tableoid AS contableoid, "
6861                                                           "c.oid AS conoid, "
6862                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6863                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6864                                                           "t.reloptions AS indreloptions, "
6865                                                           "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
6866                                                           "  FROM pg_catalog.pg_attribute "
6867                                                           "  WHERE attrelid = i.indexrelid AND "
6868                                                           "    attstattarget >= 0) AS indstatcols,"
6869                                                           "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
6870                                                           "  FROM pg_catalog.pg_attribute "
6871                                                           "  WHERE attrelid = i.indexrelid AND "
6872                                                           "    attstattarget >= 0) AS indstatvals "
6873                                                           "FROM pg_catalog.pg_index i "
6874                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6875                                                           "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
6876                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6877                                                           "ON (i.indrelid = c.conrelid AND "
6878                                                           "i.indexrelid = c.conindid AND "
6879                                                           "c.contype IN ('p','u','x')) "
6880                                                           "LEFT JOIN pg_catalog.pg_inherits inh "
6881                                                           "ON (inh.inhrelid = indexrelid) "
6882                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6883                                                           "AND (i.indisvalid OR t2.relkind = 'p') "
6884                                                           "AND i.indisready "
6885                                                           "ORDER BY indexname",
6886                                                           tbinfo->dobj.catId.oid);
6887                 }
6888                 else if (fout->remoteVersion >= 90400)
6889                 {
6890                         /*
6891                          * the test on indisready is necessary in 9.2, and harmless in
6892                          * earlier/later versions
6893                          */
6894                         appendPQExpBuffer(query,
6895                                                           "SELECT t.tableoid, t.oid, "
6896                                                           "t.relname AS indexname, "
6897                                                           "0 AS parentidx, "
6898                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6899                                                           "i.indnatts AS indnkeyatts, "
6900                                                           "i.indnatts AS indnatts, "
6901                                                           "i.indkey, i.indisclustered, "
6902                                                           "i.indisreplident, "
6903                                                           "c.contype, c.conname, "
6904                                                           "c.condeferrable, c.condeferred, "
6905                                                           "c.tableoid AS contableoid, "
6906                                                           "c.oid AS conoid, "
6907                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6908                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6909                                                           "t.reloptions AS indreloptions, "
6910                                                           "'' AS indstatcols, "
6911                                                           "'' AS indstatvals "
6912                                                           "FROM pg_catalog.pg_index i "
6913                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6914                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6915                                                           "ON (i.indrelid = c.conrelid AND "
6916                                                           "i.indexrelid = c.conindid AND "
6917                                                           "c.contype IN ('p','u','x')) "
6918                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6919                                                           "AND i.indisvalid AND i.indisready "
6920                                                           "ORDER BY indexname",
6921                                                           tbinfo->dobj.catId.oid);
6922                 }
6923                 else if (fout->remoteVersion >= 90000)
6924                 {
6925                         /*
6926                          * the test on indisready is necessary in 9.2, and harmless in
6927                          * earlier/later versions
6928                          */
6929                         appendPQExpBuffer(query,
6930                                                           "SELECT t.tableoid, t.oid, "
6931                                                           "t.relname AS indexname, "
6932                                                           "0 AS parentidx, "
6933                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6934                                                           "i.indnatts AS indnkeyatts, "
6935                                                           "i.indnatts AS indnatts, "
6936                                                           "i.indkey, i.indisclustered, "
6937                                                           "false AS indisreplident, "
6938                                                           "c.contype, c.conname, "
6939                                                           "c.condeferrable, c.condeferred, "
6940                                                           "c.tableoid AS contableoid, "
6941                                                           "c.oid AS conoid, "
6942                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6943                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6944                                                           "t.reloptions AS indreloptions, "
6945                                                           "'' AS indstatcols, "
6946                                                           "'' AS indstatvals "
6947                                                           "FROM pg_catalog.pg_index i "
6948                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6949                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6950                                                           "ON (i.indrelid = c.conrelid AND "
6951                                                           "i.indexrelid = c.conindid AND "
6952                                                           "c.contype IN ('p','u','x')) "
6953                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6954                                                           "AND i.indisvalid AND i.indisready "
6955                                                           "ORDER BY indexname",
6956                                                           tbinfo->dobj.catId.oid);
6957                 }
6958                 else if (fout->remoteVersion >= 80200)
6959                 {
6960                         appendPQExpBuffer(query,
6961                                                           "SELECT t.tableoid, t.oid, "
6962                                                           "t.relname AS indexname, "
6963                                                           "0 AS parentidx, "
6964                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6965                                                           "i.indnatts AS indnkeyatts, "
6966                                                           "i.indnatts AS indnatts, "
6967                                                           "i.indkey, i.indisclustered, "
6968                                                           "false AS indisreplident, "
6969                                                           "c.contype, c.conname, "
6970                                                           "c.condeferrable, c.condeferred, "
6971                                                           "c.tableoid AS contableoid, "
6972                                                           "c.oid AS conoid, "
6973                                                           "null AS condef, "
6974                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6975                                                           "t.reloptions AS indreloptions, "
6976                                                           "'' AS indstatcols, "
6977                                                           "'' AS indstatvals "
6978                                                           "FROM pg_catalog.pg_index i "
6979                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6980                                                           "LEFT JOIN pg_catalog.pg_depend d "
6981                                                           "ON (d.classid = t.tableoid "
6982                                                           "AND d.objid = t.oid "
6983                                                           "AND d.deptype = 'i') "
6984                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6985                                                           "ON (d.refclassid = c.tableoid "
6986                                                           "AND d.refobjid = c.oid) "
6987                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6988                                                           "AND i.indisvalid "
6989                                                           "ORDER BY indexname",
6990                                                           tbinfo->dobj.catId.oid);
6991                 }
6992                 else
6993                 {
6994                         appendPQExpBuffer(query,
6995                                                           "SELECT t.tableoid, t.oid, "
6996                                                           "t.relname AS indexname, "
6997                                                           "0 AS parentidx, "
6998                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6999                                                           "t.relnatts AS indnkeyatts, "
7000                                                           "t.relnatts AS indnatts, "
7001                                                           "i.indkey, i.indisclustered, "
7002                                                           "false AS indisreplident, "
7003                                                           "c.contype, c.conname, "
7004                                                           "c.condeferrable, c.condeferred, "
7005                                                           "c.tableoid AS contableoid, "
7006                                                           "c.oid AS conoid, "
7007                                                           "null AS condef, "
7008                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
7009                                                           "null AS indreloptions, "
7010                                                           "'' AS indstatcols, "
7011                                                           "'' AS indstatvals "
7012                                                           "FROM pg_catalog.pg_index i "
7013                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
7014                                                           "LEFT JOIN pg_catalog.pg_depend d "
7015                                                           "ON (d.classid = t.tableoid "
7016                                                           "AND d.objid = t.oid "
7017                                                           "AND d.deptype = 'i') "
7018                                                           "LEFT JOIN pg_catalog.pg_constraint c "
7019                                                           "ON (d.refclassid = c.tableoid "
7020                                                           "AND d.refobjid = c.oid) "
7021                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
7022                                                           "ORDER BY indexname",
7023                                                           tbinfo->dobj.catId.oid);
7024                 }
7025
7026                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7027
7028                 ntups = PQntuples(res);
7029
7030                 i_tableoid = PQfnumber(res, "tableoid");
7031                 i_oid = PQfnumber(res, "oid");
7032                 i_indexname = PQfnumber(res, "indexname");
7033                 i_parentidx = PQfnumber(res, "parentidx");
7034                 i_indexdef = PQfnumber(res, "indexdef");
7035                 i_indnkeyatts = PQfnumber(res, "indnkeyatts");
7036                 i_indnatts = PQfnumber(res, "indnatts");
7037                 i_indkey = PQfnumber(res, "indkey");
7038                 i_indisclustered = PQfnumber(res, "indisclustered");
7039                 i_indisreplident = PQfnumber(res, "indisreplident");
7040                 i_contype = PQfnumber(res, "contype");
7041                 i_conname = PQfnumber(res, "conname");
7042                 i_condeferrable = PQfnumber(res, "condeferrable");
7043                 i_condeferred = PQfnumber(res, "condeferred");
7044                 i_contableoid = PQfnumber(res, "contableoid");
7045                 i_conoid = PQfnumber(res, "conoid");
7046                 i_condef = PQfnumber(res, "condef");
7047                 i_tablespace = PQfnumber(res, "tablespace");
7048                 i_indreloptions = PQfnumber(res, "indreloptions");
7049                 i_indstatcols = PQfnumber(res, "indstatcols");
7050                 i_indstatvals = PQfnumber(res, "indstatvals");
7051
7052                 tbinfo->indexes = indxinfo =
7053                         (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
7054                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7055                 tbinfo->numIndexes = ntups;
7056
7057                 for (j = 0; j < ntups; j++)
7058                 {
7059                         char            contype;
7060
7061                         indxinfo[j].dobj.objType = DO_INDEX;
7062                         indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
7063                         indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7064                         AssignDumpId(&indxinfo[j].dobj);
7065                         indxinfo[j].dobj.dump = tbinfo->dobj.dump;
7066                         indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
7067                         indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7068                         indxinfo[j].indextable = tbinfo;
7069                         indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
7070                         indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
7071                         indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
7072                         indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
7073                         indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
7074                         indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
7075                         indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
7076                         indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
7077                         parseOidArray(PQgetvalue(res, j, i_indkey),
7078                                                   indxinfo[j].indkeys, indxinfo[j].indnattrs);
7079                         indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
7080                         indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
7081                         indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
7082                         contype = *(PQgetvalue(res, j, i_contype));
7083
7084                         if (contype == 'p' || contype == 'u' || contype == 'x')
7085                         {
7086                                 /*
7087                                  * If we found a constraint matching the index, create an
7088                                  * entry for it.
7089                                  */
7090                                 constrinfo[j].dobj.objType = DO_CONSTRAINT;
7091                                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7092                                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7093                                 AssignDumpId(&constrinfo[j].dobj);
7094                                 constrinfo[j].dobj.dump = tbinfo->dobj.dump;
7095                                 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7096                                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7097                                 constrinfo[j].contable = tbinfo;
7098                                 constrinfo[j].condomain = NULL;
7099                                 constrinfo[j].contype = contype;
7100                                 if (contype == 'x')
7101                                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
7102                                 else
7103                                         constrinfo[j].condef = NULL;
7104                                 constrinfo[j].confrelid = InvalidOid;
7105                                 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
7106                                 constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
7107                                 constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
7108                                 constrinfo[j].conislocal = true;
7109                                 constrinfo[j].separate = true;
7110
7111                                 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
7112                         }
7113                         else
7114                         {
7115                                 /* Plain secondary index */
7116                                 indxinfo[j].indexconstraint = 0;
7117                         }
7118                 }
7119
7120                 PQclear(res);
7121         }
7122
7123         destroyPQExpBuffer(query);
7124 }
7125
7126 /*
7127  * getExtendedStatistics
7128  *        get information about extended-statistics objects.
7129  *
7130  * Note: extended statistics data is not returned directly to the caller, but
7131  * it does get entered into the DumpableObject tables.
7132  */
7133 void
7134 getExtendedStatistics(Archive *fout)
7135 {
7136         PQExpBuffer query;
7137         PGresult   *res;
7138         StatsExtInfo *statsextinfo;
7139         int                     ntups;
7140         int                     i_tableoid;
7141         int                     i_oid;
7142         int                     i_stxname;
7143         int                     i_stxnamespace;
7144         int                     i_rolname;
7145         int                     i;
7146
7147         /* Extended statistics were new in v10 */
7148         if (fout->remoteVersion < 100000)
7149                 return;
7150
7151         query = createPQExpBuffer();
7152
7153         appendPQExpBuffer(query, "SELECT tableoid, oid, stxname, "
7154                                           "stxnamespace, (%s stxowner) AS rolname "
7155                                           "FROM pg_catalog.pg_statistic_ext",
7156                                           username_subquery);
7157
7158         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7159
7160         ntups = PQntuples(res);
7161
7162         i_tableoid = PQfnumber(res, "tableoid");
7163         i_oid = PQfnumber(res, "oid");
7164         i_stxname = PQfnumber(res, "stxname");
7165         i_stxnamespace = PQfnumber(res, "stxnamespace");
7166         i_rolname = PQfnumber(res, "rolname");
7167
7168         statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
7169
7170         for (i = 0; i < ntups; i++)
7171         {
7172                 statsextinfo[i].dobj.objType = DO_STATSEXT;
7173                 statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7174                 statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7175                 AssignDumpId(&statsextinfo[i].dobj);
7176                 statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
7177                 statsextinfo[i].dobj.namespace =
7178                         findNamespace(fout,
7179                                                   atooid(PQgetvalue(res, i, i_stxnamespace)));
7180                 statsextinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7181
7182                 /* Decide whether we want to dump it */
7183                 selectDumpableObject(&(statsextinfo[i].dobj), fout);
7184
7185                 /* Stats objects do not currently have ACLs. */
7186                 statsextinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7187         }
7188
7189         PQclear(res);
7190         destroyPQExpBuffer(query);
7191 }
7192
7193 /*
7194  * getConstraints
7195  *
7196  * Get info about constraints on dumpable tables.
7197  *
7198  * Currently handles foreign keys only.
7199  * Unique and primary key constraints are handled with indexes,
7200  * while check constraints are processed in getTableAttrs().
7201  */
7202 void
7203 getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
7204 {
7205         int                     i,
7206                                 j;
7207         ConstraintInfo *constrinfo;
7208         PQExpBuffer query;
7209         PGresult   *res;
7210         int                     i_contableoid,
7211                                 i_conoid,
7212                                 i_conname,
7213                                 i_confrelid,
7214                                 i_condef;
7215         int                     ntups;
7216
7217         query = createPQExpBuffer();
7218
7219         for (i = 0; i < numTables; i++)
7220         {
7221                 TableInfo  *tbinfo = &tblinfo[i];
7222
7223                 /*
7224                  * For partitioned tables, foreign keys have no triggers so they must
7225                  * be included anyway in case some foreign keys are defined.
7226                  */
7227                 if ((!tbinfo->hastriggers &&
7228                          tbinfo->relkind != RELKIND_PARTITIONED_TABLE) ||
7229                         !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7230                         continue;
7231
7232                 pg_log_info("reading foreign key constraints for table \"%s.%s\"",
7233                                         tbinfo->dobj.namespace->dobj.name,
7234                                         tbinfo->dobj.name);
7235
7236                 resetPQExpBuffer(query);
7237                 if (fout->remoteVersion >= 110000)
7238                         appendPQExpBuffer(query,
7239                                                           "SELECT tableoid, oid, conname, confrelid, "
7240                                                           "pg_catalog.pg_get_constraintdef(oid) AS condef "
7241                                                           "FROM pg_catalog.pg_constraint "
7242                                                           "WHERE conrelid = '%u'::pg_catalog.oid "
7243                                                           "AND conparentid = 0 "
7244                                                           "AND contype = 'f'",
7245                                                           tbinfo->dobj.catId.oid);
7246                 else
7247                         appendPQExpBuffer(query,
7248                                                           "SELECT tableoid, oid, conname, confrelid, "
7249                                                           "pg_catalog.pg_get_constraintdef(oid) AS condef "
7250                                                           "FROM pg_catalog.pg_constraint "
7251                                                           "WHERE conrelid = '%u'::pg_catalog.oid "
7252                                                           "AND contype = 'f'",
7253                                                           tbinfo->dobj.catId.oid);
7254                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7255
7256                 ntups = PQntuples(res);
7257
7258                 i_contableoid = PQfnumber(res, "tableoid");
7259                 i_conoid = PQfnumber(res, "oid");
7260                 i_conname = PQfnumber(res, "conname");
7261                 i_confrelid = PQfnumber(res, "confrelid");
7262                 i_condef = PQfnumber(res, "condef");
7263
7264                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7265
7266                 for (j = 0; j < ntups; j++)
7267                 {
7268                         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
7269                         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7270                         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7271                         AssignDumpId(&constrinfo[j].dobj);
7272                         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7273                         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7274                         constrinfo[j].contable = tbinfo;
7275                         constrinfo[j].condomain = NULL;
7276                         constrinfo[j].contype = 'f';
7277                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
7278                         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
7279                         constrinfo[j].conindex = 0;
7280                         constrinfo[j].condeferrable = false;
7281                         constrinfo[j].condeferred = false;
7282                         constrinfo[j].conislocal = true;
7283                         constrinfo[j].separate = true;
7284                 }
7285
7286                 PQclear(res);
7287         }
7288
7289         destroyPQExpBuffer(query);
7290 }
7291
7292 /*
7293  * getDomainConstraints
7294  *
7295  * Get info about constraints on a domain.
7296  */
7297 static void
7298 getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
7299 {
7300         int                     i;
7301         ConstraintInfo *constrinfo;
7302         PQExpBuffer query;
7303         PGresult   *res;
7304         int                     i_tableoid,
7305                                 i_oid,
7306                                 i_conname,
7307                                 i_consrc;
7308         int                     ntups;
7309
7310         query = createPQExpBuffer();
7311
7312         if (fout->remoteVersion >= 90100)
7313                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
7314                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7315                                                   "convalidated "
7316                                                   "FROM pg_catalog.pg_constraint "
7317                                                   "WHERE contypid = '%u'::pg_catalog.oid "
7318                                                   "ORDER BY conname",
7319                                                   tyinfo->dobj.catId.oid);
7320
7321         else
7322                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
7323                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7324                                                   "true as convalidated "
7325                                                   "FROM pg_catalog.pg_constraint "
7326                                                   "WHERE contypid = '%u'::pg_catalog.oid "
7327                                                   "ORDER BY conname",
7328                                                   tyinfo->dobj.catId.oid);
7329
7330         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7331
7332         ntups = PQntuples(res);
7333
7334         i_tableoid = PQfnumber(res, "tableoid");
7335         i_oid = PQfnumber(res, "oid");
7336         i_conname = PQfnumber(res, "conname");
7337         i_consrc = PQfnumber(res, "consrc");
7338
7339         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7340
7341         tyinfo->nDomChecks = ntups;
7342         tyinfo->domChecks = constrinfo;
7343
7344         for (i = 0; i < ntups; i++)
7345         {
7346                 bool            validated = PQgetvalue(res, i, 4)[0] == 't';
7347
7348                 constrinfo[i].dobj.objType = DO_CONSTRAINT;
7349                 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7350                 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7351                 AssignDumpId(&constrinfo[i].dobj);
7352                 constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
7353                 constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
7354                 constrinfo[i].contable = NULL;
7355                 constrinfo[i].condomain = tyinfo;
7356                 constrinfo[i].contype = 'c';
7357                 constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
7358                 constrinfo[i].confrelid = InvalidOid;
7359                 constrinfo[i].conindex = 0;
7360                 constrinfo[i].condeferrable = false;
7361                 constrinfo[i].condeferred = false;
7362                 constrinfo[i].conislocal = true;
7363
7364                 constrinfo[i].separate = !validated;
7365
7366                 /*
7367                  * Make the domain depend on the constraint, ensuring it won't be
7368                  * output till any constraint dependencies are OK.  If the constraint
7369                  * has not been validated, it's going to be dumped after the domain
7370                  * anyway, so this doesn't matter.
7371                  */
7372                 if (validated)
7373                         addObjectDependency(&tyinfo->dobj,
7374                                                                 constrinfo[i].dobj.dumpId);
7375         }
7376
7377         PQclear(res);
7378
7379         destroyPQExpBuffer(query);
7380 }
7381
7382 /*
7383  * getRules
7384  *        get basic information about every rule in the system
7385  *
7386  * numRules is set to the number of rules read in
7387  */
7388 RuleInfo *
7389 getRules(Archive *fout, int *numRules)
7390 {
7391         PGresult   *res;
7392         int                     ntups;
7393         int                     i;
7394         PQExpBuffer query = createPQExpBuffer();
7395         RuleInfo   *ruleinfo;
7396         int                     i_tableoid;
7397         int                     i_oid;
7398         int                     i_rulename;
7399         int                     i_ruletable;
7400         int                     i_ev_type;
7401         int                     i_is_instead;
7402         int                     i_ev_enabled;
7403
7404         if (fout->remoteVersion >= 80300)
7405         {
7406                 appendPQExpBufferStr(query, "SELECT "
7407                                                          "tableoid, oid, rulename, "
7408                                                          "ev_class AS ruletable, ev_type, is_instead, "
7409                                                          "ev_enabled "
7410                                                          "FROM pg_rewrite "
7411                                                          "ORDER BY oid");
7412         }
7413         else
7414         {
7415                 appendPQExpBufferStr(query, "SELECT "
7416                                                          "tableoid, oid, rulename, "
7417                                                          "ev_class AS ruletable, ev_type, is_instead, "
7418                                                          "'O'::char AS ev_enabled "
7419                                                          "FROM pg_rewrite "
7420                                                          "ORDER BY oid");
7421         }
7422
7423         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7424
7425         ntups = PQntuples(res);
7426
7427         *numRules = ntups;
7428
7429         ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
7430
7431         i_tableoid = PQfnumber(res, "tableoid");
7432         i_oid = PQfnumber(res, "oid");
7433         i_rulename = PQfnumber(res, "rulename");
7434         i_ruletable = PQfnumber(res, "ruletable");
7435         i_ev_type = PQfnumber(res, "ev_type");
7436         i_is_instead = PQfnumber(res, "is_instead");
7437         i_ev_enabled = PQfnumber(res, "ev_enabled");
7438
7439         for (i = 0; i < ntups; i++)
7440         {
7441                 Oid                     ruletableoid;
7442
7443                 ruleinfo[i].dobj.objType = DO_RULE;
7444                 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7445                 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7446                 AssignDumpId(&ruleinfo[i].dobj);
7447                 ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
7448                 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
7449                 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
7450                 if (ruleinfo[i].ruletable == NULL)
7451                         fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
7452                                                   ruletableoid, ruleinfo[i].dobj.catId.oid);
7453                 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
7454                 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
7455                 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
7456                 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
7457                 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
7458                 if (ruleinfo[i].ruletable)
7459                 {
7460                         /*
7461                          * If the table is a view or materialized view, force its ON
7462                          * SELECT rule to be sorted before the view itself --- this
7463                          * ensures that any dependencies for the rule affect the table's
7464                          * positioning. Other rules are forced to appear after their
7465                          * table.
7466                          */
7467                         if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
7468                                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
7469                                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
7470                         {
7471                                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
7472                                                                         ruleinfo[i].dobj.dumpId);
7473                                 /* We'll merge the rule into CREATE VIEW, if possible */
7474                                 ruleinfo[i].separate = false;
7475                         }
7476                         else
7477                         {
7478                                 addObjectDependency(&ruleinfo[i].dobj,
7479                                                                         ruleinfo[i].ruletable->dobj.dumpId);
7480                                 ruleinfo[i].separate = true;
7481                         }
7482                 }
7483                 else
7484                         ruleinfo[i].separate = true;
7485         }
7486
7487         PQclear(res);
7488
7489         destroyPQExpBuffer(query);
7490
7491         return ruleinfo;
7492 }
7493
7494 /*
7495  * getTriggers
7496  *        get information about every trigger on a dumpable table
7497  *
7498  * Note: trigger data is not returned directly to the caller, but it
7499  * does get entered into the DumpableObject tables.
7500  */
7501 void
7502 getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
7503 {
7504         int                     i,
7505                                 j;
7506         PQExpBuffer query = createPQExpBuffer();
7507         PGresult   *res;
7508         TriggerInfo *tginfo;
7509         int                     i_tableoid,
7510                                 i_oid,
7511                                 i_tgname,
7512                                 i_tgfname,
7513                                 i_tgtype,
7514                                 i_tgnargs,
7515                                 i_tgargs,
7516                                 i_tgisconstraint,
7517                                 i_tgconstrname,
7518                                 i_tgconstrrelid,
7519                                 i_tgconstrrelname,
7520                                 i_tgenabled,
7521                                 i_tgdeferrable,
7522                                 i_tginitdeferred,
7523                                 i_tgdef;
7524         int                     ntups;
7525
7526         for (i = 0; i < numTables; i++)
7527         {
7528                 TableInfo  *tbinfo = &tblinfo[i];
7529
7530                 if (!tbinfo->hastriggers ||
7531                         !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7532                         continue;
7533
7534                 pg_log_info("reading triggers for table \"%s.%s\"",
7535                                         tbinfo->dobj.namespace->dobj.name,
7536                                         tbinfo->dobj.name);
7537
7538                 resetPQExpBuffer(query);
7539                 if (fout->remoteVersion >= 90000)
7540                 {
7541                         /*
7542                          * NB: think not to use pretty=true in pg_get_triggerdef.  It
7543                          * could result in non-forward-compatible dumps of WHEN clauses
7544                          * due to under-parenthesization.
7545                          */
7546                         appendPQExpBuffer(query,
7547                                                           "SELECT tgname, "
7548                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7549                                                           "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
7550                                                           "tgenabled, tableoid, oid "
7551                                                           "FROM pg_catalog.pg_trigger t "
7552                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7553                                                           "AND NOT tgisinternal",
7554                                                           tbinfo->dobj.catId.oid);
7555                 }
7556                 else if (fout->remoteVersion >= 80300)
7557                 {
7558                         /*
7559                          * We ignore triggers that are tied to a foreign-key constraint
7560                          */
7561                         appendPQExpBuffer(query,
7562                                                           "SELECT tgname, "
7563                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7564                                                           "tgtype, tgnargs, tgargs, tgenabled, "
7565                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
7566                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
7567                                                           "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
7568                                                           "FROM pg_catalog.pg_trigger t "
7569                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7570                                                           "AND tgconstraint = 0",
7571                                                           tbinfo->dobj.catId.oid);
7572                 }
7573                 else
7574                 {
7575                         /*
7576                          * We ignore triggers that are tied to a foreign-key constraint,
7577                          * but in these versions we have to grovel through pg_constraint
7578                          * to find out
7579                          */
7580                         appendPQExpBuffer(query,
7581                                                           "SELECT tgname, "
7582                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7583                                                           "tgtype, tgnargs, tgargs, tgenabled, "
7584                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
7585                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
7586                                                           "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
7587                                                           "FROM pg_catalog.pg_trigger t "
7588                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7589                                                           "AND (NOT tgisconstraint "
7590                                                           " OR NOT EXISTS"
7591                                                           "  (SELECT 1 FROM pg_catalog.pg_depend d "
7592                                                           "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
7593                                                           "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
7594                                                           tbinfo->dobj.catId.oid);
7595                 }
7596
7597                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7598
7599                 ntups = PQntuples(res);
7600
7601                 i_tableoid = PQfnumber(res, "tableoid");
7602                 i_oid = PQfnumber(res, "oid");
7603                 i_tgname = PQfnumber(res, "tgname");
7604                 i_tgfname = PQfnumber(res, "tgfname");
7605                 i_tgtype = PQfnumber(res, "tgtype");
7606                 i_tgnargs = PQfnumber(res, "tgnargs");
7607                 i_tgargs = PQfnumber(res, "tgargs");
7608                 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
7609                 i_tgconstrname = PQfnumber(res, "tgconstrname");
7610                 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
7611                 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
7612                 i_tgenabled = PQfnumber(res, "tgenabled");
7613                 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
7614                 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
7615                 i_tgdef = PQfnumber(res, "tgdef");
7616
7617                 tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
7618
7619                 tbinfo->numTriggers = ntups;
7620                 tbinfo->triggers = tginfo;
7621
7622                 for (j = 0; j < ntups; j++)
7623                 {
7624                         tginfo[j].dobj.objType = DO_TRIGGER;
7625                         tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
7626                         tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7627                         AssignDumpId(&tginfo[j].dobj);
7628                         tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
7629                         tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
7630                         tginfo[j].tgtable = tbinfo;
7631                         tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
7632                         if (i_tgdef >= 0)
7633                         {
7634                                 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
7635
7636                                 /* remaining fields are not valid if we have tgdef */
7637                                 tginfo[j].tgfname = NULL;
7638                                 tginfo[j].tgtype = 0;
7639                                 tginfo[j].tgnargs = 0;
7640                                 tginfo[j].tgargs = NULL;
7641                                 tginfo[j].tgisconstraint = false;
7642                                 tginfo[j].tgdeferrable = false;
7643                                 tginfo[j].tginitdeferred = false;
7644                                 tginfo[j].tgconstrname = NULL;
7645                                 tginfo[j].tgconstrrelid = InvalidOid;
7646                                 tginfo[j].tgconstrrelname = NULL;
7647                         }
7648                         else
7649                         {
7650                                 tginfo[j].tgdef = NULL;
7651
7652                                 tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
7653                                 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
7654                                 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
7655                                 tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
7656                                 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
7657                                 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
7658                                 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
7659
7660                                 if (tginfo[j].tgisconstraint)
7661                                 {
7662                                         tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
7663                                         tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
7664                                         if (OidIsValid(tginfo[j].tgconstrrelid))
7665                                         {
7666                                                 if (PQgetisnull(res, j, i_tgconstrrelname))
7667                                                         fatal("query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)",
7668                                                                                   tginfo[j].dobj.name,
7669                                                                                   tbinfo->dobj.name,
7670                                                                                   tginfo[j].tgconstrrelid);
7671                                                 tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
7672                                         }
7673                                         else
7674                                                 tginfo[j].tgconstrrelname = NULL;
7675                                 }
7676                                 else
7677                                 {
7678                                         tginfo[j].tgconstrname = NULL;
7679                                         tginfo[j].tgconstrrelid = InvalidOid;
7680                                         tginfo[j].tgconstrrelname = NULL;
7681                                 }
7682                         }
7683                 }
7684
7685                 PQclear(res);
7686         }
7687
7688         destroyPQExpBuffer(query);
7689 }
7690
7691 /*
7692  * getEventTriggers
7693  *        get information about event triggers
7694  */
7695 EventTriggerInfo *
7696 getEventTriggers(Archive *fout, int *numEventTriggers)
7697 {
7698         int                     i;
7699         PQExpBuffer query;
7700         PGresult   *res;
7701         EventTriggerInfo *evtinfo;
7702         int                     i_tableoid,
7703                                 i_oid,
7704                                 i_evtname,
7705                                 i_evtevent,
7706                                 i_evtowner,
7707                                 i_evttags,
7708                                 i_evtfname,
7709                                 i_evtenabled;
7710         int                     ntups;
7711
7712         /* Before 9.3, there are no event triggers */
7713         if (fout->remoteVersion < 90300)
7714         {
7715                 *numEventTriggers = 0;
7716                 return NULL;
7717         }
7718
7719         query = createPQExpBuffer();
7720
7721         appendPQExpBuffer(query,
7722                                           "SELECT e.tableoid, e.oid, evtname, evtenabled, "
7723                                           "evtevent, (%s evtowner) AS evtowner, "
7724                                           "array_to_string(array("
7725                                           "select quote_literal(x) "
7726                                           " from unnest(evttags) as t(x)), ', ') as evttags, "
7727                                           "e.evtfoid::regproc as evtfname "
7728                                           "FROM pg_event_trigger e "
7729                                           "ORDER BY e.oid",
7730                                           username_subquery);
7731
7732         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7733
7734         ntups = PQntuples(res);
7735
7736         *numEventTriggers = ntups;
7737
7738         evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
7739
7740         i_tableoid = PQfnumber(res, "tableoid");
7741         i_oid = PQfnumber(res, "oid");
7742         i_evtname = PQfnumber(res, "evtname");
7743         i_evtevent = PQfnumber(res, "evtevent");
7744         i_evtowner = PQfnumber(res, "evtowner");
7745         i_evttags = PQfnumber(res, "evttags");
7746         i_evtfname = PQfnumber(res, "evtfname");
7747         i_evtenabled = PQfnumber(res, "evtenabled");
7748
7749         for (i = 0; i < ntups; i++)
7750         {
7751                 evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
7752                 evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7753                 evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7754                 AssignDumpId(&evtinfo[i].dobj);
7755                 evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
7756                 evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
7757                 evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
7758                 evtinfo[i].evtowner = pg_strdup(PQgetvalue(res, i, i_evtowner));
7759                 evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
7760                 evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
7761                 evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
7762
7763                 /* Decide whether we want to dump it */
7764                 selectDumpableObject(&(evtinfo[i].dobj), fout);
7765
7766                 /* Event Triggers do not currently have ACLs. */
7767                 evtinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7768         }
7769
7770         PQclear(res);
7771
7772         destroyPQExpBuffer(query);
7773
7774         return evtinfo;
7775 }
7776
7777 /*
7778  * getProcLangs
7779  *        get basic information about every procedural language in the system
7780  *
7781  * numProcLangs is set to the number of langs read in
7782  *
7783  * NB: this must run after getFuncs() because we assume we can do
7784  * findFuncByOid().
7785  */
7786 ProcLangInfo *
7787 getProcLangs(Archive *fout, int *numProcLangs)
7788 {
7789         DumpOptions *dopt = fout->dopt;
7790         PGresult   *res;
7791         int                     ntups;
7792         int                     i;
7793         PQExpBuffer query = createPQExpBuffer();
7794         ProcLangInfo *planginfo;
7795         int                     i_tableoid;
7796         int                     i_oid;
7797         int                     i_lanname;
7798         int                     i_lanpltrusted;
7799         int                     i_lanplcallfoid;
7800         int                     i_laninline;
7801         int                     i_lanvalidator;
7802         int                     i_lanacl;
7803         int                     i_rlanacl;
7804         int                     i_initlanacl;
7805         int                     i_initrlanacl;
7806         int                     i_lanowner;
7807
7808         if (fout->remoteVersion >= 90600)
7809         {
7810                 PQExpBuffer acl_subquery = createPQExpBuffer();
7811                 PQExpBuffer racl_subquery = createPQExpBuffer();
7812                 PQExpBuffer initacl_subquery = createPQExpBuffer();
7813                 PQExpBuffer initracl_subquery = createPQExpBuffer();
7814
7815                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
7816                                                 initracl_subquery, "l.lanacl", "l.lanowner", "'l'",
7817                                                 dopt->binary_upgrade);
7818
7819                 /* pg_language has a laninline column */
7820                 appendPQExpBuffer(query, "SELECT l.tableoid, l.oid, "
7821                                                   "l.lanname, l.lanpltrusted, l.lanplcallfoid, "
7822                                                   "l.laninline, l.lanvalidator, "
7823                                                   "%s AS lanacl, "
7824                                                   "%s AS rlanacl, "
7825                                                   "%s AS initlanacl, "
7826                                                   "%s AS initrlanacl, "
7827                                                   "(%s l.lanowner) AS lanowner "
7828                                                   "FROM pg_language l "
7829                                                   "LEFT JOIN pg_init_privs pip ON "
7830                                                   "(l.oid = pip.objoid "
7831                                                   "AND pip.classoid = 'pg_language'::regclass "
7832                                                   "AND pip.objsubid = 0) "
7833                                                   "WHERE l.lanispl "
7834                                                   "ORDER BY l.oid",
7835                                                   acl_subquery->data,
7836                                                   racl_subquery->data,
7837                                                   initacl_subquery->data,
7838                                                   initracl_subquery->data,
7839                                                   username_subquery);
7840
7841                 destroyPQExpBuffer(acl_subquery);
7842                 destroyPQExpBuffer(racl_subquery);
7843                 destroyPQExpBuffer(initacl_subquery);
7844                 destroyPQExpBuffer(initracl_subquery);
7845         }
7846         else if (fout->remoteVersion >= 90000)
7847         {
7848                 /* pg_language has a laninline column */
7849                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7850                                                   "lanname, lanpltrusted, lanplcallfoid, "
7851                                                   "laninline, lanvalidator, lanacl, NULL AS rlanacl, "
7852                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7853                                                   "(%s lanowner) AS lanowner "
7854                                                   "FROM pg_language "
7855                                                   "WHERE lanispl "
7856                                                   "ORDER BY oid",
7857                                                   username_subquery);
7858         }
7859         else if (fout->remoteVersion >= 80300)
7860         {
7861                 /* pg_language has a lanowner column */
7862                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7863                                                   "lanname, lanpltrusted, lanplcallfoid, "
7864                                                   "0 AS laninline, lanvalidator, lanacl, "
7865                                                   "NULL AS rlanacl, "
7866                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7867                                                   "(%s lanowner) AS lanowner "
7868                                                   "FROM pg_language "
7869                                                   "WHERE lanispl "
7870                                                   "ORDER BY oid",
7871                                                   username_subquery);
7872         }
7873         else if (fout->remoteVersion >= 80100)
7874         {
7875                 /* Languages are owned by the bootstrap superuser, OID 10 */
7876                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7877                                                   "lanname, lanpltrusted, lanplcallfoid, "
7878                                                   "0 AS laninline, lanvalidator, lanacl, "
7879                                                   "NULL AS rlanacl, "
7880                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7881                                                   "(%s '10') AS lanowner "
7882                                                   "FROM pg_language "
7883                                                   "WHERE lanispl "
7884                                                   "ORDER BY oid",
7885                                                   username_subquery);
7886         }
7887         else
7888         {
7889                 /* Languages are owned by the bootstrap superuser, sysid 1 */
7890                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7891                                                   "lanname, lanpltrusted, lanplcallfoid, "
7892                                                   "0 AS laninline, lanvalidator, lanacl, "
7893                                                   "NULL AS rlanacl, "
7894                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7895                                                   "(%s '1') AS lanowner "
7896                                                   "FROM pg_language "
7897                                                   "WHERE lanispl "
7898                                                   "ORDER BY oid",
7899                                                   username_subquery);
7900         }
7901
7902         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7903
7904         ntups = PQntuples(res);
7905
7906         *numProcLangs = ntups;
7907
7908         planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
7909
7910         i_tableoid = PQfnumber(res, "tableoid");
7911         i_oid = PQfnumber(res, "oid");
7912         i_lanname = PQfnumber(res, "lanname");
7913         i_lanpltrusted = PQfnumber(res, "lanpltrusted");
7914         i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
7915         i_laninline = PQfnumber(res, "laninline");
7916         i_lanvalidator = PQfnumber(res, "lanvalidator");
7917         i_lanacl = PQfnumber(res, "lanacl");
7918         i_rlanacl = PQfnumber(res, "rlanacl");
7919         i_initlanacl = PQfnumber(res, "initlanacl");
7920         i_initrlanacl = PQfnumber(res, "initrlanacl");
7921         i_lanowner = PQfnumber(res, "lanowner");
7922
7923         for (i = 0; i < ntups; i++)
7924         {
7925                 planginfo[i].dobj.objType = DO_PROCLANG;
7926                 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7927                 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7928                 AssignDumpId(&planginfo[i].dobj);
7929
7930                 planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
7931                 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
7932                 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
7933                 planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
7934                 planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
7935                 planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
7936                 planginfo[i].rlanacl = pg_strdup(PQgetvalue(res, i, i_rlanacl));
7937                 planginfo[i].initlanacl = pg_strdup(PQgetvalue(res, i, i_initlanacl));
7938                 planginfo[i].initrlanacl = pg_strdup(PQgetvalue(res, i, i_initrlanacl));
7939                 planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
7940
7941                 /* Decide whether we want to dump it */
7942                 selectDumpableProcLang(&(planginfo[i]), fout);
7943
7944                 /* Do not try to dump ACL if no ACL exists. */
7945                 if (PQgetisnull(res, i, i_lanacl) && PQgetisnull(res, i, i_rlanacl) &&
7946                         PQgetisnull(res, i, i_initlanacl) &&
7947                         PQgetisnull(res, i, i_initrlanacl))
7948                         planginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7949         }
7950
7951         PQclear(res);
7952
7953         destroyPQExpBuffer(query);
7954
7955         return planginfo;
7956 }
7957
7958 /*
7959  * getCasts
7960  *        get basic information about every cast in the system
7961  *
7962  * numCasts is set to the number of casts read in
7963  */
7964 CastInfo *
7965 getCasts(Archive *fout, int *numCasts)
7966 {
7967         PGresult   *res;
7968         int                     ntups;
7969         int                     i;
7970         PQExpBuffer query = createPQExpBuffer();
7971         CastInfo   *castinfo;
7972         int                     i_tableoid;
7973         int                     i_oid;
7974         int                     i_castsource;
7975         int                     i_casttarget;
7976         int                     i_castfunc;
7977         int                     i_castcontext;
7978         int                     i_castmethod;
7979
7980         if (fout->remoteVersion >= 80400)
7981         {
7982                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
7983                                                          "castsource, casttarget, castfunc, castcontext, "
7984                                                          "castmethod "
7985                                                          "FROM pg_cast ORDER BY 3,4");
7986         }
7987         else
7988         {
7989                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
7990                                                          "castsource, casttarget, castfunc, castcontext, "
7991                                                          "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
7992                                                          "FROM pg_cast ORDER BY 3,4");
7993         }
7994
7995         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7996
7997         ntups = PQntuples(res);
7998
7999         *numCasts = ntups;
8000
8001         castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
8002
8003         i_tableoid = PQfnumber(res, "tableoid");
8004         i_oid = PQfnumber(res, "oid");
8005         i_castsource = PQfnumber(res, "castsource");
8006         i_casttarget = PQfnumber(res, "casttarget");
8007         i_castfunc = PQfnumber(res, "castfunc");
8008         i_castcontext = PQfnumber(res, "castcontext");
8009         i_castmethod = PQfnumber(res, "castmethod");
8010
8011         for (i = 0; i < ntups; i++)
8012         {
8013                 PQExpBufferData namebuf;
8014                 TypeInfo   *sTypeInfo;
8015                 TypeInfo   *tTypeInfo;
8016
8017                 castinfo[i].dobj.objType = DO_CAST;
8018                 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8019                 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8020                 AssignDumpId(&castinfo[i].dobj);
8021                 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
8022                 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
8023                 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
8024                 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
8025                 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
8026
8027                 /*
8028                  * Try to name cast as concatenation of typnames.  This is only used
8029                  * for purposes of sorting.  If we fail to find either type, the name
8030                  * will be an empty string.
8031                  */
8032                 initPQExpBuffer(&namebuf);
8033                 sTypeInfo = findTypeByOid(castinfo[i].castsource);
8034                 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
8035                 if (sTypeInfo && tTypeInfo)
8036                         appendPQExpBuffer(&namebuf, "%s %s",
8037                                                           sTypeInfo->dobj.name, tTypeInfo->dobj.name);
8038                 castinfo[i].dobj.name = namebuf.data;
8039
8040                 /* Decide whether we want to dump it */
8041                 selectDumpableCast(&(castinfo[i]), fout);
8042
8043                 /* Casts do not currently have ACLs. */
8044                 castinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8045         }
8046
8047         PQclear(res);
8048
8049         destroyPQExpBuffer(query);
8050
8051         return castinfo;
8052 }
8053
8054 static char *
8055 get_language_name(Archive *fout, Oid langid)
8056 {
8057         PQExpBuffer query;
8058         PGresult   *res;
8059         char       *lanname;
8060
8061         query = createPQExpBuffer();
8062         appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
8063         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8064         lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
8065         destroyPQExpBuffer(query);
8066         PQclear(res);
8067
8068         return lanname;
8069 }
8070
8071 /*
8072  * getTransforms
8073  *        get basic information about every transform in the system
8074  *
8075  * numTransforms is set to the number of transforms read in
8076  */
8077 TransformInfo *
8078 getTransforms(Archive *fout, int *numTransforms)
8079 {
8080         PGresult   *res;
8081         int                     ntups;
8082         int                     i;
8083         PQExpBuffer query;
8084         TransformInfo *transforminfo;
8085         int                     i_tableoid;
8086         int                     i_oid;
8087         int                     i_trftype;
8088         int                     i_trflang;
8089         int                     i_trffromsql;
8090         int                     i_trftosql;
8091
8092         /* Transforms didn't exist pre-9.5 */
8093         if (fout->remoteVersion < 90500)
8094         {
8095                 *numTransforms = 0;
8096                 return NULL;
8097         }
8098
8099         query = createPQExpBuffer();
8100
8101         appendPQExpBuffer(query, "SELECT tableoid, oid, "
8102                                           "trftype, trflang, trffromsql::oid, trftosql::oid "
8103                                           "FROM pg_transform "
8104                                           "ORDER BY 3,4");
8105
8106         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8107
8108         ntups = PQntuples(res);
8109
8110         *numTransforms = ntups;
8111
8112         transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
8113
8114         i_tableoid = PQfnumber(res, "tableoid");
8115         i_oid = PQfnumber(res, "oid");
8116         i_trftype = PQfnumber(res, "trftype");
8117         i_trflang = PQfnumber(res, "trflang");
8118         i_trffromsql = PQfnumber(res, "trffromsql");
8119         i_trftosql = PQfnumber(res, "trftosql");
8120
8121         for (i = 0; i < ntups; i++)
8122         {
8123                 PQExpBufferData namebuf;
8124                 TypeInfo   *typeInfo;
8125                 char       *lanname;
8126
8127                 transforminfo[i].dobj.objType = DO_TRANSFORM;
8128                 transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8129                 transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8130                 AssignDumpId(&transforminfo[i].dobj);
8131                 transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
8132                 transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
8133                 transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
8134                 transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
8135
8136                 /*
8137                  * Try to name transform as concatenation of type and language name.
8138                  * This is only used for purposes of sorting.  If we fail to find
8139                  * either, the name will be an empty string.
8140                  */
8141                 initPQExpBuffer(&namebuf);
8142                 typeInfo = findTypeByOid(transforminfo[i].trftype);
8143                 lanname = get_language_name(fout, transforminfo[i].trflang);
8144                 if (typeInfo && lanname)
8145                         appendPQExpBuffer(&namebuf, "%s %s",
8146                                                           typeInfo->dobj.name, lanname);
8147                 transforminfo[i].dobj.name = namebuf.data;
8148                 free(lanname);
8149
8150                 /* Decide whether we want to dump it */
8151                 selectDumpableObject(&(transforminfo[i].dobj), fout);
8152         }
8153
8154         PQclear(res);
8155
8156         destroyPQExpBuffer(query);
8157
8158         return transforminfo;
8159 }
8160
8161 /*
8162  * getTableAttrs -
8163  *        for each interesting table, read info about its attributes
8164  *        (names, types, default values, CHECK constraints, etc)
8165  *
8166  * This is implemented in a very inefficient way right now, looping
8167  * through the tblinfo and doing a join per table to find the attrs and their
8168  * types.  However, because we want type names and so forth to be named
8169  * relative to the schema of each table, we couldn't do it in just one
8170  * query.  (Maybe one query per schema?)
8171  *
8172  *      modifies tblinfo
8173  */
8174 void
8175 getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
8176 {
8177         DumpOptions *dopt = fout->dopt;
8178         int                     i,
8179                                 j;
8180         PQExpBuffer q = createPQExpBuffer();
8181         int                     i_attnum;
8182         int                     i_attname;
8183         int                     i_atttypname;
8184         int                     i_atttypmod;
8185         int                     i_attstattarget;
8186         int                     i_attstorage;
8187         int                     i_typstorage;
8188         int                     i_attnotnull;
8189         int                     i_atthasdef;
8190         int                     i_attidentity;
8191         int                     i_attgenerated;
8192         int                     i_attisdropped;
8193         int                     i_attlen;
8194         int                     i_attalign;
8195         int                     i_attislocal;
8196         int                     i_attoptions;
8197         int                     i_attcollation;
8198         int                     i_attfdwoptions;
8199         int                     i_attmissingval;
8200         PGresult   *res;
8201         int                     ntups;
8202         bool            hasdefaults;
8203
8204         for (i = 0; i < numTables; i++)
8205         {
8206                 TableInfo  *tbinfo = &tblinfo[i];
8207
8208                 /* Don't bother to collect info for sequences */
8209                 if (tbinfo->relkind == RELKIND_SEQUENCE)
8210                         continue;
8211
8212                 /* Don't bother with uninteresting tables, either */
8213                 if (!tbinfo->interesting)
8214                         continue;
8215
8216                 /* find all the user attributes and their types */
8217
8218                 /*
8219                  * we must read the attribute names in attribute number order! because
8220                  * we will use the attnum to index into the attnames array later.
8221                  */
8222                 pg_log_info("finding the columns and types of table \"%s.%s\"",
8223                                         tbinfo->dobj.namespace->dobj.name,
8224                                         tbinfo->dobj.name);
8225
8226                 resetPQExpBuffer(q);
8227
8228                 appendPQExpBuffer(q,
8229                                                   "SELECT\n"
8230                                                   "a.attnum,\n"
8231                                                   "a.attname,\n"
8232                                                   "a.atttypmod,\n"
8233                                                   "a.attstattarget,\n"
8234                                                   "a.attstorage,\n"
8235                                                   "t.typstorage,\n"
8236                                                   "a.attnotnull,\n"
8237                                                   "a.atthasdef,\n"
8238                                                   "a.attisdropped,\n"
8239                                                   "a.attlen,\n"
8240                                                   "a.attalign,\n"
8241                                                   "a.attislocal,\n"
8242                                                   "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n");
8243
8244                 if (fout->remoteVersion >= 120000)
8245                         appendPQExpBuffer(q,
8246                                                           "a.attgenerated,\n");
8247                 else
8248                         appendPQExpBuffer(q,
8249                                                           "'' AS attgenerated,\n");
8250
8251                 if (fout->remoteVersion >= 110000)
8252                         appendPQExpBuffer(q,
8253                                                           "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
8254                                                           "THEN a.attmissingval ELSE null END AS attmissingval,\n");
8255                 else
8256                         appendPQExpBuffer(q,
8257                                                           "NULL AS attmissingval,\n");
8258
8259                 if (fout->remoteVersion >= 100000)
8260                         appendPQExpBuffer(q,
8261                                                           "a.attidentity,\n");
8262                 else
8263                         appendPQExpBuffer(q,
8264                                                           "'' AS attidentity,\n");
8265
8266                 if (fout->remoteVersion >= 90200)
8267                         appendPQExpBuffer(q,
8268                                                           "pg_catalog.array_to_string(ARRAY("
8269                                                           "SELECT pg_catalog.quote_ident(option_name) || "
8270                                                           "' ' || pg_catalog.quote_literal(option_value) "
8271                                                           "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
8272                                                           "ORDER BY option_name"
8273                                                           "), E',\n    ') AS attfdwoptions,\n");
8274                 else
8275                         appendPQExpBuffer(q,
8276                                                           "'' AS attfdwoptions,\n");
8277
8278                 if (fout->remoteVersion >= 90100)
8279                 {
8280                         /*
8281                          * Since we only want to dump COLLATE clauses for attributes whose
8282                          * collation is different from their type's default, we use a CASE
8283                          * here to suppress uninteresting attcollations cheaply.
8284                          */
8285                         appendPQExpBuffer(q,
8286                                                           "CASE WHEN a.attcollation <> t.typcollation "
8287                                                           "THEN a.attcollation ELSE 0 END AS attcollation,\n");
8288                 }
8289                 else
8290                         appendPQExpBuffer(q,
8291                                                           "0 AS attcollation,\n");
8292
8293                 if (fout->remoteVersion >= 90000)
8294                         appendPQExpBuffer(q,
8295                                                           "array_to_string(a.attoptions, ', ') AS attoptions\n");
8296                 else
8297                         appendPQExpBuffer(q,
8298                                                           "'' AS attoptions\n");
8299
8300                 /* need left join here to not fail on dropped columns ... */
8301                 appendPQExpBuffer(q,
8302                                                   "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
8303                                                   "ON a.atttypid = t.oid\n"
8304                                                   "WHERE a.attrelid = '%u'::pg_catalog.oid "
8305                                                   "AND a.attnum > 0::pg_catalog.int2\n"
8306                                                   "ORDER BY a.attnum",
8307                                                   tbinfo->dobj.catId.oid);
8308
8309                 res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8310
8311                 ntups = PQntuples(res);
8312
8313                 i_attnum = PQfnumber(res, "attnum");
8314                 i_attname = PQfnumber(res, "attname");
8315                 i_atttypname = PQfnumber(res, "atttypname");
8316                 i_atttypmod = PQfnumber(res, "atttypmod");
8317                 i_attstattarget = PQfnumber(res, "attstattarget");
8318                 i_attstorage = PQfnumber(res, "attstorage");
8319                 i_typstorage = PQfnumber(res, "typstorage");
8320                 i_attnotnull = PQfnumber(res, "attnotnull");
8321                 i_atthasdef = PQfnumber(res, "atthasdef");
8322                 i_attidentity = PQfnumber(res, "attidentity");
8323                 i_attgenerated = PQfnumber(res, "attgenerated");
8324                 i_attisdropped = PQfnumber(res, "attisdropped");
8325                 i_attlen = PQfnumber(res, "attlen");
8326                 i_attalign = PQfnumber(res, "attalign");
8327                 i_attislocal = PQfnumber(res, "attislocal");
8328                 i_attoptions = PQfnumber(res, "attoptions");
8329                 i_attcollation = PQfnumber(res, "attcollation");
8330                 i_attfdwoptions = PQfnumber(res, "attfdwoptions");
8331                 i_attmissingval = PQfnumber(res, "attmissingval");
8332
8333                 tbinfo->numatts = ntups;
8334                 tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
8335                 tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
8336                 tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
8337                 tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
8338                 tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
8339                 tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
8340                 tbinfo->attidentity = (char *) pg_malloc(ntups * sizeof(char));
8341                 tbinfo->attgenerated = (char *) pg_malloc(ntups * sizeof(char));
8342                 tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
8343                 tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
8344                 tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
8345                 tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
8346                 tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
8347                 tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
8348                 tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
8349                 tbinfo->attmissingval = (char **) pg_malloc(ntups * sizeof(char *));
8350                 tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
8351                 tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
8352                 tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
8353                 hasdefaults = false;
8354
8355                 for (j = 0; j < ntups; j++)
8356                 {
8357                         if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
8358                                 fatal("invalid column numbering in table \"%s\"",
8359                                                           tbinfo->dobj.name);
8360                         tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
8361                         tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
8362                         tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
8363                         tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
8364                         tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
8365                         tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
8366                         tbinfo->attidentity[j] = *(PQgetvalue(res, j, i_attidentity));
8367                         tbinfo->attgenerated[j] = *(PQgetvalue(res, j, i_attgenerated));
8368                         tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
8369                         tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
8370                         tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
8371                         tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
8372                         tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
8373                         tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
8374                         tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
8375                         tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
8376                         tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
8377                         tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, j, i_attmissingval));
8378                         tbinfo->attrdefs[j] = NULL; /* fix below */
8379                         if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
8380                                 hasdefaults = true;
8381                         /* these flags will be set in flagInhAttrs() */
8382                         tbinfo->inhNotNull[j] = false;
8383                 }
8384
8385                 PQclear(res);
8386
8387                 /*
8388                  * Get info about column defaults
8389                  */
8390                 if (hasdefaults)
8391                 {
8392                         AttrDefInfo *attrdefs;
8393                         int                     numDefaults;
8394
8395                         pg_log_info("finding default expressions of table \"%s.%s\"",
8396                                                 tbinfo->dobj.namespace->dobj.name,
8397                                                 tbinfo->dobj.name);
8398
8399                         printfPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
8400                                                           "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
8401                                                           "FROM pg_catalog.pg_attrdef "
8402                                                           "WHERE adrelid = '%u'::pg_catalog.oid",
8403                                                           tbinfo->dobj.catId.oid);
8404
8405                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8406
8407                         numDefaults = PQntuples(res);
8408                         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
8409
8410                         for (j = 0; j < numDefaults; j++)
8411                         {
8412                                 int                     adnum;
8413
8414                                 adnum = atoi(PQgetvalue(res, j, 2));
8415
8416                                 if (adnum <= 0 || adnum > ntups)
8417                                         fatal("invalid adnum value %d for table \"%s\"",
8418                                                                   adnum, tbinfo->dobj.name);
8419
8420                                 /*
8421                                  * dropped columns shouldn't have defaults, but just in case,
8422                                  * ignore 'em
8423                                  */
8424                                 if (tbinfo->attisdropped[adnum - 1])
8425                                         continue;
8426
8427                                 attrdefs[j].dobj.objType = DO_ATTRDEF;
8428                                 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
8429                                 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
8430                                 AssignDumpId(&attrdefs[j].dobj);
8431                                 attrdefs[j].adtable = tbinfo;
8432                                 attrdefs[j].adnum = adnum;
8433                                 attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
8434
8435                                 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
8436                                 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
8437
8438                                 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
8439
8440                                 /*
8441                                  * Defaults on a VIEW must always be dumped as separate ALTER
8442                                  * TABLE commands.  Defaults on regular tables are dumped as
8443                                  * part of the CREATE TABLE if possible, which it won't be if
8444                                  * the column is not going to be emitted explicitly.
8445                                  */
8446                                 if (tbinfo->relkind == RELKIND_VIEW)
8447                                 {
8448                                         attrdefs[j].separate = true;
8449                                 }
8450                                 else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
8451                                 {
8452                                         /* column will be suppressed, print default separately */
8453                                         attrdefs[j].separate = true;
8454                                 }
8455                                 else
8456                                 {
8457                                         attrdefs[j].separate = false;
8458
8459                                         /*
8460                                          * Mark the default as needing to appear before the table,
8461                                          * so that any dependencies it has must be emitted before
8462                                          * the CREATE TABLE.  If this is not possible, we'll
8463                                          * change to "separate" mode while sorting dependencies.
8464                                          */
8465                                         addObjectDependency(&tbinfo->dobj,
8466                                                                                 attrdefs[j].dobj.dumpId);
8467                                 }
8468
8469                                 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
8470                         }
8471                         PQclear(res);
8472                 }
8473
8474                 /*
8475                  * Get info about table CHECK constraints
8476                  */
8477                 if (tbinfo->ncheck > 0)
8478                 {
8479                         ConstraintInfo *constrs;
8480                         int                     numConstrs;
8481
8482                         pg_log_info("finding check constraints for table \"%s.%s\"",
8483                                                 tbinfo->dobj.namespace->dobj.name,
8484                                                 tbinfo->dobj.name);
8485
8486                         resetPQExpBuffer(q);
8487                         if (fout->remoteVersion >= 90200)
8488                         {
8489                                 /*
8490                                  * convalidated is new in 9.2 (actually, it is there in 9.1,
8491                                  * but it wasn't ever false for check constraints until 9.2).
8492                                  */
8493                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8494                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8495                                                                   "conislocal, convalidated "
8496                                                                   "FROM pg_catalog.pg_constraint "
8497                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8498                                                                   "   AND contype = 'c' "
8499                                                                   "ORDER BY conname",
8500                                                                   tbinfo->dobj.catId.oid);
8501                         }
8502                         else if (fout->remoteVersion >= 80400)
8503                         {
8504                                 /* conislocal is new in 8.4 */
8505                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8506                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8507                                                                   "conislocal, true AS convalidated "
8508                                                                   "FROM pg_catalog.pg_constraint "
8509                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8510                                                                   "   AND contype = 'c' "
8511                                                                   "ORDER BY conname",
8512                                                                   tbinfo->dobj.catId.oid);
8513                         }
8514                         else
8515                         {
8516                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8517                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8518                                                                   "true AS conislocal, true AS convalidated "
8519                                                                   "FROM pg_catalog.pg_constraint "
8520                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8521                                                                   "   AND contype = 'c' "
8522                                                                   "ORDER BY conname",
8523                                                                   tbinfo->dobj.catId.oid);
8524                         }
8525
8526                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8527
8528                         numConstrs = PQntuples(res);
8529                         if (numConstrs != tbinfo->ncheck)
8530                         {
8531                                 pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
8532                                                                           "expected %d check constraints on table \"%s\" but found %d",
8533                                                                           tbinfo->ncheck),
8534                                                   tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
8535                                 pg_log_error("(The system catalogs might be corrupted.)");
8536                                 exit_nicely(1);
8537                         }
8538
8539                         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
8540                         tbinfo->checkexprs = constrs;
8541
8542                         for (j = 0; j < numConstrs; j++)
8543                         {
8544                                 bool            validated = PQgetvalue(res, j, 5)[0] == 't';
8545
8546                                 constrs[j].dobj.objType = DO_CONSTRAINT;
8547                                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
8548                                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
8549                                 AssignDumpId(&constrs[j].dobj);
8550                                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
8551                                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
8552                                 constrs[j].contable = tbinfo;
8553                                 constrs[j].condomain = NULL;
8554                                 constrs[j].contype = 'c';
8555                                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
8556                                 constrs[j].confrelid = InvalidOid;
8557                                 constrs[j].conindex = 0;
8558                                 constrs[j].condeferrable = false;
8559                                 constrs[j].condeferred = false;
8560                                 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
8561
8562                                 /*
8563                                  * An unvalidated constraint needs to be dumped separately, so
8564                                  * that potentially-violating existing data is loaded before
8565                                  * the constraint.
8566                                  */
8567                                 constrs[j].separate = !validated;
8568
8569                                 constrs[j].dobj.dump = tbinfo->dobj.dump;
8570
8571                                 /*
8572                                  * Mark the constraint as needing to appear before the table
8573                                  * --- this is so that any other dependencies of the
8574                                  * constraint will be emitted before we try to create the
8575                                  * table.  If the constraint is to be dumped separately, it
8576                                  * will be dumped after data is loaded anyway, so don't do it.
8577                                  * (There's an automatic dependency in the opposite direction
8578                                  * anyway, so don't need to add one manually here.)
8579                                  */
8580                                 if (!constrs[j].separate)
8581                                         addObjectDependency(&tbinfo->dobj,
8582                                                                                 constrs[j].dobj.dumpId);
8583
8584                                 /*
8585                                  * If the constraint is inherited, this will be detected later
8586                                  * (in pre-8.4 databases).  We also detect later if the
8587                                  * constraint must be split out from the table definition.
8588                                  */
8589                         }
8590                         PQclear(res);
8591                 }
8592         }
8593
8594         destroyPQExpBuffer(q);
8595 }
8596
8597 /*
8598  * Test whether a column should be printed as part of table's CREATE TABLE.
8599  * Column number is zero-based.
8600  *
8601  * Normally this is always true, but it's false for dropped columns, as well
8602  * as those that were inherited without any local definition.  (If we print
8603  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
8604  * However, in binary_upgrade mode, we must print all such columns anyway and
8605  * fix the attislocal/attisdropped state later, so as to keep control of the
8606  * physical column order.
8607  *
8608  * This function exists because there are scattered nonobvious places that
8609  * must be kept in sync with this decision.
8610  */
8611 bool
8612 shouldPrintColumn(DumpOptions *dopt, TableInfo *tbinfo, int colno)
8613 {
8614         if (dopt->binary_upgrade)
8615                 return true;
8616         return (tbinfo->attislocal[colno] && !tbinfo->attisdropped[colno]);
8617 }
8618
8619
8620 /*
8621  * getTSParsers:
8622  *        read all text search parsers in the system catalogs and return them
8623  *        in the TSParserInfo* structure
8624  *
8625  *      numTSParsers is set to the number of parsers read in
8626  */
8627 TSParserInfo *
8628 getTSParsers(Archive *fout, int *numTSParsers)
8629 {
8630         PGresult   *res;
8631         int                     ntups;
8632         int                     i;
8633         PQExpBuffer query;
8634         TSParserInfo *prsinfo;
8635         int                     i_tableoid;
8636         int                     i_oid;
8637         int                     i_prsname;
8638         int                     i_prsnamespace;
8639         int                     i_prsstart;
8640         int                     i_prstoken;
8641         int                     i_prsend;
8642         int                     i_prsheadline;
8643         int                     i_prslextype;
8644
8645         /* Before 8.3, there is no built-in text search support */
8646         if (fout->remoteVersion < 80300)
8647         {
8648                 *numTSParsers = 0;
8649                 return NULL;
8650         }
8651
8652         query = createPQExpBuffer();
8653
8654         /*
8655          * find all text search objects, including builtin ones; we filter out
8656          * system-defined objects at dump-out time.
8657          */
8658
8659         appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
8660                                                  "prsstart::oid, prstoken::oid, "
8661                                                  "prsend::oid, prsheadline::oid, prslextype::oid "
8662                                                  "FROM pg_ts_parser");
8663
8664         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8665
8666         ntups = PQntuples(res);
8667         *numTSParsers = ntups;
8668
8669         prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
8670
8671         i_tableoid = PQfnumber(res, "tableoid");
8672         i_oid = PQfnumber(res, "oid");
8673         i_prsname = PQfnumber(res, "prsname");
8674         i_prsnamespace = PQfnumber(res, "prsnamespace");
8675         i_prsstart = PQfnumber(res, "prsstart");
8676         i_prstoken = PQfnumber(res, "prstoken");
8677         i_prsend = PQfnumber(res, "prsend");
8678         i_prsheadline = PQfnumber(res, "prsheadline");
8679         i_prslextype = PQfnumber(res, "prslextype");
8680
8681         for (i = 0; i < ntups; i++)
8682         {
8683                 prsinfo[i].dobj.objType = DO_TSPARSER;
8684                 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8685                 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8686                 AssignDumpId(&prsinfo[i].dobj);
8687                 prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
8688                 prsinfo[i].dobj.namespace =
8689                         findNamespace(fout,
8690                                                   atooid(PQgetvalue(res, i, i_prsnamespace)));
8691                 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
8692                 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
8693                 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
8694                 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
8695                 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
8696
8697                 /* Decide whether we want to dump it */
8698                 selectDumpableObject(&(prsinfo[i].dobj), fout);
8699
8700                 /* Text Search Parsers do not currently have ACLs. */
8701                 prsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8702         }
8703
8704         PQclear(res);
8705
8706         destroyPQExpBuffer(query);
8707
8708         return prsinfo;
8709 }
8710
8711 /*
8712  * getTSDictionaries:
8713  *        read all text search dictionaries in the system catalogs and return them
8714  *        in the TSDictInfo* structure
8715  *
8716  *      numTSDicts is set to the number of dictionaries read in
8717  */
8718 TSDictInfo *
8719 getTSDictionaries(Archive *fout, int *numTSDicts)
8720 {
8721         PGresult   *res;
8722         int                     ntups;
8723         int                     i;
8724         PQExpBuffer query;
8725         TSDictInfo *dictinfo;
8726         int                     i_tableoid;
8727         int                     i_oid;
8728         int                     i_dictname;
8729         int                     i_dictnamespace;
8730         int                     i_rolname;
8731         int                     i_dicttemplate;
8732         int                     i_dictinitoption;
8733
8734         /* Before 8.3, there is no built-in text search support */
8735         if (fout->remoteVersion < 80300)
8736         {
8737                 *numTSDicts = 0;
8738                 return NULL;
8739         }
8740
8741         query = createPQExpBuffer();
8742
8743         appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
8744                                           "dictnamespace, (%s dictowner) AS rolname, "
8745                                           "dicttemplate, dictinitoption "
8746                                           "FROM pg_ts_dict",
8747                                           username_subquery);
8748
8749         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8750
8751         ntups = PQntuples(res);
8752         *numTSDicts = ntups;
8753
8754         dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
8755
8756         i_tableoid = PQfnumber(res, "tableoid");
8757         i_oid = PQfnumber(res, "oid");
8758         i_dictname = PQfnumber(res, "dictname");
8759         i_dictnamespace = PQfnumber(res, "dictnamespace");
8760         i_rolname = PQfnumber(res, "rolname");
8761         i_dictinitoption = PQfnumber(res, "dictinitoption");
8762         i_dicttemplate = PQfnumber(res, "dicttemplate");
8763
8764         for (i = 0; i < ntups; i++)
8765         {
8766                 dictinfo[i].dobj.objType = DO_TSDICT;
8767                 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8768                 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8769                 AssignDumpId(&dictinfo[i].dobj);
8770                 dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
8771                 dictinfo[i].dobj.namespace =
8772                         findNamespace(fout,
8773                                                   atooid(PQgetvalue(res, i, i_dictnamespace)));
8774                 dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8775                 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
8776                 if (PQgetisnull(res, i, i_dictinitoption))
8777                         dictinfo[i].dictinitoption = NULL;
8778                 else
8779                         dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
8780
8781                 /* Decide whether we want to dump it */
8782                 selectDumpableObject(&(dictinfo[i].dobj), fout);
8783
8784                 /* Text Search Dictionaries do not currently have ACLs. */
8785                 dictinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8786         }
8787
8788         PQclear(res);
8789
8790         destroyPQExpBuffer(query);
8791
8792         return dictinfo;
8793 }
8794
8795 /*
8796  * getTSTemplates:
8797  *        read all text search templates in the system catalogs and return them
8798  *        in the TSTemplateInfo* structure
8799  *
8800  *      numTSTemplates is set to the number of templates read in
8801  */
8802 TSTemplateInfo *
8803 getTSTemplates(Archive *fout, int *numTSTemplates)
8804 {
8805         PGresult   *res;
8806         int                     ntups;
8807         int                     i;
8808         PQExpBuffer query;
8809         TSTemplateInfo *tmplinfo;
8810         int                     i_tableoid;
8811         int                     i_oid;
8812         int                     i_tmplname;
8813         int                     i_tmplnamespace;
8814         int                     i_tmplinit;
8815         int                     i_tmpllexize;
8816
8817         /* Before 8.3, there is no built-in text search support */
8818         if (fout->remoteVersion < 80300)
8819         {
8820                 *numTSTemplates = 0;
8821                 return NULL;
8822         }
8823
8824         query = createPQExpBuffer();
8825
8826         appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
8827                                                  "tmplnamespace, tmplinit::oid, tmpllexize::oid "
8828                                                  "FROM pg_ts_template");
8829
8830         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8831
8832         ntups = PQntuples(res);
8833         *numTSTemplates = ntups;
8834
8835         tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
8836
8837         i_tableoid = PQfnumber(res, "tableoid");
8838         i_oid = PQfnumber(res, "oid");
8839         i_tmplname = PQfnumber(res, "tmplname");
8840         i_tmplnamespace = PQfnumber(res, "tmplnamespace");
8841         i_tmplinit = PQfnumber(res, "tmplinit");
8842         i_tmpllexize = PQfnumber(res, "tmpllexize");
8843
8844         for (i = 0; i < ntups; i++)
8845         {
8846                 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
8847                 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8848                 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8849                 AssignDumpId(&tmplinfo[i].dobj);
8850                 tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
8851                 tmplinfo[i].dobj.namespace =
8852                         findNamespace(fout,
8853                                                   atooid(PQgetvalue(res, i, i_tmplnamespace)));
8854                 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
8855                 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
8856
8857                 /* Decide whether we want to dump it */
8858                 selectDumpableObject(&(tmplinfo[i].dobj), fout);
8859
8860                 /* Text Search Templates do not currently have ACLs. */
8861                 tmplinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8862         }
8863
8864         PQclear(res);
8865
8866         destroyPQExpBuffer(query);
8867
8868         return tmplinfo;
8869 }
8870
8871 /*
8872  * getTSConfigurations:
8873  *        read all text search configurations in the system catalogs and return
8874  *        them in the TSConfigInfo* structure
8875  *
8876  *      numTSConfigs is set to the number of configurations read in
8877  */
8878 TSConfigInfo *
8879 getTSConfigurations(Archive *fout, int *numTSConfigs)
8880 {
8881         PGresult   *res;
8882         int                     ntups;
8883         int                     i;
8884         PQExpBuffer query;
8885         TSConfigInfo *cfginfo;
8886         int                     i_tableoid;
8887         int                     i_oid;
8888         int                     i_cfgname;
8889         int                     i_cfgnamespace;
8890         int                     i_rolname;
8891         int                     i_cfgparser;
8892
8893         /* Before 8.3, there is no built-in text search support */
8894         if (fout->remoteVersion < 80300)
8895         {
8896                 *numTSConfigs = 0;
8897                 return NULL;
8898         }
8899
8900         query = createPQExpBuffer();
8901
8902         appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
8903                                           "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
8904                                           "FROM pg_ts_config",
8905                                           username_subquery);
8906
8907         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8908
8909         ntups = PQntuples(res);
8910         *numTSConfigs = ntups;
8911
8912         cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
8913
8914         i_tableoid = PQfnumber(res, "tableoid");
8915         i_oid = PQfnumber(res, "oid");
8916         i_cfgname = PQfnumber(res, "cfgname");
8917         i_cfgnamespace = PQfnumber(res, "cfgnamespace");
8918         i_rolname = PQfnumber(res, "rolname");
8919         i_cfgparser = PQfnumber(res, "cfgparser");
8920
8921         for (i = 0; i < ntups; i++)
8922         {
8923                 cfginfo[i].dobj.objType = DO_TSCONFIG;
8924                 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8925                 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8926                 AssignDumpId(&cfginfo[i].dobj);
8927                 cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
8928                 cfginfo[i].dobj.namespace =
8929                         findNamespace(fout,
8930                                                   atooid(PQgetvalue(res, i, i_cfgnamespace)));
8931                 cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8932                 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
8933
8934                 /* Decide whether we want to dump it */
8935                 selectDumpableObject(&(cfginfo[i].dobj), fout);
8936
8937                 /* Text Search Configurations do not currently have ACLs. */
8938                 cfginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8939         }
8940
8941         PQclear(res);
8942
8943         destroyPQExpBuffer(query);
8944
8945         return cfginfo;
8946 }
8947
8948 /*
8949  * getForeignDataWrappers:
8950  *        read all foreign-data wrappers in the system catalogs and return
8951  *        them in the FdwInfo* structure
8952  *
8953  *      numForeignDataWrappers is set to the number of fdws read in
8954  */
8955 FdwInfo *
8956 getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
8957 {
8958         DumpOptions *dopt = fout->dopt;
8959         PGresult   *res;
8960         int                     ntups;
8961         int                     i;
8962         PQExpBuffer query;
8963         FdwInfo    *fdwinfo;
8964         int                     i_tableoid;
8965         int                     i_oid;
8966         int                     i_fdwname;
8967         int                     i_rolname;
8968         int                     i_fdwhandler;
8969         int                     i_fdwvalidator;
8970         int                     i_fdwacl;
8971         int                     i_rfdwacl;
8972         int                     i_initfdwacl;
8973         int                     i_initrfdwacl;
8974         int                     i_fdwoptions;
8975
8976         /* Before 8.4, there are no foreign-data wrappers */
8977         if (fout->remoteVersion < 80400)
8978         {
8979                 *numForeignDataWrappers = 0;
8980                 return NULL;
8981         }
8982
8983         query = createPQExpBuffer();
8984
8985         if (fout->remoteVersion >= 90600)
8986         {
8987                 PQExpBuffer acl_subquery = createPQExpBuffer();
8988                 PQExpBuffer racl_subquery = createPQExpBuffer();
8989                 PQExpBuffer initacl_subquery = createPQExpBuffer();
8990                 PQExpBuffer initracl_subquery = createPQExpBuffer();
8991
8992                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
8993                                                 initracl_subquery, "f.fdwacl", "f.fdwowner", "'F'",
8994                                                 dopt->binary_upgrade);
8995
8996                 appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.fdwname, "
8997                                                   "(%s f.fdwowner) AS rolname, "
8998                                                   "f.fdwhandler::pg_catalog.regproc, "
8999                                                   "f.fdwvalidator::pg_catalog.regproc, "
9000                                                   "%s AS fdwacl, "
9001                                                   "%s AS rfdwacl, "
9002                                                   "%s AS initfdwacl, "
9003                                                   "%s AS initrfdwacl, "
9004                                                   "array_to_string(ARRAY("
9005                                                   "SELECT quote_ident(option_name) || ' ' || "
9006                                                   "quote_literal(option_value) "
9007                                                   "FROM pg_options_to_table(f.fdwoptions) "
9008                                                   "ORDER BY option_name"
9009                                                   "), E',\n    ') AS fdwoptions "
9010                                                   "FROM pg_foreign_data_wrapper f "
9011                                                   "LEFT JOIN pg_init_privs pip ON "
9012                                                   "(f.oid = pip.objoid "
9013                                                   "AND pip.classoid = 'pg_foreign_data_wrapper'::regclass "
9014                                                   "AND pip.objsubid = 0) ",
9015                                                   username_subquery,
9016                                                   acl_subquery->data,
9017                                                   racl_subquery->data,
9018                                                   initacl_subquery->data,
9019                                                   initracl_subquery->data);
9020
9021                 destroyPQExpBuffer(acl_subquery);
9022                 destroyPQExpBuffer(racl_subquery);
9023                 destroyPQExpBuffer(initacl_subquery);
9024                 destroyPQExpBuffer(initracl_subquery);
9025         }
9026         else if (fout->remoteVersion >= 90100)
9027         {
9028                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
9029                                                   "(%s fdwowner) AS rolname, "
9030                                                   "fdwhandler::pg_catalog.regproc, "
9031                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
9032                                                   "NULL as rfdwacl, "
9033                                                   "NULL as initfdwacl, NULL AS initrfdwacl, "
9034                                                   "array_to_string(ARRAY("
9035                                                   "SELECT quote_ident(option_name) || ' ' || "
9036                                                   "quote_literal(option_value) "
9037                                                   "FROM pg_options_to_table(fdwoptions) "
9038                                                   "ORDER BY option_name"
9039                                                   "), E',\n    ') AS fdwoptions "
9040                                                   "FROM pg_foreign_data_wrapper",
9041                                                   username_subquery);
9042         }
9043         else
9044         {
9045                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
9046                                                   "(%s fdwowner) AS rolname, "
9047                                                   "'-' AS fdwhandler, "
9048                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
9049                                                   "NULL as rfdwacl, "
9050                                                   "NULL as initfdwacl, NULL AS initrfdwacl, "
9051                                                   "array_to_string(ARRAY("
9052                                                   "SELECT quote_ident(option_name) || ' ' || "
9053                                                   "quote_literal(option_value) "
9054                                                   "FROM pg_options_to_table(fdwoptions) "
9055                                                   "ORDER BY option_name"
9056                                                   "), E',\n    ') AS fdwoptions "
9057                                                   "FROM pg_foreign_data_wrapper",
9058                                                   username_subquery);
9059         }
9060
9061         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9062
9063         ntups = PQntuples(res);
9064         *numForeignDataWrappers = ntups;
9065
9066         fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
9067
9068         i_tableoid = PQfnumber(res, "tableoid");
9069         i_oid = PQfnumber(res, "oid");
9070         i_fdwname = PQfnumber(res, "fdwname");
9071         i_rolname = PQfnumber(res, "rolname");
9072         i_fdwhandler = PQfnumber(res, "fdwhandler");
9073         i_fdwvalidator = PQfnumber(res, "fdwvalidator");
9074         i_fdwacl = PQfnumber(res, "fdwacl");
9075         i_rfdwacl = PQfnumber(res, "rfdwacl");
9076         i_initfdwacl = PQfnumber(res, "initfdwacl");
9077         i_initrfdwacl = PQfnumber(res, "initrfdwacl");
9078         i_fdwoptions = PQfnumber(res, "fdwoptions");
9079
9080         for (i = 0; i < ntups; i++)
9081         {
9082                 fdwinfo[i].dobj.objType = DO_FDW;
9083                 fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9084                 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9085                 AssignDumpId(&fdwinfo[i].dobj);
9086                 fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
9087                 fdwinfo[i].dobj.namespace = NULL;
9088                 fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
9089                 fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
9090                 fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
9091                 fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
9092                 fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
9093                 fdwinfo[i].rfdwacl = pg_strdup(PQgetvalue(res, i, i_rfdwacl));
9094                 fdwinfo[i].initfdwacl = pg_strdup(PQgetvalue(res, i, i_initfdwacl));
9095                 fdwinfo[i].initrfdwacl = pg_strdup(PQgetvalue(res, i, i_initrfdwacl));
9096
9097                 /* Decide whether we want to dump it */
9098                 selectDumpableObject(&(fdwinfo[i].dobj), fout);
9099
9100                 /* Do not try to dump ACL if no ACL exists. */
9101                 if (PQgetisnull(res, i, i_fdwacl) && PQgetisnull(res, i, i_rfdwacl) &&
9102                         PQgetisnull(res, i, i_initfdwacl) &&
9103                         PQgetisnull(res, i, i_initrfdwacl))
9104                         fdwinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
9105         }
9106
9107         PQclear(res);
9108
9109         destroyPQExpBuffer(query);
9110
9111         return fdwinfo;
9112 }
9113
9114 /*
9115  * getForeignServers:
9116  *        read all foreign servers in the system catalogs and return
9117  *        them in the ForeignServerInfo * structure
9118  *
9119  *      numForeignServers is set to the number of servers read in
9120  */
9121 ForeignServerInfo *
9122 getForeignServers(Archive *fout, int *numForeignServers)
9123 {
9124         DumpOptions *dopt = fout->dopt;
9125         PGresult   *res;
9126         int                     ntups;
9127         int                     i;
9128         PQExpBuffer query;
9129         ForeignServerInfo *srvinfo;
9130         int                     i_tableoid;
9131         int                     i_oid;
9132         int                     i_srvname;
9133         int                     i_rolname;
9134         int                     i_srvfdw;
9135         int                     i_srvtype;
9136         int                     i_srvversion;
9137         int                     i_srvacl;
9138         int                     i_rsrvacl;
9139         int                     i_initsrvacl;
9140         int                     i_initrsrvacl;
9141         int                     i_srvoptions;
9142
9143         /* Before 8.4, there are no foreign servers */
9144         if (fout->remoteVersion < 80400)
9145         {
9146                 *numForeignServers = 0;
9147                 return NULL;
9148         }
9149
9150         query = createPQExpBuffer();
9151
9152         if (fout->remoteVersion >= 90600)
9153         {
9154                 PQExpBuffer acl_subquery = createPQExpBuffer();
9155                 PQExpBuffer racl_subquery = createPQExpBuffer();
9156                 PQExpBuffer initacl_subquery = createPQExpBuffer();
9157                 PQExpBuffer initracl_subquery = createPQExpBuffer();
9158
9159                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9160                                                 initracl_subquery, "f.srvacl", "f.srvowner", "'S'",
9161                                                 dopt->binary_upgrade);
9162
9163                 appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.srvname, "
9164                                                   "(%s f.srvowner) AS rolname, "
9165                                                   "f.srvfdw, f.srvtype, f.srvversion, "
9166                                                   "%s AS srvacl, "
9167                                                   "%s AS rsrvacl, "
9168                                                   "%s AS initsrvacl, "
9169                                                   "%s AS initrsrvacl, "
9170                                                   "array_to_string(ARRAY("
9171                                                   "SELECT quote_ident(option_name) || ' ' || "
9172                                                   "quote_literal(option_value) "
9173                                                   "FROM pg_options_to_table(f.srvoptions) "
9174                                                   "ORDER BY option_name"
9175                                                   "), E',\n    ') AS srvoptions "
9176                                                   "FROM pg_foreign_server f "
9177                                                   "LEFT JOIN pg_init_privs pip "
9178                                                   "ON (f.oid = pip.objoid "
9179                                                   "AND pip.classoid = 'pg_foreign_server'::regclass "
9180                                                   "AND pip.objsubid = 0) ",
9181                                                   username_subquery,
9182                                                   acl_subquery->data,
9183                                                   racl_subquery->data,
9184                                                   initacl_subquery->data,
9185                                                   initracl_subquery->data);
9186
9187                 destroyPQExpBuffer(acl_subquery);
9188                 destroyPQExpBuffer(racl_subquery);
9189                 destroyPQExpBuffer(initacl_subquery);
9190                 destroyPQExpBuffer(initracl_subquery);
9191         }
9192         else
9193         {
9194                 appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
9195                                                   "(%s srvowner) AS rolname, "
9196                                                   "srvfdw, srvtype, srvversion, srvacl, "
9197                                                   "NULL AS rsrvacl, "
9198                                                   "NULL AS initsrvacl, NULL AS initrsrvacl, "
9199                                                   "array_to_string(ARRAY("
9200                                                   "SELECT quote_ident(option_name) || ' ' || "
9201                                                   "quote_literal(option_value) "
9202                                                   "FROM pg_options_to_table(srvoptions) "
9203                                                   "ORDER BY option_name"
9204                                                   "), E',\n    ') AS srvoptions "
9205                                                   "FROM pg_foreign_server",
9206                                                   username_subquery);
9207         }
9208
9209         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9210
9211         ntups = PQntuples(res);
9212         *numForeignServers = ntups;
9213
9214         srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
9215
9216         i_tableoid = PQfnumber(res, "tableoid");
9217         i_oid = PQfnumber(res, "oid");
9218         i_srvname = PQfnumber(res, "srvname");
9219         i_rolname = PQfnumber(res, "rolname");
9220         i_srvfdw = PQfnumber(res, "srvfdw");
9221         i_srvtype = PQfnumber(res, "srvtype");
9222         i_srvversion = PQfnumber(res, "srvversion");
9223         i_srvacl = PQfnumber(res, "srvacl");
9224         i_rsrvacl = PQfnumber(res, "rsrvacl");
9225         i_initsrvacl = PQfnumber(res, "initsrvacl");
9226         i_initrsrvacl = PQfnumber(res, "initrsrvacl");
9227         i_srvoptions = PQfnumber(res, "srvoptions");
9228
9229         for (i = 0; i < ntups; i++)
9230         {
9231                 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
9232                 srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9233                 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9234                 AssignDumpId(&srvinfo[i].dobj);
9235                 srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
9236                 srvinfo[i].dobj.namespace = NULL;
9237                 srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
9238                 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
9239                 srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
9240                 srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
9241                 srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
9242                 srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
9243                 srvinfo[i].rsrvacl = pg_strdup(PQgetvalue(res, i, i_rsrvacl));
9244                 srvinfo[i].initsrvacl = pg_strdup(PQgetvalue(res, i, i_initsrvacl));
9245                 srvinfo[i].initrsrvacl = pg_strdup(PQgetvalue(res, i, i_initrsrvacl));
9246
9247                 /* Decide whether we want to dump it */
9248                 selectDumpableObject(&(srvinfo[i].dobj), fout);
9249
9250                 /* Do not try to dump ACL if no ACL exists. */
9251                 if (PQgetisnull(res, i, i_srvacl) && PQgetisnull(res, i, i_rsrvacl) &&
9252                         PQgetisnull(res, i, i_initsrvacl) &&
9253                         PQgetisnull(res, i, i_initrsrvacl))
9254                         srvinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
9255         }
9256
9257         PQclear(res);
9258
9259         destroyPQExpBuffer(query);
9260
9261         return srvinfo;
9262 }
9263
9264 /*
9265  * getDefaultACLs:
9266  *        read all default ACL information in the system catalogs and return
9267  *        them in the DefaultACLInfo structure
9268  *
9269  *      numDefaultACLs is set to the number of ACLs read in
9270  */
9271 DefaultACLInfo *
9272 getDefaultACLs(Archive *fout, int *numDefaultACLs)
9273 {
9274         DumpOptions *dopt = fout->dopt;
9275         DefaultACLInfo *daclinfo;
9276         PQExpBuffer query;
9277         PGresult   *res;
9278         int                     i_oid;
9279         int                     i_tableoid;
9280         int                     i_defaclrole;
9281         int                     i_defaclnamespace;
9282         int                     i_defaclobjtype;
9283         int                     i_defaclacl;
9284         int                     i_rdefaclacl;
9285         int                     i_initdefaclacl;
9286         int                     i_initrdefaclacl;
9287         int                     i,
9288                                 ntups;
9289
9290         if (fout->remoteVersion < 90000)
9291         {
9292                 *numDefaultACLs = 0;
9293                 return NULL;
9294         }
9295
9296         query = createPQExpBuffer();
9297
9298         if (fout->remoteVersion >= 90600)
9299         {
9300                 PQExpBuffer acl_subquery = createPQExpBuffer();
9301                 PQExpBuffer racl_subquery = createPQExpBuffer();
9302                 PQExpBuffer initacl_subquery = createPQExpBuffer();
9303                 PQExpBuffer initracl_subquery = createPQExpBuffer();
9304
9305                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9306                                                 initracl_subquery, "defaclacl", "defaclrole",
9307                                                 "CASE WHEN defaclobjtype = 'S' THEN 's' ELSE defaclobjtype END::\"char\"",
9308                                                 dopt->binary_upgrade);
9309
9310                 appendPQExpBuffer(query, "SELECT d.oid, d.tableoid, "
9311                                                   "(%s d.defaclrole) AS defaclrole, "
9312                                                   "d.defaclnamespace, "
9313                                                   "d.defaclobjtype, "
9314                                                   "%s AS defaclacl, "
9315                                                   "%s AS rdefaclacl, "
9316                                                   "%s AS initdefaclacl, "
9317                                                   "%s AS initrdefaclacl "
9318                                                   "FROM pg_default_acl d "
9319                                                   "LEFT JOIN pg_init_privs pip ON "
9320                                                   "(d.oid = pip.objoid "
9321                                                   "AND pip.classoid = 'pg_default_acl'::regclass "
9322                                                   "AND pip.objsubid = 0) ",
9323                                                   username_subquery,
9324                                                   acl_subquery->data,
9325                                                   racl_subquery->data,
9326                                                   initacl_subquery->data,
9327                                                   initracl_subquery->data);
9328         }
9329         else
9330         {
9331                 appendPQExpBuffer(query, "SELECT oid, tableoid, "
9332                                                   "(%s defaclrole) AS defaclrole, "
9333                                                   "defaclnamespace, "
9334                                                   "defaclobjtype, "
9335                                                   "defaclacl, "
9336                                                   "NULL AS rdefaclacl, "
9337                                                   "NULL AS initdefaclacl, "
9338                                                   "NULL AS initrdefaclacl "
9339                                                   "FROM pg_default_acl",
9340                                                   username_subquery);
9341         }
9342
9343         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9344
9345         ntups = PQntuples(res);
9346         *numDefaultACLs = ntups;
9347
9348         daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
9349
9350         i_oid = PQfnumber(res, "oid");
9351         i_tableoid = PQfnumber(res, "tableoid");
9352         i_defaclrole = PQfnumber(res, "defaclrole");
9353         i_defaclnamespace = PQfnumber(res, "defaclnamespace");
9354         i_defaclobjtype = PQfnumber(res, "defaclobjtype");
9355         i_defaclacl = PQfnumber(res, "defaclacl");
9356         i_rdefaclacl = PQfnumber(res, "rdefaclacl");
9357         i_initdefaclacl = PQfnumber(res, "initdefaclacl");
9358         i_initrdefaclacl = PQfnumber(res, "initrdefaclacl");
9359
9360         for (i = 0; i < ntups; i++)
9361         {
9362                 Oid                     nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
9363
9364                 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
9365                 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9366                 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9367                 AssignDumpId(&daclinfo[i].dobj);
9368                 /* cheesy ... is it worth coming up with a better object name? */
9369                 daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
9370
9371                 if (nspid != InvalidOid)
9372                         daclinfo[i].dobj.namespace = findNamespace(fout, nspid);
9373                 else
9374                         daclinfo[i].dobj.namespace = NULL;
9375
9376                 daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
9377                 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
9378                 daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
9379                 daclinfo[i].rdefaclacl = pg_strdup(PQgetvalue(res, i, i_rdefaclacl));
9380                 daclinfo[i].initdefaclacl = pg_strdup(PQgetvalue(res, i, i_initdefaclacl));
9381                 daclinfo[i].initrdefaclacl = pg_strdup(PQgetvalue(res, i, i_initrdefaclacl));
9382
9383                 /* Decide whether we want to dump it */
9384                 selectDumpableDefaultACL(&(daclinfo[i]), dopt);
9385         }
9386
9387         PQclear(res);
9388
9389         destroyPQExpBuffer(query);
9390
9391         return daclinfo;
9392 }
9393
9394 /*
9395  * dumpComment --
9396  *
9397  * This routine is used to dump any comments associated with the
9398  * object handed to this routine. The routine takes the object type
9399  * and object name (ready to print, except for schema decoration), plus
9400  * the namespace and owner of the object (for labeling the ArchiveEntry),
9401  * plus catalog ID and subid which are the lookup key for pg_description,
9402  * plus the dump ID for the object (for setting a dependency).
9403  * If a matching pg_description entry is found, it is dumped.
9404  *
9405  * Note: in some cases, such as comments for triggers and rules, the "type"
9406  * string really looks like, e.g., "TRIGGER name ON".  This is a bit of a hack
9407  * but it doesn't seem worth complicating the API for all callers to make
9408  * it cleaner.
9409  *
9410  * Note: although this routine takes a dumpId for dependency purposes,
9411  * that purpose is just to mark the dependency in the emitted dump file
9412  * for possible future use by pg_restore.  We do NOT use it for determining
9413  * ordering of the comment in the dump file, because this routine is called
9414  * after dependency sorting occurs.  This routine should be called just after
9415  * calling ArchiveEntry() for the specified object.
9416  */
9417 static void
9418 dumpComment(Archive *fout, const char *type, const char *name,
9419                         const char *namespace, const char *owner,
9420                         CatalogId catalogId, int subid, DumpId dumpId)
9421 {
9422         DumpOptions *dopt = fout->dopt;
9423         CommentItem *comments;
9424         int                     ncomments;
9425
9426         /* do nothing, if --no-comments is supplied */
9427         if (dopt->no_comments)
9428                 return;
9429
9430         /* Comments are schema not data ... except blob comments are data */
9431         if (strcmp(type, "LARGE OBJECT") != 0)
9432         {
9433                 if (dopt->dataOnly)
9434                         return;
9435         }
9436         else
9437         {
9438                 /* We do dump blob comments in binary-upgrade mode */
9439                 if (dopt->schemaOnly && !dopt->binary_upgrade)
9440                         return;
9441         }
9442
9443         /* Search for comments associated with catalogId, using table */
9444         ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
9445                                                          &comments);
9446
9447         /* Is there one matching the subid? */
9448         while (ncomments > 0)
9449         {
9450                 if (comments->objsubid == subid)
9451                         break;
9452                 comments++;
9453                 ncomments--;
9454         }
9455
9456         /* If a comment exists, build COMMENT ON statement */
9457         if (ncomments > 0)
9458         {
9459                 PQExpBuffer query = createPQExpBuffer();
9460                 PQExpBuffer tag = createPQExpBuffer();
9461
9462                 appendPQExpBuffer(query, "COMMENT ON %s ", type);
9463                 if (namespace && *namespace)
9464                         appendPQExpBuffer(query, "%s.", fmtId(namespace));
9465                 appendPQExpBuffer(query, "%s IS ", name);
9466                 appendStringLiteralAH(query, comments->descr, fout);
9467                 appendPQExpBufferStr(query, ";\n");
9468
9469                 appendPQExpBuffer(tag, "%s %s", type, name);
9470
9471                 /*
9472                  * We mark comments as SECTION_NONE because they really belong in the
9473                  * same section as their parent, whether that is pre-data or
9474                  * post-data.
9475                  */
9476                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
9477                                          ARCHIVE_OPTS(.tag = tag->data,
9478                                                                   .namespace = namespace,
9479                                                                   .owner = owner,
9480                                                                   .description = "COMMENT",
9481                                                                   .section = SECTION_NONE,
9482                                                                   .createStmt = query->data,
9483                                                                   .deps = &dumpId,
9484                                                                   .nDeps = 1));
9485
9486                 destroyPQExpBuffer(query);
9487                 destroyPQExpBuffer(tag);
9488         }
9489 }
9490
9491 /*
9492  * dumpTableComment --
9493  *
9494  * As above, but dump comments for both the specified table (or view)
9495  * and its columns.
9496  */
9497 static void
9498 dumpTableComment(Archive *fout, TableInfo *tbinfo,
9499                                  const char *reltypename)
9500 {
9501         DumpOptions *dopt = fout->dopt;
9502         CommentItem *comments;
9503         int                     ncomments;
9504         PQExpBuffer query;
9505         PQExpBuffer tag;
9506
9507         /* do nothing, if --no-comments is supplied */
9508         if (dopt->no_comments)
9509                 return;
9510
9511         /* Comments are SCHEMA not data */
9512         if (dopt->dataOnly)
9513                 return;
9514
9515         /* Search for comments associated with relation, using table */
9516         ncomments = findComments(fout,
9517                                                          tbinfo->dobj.catId.tableoid,
9518                                                          tbinfo->dobj.catId.oid,
9519                                                          &comments);
9520
9521         /* If comments exist, build COMMENT ON statements */
9522         if (ncomments <= 0)
9523                 return;
9524
9525         query = createPQExpBuffer();
9526         tag = createPQExpBuffer();
9527
9528         while (ncomments > 0)
9529         {
9530                 const char *descr = comments->descr;
9531                 int                     objsubid = comments->objsubid;
9532
9533                 if (objsubid == 0)
9534                 {
9535                         resetPQExpBuffer(tag);
9536                         appendPQExpBuffer(tag, "%s %s", reltypename,
9537                                                           fmtId(tbinfo->dobj.name));
9538
9539                         resetPQExpBuffer(query);
9540                         appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
9541                                                           fmtQualifiedDumpable(tbinfo));
9542                         appendStringLiteralAH(query, descr, fout);
9543                         appendPQExpBufferStr(query, ";\n");
9544
9545                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
9546                                                  ARCHIVE_OPTS(.tag = tag->data,
9547                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
9548                                                                           .owner = tbinfo->rolname,
9549                                                                           .description = "COMMENT",
9550                                                                           .section = SECTION_NONE,
9551                                                                           .createStmt = query->data,
9552                                                                           .deps = &(tbinfo->dobj.dumpId),
9553                                                                           .nDeps = 1));
9554                 }
9555                 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
9556                 {
9557                         resetPQExpBuffer(tag);
9558                         appendPQExpBuffer(tag, "COLUMN %s.",
9559                                                           fmtId(tbinfo->dobj.name));
9560                         appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
9561
9562                         resetPQExpBuffer(query);
9563                         appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
9564                                                           fmtQualifiedDumpable(tbinfo));
9565                         appendPQExpBuffer(query, "%s IS ",
9566                                                           fmtId(tbinfo->attnames[objsubid - 1]));
9567                         appendStringLiteralAH(query, descr, fout);
9568                         appendPQExpBufferStr(query, ";\n");
9569
9570                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
9571                                                  ARCHIVE_OPTS(.tag = tag->data,
9572                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
9573                                                                           .owner = tbinfo->rolname,
9574                                                                           .description = "COMMENT",
9575                                                                           .section = SECTION_NONE,
9576                                                                           .createStmt = query->data,
9577                                                                           .deps = &(tbinfo->dobj.dumpId),
9578                                                                           .nDeps = 1));
9579                 }
9580
9581                 comments++;
9582                 ncomments--;
9583         }
9584
9585         destroyPQExpBuffer(query);
9586         destroyPQExpBuffer(tag);
9587 }
9588
9589 /*
9590  * findComments --
9591  *
9592  * Find the comment(s), if any, associated with the given object.  All the
9593  * objsubid values associated with the given classoid/objoid are found with
9594  * one search.
9595  */
9596 static int
9597 findComments(Archive *fout, Oid classoid, Oid objoid,
9598                          CommentItem **items)
9599 {
9600         /* static storage for table of comments */
9601         static CommentItem *comments = NULL;
9602         static int      ncomments = -1;
9603
9604         CommentItem *middle = NULL;
9605         CommentItem *low;
9606         CommentItem *high;
9607         int                     nmatch;
9608
9609         /* Get comments if we didn't already */
9610         if (ncomments < 0)
9611                 ncomments = collectComments(fout, &comments);
9612
9613         /*
9614          * Do binary search to find some item matching the object.
9615          */
9616         low = &comments[0];
9617         high = &comments[ncomments - 1];
9618         while (low <= high)
9619         {
9620                 middle = low + (high - low) / 2;
9621
9622                 if (classoid < middle->classoid)
9623                         high = middle - 1;
9624                 else if (classoid > middle->classoid)
9625                         low = middle + 1;
9626                 else if (objoid < middle->objoid)
9627                         high = middle - 1;
9628                 else if (objoid > middle->objoid)
9629                         low = middle + 1;
9630                 else
9631                         break;                          /* found a match */
9632         }
9633
9634         if (low > high)                         /* no matches */
9635         {
9636                 *items = NULL;
9637                 return 0;
9638         }
9639
9640         /*
9641          * Now determine how many items match the object.  The search loop
9642          * invariant still holds: only items between low and high inclusive could
9643          * match.
9644          */
9645         nmatch = 1;
9646         while (middle > low)
9647         {
9648                 if (classoid != middle[-1].classoid ||
9649                         objoid != middle[-1].objoid)
9650                         break;
9651                 middle--;
9652                 nmatch++;
9653         }
9654
9655         *items = middle;
9656
9657         middle += nmatch;
9658         while (middle <= high)
9659         {
9660                 if (classoid != middle->classoid ||
9661                         objoid != middle->objoid)
9662                         break;
9663                 middle++;
9664                 nmatch++;
9665         }
9666
9667         return nmatch;
9668 }
9669
9670 /*
9671  * collectComments --
9672  *
9673  * Construct a table of all comments available for database objects.
9674  * We used to do per-object queries for the comments, but it's much faster
9675  * to pull them all over at once, and on most databases the memory cost
9676  * isn't high.
9677  *
9678  * The table is sorted by classoid/objid/objsubid for speed in lookup.
9679  */
9680 static int
9681 collectComments(Archive *fout, CommentItem **items)
9682 {
9683         PGresult   *res;
9684         PQExpBuffer query;
9685         int                     i_description;
9686         int                     i_classoid;
9687         int                     i_objoid;
9688         int                     i_objsubid;
9689         int                     ntups;
9690         int                     i;
9691         CommentItem *comments;
9692
9693         query = createPQExpBuffer();
9694
9695         appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
9696                                                  "FROM pg_catalog.pg_description "
9697                                                  "ORDER BY classoid, objoid, objsubid");
9698
9699         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9700
9701         /* Construct lookup table containing OIDs in numeric form */
9702
9703         i_description = PQfnumber(res, "description");
9704         i_classoid = PQfnumber(res, "classoid");
9705         i_objoid = PQfnumber(res, "objoid");
9706         i_objsubid = PQfnumber(res, "objsubid");
9707
9708         ntups = PQntuples(res);
9709
9710         comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
9711
9712         for (i = 0; i < ntups; i++)
9713         {
9714                 comments[i].descr = PQgetvalue(res, i, i_description);
9715                 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
9716                 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
9717                 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
9718         }
9719
9720         /* Do NOT free the PGresult since we are keeping pointers into it */
9721         destroyPQExpBuffer(query);
9722
9723         *items = comments;
9724         return ntups;
9725 }
9726
9727 /*
9728  * dumpDumpableObject
9729  *
9730  * This routine and its subsidiaries are responsible for creating
9731  * ArchiveEntries (TOC objects) for each object to be dumped.
9732  */
9733 static void
9734 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
9735 {
9736         switch (dobj->objType)
9737         {
9738                 case DO_NAMESPACE:
9739                         dumpNamespace(fout, (NamespaceInfo *) dobj);
9740                         break;
9741                 case DO_EXTENSION:
9742                         dumpExtension(fout, (ExtensionInfo *) dobj);
9743                         break;
9744                 case DO_TYPE:
9745                         dumpType(fout, (TypeInfo *) dobj);
9746                         break;
9747                 case DO_SHELL_TYPE:
9748                         dumpShellType(fout, (ShellTypeInfo *) dobj);
9749                         break;
9750                 case DO_FUNC:
9751                         dumpFunc(fout, (FuncInfo *) dobj);
9752                         break;
9753                 case DO_AGG:
9754                         dumpAgg(fout, (AggInfo *) dobj);
9755                         break;
9756                 case DO_OPERATOR:
9757                         dumpOpr(fout, (OprInfo *) dobj);
9758                         break;
9759                 case DO_ACCESS_METHOD:
9760                         dumpAccessMethod(fout, (AccessMethodInfo *) dobj);
9761                         break;
9762                 case DO_OPCLASS:
9763                         dumpOpclass(fout, (OpclassInfo *) dobj);
9764                         break;
9765                 case DO_OPFAMILY:
9766                         dumpOpfamily(fout, (OpfamilyInfo *) dobj);
9767                         break;
9768                 case DO_COLLATION:
9769                         dumpCollation(fout, (CollInfo *) dobj);
9770                         break;
9771                 case DO_CONVERSION:
9772                         dumpConversion(fout, (ConvInfo *) dobj);
9773                         break;
9774                 case DO_TABLE:
9775                         dumpTable(fout, (TableInfo *) dobj);
9776                         break;
9777                 case DO_ATTRDEF:
9778                         dumpAttrDef(fout, (AttrDefInfo *) dobj);
9779                         break;
9780                 case DO_INDEX:
9781                         dumpIndex(fout, (IndxInfo *) dobj);
9782                         break;
9783                 case DO_INDEX_ATTACH:
9784                         dumpIndexAttach(fout, (IndexAttachInfo *) dobj);
9785                         break;
9786                 case DO_STATSEXT:
9787                         dumpStatisticsExt(fout, (StatsExtInfo *) dobj);
9788                         break;
9789                 case DO_REFRESH_MATVIEW:
9790                         refreshMatViewData(fout, (TableDataInfo *) dobj);
9791                         break;
9792                 case DO_RULE:
9793                         dumpRule(fout, (RuleInfo *) dobj);
9794                         break;
9795                 case DO_TRIGGER:
9796                         dumpTrigger(fout, (TriggerInfo *) dobj);
9797                         break;
9798                 case DO_EVENT_TRIGGER:
9799                         dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
9800                         break;
9801                 case DO_CONSTRAINT:
9802                         dumpConstraint(fout, (ConstraintInfo *) dobj);
9803                         break;
9804                 case DO_FK_CONSTRAINT:
9805                         dumpConstraint(fout, (ConstraintInfo *) dobj);
9806                         break;
9807                 case DO_PROCLANG:
9808                         dumpProcLang(fout, (ProcLangInfo *) dobj);
9809                         break;
9810                 case DO_CAST:
9811                         dumpCast(fout, (CastInfo *) dobj);
9812                         break;
9813                 case DO_TRANSFORM:
9814                         dumpTransform(fout, (TransformInfo *) dobj);
9815                         break;
9816                 case DO_SEQUENCE_SET:
9817                         dumpSequenceData(fout, (TableDataInfo *) dobj);
9818                         break;
9819                 case DO_TABLE_DATA:
9820                         dumpTableData(fout, (TableDataInfo *) dobj);
9821                         break;
9822                 case DO_DUMMY_TYPE:
9823                         /* table rowtypes and array types are never dumped separately */
9824                         break;
9825                 case DO_TSPARSER:
9826                         dumpTSParser(fout, (TSParserInfo *) dobj);
9827                         break;
9828                 case DO_TSDICT:
9829                         dumpTSDictionary(fout, (TSDictInfo *) dobj);
9830                         break;
9831                 case DO_TSTEMPLATE:
9832                         dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
9833                         break;
9834                 case DO_TSCONFIG:
9835                         dumpTSConfig(fout, (TSConfigInfo *) dobj);
9836                         break;
9837                 case DO_FDW:
9838                         dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
9839                         break;
9840                 case DO_FOREIGN_SERVER:
9841                         dumpForeignServer(fout, (ForeignServerInfo *) dobj);
9842                         break;
9843                 case DO_DEFAULT_ACL:
9844                         dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
9845                         break;
9846                 case DO_BLOB:
9847                         dumpBlob(fout, (BlobInfo *) dobj);
9848                         break;
9849                 case DO_BLOB_DATA:
9850                         if (dobj->dump & DUMP_COMPONENT_DATA)
9851                         {
9852                                 TocEntry   *te;
9853
9854                                 te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
9855                                                                   ARCHIVE_OPTS(.tag = dobj->name,
9856                                                                                            .description = "BLOBS",
9857                                                                                            .section = SECTION_DATA,
9858                                                                                            .dumpFn = dumpBlobs));
9859
9860                                 /*
9861                                  * Set the TocEntry's dataLength in case we are doing a
9862                                  * parallel dump and want to order dump jobs by table size.
9863                                  * (We need some size estimate for every TocEntry with a
9864                                  * DataDumper function.)  We don't currently have any cheap
9865                                  * way to estimate the size of blobs, but it doesn't matter;
9866                                  * let's just set the size to a large value so parallel dumps
9867                                  * will launch this job first.  If there's lots of blobs, we
9868                                  * win, and if there aren't, we don't lose much.  (If you want
9869                                  * to improve on this, really what you should be thinking
9870                                  * about is allowing blob dumping to be parallelized, not just
9871                                  * getting a smarter estimate for the single TOC entry.)
9872                                  */
9873                                 te->dataLength = MaxBlockNumber;
9874                         }
9875                         break;
9876                 case DO_POLICY:
9877                         dumpPolicy(fout, (PolicyInfo *) dobj);
9878                         break;
9879                 case DO_PUBLICATION:
9880                         dumpPublication(fout, (PublicationInfo *) dobj);
9881                         break;
9882                 case DO_PUBLICATION_REL:
9883                         dumpPublicationTable(fout, (PublicationRelInfo *) dobj);
9884                         break;
9885                 case DO_SUBSCRIPTION:
9886                         dumpSubscription(fout, (SubscriptionInfo *) dobj);
9887                         break;
9888                 case DO_PRE_DATA_BOUNDARY:
9889                 case DO_POST_DATA_BOUNDARY:
9890                         /* never dumped, nothing to do */
9891                         break;
9892         }
9893 }
9894
9895 /*
9896  * dumpNamespace
9897  *        writes out to fout the queries to recreate a user-defined namespace
9898  */
9899 static void
9900 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
9901 {
9902         DumpOptions *dopt = fout->dopt;
9903         PQExpBuffer q;
9904         PQExpBuffer delq;
9905         char       *qnspname;
9906
9907         /* Skip if not to be dumped */
9908         if (!nspinfo->dobj.dump || dopt->dataOnly)
9909                 return;
9910
9911         q = createPQExpBuffer();
9912         delq = createPQExpBuffer();
9913
9914         qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
9915
9916         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
9917
9918         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
9919
9920         if (dopt->binary_upgrade)
9921                 binary_upgrade_extension_member(q, &nspinfo->dobj,
9922                                                                                 "SCHEMA", qnspname, NULL);
9923
9924         if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
9925                 ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
9926                                          ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
9927                                                                   .owner = nspinfo->rolname,
9928                                                                   .description = "SCHEMA",
9929                                                                   .section = SECTION_PRE_DATA,
9930                                                                   .createStmt = q->data,
9931                                                                   .dropStmt = delq->data));
9932
9933         /* Dump Schema Comments and Security Labels */
9934         if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
9935                 dumpComment(fout, "SCHEMA", qnspname,
9936                                         NULL, nspinfo->rolname,
9937                                         nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
9938
9939         if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
9940                 dumpSecLabel(fout, "SCHEMA", qnspname,
9941                                          NULL, nspinfo->rolname,
9942                                          nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
9943
9944         if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
9945                 dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
9946                                 qnspname, NULL, NULL,
9947                                 nspinfo->rolname, nspinfo->nspacl, nspinfo->rnspacl,
9948                                 nspinfo->initnspacl, nspinfo->initrnspacl);
9949
9950         free(qnspname);
9951
9952         destroyPQExpBuffer(q);
9953         destroyPQExpBuffer(delq);
9954 }
9955
9956 /*
9957  * dumpExtension
9958  *        writes out to fout the queries to recreate an extension
9959  */
9960 static void
9961 dumpExtension(Archive *fout, ExtensionInfo *extinfo)
9962 {
9963         DumpOptions *dopt = fout->dopt;
9964         PQExpBuffer q;
9965         PQExpBuffer delq;
9966         char       *qextname;
9967
9968         /* Skip if not to be dumped */
9969         if (!extinfo->dobj.dump || dopt->dataOnly)
9970                 return;
9971
9972         q = createPQExpBuffer();
9973         delq = createPQExpBuffer();
9974
9975         qextname = pg_strdup(fmtId(extinfo->dobj.name));
9976
9977         appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
9978
9979         if (!dopt->binary_upgrade)
9980         {
9981                 /*
9982                  * In a regular dump, we simply create the extension, intentionally
9983                  * not specifying a version, so that the destination installation's
9984                  * default version is used.
9985                  *
9986                  * Use of IF NOT EXISTS here is unlike our behavior for other object
9987                  * types; but there are various scenarios in which it's convenient to
9988                  * manually create the desired extension before restoring, so we
9989                  * prefer to allow it to exist already.
9990                  */
9991                 appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
9992                                                   qextname, fmtId(extinfo->namespace));
9993         }
9994         else
9995         {
9996                 /*
9997                  * In binary-upgrade mode, it's critical to reproduce the state of the
9998                  * database exactly, so our procedure is to create an empty extension,
9999                  * restore all the contained objects normally, and add them to the
10000                  * extension one by one.  This function performs just the first of
10001                  * those steps.  binary_upgrade_extension_member() takes care of
10002                  * adding member objects as they're created.
10003                  */
10004                 int                     i;
10005                 int                     n;
10006
10007                 appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
10008
10009                 /*
10010                  * We unconditionally create the extension, so we must drop it if it
10011                  * exists.  This could happen if the user deleted 'plpgsql' and then
10012                  * readded it, causing its oid to be greater than g_last_builtin_oid.
10013                  */
10014                 appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
10015
10016                 appendPQExpBufferStr(q,
10017                                                          "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
10018                 appendStringLiteralAH(q, extinfo->dobj.name, fout);
10019                 appendPQExpBufferStr(q, ", ");
10020                 appendStringLiteralAH(q, extinfo->namespace, fout);
10021                 appendPQExpBufferStr(q, ", ");
10022                 appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
10023                 appendStringLiteralAH(q, extinfo->extversion, fout);
10024                 appendPQExpBufferStr(q, ", ");
10025
10026                 /*
10027                  * Note that we're pushing extconfig (an OID array) back into
10028                  * pg_extension exactly as-is.  This is OK because pg_class OIDs are
10029                  * preserved in binary upgrade.
10030                  */
10031                 if (strlen(extinfo->extconfig) > 2)
10032                         appendStringLiteralAH(q, extinfo->extconfig, fout);
10033                 else
10034                         appendPQExpBufferStr(q, "NULL");
10035                 appendPQExpBufferStr(q, ", ");
10036                 if (strlen(extinfo->extcondition) > 2)
10037                         appendStringLiteralAH(q, extinfo->extcondition, fout);
10038                 else
10039                         appendPQExpBufferStr(q, "NULL");
10040                 appendPQExpBufferStr(q, ", ");
10041                 appendPQExpBufferStr(q, "ARRAY[");
10042                 n = 0;
10043                 for (i = 0; i < extinfo->dobj.nDeps; i++)
10044                 {
10045                         DumpableObject *extobj;
10046
10047                         extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
10048                         if (extobj && extobj->objType == DO_EXTENSION)
10049                         {
10050                                 if (n++ > 0)
10051                                         appendPQExpBufferChar(q, ',');
10052                                 appendStringLiteralAH(q, extobj->name, fout);
10053                         }
10054                 }
10055                 appendPQExpBufferStr(q, "]::pg_catalog.text[]");
10056                 appendPQExpBufferStr(q, ");\n");
10057         }
10058
10059         if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10060                 ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
10061                                          ARCHIVE_OPTS(.tag = extinfo->dobj.name,
10062                                                                   .description = "EXTENSION",
10063                                                                   .section = SECTION_PRE_DATA,
10064                                                                   .createStmt = q->data,
10065                                                                   .dropStmt = delq->data));
10066
10067         /* Dump Extension Comments and Security Labels */
10068         if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10069                 dumpComment(fout, "EXTENSION", qextname,
10070                                         NULL, "",
10071                                         extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
10072
10073         if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10074                 dumpSecLabel(fout, "EXTENSION", qextname,
10075                                          NULL, "",
10076                                          extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
10077
10078         free(qextname);
10079
10080         destroyPQExpBuffer(q);
10081         destroyPQExpBuffer(delq);
10082 }
10083
10084 /*
10085  * dumpType
10086  *        writes out to fout the queries to recreate a user-defined type
10087  */
10088 static void
10089 dumpType(Archive *fout, TypeInfo *tyinfo)
10090 {
10091         DumpOptions *dopt = fout->dopt;
10092
10093         /* Skip if not to be dumped */
10094         if (!tyinfo->dobj.dump || dopt->dataOnly)
10095                 return;
10096
10097         /* Dump out in proper style */
10098         if (tyinfo->typtype == TYPTYPE_BASE)
10099                 dumpBaseType(fout, tyinfo);
10100         else if (tyinfo->typtype == TYPTYPE_DOMAIN)
10101                 dumpDomain(fout, tyinfo);
10102         else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
10103                 dumpCompositeType(fout, tyinfo);
10104         else if (tyinfo->typtype == TYPTYPE_ENUM)
10105                 dumpEnumType(fout, tyinfo);
10106         else if (tyinfo->typtype == TYPTYPE_RANGE)
10107                 dumpRangeType(fout, tyinfo);
10108         else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
10109                 dumpUndefinedType(fout, tyinfo);
10110         else
10111                 pg_log_warning("typtype of data type \"%s\" appears to be invalid",
10112                                   tyinfo->dobj.name);
10113 }
10114
10115 /*
10116  * dumpEnumType
10117  *        writes out to fout the queries to recreate a user-defined enum type
10118  */
10119 static void
10120 dumpEnumType(Archive *fout, TypeInfo *tyinfo)
10121 {
10122         DumpOptions *dopt = fout->dopt;
10123         PQExpBuffer q = createPQExpBuffer();
10124         PQExpBuffer delq = createPQExpBuffer();
10125         PQExpBuffer query = createPQExpBuffer();
10126         PGresult   *res;
10127         int                     num,
10128                                 i;
10129         Oid                     enum_oid;
10130         char       *qtypname;
10131         char       *qualtypname;
10132         char       *label;
10133
10134         if (fout->remoteVersion >= 90100)
10135                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
10136                                                   "FROM pg_catalog.pg_enum "
10137                                                   "WHERE enumtypid = '%u'"
10138                                                   "ORDER BY enumsortorder",
10139                                                   tyinfo->dobj.catId.oid);
10140         else
10141                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
10142                                                   "FROM pg_catalog.pg_enum "
10143                                                   "WHERE enumtypid = '%u'"
10144                                                   "ORDER BY oid",
10145                                                   tyinfo->dobj.catId.oid);
10146
10147         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10148
10149         num = PQntuples(res);
10150
10151         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10152         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10153
10154         /*
10155          * CASCADE shouldn't be required here as for normal types since the I/O
10156          * functions are generic and do not get dropped.
10157          */
10158         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10159
10160         if (dopt->binary_upgrade)
10161                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10162                                                                                                  tyinfo->dobj.catId.oid,
10163                                                                                                  false);
10164
10165         appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
10166                                           qualtypname);
10167
10168         if (!dopt->binary_upgrade)
10169         {
10170                 /* Labels with server-assigned oids */
10171                 for (i = 0; i < num; i++)
10172                 {
10173                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
10174                         if (i > 0)
10175                                 appendPQExpBufferChar(q, ',');
10176                         appendPQExpBufferStr(q, "\n    ");
10177                         appendStringLiteralAH(q, label, fout);
10178                 }
10179         }
10180
10181         appendPQExpBufferStr(q, "\n);\n");
10182
10183         if (dopt->binary_upgrade)
10184         {
10185                 /* Labels with dump-assigned (preserved) oids */
10186                 for (i = 0; i < num; i++)
10187                 {
10188                         enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
10189                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
10190
10191                         if (i == 0)
10192                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
10193                         appendPQExpBuffer(q,
10194                                                           "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
10195                                                           enum_oid);
10196                         appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
10197                         appendStringLiteralAH(q, label, fout);
10198                         appendPQExpBufferStr(q, ";\n\n");
10199                 }
10200         }
10201
10202         if (dopt->binary_upgrade)
10203                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10204                                                                                 "TYPE", qtypname,
10205                                                                                 tyinfo->dobj.namespace->dobj.name);
10206
10207         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10208                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10209                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10210                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10211                                                                   .owner = tyinfo->rolname,
10212                                                                   .description = "TYPE",
10213                                                                   .section = SECTION_PRE_DATA,
10214                                                                   .createStmt = q->data,
10215                                                                   .dropStmt = delq->data));
10216
10217         /* Dump Type Comments and Security Labels */
10218         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10219                 dumpComment(fout, "TYPE", qtypname,
10220                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10221                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10222
10223         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10224                 dumpSecLabel(fout, "TYPE", qtypname,
10225                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10226                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10227
10228         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10229                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10230                                 qtypname, NULL,
10231                                 tyinfo->dobj.namespace->dobj.name,
10232                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10233                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10234
10235         PQclear(res);
10236         destroyPQExpBuffer(q);
10237         destroyPQExpBuffer(delq);
10238         destroyPQExpBuffer(query);
10239         free(qtypname);
10240         free(qualtypname);
10241 }
10242
10243 /*
10244  * dumpRangeType
10245  *        writes out to fout the queries to recreate a user-defined range type
10246  */
10247 static void
10248 dumpRangeType(Archive *fout, TypeInfo *tyinfo)
10249 {
10250         DumpOptions *dopt = fout->dopt;
10251         PQExpBuffer q = createPQExpBuffer();
10252         PQExpBuffer delq = createPQExpBuffer();
10253         PQExpBuffer query = createPQExpBuffer();
10254         PGresult   *res;
10255         Oid                     collationOid;
10256         char       *qtypname;
10257         char       *qualtypname;
10258         char       *procname;
10259
10260         appendPQExpBuffer(query,
10261                                           "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
10262                                           "opc.opcname AS opcname, "
10263                                           "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
10264                                           "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
10265                                           "opc.opcdefault, "
10266                                           "CASE WHEN rngcollation = st.typcollation THEN 0 "
10267                                           "     ELSE rngcollation END AS collation, "
10268                                           "rngcanonical, rngsubdiff "
10269                                           "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
10270                                           "     pg_catalog.pg_opclass opc "
10271                                           "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
10272                                           "rngtypid = '%u'",
10273                                           tyinfo->dobj.catId.oid);
10274
10275         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10276
10277         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10278         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10279
10280         /*
10281          * CASCADE shouldn't be required here as for normal types since the I/O
10282          * functions are generic and do not get dropped.
10283          */
10284         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10285
10286         if (dopt->binary_upgrade)
10287                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10288                                                                                                  tyinfo->dobj.catId.oid,
10289                                                                                                  false);
10290
10291         appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
10292                                           qualtypname);
10293
10294         appendPQExpBuffer(q, "\n    subtype = %s",
10295                                           PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
10296
10297         /* print subtype_opclass only if not default for subtype */
10298         if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
10299         {
10300                 char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
10301                 char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
10302
10303                 appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
10304                                                   fmtId(nspname));
10305                 appendPQExpBufferStr(q, fmtId(opcname));
10306         }
10307
10308         collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
10309         if (OidIsValid(collationOid))
10310         {
10311                 CollInfo   *coll = findCollationByOid(collationOid);
10312
10313                 if (coll)
10314                         appendPQExpBuffer(q, ",\n    collation = %s",
10315                                                           fmtQualifiedDumpable(coll));
10316         }
10317
10318         procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
10319         if (strcmp(procname, "-") != 0)
10320                 appendPQExpBuffer(q, ",\n    canonical = %s", procname);
10321
10322         procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
10323         if (strcmp(procname, "-") != 0)
10324                 appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
10325
10326         appendPQExpBufferStr(q, "\n);\n");
10327
10328         if (dopt->binary_upgrade)
10329                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10330                                                                                 "TYPE", qtypname,
10331                                                                                 tyinfo->dobj.namespace->dobj.name);
10332
10333         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10334                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10335                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10336                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10337                                                                   .owner = tyinfo->rolname,
10338                                                                   .description = "TYPE",
10339                                                                   .section = SECTION_PRE_DATA,
10340                                                                   .createStmt = q->data,
10341                                                                   .dropStmt = delq->data));
10342
10343         /* Dump Type Comments and Security Labels */
10344         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10345                 dumpComment(fout, "TYPE", qtypname,
10346                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10347                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10348
10349         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10350                 dumpSecLabel(fout, "TYPE", qtypname,
10351                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10352                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10353
10354         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10355                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10356                                 qtypname, NULL,
10357                                 tyinfo->dobj.namespace->dobj.name,
10358                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10359                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10360
10361         PQclear(res);
10362         destroyPQExpBuffer(q);
10363         destroyPQExpBuffer(delq);
10364         destroyPQExpBuffer(query);
10365         free(qtypname);
10366         free(qualtypname);
10367 }
10368
10369 /*
10370  * dumpUndefinedType
10371  *        writes out to fout the queries to recreate a !typisdefined type
10372  *
10373  * This is a shell type, but we use different terminology to distinguish
10374  * this case from where we have to emit a shell type definition to break
10375  * circular dependencies.  An undefined type shouldn't ever have anything
10376  * depending on it.
10377  */
10378 static void
10379 dumpUndefinedType(Archive *fout, TypeInfo *tyinfo)
10380 {
10381         DumpOptions *dopt = fout->dopt;
10382         PQExpBuffer q = createPQExpBuffer();
10383         PQExpBuffer delq = createPQExpBuffer();
10384         char       *qtypname;
10385         char       *qualtypname;
10386
10387         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10388         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10389
10390         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10391
10392         if (dopt->binary_upgrade)
10393                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10394                                                                                                  tyinfo->dobj.catId.oid,
10395                                                                                                  false);
10396
10397         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
10398                                           qualtypname);
10399
10400         if (dopt->binary_upgrade)
10401                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10402                                                                                 "TYPE", qtypname,
10403                                                                                 tyinfo->dobj.namespace->dobj.name);
10404
10405         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10406                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10407                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10408                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10409                                                                   .owner = tyinfo->rolname,
10410                                                                   .description = "TYPE",
10411                                                                   .section = SECTION_PRE_DATA,
10412                                                                   .createStmt = q->data,
10413                                                                   .dropStmt = delq->data));
10414
10415         /* Dump Type Comments and Security Labels */
10416         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10417                 dumpComment(fout, "TYPE", qtypname,
10418                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10419                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10420
10421         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10422                 dumpSecLabel(fout, "TYPE", qtypname,
10423                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10424                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10425
10426         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10427                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10428                                 qtypname, NULL,
10429                                 tyinfo->dobj.namespace->dobj.name,
10430                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10431                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10432
10433         destroyPQExpBuffer(q);
10434         destroyPQExpBuffer(delq);
10435         free(qtypname);
10436         free(qualtypname);
10437 }
10438
10439 /*
10440  * dumpBaseType
10441  *        writes out to fout the queries to recreate a user-defined base type
10442  */
10443 static void
10444 dumpBaseType(Archive *fout, TypeInfo *tyinfo)
10445 {
10446         DumpOptions *dopt = fout->dopt;
10447         PQExpBuffer q = createPQExpBuffer();
10448         PQExpBuffer delq = createPQExpBuffer();
10449         PQExpBuffer query = createPQExpBuffer();
10450         PGresult   *res;
10451         char       *qtypname;
10452         char       *qualtypname;
10453         char       *typlen;
10454         char       *typinput;
10455         char       *typoutput;
10456         char       *typreceive;
10457         char       *typsend;
10458         char       *typmodin;
10459         char       *typmodout;
10460         char       *typanalyze;
10461         Oid                     typreceiveoid;
10462         Oid                     typsendoid;
10463         Oid                     typmodinoid;
10464         Oid                     typmodoutoid;
10465         Oid                     typanalyzeoid;
10466         char       *typcategory;
10467         char       *typispreferred;
10468         char       *typdelim;
10469         char       *typbyval;
10470         char       *typalign;
10471         char       *typstorage;
10472         char       *typcollatable;
10473         char       *typdefault;
10474         bool            typdefault_is_literal = false;
10475
10476         /* Fetch type-specific details */
10477         if (fout->remoteVersion >= 90100)
10478         {
10479                 appendPQExpBuffer(query, "SELECT typlen, "
10480                                                   "typinput, typoutput, typreceive, typsend, "
10481                                                   "typmodin, typmodout, typanalyze, "
10482                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10483                                                   "typsend::pg_catalog.oid AS typsendoid, "
10484                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10485                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10486                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10487                                                   "typcategory, typispreferred, "
10488                                                   "typdelim, typbyval, typalign, typstorage, "
10489                                                   "(typcollation <> 0) AS typcollatable, "
10490                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
10491                                                   "FROM pg_catalog.pg_type "
10492                                                   "WHERE oid = '%u'::pg_catalog.oid",
10493                                                   tyinfo->dobj.catId.oid);
10494         }
10495         else if (fout->remoteVersion >= 80400)
10496         {
10497                 appendPQExpBuffer(query, "SELECT typlen, "
10498                                                   "typinput, typoutput, typreceive, typsend, "
10499                                                   "typmodin, typmodout, typanalyze, "
10500                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10501                                                   "typsend::pg_catalog.oid AS typsendoid, "
10502                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10503                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10504                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10505                                                   "typcategory, typispreferred, "
10506                                                   "typdelim, typbyval, typalign, typstorage, "
10507                                                   "false AS typcollatable, "
10508                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
10509                                                   "FROM pg_catalog.pg_type "
10510                                                   "WHERE oid = '%u'::pg_catalog.oid",
10511                                                   tyinfo->dobj.catId.oid);
10512         }
10513         else if (fout->remoteVersion >= 80300)
10514         {
10515                 /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
10516                 appendPQExpBuffer(query, "SELECT typlen, "
10517                                                   "typinput, typoutput, typreceive, typsend, "
10518                                                   "typmodin, typmodout, typanalyze, "
10519                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10520                                                   "typsend::pg_catalog.oid AS typsendoid, "
10521                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10522                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10523                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10524                                                   "'U' AS typcategory, false AS typispreferred, "
10525                                                   "typdelim, typbyval, typalign, typstorage, "
10526                                                   "false AS typcollatable, "
10527                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10528                                                   "FROM pg_catalog.pg_type "
10529                                                   "WHERE oid = '%u'::pg_catalog.oid",
10530                                                   tyinfo->dobj.catId.oid);
10531         }
10532         else
10533         {
10534                 appendPQExpBuffer(query, "SELECT typlen, "
10535                                                   "typinput, typoutput, typreceive, typsend, "
10536                                                   "'-' AS typmodin, '-' AS typmodout, "
10537                                                   "typanalyze, "
10538                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10539                                                   "typsend::pg_catalog.oid AS typsendoid, "
10540                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
10541                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10542                                                   "'U' AS typcategory, false AS typispreferred, "
10543                                                   "typdelim, typbyval, typalign, typstorage, "
10544                                                   "false AS typcollatable, "
10545                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10546                                                   "FROM pg_catalog.pg_type "
10547                                                   "WHERE oid = '%u'::pg_catalog.oid",
10548                                                   tyinfo->dobj.catId.oid);
10549         }
10550
10551         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10552
10553         typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
10554         typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
10555         typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
10556         typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
10557         typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
10558         typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
10559         typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
10560         typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
10561         typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
10562         typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
10563         typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
10564         typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
10565         typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
10566         typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
10567         typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
10568         typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
10569         typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
10570         typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
10571         typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
10572         typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
10573         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
10574                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
10575         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
10576         {
10577                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
10578                 typdefault_is_literal = true;   /* it needs quotes */
10579         }
10580         else
10581                 typdefault = NULL;
10582
10583         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10584         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10585
10586         /*
10587          * The reason we include CASCADE is that the circular dependency between
10588          * the type and its I/O functions makes it impossible to drop the type any
10589          * other way.
10590          */
10591         appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
10592
10593         /*
10594          * We might already have a shell type, but setting pg_type_oid is
10595          * harmless, and in any case we'd better set the array type OID.
10596          */
10597         if (dopt->binary_upgrade)
10598                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10599                                                                                                  tyinfo->dobj.catId.oid,
10600                                                                                                  false);
10601
10602         appendPQExpBuffer(q,
10603                                           "CREATE TYPE %s (\n"
10604                                           "    INTERNALLENGTH = %s",
10605                                           qualtypname,
10606                                           (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
10607
10608         /* regproc result is sufficiently quoted already */
10609         appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
10610         appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
10611         if (OidIsValid(typreceiveoid))
10612                 appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
10613         if (OidIsValid(typsendoid))
10614                 appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
10615         if (OidIsValid(typmodinoid))
10616                 appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
10617         if (OidIsValid(typmodoutoid))
10618                 appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
10619         if (OidIsValid(typanalyzeoid))
10620                 appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
10621
10622         if (strcmp(typcollatable, "t") == 0)
10623                 appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
10624
10625         if (typdefault != NULL)
10626         {
10627                 appendPQExpBufferStr(q, ",\n    DEFAULT = ");
10628                 if (typdefault_is_literal)
10629                         appendStringLiteralAH(q, typdefault, fout);
10630                 else
10631                         appendPQExpBufferStr(q, typdefault);
10632         }
10633
10634         if (OidIsValid(tyinfo->typelem))
10635         {
10636                 char       *elemType;
10637
10638                 elemType = getFormattedTypeName(fout, tyinfo->typelem, zeroAsOpaque);
10639                 appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
10640                 free(elemType);
10641         }
10642
10643         if (strcmp(typcategory, "U") != 0)
10644         {
10645                 appendPQExpBufferStr(q, ",\n    CATEGORY = ");
10646                 appendStringLiteralAH(q, typcategory, fout);
10647         }
10648
10649         if (strcmp(typispreferred, "t") == 0)
10650                 appendPQExpBufferStr(q, ",\n    PREFERRED = true");
10651
10652         if (typdelim && strcmp(typdelim, ",") != 0)
10653         {
10654                 appendPQExpBufferStr(q, ",\n    DELIMITER = ");
10655                 appendStringLiteralAH(q, typdelim, fout);
10656         }
10657
10658         if (strcmp(typalign, "c") == 0)
10659                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
10660         else if (strcmp(typalign, "s") == 0)
10661                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
10662         else if (strcmp(typalign, "i") == 0)
10663                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
10664         else if (strcmp(typalign, "d") == 0)
10665                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
10666
10667         if (strcmp(typstorage, "p") == 0)
10668                 appendPQExpBufferStr(q, ",\n    STORAGE = plain");
10669         else if (strcmp(typstorage, "e") == 0)
10670                 appendPQExpBufferStr(q, ",\n    STORAGE = external");
10671         else if (strcmp(typstorage, "x") == 0)
10672                 appendPQExpBufferStr(q, ",\n    STORAGE = extended");
10673         else if (strcmp(typstorage, "m") == 0)
10674                 appendPQExpBufferStr(q, ",\n    STORAGE = main");
10675
10676         if (strcmp(typbyval, "t") == 0)
10677                 appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
10678
10679         appendPQExpBufferStr(q, "\n);\n");
10680
10681         if (dopt->binary_upgrade)
10682                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10683                                                                                 "TYPE", qtypname,
10684                                                                                 tyinfo->dobj.namespace->dobj.name);
10685
10686         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10687                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10688                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10689                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10690                                                                   .owner = tyinfo->rolname,
10691                                                                   .description = "TYPE",
10692                                                                   .section = SECTION_PRE_DATA,
10693                                                                   .createStmt = q->data,
10694                                                                   .dropStmt = delq->data));
10695
10696         /* Dump Type Comments and Security Labels */
10697         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10698                 dumpComment(fout, "TYPE", qtypname,
10699                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10700                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10701
10702         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10703                 dumpSecLabel(fout, "TYPE", qtypname,
10704                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10705                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10706
10707         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10708                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10709                                 qtypname, NULL,
10710                                 tyinfo->dobj.namespace->dobj.name,
10711                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10712                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10713
10714         PQclear(res);
10715         destroyPQExpBuffer(q);
10716         destroyPQExpBuffer(delq);
10717         destroyPQExpBuffer(query);
10718         free(qtypname);
10719         free(qualtypname);
10720 }
10721
10722 /*
10723  * dumpDomain
10724  *        writes out to fout the queries to recreate a user-defined domain
10725  */
10726 static void
10727 dumpDomain(Archive *fout, TypeInfo *tyinfo)
10728 {
10729         DumpOptions *dopt = fout->dopt;
10730         PQExpBuffer q = createPQExpBuffer();
10731         PQExpBuffer delq = createPQExpBuffer();
10732         PQExpBuffer query = createPQExpBuffer();
10733         PGresult   *res;
10734         int                     i;
10735         char       *qtypname;
10736         char       *qualtypname;
10737         char       *typnotnull;
10738         char       *typdefn;
10739         char       *typdefault;
10740         Oid                     typcollation;
10741         bool            typdefault_is_literal = false;
10742
10743         /* Fetch domain specific details */
10744         if (fout->remoteVersion >= 90100)
10745         {
10746                 /* typcollation is new in 9.1 */
10747                 appendPQExpBuffer(query, "SELECT t.typnotnull, "
10748                                                   "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
10749                                                   "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
10750                                                   "t.typdefault, "
10751                                                   "CASE WHEN t.typcollation <> u.typcollation "
10752                                                   "THEN t.typcollation ELSE 0 END AS typcollation "
10753                                                   "FROM pg_catalog.pg_type t "
10754                                                   "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
10755                                                   "WHERE t.oid = '%u'::pg_catalog.oid",
10756                                                   tyinfo->dobj.catId.oid);
10757         }
10758         else
10759         {
10760                 appendPQExpBuffer(query, "SELECT typnotnull, "
10761                                                   "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
10762                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
10763                                                   "typdefault, 0 AS typcollation "
10764                                                   "FROM pg_catalog.pg_type "
10765                                                   "WHERE oid = '%u'::pg_catalog.oid",
10766                                                   tyinfo->dobj.catId.oid);
10767         }
10768
10769         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10770
10771         typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
10772         typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
10773         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
10774                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
10775         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
10776         {
10777                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
10778                 typdefault_is_literal = true;   /* it needs quotes */
10779         }
10780         else
10781                 typdefault = NULL;
10782         typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
10783
10784         if (dopt->binary_upgrade)
10785                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10786                                                                                                  tyinfo->dobj.catId.oid,
10787                                                                                                  true); /* force array type */
10788
10789         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10790         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10791
10792         appendPQExpBuffer(q,
10793                                           "CREATE DOMAIN %s AS %s",
10794                                           qualtypname,
10795                                           typdefn);
10796
10797         /* Print collation only if different from base type's collation */
10798         if (OidIsValid(typcollation))
10799         {
10800                 CollInfo   *coll;
10801
10802                 coll = findCollationByOid(typcollation);
10803                 if (coll)
10804                         appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
10805         }
10806
10807         if (typnotnull[0] == 't')
10808                 appendPQExpBufferStr(q, " NOT NULL");
10809
10810         if (typdefault != NULL)
10811         {
10812                 appendPQExpBufferStr(q, " DEFAULT ");
10813                 if (typdefault_is_literal)
10814                         appendStringLiteralAH(q, typdefault, fout);
10815                 else
10816                         appendPQExpBufferStr(q, typdefault);
10817         }
10818
10819         PQclear(res);
10820
10821         /*
10822          * Add any CHECK constraints for the domain
10823          */
10824         for (i = 0; i < tyinfo->nDomChecks; i++)
10825         {
10826                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
10827
10828                 if (!domcheck->separate)
10829                         appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
10830                                                           fmtId(domcheck->dobj.name), domcheck->condef);
10831         }
10832
10833         appendPQExpBufferStr(q, ";\n");
10834
10835         appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
10836
10837         if (dopt->binary_upgrade)
10838                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10839                                                                                 "DOMAIN", qtypname,
10840                                                                                 tyinfo->dobj.namespace->dobj.name);
10841
10842         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10843                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10844                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10845                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10846                                                                   .owner = tyinfo->rolname,
10847                                                                   .description = "DOMAIN",
10848                                                                   .section = SECTION_PRE_DATA,
10849                                                                   .createStmt = q->data,
10850                                                                   .dropStmt = delq->data));
10851
10852         /* Dump Domain Comments and Security Labels */
10853         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10854                 dumpComment(fout, "DOMAIN", qtypname,
10855                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10856                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10857
10858         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10859                 dumpSecLabel(fout, "DOMAIN", qtypname,
10860                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10861                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10862
10863         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10864                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10865                                 qtypname, NULL,
10866                                 tyinfo->dobj.namespace->dobj.name,
10867                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10868                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10869
10870         /* Dump any per-constraint comments */
10871         for (i = 0; i < tyinfo->nDomChecks; i++)
10872         {
10873                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
10874                 PQExpBuffer conprefix = createPQExpBuffer();
10875
10876                 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
10877                                                   fmtId(domcheck->dobj.name));
10878
10879                 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10880                         dumpComment(fout, conprefix->data, qtypname,
10881                                                 tyinfo->dobj.namespace->dobj.name,
10882                                                 tyinfo->rolname,
10883                                                 domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
10884
10885                 destroyPQExpBuffer(conprefix);
10886         }
10887
10888         destroyPQExpBuffer(q);
10889         destroyPQExpBuffer(delq);
10890         destroyPQExpBuffer(query);
10891         free(qtypname);
10892         free(qualtypname);
10893 }
10894
10895 /*
10896  * dumpCompositeType
10897  *        writes out to fout the queries to recreate a user-defined stand-alone
10898  *        composite type
10899  */
10900 static void
10901 dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
10902 {
10903         DumpOptions *dopt = fout->dopt;
10904         PQExpBuffer q = createPQExpBuffer();
10905         PQExpBuffer dropped = createPQExpBuffer();
10906         PQExpBuffer delq = createPQExpBuffer();
10907         PQExpBuffer query = createPQExpBuffer();
10908         PGresult   *res;
10909         char       *qtypname;
10910         char       *qualtypname;
10911         int                     ntups;
10912         int                     i_attname;
10913         int                     i_atttypdefn;
10914         int                     i_attlen;
10915         int                     i_attalign;
10916         int                     i_attisdropped;
10917         int                     i_attcollation;
10918         int                     i;
10919         int                     actual_atts;
10920
10921         /* Fetch type specific details */
10922         if (fout->remoteVersion >= 90100)
10923         {
10924                 /*
10925                  * attcollation is new in 9.1.  Since we only want to dump COLLATE
10926                  * clauses for attributes whose collation is different from their
10927                  * type's default, we use a CASE here to suppress uninteresting
10928                  * attcollations cheaply.  atttypid will be 0 for dropped columns;
10929                  * collation does not matter for those.
10930                  */
10931                 appendPQExpBuffer(query, "SELECT a.attname, "
10932                                                   "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
10933                                                   "a.attlen, a.attalign, a.attisdropped, "
10934                                                   "CASE WHEN a.attcollation <> at.typcollation "
10935                                                   "THEN a.attcollation ELSE 0 END AS attcollation "
10936                                                   "FROM pg_catalog.pg_type ct "
10937                                                   "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
10938                                                   "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
10939                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
10940                                                   "ORDER BY a.attnum ",
10941                                                   tyinfo->dobj.catId.oid);
10942         }
10943         else
10944         {
10945                 /*
10946                  * Since ALTER TYPE could not drop columns until 9.1, attisdropped
10947                  * should always be false.
10948                  */
10949                 appendPQExpBuffer(query, "SELECT a.attname, "
10950                                                   "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
10951                                                   "a.attlen, a.attalign, a.attisdropped, "
10952                                                   "0 AS attcollation "
10953                                                   "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
10954                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
10955                                                   "AND a.attrelid = ct.typrelid "
10956                                                   "ORDER BY a.attnum ",
10957                                                   tyinfo->dobj.catId.oid);
10958         }
10959
10960         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10961
10962         ntups = PQntuples(res);
10963
10964         i_attname = PQfnumber(res, "attname");
10965         i_atttypdefn = PQfnumber(res, "atttypdefn");
10966         i_attlen = PQfnumber(res, "attlen");
10967         i_attalign = PQfnumber(res, "attalign");
10968         i_attisdropped = PQfnumber(res, "attisdropped");
10969         i_attcollation = PQfnumber(res, "attcollation");
10970
10971         if (dopt->binary_upgrade)
10972         {
10973                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10974                                                                                                  tyinfo->dobj.catId.oid,
10975                                                                                                  false);
10976                 binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid, false);
10977         }
10978
10979         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10980         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10981
10982         appendPQExpBuffer(q, "CREATE TYPE %s AS (",
10983                                           qualtypname);
10984
10985         actual_atts = 0;
10986         for (i = 0; i < ntups; i++)
10987         {
10988                 char       *attname;
10989                 char       *atttypdefn;
10990                 char       *attlen;
10991                 char       *attalign;
10992                 bool            attisdropped;
10993                 Oid                     attcollation;
10994
10995                 attname = PQgetvalue(res, i, i_attname);
10996                 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
10997                 attlen = PQgetvalue(res, i, i_attlen);
10998                 attalign = PQgetvalue(res, i, i_attalign);
10999                 attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
11000                 attcollation = atooid(PQgetvalue(res, i, i_attcollation));
11001
11002                 if (attisdropped && !dopt->binary_upgrade)
11003                         continue;
11004
11005                 /* Format properly if not first attr */
11006                 if (actual_atts++ > 0)
11007                         appendPQExpBufferChar(q, ',');
11008                 appendPQExpBufferStr(q, "\n\t");
11009
11010                 if (!attisdropped)
11011                 {
11012                         appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
11013
11014                         /* Add collation if not default for the column type */
11015                         if (OidIsValid(attcollation))
11016                         {
11017                                 CollInfo   *coll;
11018
11019                                 coll = findCollationByOid(attcollation);
11020                                 if (coll)
11021                                         appendPQExpBuffer(q, " COLLATE %s",
11022                                                                           fmtQualifiedDumpable(coll));
11023                         }
11024                 }
11025                 else
11026                 {
11027                         /*
11028                          * This is a dropped attribute and we're in binary_upgrade mode.
11029                          * Insert a placeholder for it in the CREATE TYPE command, and set
11030                          * length and alignment with direct UPDATE to the catalogs
11031                          * afterwards. See similar code in dumpTableSchema().
11032                          */
11033                         appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
11034
11035                         /* stash separately for insertion after the CREATE TYPE */
11036                         appendPQExpBufferStr(dropped,
11037                                                                  "\n-- For binary upgrade, recreate dropped column.\n");
11038                         appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
11039                                                           "SET attlen = %s, "
11040                                                           "attalign = '%s', attbyval = false\n"
11041                                                           "WHERE attname = ", attlen, attalign);
11042                         appendStringLiteralAH(dropped, attname, fout);
11043                         appendPQExpBufferStr(dropped, "\n  AND attrelid = ");
11044                         appendStringLiteralAH(dropped, qualtypname, fout);
11045                         appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
11046
11047                         appendPQExpBuffer(dropped, "ALTER TYPE %s ",
11048                                                           qualtypname);
11049                         appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
11050                                                           fmtId(attname));
11051                 }
11052         }
11053         appendPQExpBufferStr(q, "\n);\n");
11054         appendPQExpBufferStr(q, dropped->data);
11055
11056         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
11057
11058         if (dopt->binary_upgrade)
11059                 binary_upgrade_extension_member(q, &tyinfo->dobj,
11060                                                                                 "TYPE", qtypname,
11061                                                                                 tyinfo->dobj.namespace->dobj.name);
11062
11063         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11064                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
11065                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
11066                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
11067                                                                   .owner = tyinfo->rolname,
11068                                                                   .description = "TYPE",
11069                                                                   .section = SECTION_PRE_DATA,
11070                                                                   .createStmt = q->data,
11071                                                                   .dropStmt = delq->data));
11072
11073
11074         /* Dump Type Comments and Security Labels */
11075         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11076                 dumpComment(fout, "TYPE", qtypname,
11077                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11078                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11079
11080         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11081                 dumpSecLabel(fout, "TYPE", qtypname,
11082                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11083                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11084
11085         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
11086                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
11087                                 qtypname, NULL,
11088                                 tyinfo->dobj.namespace->dobj.name,
11089                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
11090                                 tyinfo->inittypacl, tyinfo->initrtypacl);
11091
11092         PQclear(res);
11093         destroyPQExpBuffer(q);
11094         destroyPQExpBuffer(dropped);
11095         destroyPQExpBuffer(delq);
11096         destroyPQExpBuffer(query);
11097         free(qtypname);
11098         free(qualtypname);
11099
11100         /* Dump any per-column comments */
11101         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11102                 dumpCompositeTypeColComments(fout, tyinfo);
11103 }
11104
11105 /*
11106  * dumpCompositeTypeColComments
11107  *        writes out to fout the queries to recreate comments on the columns of
11108  *        a user-defined stand-alone composite type
11109  */
11110 static void
11111 dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
11112 {
11113         CommentItem *comments;
11114         int                     ncomments;
11115         PGresult   *res;
11116         PQExpBuffer query;
11117         PQExpBuffer target;
11118         Oid                     pgClassOid;
11119         int                     i;
11120         int                     ntups;
11121         int                     i_attname;
11122         int                     i_attnum;
11123
11124         /* do nothing, if --no-comments is supplied */
11125         if (fout->dopt->no_comments)
11126                 return;
11127
11128         query = createPQExpBuffer();
11129
11130         appendPQExpBuffer(query,
11131                                           "SELECT c.tableoid, a.attname, a.attnum "
11132                                           "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
11133                                           "WHERE c.oid = '%u' AND c.oid = a.attrelid "
11134                                           "  AND NOT a.attisdropped "
11135                                           "ORDER BY a.attnum ",
11136                                           tyinfo->typrelid);
11137
11138         /* Fetch column attnames */
11139         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11140
11141         ntups = PQntuples(res);
11142         if (ntups < 1)
11143         {
11144                 PQclear(res);
11145                 destroyPQExpBuffer(query);
11146                 return;
11147         }
11148
11149         pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
11150
11151         /* Search for comments associated with type's pg_class OID */
11152         ncomments = findComments(fout,
11153                                                          pgClassOid,
11154                                                          tyinfo->typrelid,
11155                                                          &comments);
11156
11157         /* If no comments exist, we're done */
11158         if (ncomments <= 0)
11159         {
11160                 PQclear(res);
11161                 destroyPQExpBuffer(query);
11162                 return;
11163         }
11164
11165         /* Build COMMENT ON statements */
11166         target = createPQExpBuffer();
11167
11168         i_attnum = PQfnumber(res, "attnum");
11169         i_attname = PQfnumber(res, "attname");
11170         while (ncomments > 0)
11171         {
11172                 const char *attname;
11173
11174                 attname = NULL;
11175                 for (i = 0; i < ntups; i++)
11176                 {
11177                         if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
11178                         {
11179                                 attname = PQgetvalue(res, i, i_attname);
11180                                 break;
11181                         }
11182                 }
11183                 if (attname)                    /* just in case we don't find it */
11184                 {
11185                         const char *descr = comments->descr;
11186
11187                         resetPQExpBuffer(target);
11188                         appendPQExpBuffer(target, "COLUMN %s.",
11189                                                           fmtId(tyinfo->dobj.name));
11190                         appendPQExpBufferStr(target, fmtId(attname));
11191
11192                         resetPQExpBuffer(query);
11193                         appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
11194                                                           fmtQualifiedDumpable(tyinfo));
11195                         appendPQExpBuffer(query, "%s IS ", fmtId(attname));
11196                         appendStringLiteralAH(query, descr, fout);
11197                         appendPQExpBufferStr(query, ";\n");
11198
11199                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
11200                                                  ARCHIVE_OPTS(.tag = target->data,
11201                                                                           .namespace = tyinfo->dobj.namespace->dobj.name,
11202                                                                           .owner = tyinfo->rolname,
11203                                                                           .description = "COMMENT",
11204                                                                           .section = SECTION_NONE,
11205                                                                           .createStmt = query->data,
11206                                                                           .deps = &(tyinfo->dobj.dumpId),
11207                                                                           .nDeps = 1));
11208                 }
11209
11210                 comments++;
11211                 ncomments--;
11212         }
11213
11214         PQclear(res);
11215         destroyPQExpBuffer(query);
11216         destroyPQExpBuffer(target);
11217 }
11218
11219 /*
11220  * dumpShellType
11221  *        writes out to fout the queries to create a shell type
11222  *
11223  * We dump a shell definition in advance of the I/O functions for the type.
11224  */
11225 static void
11226 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
11227 {
11228         DumpOptions *dopt = fout->dopt;
11229         PQExpBuffer q;
11230
11231         /* Skip if not to be dumped */
11232         if (!stinfo->dobj.dump || dopt->dataOnly)
11233                 return;
11234
11235         q = createPQExpBuffer();
11236
11237         /*
11238          * Note the lack of a DROP command for the shell type; any required DROP
11239          * is driven off the base type entry, instead.  This interacts with
11240          * _printTocEntry()'s use of the presence of a DROP command to decide
11241          * whether an entry needs an ALTER OWNER command.  We don't want to alter
11242          * the shell type's owner immediately on creation; that should happen only
11243          * after it's filled in, otherwise the backend complains.
11244          */
11245
11246         if (dopt->binary_upgrade)
11247                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
11248                                                                                                  stinfo->baseType->dobj.catId.oid,
11249                                                                                                  false);
11250
11251         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
11252                                           fmtQualifiedDumpable(stinfo));
11253
11254         if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11255                 ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
11256                                          ARCHIVE_OPTS(.tag = stinfo->dobj.name,
11257                                                                   .namespace = stinfo->dobj.namespace->dobj.name,
11258                                                                   .owner = stinfo->baseType->rolname,
11259                                                                   .description = "SHELL TYPE",
11260                                                                   .section = SECTION_PRE_DATA,
11261                                                                   .createStmt = q->data));
11262
11263         destroyPQExpBuffer(q);
11264 }
11265
11266 /*
11267  * dumpProcLang
11268  *                writes out to fout the queries to recreate a user-defined
11269  *                procedural language
11270  */
11271 static void
11272 dumpProcLang(Archive *fout, ProcLangInfo *plang)
11273 {
11274         DumpOptions *dopt = fout->dopt;
11275         PQExpBuffer defqry;
11276         PQExpBuffer delqry;
11277         bool            useParams;
11278         char       *qlanname;
11279         FuncInfo   *funcInfo;
11280         FuncInfo   *inlineInfo = NULL;
11281         FuncInfo   *validatorInfo = NULL;
11282
11283         /* Skip if not to be dumped */
11284         if (!plang->dobj.dump || dopt->dataOnly)
11285                 return;
11286
11287         /*
11288          * Try to find the support function(s).  It is not an error if we don't
11289          * find them --- if the functions are in the pg_catalog schema, as is
11290          * standard in 8.1 and up, then we won't have loaded them. (In this case
11291          * we will emit a parameterless CREATE LANGUAGE command, which will
11292          * require PL template knowledge in the backend to reload.)
11293          */
11294
11295         funcInfo = findFuncByOid(plang->lanplcallfoid);
11296         if (funcInfo != NULL && !funcInfo->dobj.dump)
11297                 funcInfo = NULL;                /* treat not-dumped same as not-found */
11298
11299         if (OidIsValid(plang->laninline))
11300         {
11301                 inlineInfo = findFuncByOid(plang->laninline);
11302                 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
11303                         inlineInfo = NULL;
11304         }
11305
11306         if (OidIsValid(plang->lanvalidator))
11307         {
11308                 validatorInfo = findFuncByOid(plang->lanvalidator);
11309                 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
11310                         validatorInfo = NULL;
11311         }
11312
11313         /*
11314          * If the functions are dumpable then emit a traditional CREATE LANGUAGE
11315          * with parameters.  Otherwise, we'll write a parameterless command, which
11316          * will rely on data from pg_pltemplate.
11317          */
11318         useParams = (funcInfo != NULL &&
11319                                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
11320                                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
11321
11322         defqry = createPQExpBuffer();
11323         delqry = createPQExpBuffer();
11324
11325         qlanname = pg_strdup(fmtId(plang->dobj.name));
11326
11327         appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
11328                                           qlanname);
11329
11330         if (useParams)
11331         {
11332                 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
11333                                                   plang->lanpltrusted ? "TRUSTED " : "",
11334                                                   qlanname);
11335                 appendPQExpBuffer(defqry, " HANDLER %s",
11336                                                   fmtQualifiedDumpable(funcInfo));
11337                 if (OidIsValid(plang->laninline))
11338                         appendPQExpBuffer(defqry, " INLINE %s",
11339                                                           fmtQualifiedDumpable(inlineInfo));
11340                 if (OidIsValid(plang->lanvalidator))
11341                         appendPQExpBuffer(defqry, " VALIDATOR %s",
11342                                                           fmtQualifiedDumpable(validatorInfo));
11343         }
11344         else
11345         {
11346                 /*
11347                  * If not dumping parameters, then use CREATE OR REPLACE so that the
11348                  * command will not fail if the language is preinstalled in the target
11349                  * database.  We restrict the use of REPLACE to this case so as to
11350                  * eliminate the risk of replacing a language with incompatible
11351                  * parameter settings: this command will only succeed at all if there
11352                  * is a pg_pltemplate entry, and if there is one, the existing entry
11353                  * must match it too.
11354                  */
11355                 appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
11356                                                   qlanname);
11357         }
11358         appendPQExpBufferStr(defqry, ";\n");
11359
11360         if (dopt->binary_upgrade)
11361                 binary_upgrade_extension_member(defqry, &plang->dobj,
11362                                                                                 "LANGUAGE", qlanname, NULL);
11363
11364         if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
11365                 ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
11366                                          ARCHIVE_OPTS(.tag = plang->dobj.name,
11367                                                                   .owner = plang->lanowner,
11368                                                                   .description = "PROCEDURAL LANGUAGE",
11369                                                                   .section = SECTION_PRE_DATA,
11370                                                                   .createStmt = defqry->data,
11371                                                                   .dropStmt = delqry->data,
11372                                                                   ));
11373
11374         /* Dump Proc Lang Comments and Security Labels */
11375         if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
11376                 dumpComment(fout, "LANGUAGE", qlanname,
11377                                         NULL, plang->lanowner,
11378                                         plang->dobj.catId, 0, plang->dobj.dumpId);
11379
11380         if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
11381                 dumpSecLabel(fout, "LANGUAGE", qlanname,
11382                                          NULL, plang->lanowner,
11383                                          plang->dobj.catId, 0, plang->dobj.dumpId);
11384
11385         if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
11386                 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
11387                                 qlanname, NULL, NULL,
11388                                 plang->lanowner, plang->lanacl, plang->rlanacl,
11389                                 plang->initlanacl, plang->initrlanacl);
11390
11391         free(qlanname);
11392
11393         destroyPQExpBuffer(defqry);
11394         destroyPQExpBuffer(delqry);
11395 }
11396
11397 /*
11398  * format_function_arguments: generate function name and argument list
11399  *
11400  * This is used when we can rely on pg_get_function_arguments to format
11401  * the argument list.  Note, however, that pg_get_function_arguments
11402  * does not special-case zero-argument aggregates.
11403  */
11404 static char *
11405 format_function_arguments(FuncInfo *finfo, char *funcargs, bool is_agg)
11406 {
11407         PQExpBufferData fn;
11408
11409         initPQExpBuffer(&fn);
11410         appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
11411         if (is_agg && finfo->nargs == 0)
11412                 appendPQExpBufferStr(&fn, "(*)");
11413         else
11414                 appendPQExpBuffer(&fn, "(%s)", funcargs);
11415         return fn.data;
11416 }
11417
11418 /*
11419  * format_function_arguments_old: generate function name and argument list
11420  *
11421  * The argument type names are qualified if needed.  The function name
11422  * is never qualified.
11423  *
11424  * This is used only with pre-8.4 servers, so we aren't expecting to see
11425  * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
11426  *
11427  * Any or all of allargtypes, argmodes, argnames may be NULL.
11428  */
11429 static char *
11430 format_function_arguments_old(Archive *fout,
11431                                                           FuncInfo *finfo, int nallargs,
11432                                                           char **allargtypes,
11433                                                           char **argmodes,
11434                                                           char **argnames)
11435 {
11436         PQExpBufferData fn;
11437         int                     j;
11438
11439         initPQExpBuffer(&fn);
11440         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11441         for (j = 0; j < nallargs; j++)
11442         {
11443                 Oid                     typid;
11444                 char       *typname;
11445                 const char *argmode;
11446                 const char *argname;
11447
11448                 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
11449                 typname = getFormattedTypeName(fout, typid, zeroAsOpaque);
11450
11451                 if (argmodes)
11452                 {
11453                         switch (argmodes[j][0])
11454                         {
11455                                 case PROARGMODE_IN:
11456                                         argmode = "";
11457                                         break;
11458                                 case PROARGMODE_OUT:
11459                                         argmode = "OUT ";
11460                                         break;
11461                                 case PROARGMODE_INOUT:
11462                                         argmode = "INOUT ";
11463                                         break;
11464                                 default:
11465                                         pg_log_warning("bogus value in proargmodes array");
11466                                         argmode = "";
11467                                         break;
11468                         }
11469                 }
11470                 else
11471                         argmode = "";
11472
11473                 argname = argnames ? argnames[j] : (char *) NULL;
11474                 if (argname && argname[0] == '\0')
11475                         argname = NULL;
11476
11477                 appendPQExpBuffer(&fn, "%s%s%s%s%s",
11478                                                   (j > 0) ? ", " : "",
11479                                                   argmode,
11480                                                   argname ? fmtId(argname) : "",
11481                                                   argname ? " " : "",
11482                                                   typname);
11483                 free(typname);
11484         }
11485         appendPQExpBufferChar(&fn, ')');
11486         return fn.data;
11487 }
11488
11489 /*
11490  * format_function_signature: generate function name and argument list
11491  *
11492  * This is like format_function_arguments_old except that only a minimal
11493  * list of input argument types is generated; this is sufficient to
11494  * reference the function, but not to define it.
11495  *
11496  * If honor_quotes is false then the function name is never quoted.
11497  * This is appropriate for use in TOC tags, but not in SQL commands.
11498  */
11499 static char *
11500 format_function_signature(Archive *fout, FuncInfo *finfo, bool honor_quotes)
11501 {
11502         PQExpBufferData fn;
11503         int                     j;
11504
11505         initPQExpBuffer(&fn);
11506         if (honor_quotes)
11507                 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11508         else
11509                 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
11510         for (j = 0; j < finfo->nargs; j++)
11511         {
11512                 char       *typname;
11513
11514                 if (j > 0)
11515                         appendPQExpBufferStr(&fn, ", ");
11516
11517                 typname = getFormattedTypeName(fout, finfo->argtypes[j],
11518                                                                            zeroAsOpaque);
11519                 appendPQExpBufferStr(&fn, typname);
11520                 free(typname);
11521         }
11522         appendPQExpBufferChar(&fn, ')');
11523         return fn.data;
11524 }
11525
11526
11527 /*
11528  * dumpFunc:
11529  *        dump out one function
11530  */
11531 static void
11532 dumpFunc(Archive *fout, FuncInfo *finfo)
11533 {
11534         DumpOptions *dopt = fout->dopt;
11535         PQExpBuffer query;
11536         PQExpBuffer q;
11537         PQExpBuffer delqry;
11538         PQExpBuffer asPart;
11539         PGresult   *res;
11540         char       *funcsig;            /* identity signature */
11541         char       *funcfullsig = NULL; /* full signature */
11542         char       *funcsig_tag;
11543         char       *proretset;
11544         char       *prosrc;
11545         char       *probin;
11546         char       *funcargs;
11547         char       *funciargs;
11548         char       *funcresult;
11549         char       *proallargtypes;
11550         char       *proargmodes;
11551         char       *proargnames;
11552         char       *protrftypes;
11553         char       *prokind;
11554         char       *provolatile;
11555         char       *proisstrict;
11556         char       *prosecdef;
11557         char       *proleakproof;
11558         char       *proconfig;
11559         char       *procost;
11560         char       *prorows;
11561         char       *prosupport;
11562         char       *proparallel;
11563         char       *lanname;
11564         char       *rettypename;
11565         int                     nallargs;
11566         char      **allargtypes = NULL;
11567         char      **argmodes = NULL;
11568         char      **argnames = NULL;
11569         char      **configitems = NULL;
11570         int                     nconfigitems = 0;
11571         const char *keyword;
11572         int                     i;
11573
11574         /* Skip if not to be dumped */
11575         if (!finfo->dobj.dump || dopt->dataOnly)
11576                 return;
11577
11578         query = createPQExpBuffer();
11579         q = createPQExpBuffer();
11580         delqry = createPQExpBuffer();
11581         asPart = createPQExpBuffer();
11582
11583         /* Fetch function-specific details */
11584         if (fout->remoteVersion >= 120000)
11585         {
11586                 /*
11587                  * prosupport was added in 12
11588                  */
11589                 appendPQExpBuffer(query,
11590                                                   "SELECT proretset, prosrc, probin, "
11591                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11592                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11593                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11594                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11595                                                   "prokind, provolatile, proisstrict, prosecdef, "
11596                                                   "proleakproof, proconfig, procost, prorows, "
11597                                                   "prosupport, proparallel, "
11598                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11599                                                   "FROM pg_catalog.pg_proc "
11600                                                   "WHERE oid = '%u'::pg_catalog.oid",
11601                                                   finfo->dobj.catId.oid);
11602         }
11603         else if (fout->remoteVersion >= 110000)
11604         {
11605                 /*
11606                  * prokind was added in 11
11607                  */
11608                 appendPQExpBuffer(query,
11609                                                   "SELECT proretset, prosrc, probin, "
11610                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11611                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11612                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11613                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11614                                                   "prokind, provolatile, proisstrict, prosecdef, "
11615                                                   "proleakproof, proconfig, procost, prorows, "
11616                                                   "'-' AS prosupport, proparallel, "
11617                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11618                                                   "FROM pg_catalog.pg_proc "
11619                                                   "WHERE oid = '%u'::pg_catalog.oid",
11620                                                   finfo->dobj.catId.oid);
11621         }
11622         else if (fout->remoteVersion >= 90600)
11623         {
11624                 /*
11625                  * proparallel was added in 9.6
11626                  */
11627                 appendPQExpBuffer(query,
11628                                                   "SELECT proretset, prosrc, probin, "
11629                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11630                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11631                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11632                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11633                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11634                                                   "provolatile, proisstrict, prosecdef, "
11635                                                   "proleakproof, proconfig, procost, prorows, "
11636                                                   "'-' AS prosupport, proparallel, "
11637                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11638                                                   "FROM pg_catalog.pg_proc "
11639                                                   "WHERE oid = '%u'::pg_catalog.oid",
11640                                                   finfo->dobj.catId.oid);
11641         }
11642         else if (fout->remoteVersion >= 90500)
11643         {
11644                 /*
11645                  * protrftypes was added in 9.5
11646                  */
11647                 appendPQExpBuffer(query,
11648                                                   "SELECT proretset, prosrc, probin, "
11649                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11650                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11651                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11652                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11653                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11654                                                   "provolatile, proisstrict, prosecdef, "
11655                                                   "proleakproof, proconfig, procost, prorows, "
11656                                                   "'-' AS prosupport, "
11657                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11658                                                   "FROM pg_catalog.pg_proc "
11659                                                   "WHERE oid = '%u'::pg_catalog.oid",
11660                                                   finfo->dobj.catId.oid);
11661         }
11662         else if (fout->remoteVersion >= 90200)
11663         {
11664                 /*
11665                  * proleakproof was added in 9.2
11666                  */
11667                 appendPQExpBuffer(query,
11668                                                   "SELECT proretset, prosrc, probin, "
11669                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11670                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11671                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11672                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11673                                                   "provolatile, proisstrict, prosecdef, "
11674                                                   "proleakproof, proconfig, procost, prorows, "
11675                                                   "'-' AS prosupport, "
11676                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11677                                                   "FROM pg_catalog.pg_proc "
11678                                                   "WHERE oid = '%u'::pg_catalog.oid",
11679                                                   finfo->dobj.catId.oid);
11680         }
11681         else if (fout->remoteVersion >= 80400)
11682         {
11683                 /*
11684                  * In 8.4 and up we rely on pg_get_function_arguments and
11685                  * pg_get_function_result instead of examining proallargtypes etc.
11686                  */
11687                 appendPQExpBuffer(query,
11688                                                   "SELECT proretset, prosrc, probin, "
11689                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11690                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11691                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11692                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11693                                                   "provolatile, proisstrict, prosecdef, "
11694                                                   "false AS proleakproof, "
11695                                                   " proconfig, procost, prorows, "
11696                                                   "'-' AS prosupport, "
11697                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11698                                                   "FROM pg_catalog.pg_proc "
11699                                                   "WHERE oid = '%u'::pg_catalog.oid",
11700                                                   finfo->dobj.catId.oid);
11701         }
11702         else if (fout->remoteVersion >= 80300)
11703         {
11704                 appendPQExpBuffer(query,
11705                                                   "SELECT proretset, prosrc, probin, "
11706                                                   "proallargtypes, proargmodes, proargnames, "
11707                                                   "'f' AS prokind, "
11708                                                   "provolatile, proisstrict, prosecdef, "
11709                                                   "false AS proleakproof, "
11710                                                   "proconfig, procost, prorows, "
11711                                                   "'-' AS prosupport, "
11712                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11713                                                   "FROM pg_catalog.pg_proc "
11714                                                   "WHERE oid = '%u'::pg_catalog.oid",
11715                                                   finfo->dobj.catId.oid);
11716         }
11717         else if (fout->remoteVersion >= 80100)
11718         {
11719                 appendPQExpBuffer(query,
11720                                                   "SELECT proretset, prosrc, probin, "
11721                                                   "proallargtypes, proargmodes, proargnames, "
11722                                                   "'f' AS prokind, "
11723                                                   "provolatile, proisstrict, prosecdef, "
11724                                                   "false AS proleakproof, "
11725                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
11726                                                   "'-' AS prosupport, "
11727                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11728                                                   "FROM pg_catalog.pg_proc "
11729                                                   "WHERE oid = '%u'::pg_catalog.oid",
11730                                                   finfo->dobj.catId.oid);
11731         }
11732         else
11733         {
11734                 appendPQExpBuffer(query,
11735                                                   "SELECT proretset, prosrc, probin, "
11736                                                   "null AS proallargtypes, "
11737                                                   "null AS proargmodes, "
11738                                                   "proargnames, "
11739                                                   "'f' AS prokind, "
11740                                                   "provolatile, proisstrict, prosecdef, "
11741                                                   "false AS proleakproof, "
11742                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
11743                                                   "'-' AS prosupport, "
11744                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11745                                                   "FROM pg_catalog.pg_proc "
11746                                                   "WHERE oid = '%u'::pg_catalog.oid",
11747                                                   finfo->dobj.catId.oid);
11748         }
11749
11750         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11751
11752         proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
11753         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
11754         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
11755         if (fout->remoteVersion >= 80400)
11756         {
11757                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
11758                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
11759                 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
11760                 proallargtypes = proargmodes = proargnames = NULL;
11761         }
11762         else
11763         {
11764                 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
11765                 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
11766                 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
11767                 funcargs = funciargs = funcresult = NULL;
11768         }
11769         if (PQfnumber(res, "protrftypes") != -1)
11770                 protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
11771         else
11772                 protrftypes = NULL;
11773         prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
11774         provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
11775         proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
11776         prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
11777         proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
11778         proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
11779         procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
11780         prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
11781         prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
11782
11783         if (PQfnumber(res, "proparallel") != -1)
11784                 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
11785         else
11786                 proparallel = NULL;
11787
11788         lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
11789
11790         /*
11791          * See backend/commands/functioncmds.c for details of how the 'AS' clause
11792          * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
11793          * versions would set it to "-".  There are no known cases in which prosrc
11794          * is unused, so the tests below for "-" are probably useless.
11795          */
11796         if (probin[0] != '\0' && strcmp(probin, "-") != 0)
11797         {
11798                 appendPQExpBufferStr(asPart, "AS ");
11799                 appendStringLiteralAH(asPart, probin, fout);
11800                 if (strcmp(prosrc, "-") != 0)
11801                 {
11802                         appendPQExpBufferStr(asPart, ", ");
11803
11804                         /*
11805                          * where we have bin, use dollar quoting if allowed and src
11806                          * contains quote or backslash; else use regular quoting.
11807                          */
11808                         if (dopt->disable_dollar_quoting ||
11809                                 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
11810                                 appendStringLiteralAH(asPart, prosrc, fout);
11811                         else
11812                                 appendStringLiteralDQ(asPart, prosrc, NULL);
11813                 }
11814         }
11815         else
11816         {
11817                 if (strcmp(prosrc, "-") != 0)
11818                 {
11819                         appendPQExpBufferStr(asPart, "AS ");
11820                         /* with no bin, dollar quote src unconditionally if allowed */
11821                         if (dopt->disable_dollar_quoting)
11822                                 appendStringLiteralAH(asPart, prosrc, fout);
11823                         else
11824                                 appendStringLiteralDQ(asPart, prosrc, NULL);
11825                 }
11826         }
11827
11828         nallargs = finfo->nargs;        /* unless we learn different from allargs */
11829
11830         if (proallargtypes && *proallargtypes)
11831         {
11832                 int                     nitems = 0;
11833
11834                 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
11835                         nitems < finfo->nargs)
11836                 {
11837                         pg_log_warning("could not parse proallargtypes array");
11838                         if (allargtypes)
11839                                 free(allargtypes);
11840                         allargtypes = NULL;
11841                 }
11842                 else
11843                         nallargs = nitems;
11844         }
11845
11846         if (proargmodes && *proargmodes)
11847         {
11848                 int                     nitems = 0;
11849
11850                 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
11851                         nitems != nallargs)
11852                 {
11853                         pg_log_warning("could not parse proargmodes array");
11854                         if (argmodes)
11855                                 free(argmodes);
11856                         argmodes = NULL;
11857                 }
11858         }
11859
11860         if (proargnames && *proargnames)
11861         {
11862                 int                     nitems = 0;
11863
11864                 if (!parsePGArray(proargnames, &argnames, &nitems) ||
11865                         nitems != nallargs)
11866                 {
11867                         pg_log_warning("could not parse proargnames array");
11868                         if (argnames)
11869                                 free(argnames);
11870                         argnames = NULL;
11871                 }
11872         }
11873
11874         if (proconfig && *proconfig)
11875         {
11876                 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
11877                 {
11878                         pg_log_warning("could not parse proconfig array");
11879                         if (configitems)
11880                                 free(configitems);
11881                         configitems = NULL;
11882                         nconfigitems = 0;
11883                 }
11884         }
11885
11886         if (funcargs)
11887         {
11888                 /* 8.4 or later; we rely on server-side code for most of the work */
11889                 funcfullsig = format_function_arguments(finfo, funcargs, false);
11890                 funcsig = format_function_arguments(finfo, funciargs, false);
11891         }
11892         else
11893                 /* pre-8.4, do it ourselves */
11894                 funcsig = format_function_arguments_old(fout,
11895                                                                                                 finfo, nallargs, allargtypes,
11896                                                                                                 argmodes, argnames);
11897
11898         funcsig_tag = format_function_signature(fout, finfo, false);
11899
11900         if (prokind[0] == PROKIND_PROCEDURE)
11901                 keyword = "PROCEDURE";
11902         else
11903                 keyword = "FUNCTION";   /* works for window functions too */
11904
11905         appendPQExpBuffer(delqry, "DROP %s %s.%s;\n",
11906                                           keyword,
11907                                           fmtId(finfo->dobj.namespace->dobj.name),
11908                                           funcsig);
11909
11910         appendPQExpBuffer(q, "CREATE %s %s.%s",
11911                                           keyword,
11912                                           fmtId(finfo->dobj.namespace->dobj.name),
11913                                           funcfullsig ? funcfullsig :
11914                                           funcsig);
11915
11916         if (prokind[0] == PROKIND_PROCEDURE)
11917                  /* no result type to output */ ;
11918         else if (funcresult)
11919                 appendPQExpBuffer(q, " RETURNS %s", funcresult);
11920         else
11921         {
11922                 rettypename = getFormattedTypeName(fout, finfo->prorettype,
11923                                                                                    zeroAsOpaque);
11924                 appendPQExpBuffer(q, " RETURNS %s%s",
11925                                                   (proretset[0] == 't') ? "SETOF " : "",
11926                                                   rettypename);
11927                 free(rettypename);
11928         }
11929
11930         appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
11931
11932         if (protrftypes != NULL && strcmp(protrftypes, "") != 0)
11933         {
11934                 Oid                *typeids = palloc(FUNC_MAX_ARGS * sizeof(Oid));
11935                 int                     i;
11936
11937                 appendPQExpBufferStr(q, " TRANSFORM ");
11938                 parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
11939                 for (i = 0; typeids[i]; i++)
11940                 {
11941                         if (i != 0)
11942                                 appendPQExpBufferStr(q, ", ");
11943                         appendPQExpBuffer(q, "FOR TYPE %s",
11944                                                           getFormattedTypeName(fout, typeids[i], zeroAsNone));
11945                 }
11946         }
11947
11948         if (prokind[0] == PROKIND_WINDOW)
11949                 appendPQExpBufferStr(q, " WINDOW");
11950
11951         if (provolatile[0] != PROVOLATILE_VOLATILE)
11952         {
11953                 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
11954                         appendPQExpBufferStr(q, " IMMUTABLE");
11955                 else if (provolatile[0] == PROVOLATILE_STABLE)
11956                         appendPQExpBufferStr(q, " STABLE");
11957                 else if (provolatile[0] != PROVOLATILE_VOLATILE)
11958                         fatal("unrecognized provolatile value for function \"%s\"",
11959                                                   finfo->dobj.name);
11960         }
11961
11962         if (proisstrict[0] == 't')
11963                 appendPQExpBufferStr(q, " STRICT");
11964
11965         if (prosecdef[0] == 't')
11966                 appendPQExpBufferStr(q, " SECURITY DEFINER");
11967
11968         if (proleakproof[0] == 't')
11969                 appendPQExpBufferStr(q, " LEAKPROOF");
11970
11971         /*
11972          * COST and ROWS are emitted only if present and not default, so as not to
11973          * break backwards-compatibility of the dump without need.  Keep this code
11974          * in sync with the defaults in functioncmds.c.
11975          */
11976         if (strcmp(procost, "0") != 0)
11977         {
11978                 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
11979                 {
11980                         /* default cost is 1 */
11981                         if (strcmp(procost, "1") != 0)
11982                                 appendPQExpBuffer(q, " COST %s", procost);
11983                 }
11984                 else
11985                 {
11986                         /* default cost is 100 */
11987                         if (strcmp(procost, "100") != 0)
11988                                 appendPQExpBuffer(q, " COST %s", procost);
11989                 }
11990         }
11991         if (proretset[0] == 't' &&
11992                 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
11993                 appendPQExpBuffer(q, " ROWS %s", prorows);
11994
11995         if (strcmp(prosupport, "-") != 0)
11996         {
11997                 /* We rely on regprocout to provide quoting and qualification */
11998                 appendPQExpBuffer(q, " SUPPORT %s", prosupport);
11999         }
12000
12001         if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
12002         {
12003                 if (proparallel[0] == PROPARALLEL_SAFE)
12004                         appendPQExpBufferStr(q, " PARALLEL SAFE");
12005                 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
12006                         appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
12007                 else if (proparallel[0] != PROPARALLEL_UNSAFE)
12008                         fatal("unrecognized proparallel value for function \"%s\"",
12009                                                   finfo->dobj.name);
12010         }
12011
12012         for (i = 0; i < nconfigitems; i++)
12013         {
12014                 /* we feel free to scribble on configitems[] here */
12015                 char       *configitem = configitems[i];
12016                 char       *pos;
12017
12018                 pos = strchr(configitem, '=');
12019                 if (pos == NULL)
12020                         continue;
12021                 *pos++ = '\0';
12022                 appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
12023
12024                 /*
12025                  * Variables that are marked GUC_LIST_QUOTE were already fully quoted
12026                  * by flatten_set_variable_args() before they were put into the
12027                  * proconfig array.  However, because the quoting rules used there
12028                  * aren't exactly like SQL's, we have to break the list value apart
12029                  * and then quote the elements as string literals.  (The elements may
12030                  * be double-quoted as-is, but we can't just feed them to the SQL
12031                  * parser; it would do the wrong thing with elements that are
12032                  * zero-length or longer than NAMEDATALEN.)
12033                  *
12034                  * Variables that are not so marked should just be emitted as simple
12035                  * string literals.  If the variable is not known to
12036                  * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
12037                  * to use GUC_LIST_QUOTE for extension variables.
12038                  */
12039                 if (variable_is_guc_list_quote(configitem))
12040                 {
12041                         char      **namelist;
12042                         char      **nameptr;
12043
12044                         /* Parse string into list of identifiers */
12045                         /* this shouldn't fail really */
12046                         if (SplitGUCList(pos, ',', &namelist))
12047                         {
12048                                 for (nameptr = namelist; *nameptr; nameptr++)
12049                                 {
12050                                         if (nameptr != namelist)
12051                                                 appendPQExpBufferStr(q, ", ");
12052                                         appendStringLiteralAH(q, *nameptr, fout);
12053                                 }
12054                         }
12055                         pg_free(namelist);
12056                 }
12057                 else
12058                         appendStringLiteralAH(q, pos, fout);
12059         }
12060
12061         appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
12062
12063         if (dopt->binary_upgrade)
12064                 binary_upgrade_extension_member(q, &finfo->dobj,
12065                                                                                 keyword, funcsig,
12066                                                                                 finfo->dobj.namespace->dobj.name);
12067
12068         if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12069                 ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
12070                                          ARCHIVE_OPTS(.tag = funcsig_tag,
12071                                                                   .namespace = finfo->dobj.namespace->dobj.name,
12072                                                                   .owner = finfo->rolname,
12073                                                                   .description = keyword,
12074                                                                   .section = SECTION_PRE_DATA,
12075                                                                   .createStmt = q->data,
12076                                                                   .dropStmt = delqry->data));
12077
12078         /* Dump Function Comments and Security Labels */
12079         if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12080                 dumpComment(fout, keyword, funcsig,
12081                                         finfo->dobj.namespace->dobj.name, finfo->rolname,
12082                                         finfo->dobj.catId, 0, finfo->dobj.dumpId);
12083
12084         if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
12085                 dumpSecLabel(fout, keyword, funcsig,
12086                                          finfo->dobj.namespace->dobj.name, finfo->rolname,
12087                                          finfo->dobj.catId, 0, finfo->dobj.dumpId);
12088
12089         if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
12090                 dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, keyword,
12091                                 funcsig, NULL,
12092                                 finfo->dobj.namespace->dobj.name,
12093                                 finfo->rolname, finfo->proacl, finfo->rproacl,
12094                                 finfo->initproacl, finfo->initrproacl);
12095
12096         PQclear(res);
12097
12098         destroyPQExpBuffer(query);
12099         destroyPQExpBuffer(q);
12100         destroyPQExpBuffer(delqry);
12101         destroyPQExpBuffer(asPart);
12102         free(funcsig);
12103         if (funcfullsig)
12104                 free(funcfullsig);
12105         free(funcsig_tag);
12106         if (allargtypes)
12107                 free(allargtypes);
12108         if (argmodes)
12109                 free(argmodes);
12110         if (argnames)
12111                 free(argnames);
12112         if (configitems)
12113                 free(configitems);
12114 }
12115
12116
12117 /*
12118  * Dump a user-defined cast
12119  */
12120 static void
12121 dumpCast(Archive *fout, CastInfo *cast)
12122 {
12123         DumpOptions *dopt = fout->dopt;
12124         PQExpBuffer defqry;
12125         PQExpBuffer delqry;
12126         PQExpBuffer labelq;
12127         PQExpBuffer castargs;
12128         FuncInfo   *funcInfo = NULL;
12129         char       *sourceType;
12130         char       *targetType;
12131
12132         /* Skip if not to be dumped */
12133         if (!cast->dobj.dump || dopt->dataOnly)
12134                 return;
12135
12136         /* Cannot dump if we don't have the cast function's info */
12137         if (OidIsValid(cast->castfunc))
12138         {
12139                 funcInfo = findFuncByOid(cast->castfunc);
12140                 if (funcInfo == NULL)
12141                         fatal("could not find function definition for function with OID %u",
12142                                                   cast->castfunc);
12143         }
12144
12145         defqry = createPQExpBuffer();
12146         delqry = createPQExpBuffer();
12147         labelq = createPQExpBuffer();
12148         castargs = createPQExpBuffer();
12149
12150         sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
12151         targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
12152         appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
12153                                           sourceType, targetType);
12154
12155         appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
12156                                           sourceType, targetType);
12157
12158         switch (cast->castmethod)
12159         {
12160                 case COERCION_METHOD_BINARY:
12161                         appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
12162                         break;
12163                 case COERCION_METHOD_INOUT:
12164                         appendPQExpBufferStr(defqry, "WITH INOUT");
12165                         break;
12166                 case COERCION_METHOD_FUNCTION:
12167                         if (funcInfo)
12168                         {
12169                                 char       *fsig = format_function_signature(fout, funcInfo, true);
12170
12171                                 /*
12172                                  * Always qualify the function name (format_function_signature
12173                                  * won't qualify it).
12174                                  */
12175                                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
12176                                                                   fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
12177                                 free(fsig);
12178                         }
12179                         else
12180                                 pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
12181                         break;
12182                 default:
12183                         pg_log_warning("bogus value in pg_cast.castmethod field");
12184         }
12185
12186         if (cast->castcontext == 'a')
12187                 appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
12188         else if (cast->castcontext == 'i')
12189                 appendPQExpBufferStr(defqry, " AS IMPLICIT");
12190         appendPQExpBufferStr(defqry, ";\n");
12191
12192         appendPQExpBuffer(labelq, "CAST (%s AS %s)",
12193                                           sourceType, targetType);
12194
12195         appendPQExpBuffer(castargs, "(%s AS %s)",
12196                                           sourceType, targetType);
12197
12198         if (dopt->binary_upgrade)
12199                 binary_upgrade_extension_member(defqry, &cast->dobj,
12200                                                                                 "CAST", castargs->data, NULL);
12201
12202         if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
12203                 ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
12204                                          ARCHIVE_OPTS(.tag = labelq->data,
12205                                                                   .description = "CAST",
12206                                                                   .section = SECTION_PRE_DATA,
12207                                                                   .createStmt = defqry->data,
12208                                                                   .dropStmt = delqry->data));
12209
12210         /* Dump Cast Comments */
12211         if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
12212                 dumpComment(fout, "CAST", castargs->data,
12213                                         NULL, "",
12214                                         cast->dobj.catId, 0, cast->dobj.dumpId);
12215
12216         free(sourceType);
12217         free(targetType);
12218
12219         destroyPQExpBuffer(defqry);
12220         destroyPQExpBuffer(delqry);
12221         destroyPQExpBuffer(labelq);
12222         destroyPQExpBuffer(castargs);
12223 }
12224
12225 /*
12226  * Dump a transform
12227  */
12228 static void
12229 dumpTransform(Archive *fout, TransformInfo *transform)
12230 {
12231         DumpOptions *dopt = fout->dopt;
12232         PQExpBuffer defqry;
12233         PQExpBuffer delqry;
12234         PQExpBuffer labelq;
12235         PQExpBuffer transformargs;
12236         FuncInfo   *fromsqlFuncInfo = NULL;
12237         FuncInfo   *tosqlFuncInfo = NULL;
12238         char       *lanname;
12239         char       *transformType;
12240
12241         /* Skip if not to be dumped */
12242         if (!transform->dobj.dump || dopt->dataOnly)
12243                 return;
12244
12245         /* Cannot dump if we don't have the transform functions' info */
12246         if (OidIsValid(transform->trffromsql))
12247         {
12248                 fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
12249                 if (fromsqlFuncInfo == NULL)
12250                         fatal("could not find function definition for function with OID %u",
12251                                                   transform->trffromsql);
12252         }
12253         if (OidIsValid(transform->trftosql))
12254         {
12255                 tosqlFuncInfo = findFuncByOid(transform->trftosql);
12256                 if (tosqlFuncInfo == NULL)
12257                         fatal("could not find function definition for function with OID %u",
12258                                                   transform->trftosql);
12259         }
12260
12261         defqry = createPQExpBuffer();
12262         delqry = createPQExpBuffer();
12263         labelq = createPQExpBuffer();
12264         transformargs = createPQExpBuffer();
12265
12266         lanname = get_language_name(fout, transform->trflang);
12267         transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
12268
12269         appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
12270                                           transformType, lanname);
12271
12272         appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
12273                                           transformType, lanname);
12274
12275         if (!transform->trffromsql && !transform->trftosql)
12276                 pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
12277
12278         if (transform->trffromsql)
12279         {
12280                 if (fromsqlFuncInfo)
12281                 {
12282                         char       *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
12283
12284                         /*
12285                          * Always qualify the function name (format_function_signature
12286                          * won't qualify it).
12287                          */
12288                         appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
12289                                                           fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
12290                         free(fsig);
12291                 }
12292                 else
12293                         pg_log_warning("bogus value in pg_transform.trffromsql field");
12294         }
12295
12296         if (transform->trftosql)
12297         {
12298                 if (transform->trffromsql)
12299                         appendPQExpBuffer(defqry, ", ");
12300
12301                 if (tosqlFuncInfo)
12302                 {
12303                         char       *fsig = format_function_signature(fout, tosqlFuncInfo, true);
12304
12305                         /*
12306                          * Always qualify the function name (format_function_signature
12307                          * won't qualify it).
12308                          */
12309                         appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
12310                                                           fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
12311                         free(fsig);
12312                 }
12313                 else
12314                         pg_log_warning("bogus value in pg_transform.trftosql field");
12315         }
12316
12317         appendPQExpBuffer(defqry, ");\n");
12318
12319         appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
12320                                           transformType, lanname);
12321
12322         appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
12323                                           transformType, lanname);
12324
12325         if (dopt->binary_upgrade)
12326                 binary_upgrade_extension_member(defqry, &transform->dobj,
12327                                                                                 "TRANSFORM", transformargs->data, NULL);
12328
12329         if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
12330                 ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
12331                                          ARCHIVE_OPTS(.tag = labelq->data,
12332                                                                   .description = "TRANSFORM",
12333                                                                   .section = SECTION_PRE_DATA,
12334                                                                   .createStmt = defqry->data,
12335                                                                   .dropStmt = delqry->data,
12336                                                                   .deps = transform->dobj.dependencies,
12337                                                                   .nDeps = transform->dobj.nDeps));
12338
12339         /* Dump Transform Comments */
12340         if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
12341                 dumpComment(fout, "TRANSFORM", transformargs->data,
12342                                         NULL, "",
12343                                         transform->dobj.catId, 0, transform->dobj.dumpId);
12344
12345         free(lanname);
12346         free(transformType);
12347         destroyPQExpBuffer(defqry);
12348         destroyPQExpBuffer(delqry);
12349         destroyPQExpBuffer(labelq);
12350         destroyPQExpBuffer(transformargs);
12351 }
12352
12353
12354 /*
12355  * dumpOpr
12356  *        write out a single operator definition
12357  */
12358 static void
12359 dumpOpr(Archive *fout, OprInfo *oprinfo)
12360 {
12361         DumpOptions *dopt = fout->dopt;
12362         PQExpBuffer query;
12363         PQExpBuffer q;
12364         PQExpBuffer delq;
12365         PQExpBuffer oprid;
12366         PQExpBuffer details;
12367         PGresult   *res;
12368         int                     i_oprkind;
12369         int                     i_oprcode;
12370         int                     i_oprleft;
12371         int                     i_oprright;
12372         int                     i_oprcom;
12373         int                     i_oprnegate;
12374         int                     i_oprrest;
12375         int                     i_oprjoin;
12376         int                     i_oprcanmerge;
12377         int                     i_oprcanhash;
12378         char       *oprkind;
12379         char       *oprcode;
12380         char       *oprleft;
12381         char       *oprright;
12382         char       *oprcom;
12383         char       *oprnegate;
12384         char       *oprrest;
12385         char       *oprjoin;
12386         char       *oprcanmerge;
12387         char       *oprcanhash;
12388         char       *oprregproc;
12389         char       *oprref;
12390
12391         /* Skip if not to be dumped */
12392         if (!oprinfo->dobj.dump || dopt->dataOnly)
12393                 return;
12394
12395         /*
12396          * some operators are invalid because they were the result of user
12397          * defining operators before commutators exist
12398          */
12399         if (!OidIsValid(oprinfo->oprcode))
12400                 return;
12401
12402         query = createPQExpBuffer();
12403         q = createPQExpBuffer();
12404         delq = createPQExpBuffer();
12405         oprid = createPQExpBuffer();
12406         details = createPQExpBuffer();
12407
12408         if (fout->remoteVersion >= 80300)
12409         {
12410                 appendPQExpBuffer(query, "SELECT oprkind, "
12411                                                   "oprcode::pg_catalog.regprocedure, "
12412                                                   "oprleft::pg_catalog.regtype, "
12413                                                   "oprright::pg_catalog.regtype, "
12414                                                   "oprcom, "
12415                                                   "oprnegate, "
12416                                                   "oprrest::pg_catalog.regprocedure, "
12417                                                   "oprjoin::pg_catalog.regprocedure, "
12418                                                   "oprcanmerge, oprcanhash "
12419                                                   "FROM pg_catalog.pg_operator "
12420                                                   "WHERE oid = '%u'::pg_catalog.oid",
12421                                                   oprinfo->dobj.catId.oid);
12422         }
12423         else
12424         {
12425                 appendPQExpBuffer(query, "SELECT oprkind, "
12426                                                   "oprcode::pg_catalog.regprocedure, "
12427                                                   "oprleft::pg_catalog.regtype, "
12428                                                   "oprright::pg_catalog.regtype, "
12429                                                   "oprcom, "
12430                                                   "oprnegate, "
12431                                                   "oprrest::pg_catalog.regprocedure, "
12432                                                   "oprjoin::pg_catalog.regprocedure, "
12433                                                   "(oprlsortop != 0) AS oprcanmerge, "
12434                                                   "oprcanhash "
12435                                                   "FROM pg_catalog.pg_operator "
12436                                                   "WHERE oid = '%u'::pg_catalog.oid",
12437                                                   oprinfo->dobj.catId.oid);
12438         }
12439
12440         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12441
12442         i_oprkind = PQfnumber(res, "oprkind");
12443         i_oprcode = PQfnumber(res, "oprcode");
12444         i_oprleft = PQfnumber(res, "oprleft");
12445         i_oprright = PQfnumber(res, "oprright");
12446         i_oprcom = PQfnumber(res, "oprcom");
12447         i_oprnegate = PQfnumber(res, "oprnegate");
12448         i_oprrest = PQfnumber(res, "oprrest");
12449         i_oprjoin = PQfnumber(res, "oprjoin");
12450         i_oprcanmerge = PQfnumber(res, "oprcanmerge");
12451         i_oprcanhash = PQfnumber(res, "oprcanhash");
12452
12453         oprkind = PQgetvalue(res, 0, i_oprkind);
12454         oprcode = PQgetvalue(res, 0, i_oprcode);
12455         oprleft = PQgetvalue(res, 0, i_oprleft);
12456         oprright = PQgetvalue(res, 0, i_oprright);
12457         oprcom = PQgetvalue(res, 0, i_oprcom);
12458         oprnegate = PQgetvalue(res, 0, i_oprnegate);
12459         oprrest = PQgetvalue(res, 0, i_oprrest);
12460         oprjoin = PQgetvalue(res, 0, i_oprjoin);
12461         oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
12462         oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
12463
12464         oprregproc = convertRegProcReference(fout, oprcode);
12465         if (oprregproc)
12466         {
12467                 appendPQExpBuffer(details, "    FUNCTION = %s", oprregproc);
12468                 free(oprregproc);
12469         }
12470
12471         appendPQExpBuffer(oprid, "%s (",
12472                                           oprinfo->dobj.name);
12473
12474         /*
12475          * right unary means there's a left arg and left unary means there's a
12476          * right arg
12477          */
12478         if (strcmp(oprkind, "r") == 0 ||
12479                 strcmp(oprkind, "b") == 0)
12480         {
12481                 appendPQExpBuffer(details, ",\n    LEFTARG = %s", oprleft);
12482                 appendPQExpBufferStr(oprid, oprleft);
12483         }
12484         else
12485                 appendPQExpBufferStr(oprid, "NONE");
12486
12487         if (strcmp(oprkind, "l") == 0 ||
12488                 strcmp(oprkind, "b") == 0)
12489         {
12490                 appendPQExpBuffer(details, ",\n    RIGHTARG = %s", oprright);
12491                 appendPQExpBuffer(oprid, ", %s)", oprright);
12492         }
12493         else
12494                 appendPQExpBufferStr(oprid, ", NONE)");
12495
12496         oprref = getFormattedOperatorName(fout, oprcom);
12497         if (oprref)
12498         {
12499                 appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", oprref);
12500                 free(oprref);
12501         }
12502
12503         oprref = getFormattedOperatorName(fout, oprnegate);
12504         if (oprref)
12505         {
12506                 appendPQExpBuffer(details, ",\n    NEGATOR = %s", oprref);
12507                 free(oprref);
12508         }
12509
12510         if (strcmp(oprcanmerge, "t") == 0)
12511                 appendPQExpBufferStr(details, ",\n    MERGES");
12512
12513         if (strcmp(oprcanhash, "t") == 0)
12514                 appendPQExpBufferStr(details, ",\n    HASHES");
12515
12516         oprregproc = convertRegProcReference(fout, oprrest);
12517         if (oprregproc)
12518         {
12519                 appendPQExpBuffer(details, ",\n    RESTRICT = %s", oprregproc);
12520                 free(oprregproc);
12521         }
12522
12523         oprregproc = convertRegProcReference(fout, oprjoin);
12524         if (oprregproc)
12525         {
12526                 appendPQExpBuffer(details, ",\n    JOIN = %s", oprregproc);
12527                 free(oprregproc);
12528         }
12529
12530         appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
12531                                           fmtId(oprinfo->dobj.namespace->dobj.name),
12532                                           oprid->data);
12533
12534         appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
12535                                           fmtId(oprinfo->dobj.namespace->dobj.name),
12536                                           oprinfo->dobj.name, details->data);
12537
12538         if (dopt->binary_upgrade)
12539                 binary_upgrade_extension_member(q, &oprinfo->dobj,
12540                                                                                 "OPERATOR", oprid->data,
12541                                                                                 oprinfo->dobj.namespace->dobj.name);
12542
12543         if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12544                 ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
12545                                          ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
12546                                                                   .namespace = oprinfo->dobj.namespace->dobj.name,
12547                                                                   .owner = oprinfo->rolname,
12548                                                                   .description = "OPERATOR",
12549                                                                   .section = SECTION_PRE_DATA,
12550                                                                   .createStmt = q->data,
12551                                                                   .dropStmt = delq->data));
12552
12553         /* Dump Operator Comments */
12554         if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12555                 dumpComment(fout, "OPERATOR", oprid->data,
12556                                         oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
12557                                         oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
12558
12559         PQclear(res);
12560
12561         destroyPQExpBuffer(query);
12562         destroyPQExpBuffer(q);
12563         destroyPQExpBuffer(delq);
12564         destroyPQExpBuffer(oprid);
12565         destroyPQExpBuffer(details);
12566 }
12567
12568 /*
12569  * Convert a function reference obtained from pg_operator
12570  *
12571  * Returns allocated string of what to print, or NULL if function references
12572  * is InvalidOid. Returned string is expected to be free'd by the caller.
12573  *
12574  * The input is a REGPROCEDURE display; we have to strip the argument-types
12575  * part.
12576  */
12577 static char *
12578 convertRegProcReference(Archive *fout, const char *proc)
12579 {
12580         char       *name;
12581         char       *paren;
12582         bool            inquote;
12583
12584         /* In all cases "-" means a null reference */
12585         if (strcmp(proc, "-") == 0)
12586                 return NULL;
12587
12588         name = pg_strdup(proc);
12589         /* find non-double-quoted left paren */
12590         inquote = false;
12591         for (paren = name; *paren; paren++)
12592         {
12593                 if (*paren == '(' && !inquote)
12594                 {
12595                         *paren = '\0';
12596                         break;
12597                 }
12598                 if (*paren == '"')
12599                         inquote = !inquote;
12600         }
12601         return name;
12602 }
12603
12604 /*
12605  * getFormattedOperatorName - retrieve the operator name for the
12606  * given operator OID (presented in string form).
12607  *
12608  * Returns an allocated string, or NULL if the given OID is invalid.
12609  * Caller is responsible for free'ing result string.
12610  *
12611  * What we produce has the format "OPERATOR(schema.oprname)".  This is only
12612  * useful in commands where the operator's argument types can be inferred from
12613  * context.  We always schema-qualify the name, though.  The predecessor to
12614  * this code tried to skip the schema qualification if possible, but that led
12615  * to wrong results in corner cases, such as if an operator and its negator
12616  * are in different schemas.
12617  */
12618 static char *
12619 getFormattedOperatorName(Archive *fout, const char *oproid)
12620 {
12621         OprInfo    *oprInfo;
12622
12623         /* In all cases "0" means a null reference */
12624         if (strcmp(oproid, "0") == 0)
12625                 return NULL;
12626
12627         oprInfo = findOprByOid(atooid(oproid));
12628         if (oprInfo == NULL)
12629         {
12630                 pg_log_warning("could not find operator with OID %s",
12631                                   oproid);
12632                 return NULL;
12633         }
12634
12635         return psprintf("OPERATOR(%s.%s)",
12636                                         fmtId(oprInfo->dobj.namespace->dobj.name),
12637                                         oprInfo->dobj.name);
12638 }
12639
12640 /*
12641  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
12642  *
12643  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
12644  * argument lists of these functions are predetermined.  Note that the
12645  * caller should ensure we are in the proper schema, because the results
12646  * are search path dependent!
12647  */
12648 static char *
12649 convertTSFunction(Archive *fout, Oid funcOid)
12650 {
12651         char       *result;
12652         char            query[128];
12653         PGresult   *res;
12654
12655         snprintf(query, sizeof(query),
12656                          "SELECT '%u'::pg_catalog.regproc", funcOid);
12657         res = ExecuteSqlQueryForSingleRow(fout, query);
12658
12659         result = pg_strdup(PQgetvalue(res, 0, 0));
12660
12661         PQclear(res);
12662
12663         return result;
12664 }
12665
12666 /*
12667  * dumpAccessMethod
12668  *        write out a single access method definition
12669  */
12670 static void
12671 dumpAccessMethod(Archive *fout, AccessMethodInfo *aminfo)
12672 {
12673         DumpOptions *dopt = fout->dopt;
12674         PQExpBuffer q;
12675         PQExpBuffer delq;
12676         char       *qamname;
12677
12678         /* Skip if not to be dumped */
12679         if (!aminfo->dobj.dump || dopt->dataOnly)
12680                 return;
12681
12682         q = createPQExpBuffer();
12683         delq = createPQExpBuffer();
12684
12685         qamname = pg_strdup(fmtId(aminfo->dobj.name));
12686
12687         appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
12688
12689         switch (aminfo->amtype)
12690         {
12691                 case AMTYPE_INDEX:
12692                         appendPQExpBuffer(q, "TYPE INDEX ");
12693                         break;
12694                 case AMTYPE_TABLE:
12695                         appendPQExpBuffer(q, "TYPE TABLE ");
12696                         break;
12697                 default:
12698                         pg_log_warning("invalid type \"%c\" of access method \"%s\"",
12699                                           aminfo->amtype, qamname);
12700                         destroyPQExpBuffer(q);
12701                         destroyPQExpBuffer(delq);
12702                         free(qamname);
12703                         return;
12704         }
12705
12706         appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
12707
12708         appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
12709                                           qamname);
12710
12711         if (dopt->binary_upgrade)
12712                 binary_upgrade_extension_member(q, &aminfo->dobj,
12713                                                                                 "ACCESS METHOD", qamname, NULL);
12714
12715         if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12716                 ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
12717                                          ARCHIVE_OPTS(.tag = aminfo->dobj.name,
12718                                                                   .description = "ACCESS METHOD",
12719                                                                   .section = SECTION_PRE_DATA,
12720                                                                   .createStmt = q->data,
12721                                                                   .dropStmt = delq->data));
12722
12723         /* Dump Access Method Comments */
12724         if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12725                 dumpComment(fout, "ACCESS METHOD", qamname,
12726                                         NULL, "",
12727                                         aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
12728
12729         destroyPQExpBuffer(q);
12730         destroyPQExpBuffer(delq);
12731         free(qamname);
12732 }
12733
12734 /*
12735  * dumpOpclass
12736  *        write out a single operator class definition
12737  */
12738 static void
12739 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
12740 {
12741         DumpOptions *dopt = fout->dopt;
12742         PQExpBuffer query;
12743         PQExpBuffer q;
12744         PQExpBuffer delq;
12745         PQExpBuffer nameusing;
12746         PGresult   *res;
12747         int                     ntups;
12748         int                     i_opcintype;
12749         int                     i_opckeytype;
12750         int                     i_opcdefault;
12751         int                     i_opcfamily;
12752         int                     i_opcfamilyname;
12753         int                     i_opcfamilynsp;
12754         int                     i_amname;
12755         int                     i_amopstrategy;
12756         int                     i_amopreqcheck;
12757         int                     i_amopopr;
12758         int                     i_sortfamily;
12759         int                     i_sortfamilynsp;
12760         int                     i_amprocnum;
12761         int                     i_amproc;
12762         int                     i_amproclefttype;
12763         int                     i_amprocrighttype;
12764         char       *opcintype;
12765         char       *opckeytype;
12766         char       *opcdefault;
12767         char       *opcfamily;
12768         char       *opcfamilyname;
12769         char       *opcfamilynsp;
12770         char       *amname;
12771         char       *amopstrategy;
12772         char       *amopreqcheck;
12773         char       *amopopr;
12774         char       *sortfamily;
12775         char       *sortfamilynsp;
12776         char       *amprocnum;
12777         char       *amproc;
12778         char       *amproclefttype;
12779         char       *amprocrighttype;
12780         bool            needComma;
12781         int                     i;
12782
12783         /* Skip if not to be dumped */
12784         if (!opcinfo->dobj.dump || dopt->dataOnly)
12785                 return;
12786
12787         query = createPQExpBuffer();
12788         q = createPQExpBuffer();
12789         delq = createPQExpBuffer();
12790         nameusing = createPQExpBuffer();
12791
12792         /* Get additional fields from the pg_opclass row */
12793         if (fout->remoteVersion >= 80300)
12794         {
12795                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
12796                                                   "opckeytype::pg_catalog.regtype, "
12797                                                   "opcdefault, opcfamily, "
12798                                                   "opfname AS opcfamilyname, "
12799                                                   "nspname AS opcfamilynsp, "
12800                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
12801                                                   "FROM pg_catalog.pg_opclass c "
12802                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
12803                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12804                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
12805                                                   opcinfo->dobj.catId.oid);
12806         }
12807         else
12808         {
12809                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
12810                                                   "opckeytype::pg_catalog.regtype, "
12811                                                   "opcdefault, NULL AS opcfamily, "
12812                                                   "NULL AS opcfamilyname, "
12813                                                   "NULL AS opcfamilynsp, "
12814                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
12815                                                   "FROM pg_catalog.pg_opclass "
12816                                                   "WHERE oid = '%u'::pg_catalog.oid",
12817                                                   opcinfo->dobj.catId.oid);
12818         }
12819
12820         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12821
12822         i_opcintype = PQfnumber(res, "opcintype");
12823         i_opckeytype = PQfnumber(res, "opckeytype");
12824         i_opcdefault = PQfnumber(res, "opcdefault");
12825         i_opcfamily = PQfnumber(res, "opcfamily");
12826         i_opcfamilyname = PQfnumber(res, "opcfamilyname");
12827         i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
12828         i_amname = PQfnumber(res, "amname");
12829
12830         /* opcintype may still be needed after we PQclear res */
12831         opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
12832         opckeytype = PQgetvalue(res, 0, i_opckeytype);
12833         opcdefault = PQgetvalue(res, 0, i_opcdefault);
12834         /* opcfamily will still be needed after we PQclear res */
12835         opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
12836         opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
12837         opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
12838         /* amname will still be needed after we PQclear res */
12839         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
12840
12841         appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
12842                                           fmtQualifiedDumpable(opcinfo));
12843         appendPQExpBuffer(delq, " USING %s;\n",
12844                                           fmtId(amname));
12845
12846         /* Build the fixed portion of the CREATE command */
12847         appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
12848                                           fmtQualifiedDumpable(opcinfo));
12849         if (strcmp(opcdefault, "t") == 0)
12850                 appendPQExpBufferStr(q, "DEFAULT ");
12851         appendPQExpBuffer(q, "FOR TYPE %s USING %s",
12852                                           opcintype,
12853                                           fmtId(amname));
12854         if (strlen(opcfamilyname) > 0)
12855         {
12856                 appendPQExpBufferStr(q, " FAMILY ");
12857                 appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
12858                 appendPQExpBufferStr(q, fmtId(opcfamilyname));
12859         }
12860         appendPQExpBufferStr(q, " AS\n    ");
12861
12862         needComma = false;
12863
12864         if (strcmp(opckeytype, "-") != 0)
12865         {
12866                 appendPQExpBuffer(q, "STORAGE %s",
12867                                                   opckeytype);
12868                 needComma = true;
12869         }
12870
12871         PQclear(res);
12872
12873         /*
12874          * Now fetch and print the OPERATOR entries (pg_amop rows).
12875          *
12876          * Print only those opfamily members that are tied to the opclass by
12877          * pg_depend entries.
12878          *
12879          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
12880          * older server's opclass in which it is used.  This is to avoid
12881          * hard-to-detect breakage if a newer pg_dump is used to dump from an
12882          * older server and then reload into that old version.  This can go away
12883          * once 8.3 is so old as to not be of interest to anyone.
12884          */
12885         resetPQExpBuffer(query);
12886
12887         if (fout->remoteVersion >= 90100)
12888         {
12889                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12890                                                   "amopopr::pg_catalog.regoperator, "
12891                                                   "opfname AS sortfamily, "
12892                                                   "nspname AS sortfamilynsp "
12893                                                   "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
12894                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
12895                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
12896                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12897                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12898                                                   "AND refobjid = '%u'::pg_catalog.oid "
12899                                                   "AND amopfamily = '%s'::pg_catalog.oid "
12900                                                   "ORDER BY amopstrategy",
12901                                                   opcinfo->dobj.catId.oid,
12902                                                   opcfamily);
12903         }
12904         else if (fout->remoteVersion >= 80400)
12905         {
12906                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12907                                                   "amopopr::pg_catalog.regoperator, "
12908                                                   "NULL AS sortfamily, "
12909                                                   "NULL AS sortfamilynsp "
12910                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12911                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12912                                                   "AND refobjid = '%u'::pg_catalog.oid "
12913                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12914                                                   "AND objid = ao.oid "
12915                                                   "ORDER BY amopstrategy",
12916                                                   opcinfo->dobj.catId.oid);
12917         }
12918         else if (fout->remoteVersion >= 80300)
12919         {
12920                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
12921                                                   "amopopr::pg_catalog.regoperator, "
12922                                                   "NULL AS sortfamily, "
12923                                                   "NULL AS sortfamilynsp "
12924                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12925                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12926                                                   "AND refobjid = '%u'::pg_catalog.oid "
12927                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12928                                                   "AND objid = ao.oid "
12929                                                   "ORDER BY amopstrategy",
12930                                                   opcinfo->dobj.catId.oid);
12931         }
12932         else
12933         {
12934                 /*
12935                  * Here, we print all entries since there are no opfamilies and hence
12936                  * no loose operators to worry about.
12937                  */
12938                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
12939                                                   "amopopr::pg_catalog.regoperator, "
12940                                                   "NULL AS sortfamily, "
12941                                                   "NULL AS sortfamilynsp "
12942                                                   "FROM pg_catalog.pg_amop "
12943                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
12944                                                   "ORDER BY amopstrategy",
12945                                                   opcinfo->dobj.catId.oid);
12946         }
12947
12948         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12949
12950         ntups = PQntuples(res);
12951
12952         i_amopstrategy = PQfnumber(res, "amopstrategy");
12953         i_amopreqcheck = PQfnumber(res, "amopreqcheck");
12954         i_amopopr = PQfnumber(res, "amopopr");
12955         i_sortfamily = PQfnumber(res, "sortfamily");
12956         i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
12957
12958         for (i = 0; i < ntups; i++)
12959         {
12960                 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
12961                 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
12962                 amopopr = PQgetvalue(res, i, i_amopopr);
12963                 sortfamily = PQgetvalue(res, i, i_sortfamily);
12964                 sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
12965
12966                 if (needComma)
12967                         appendPQExpBufferStr(q, " ,\n    ");
12968
12969                 appendPQExpBuffer(q, "OPERATOR %s %s",
12970                                                   amopstrategy, amopopr);
12971
12972                 if (strlen(sortfamily) > 0)
12973                 {
12974                         appendPQExpBufferStr(q, " FOR ORDER BY ");
12975                         appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
12976                         appendPQExpBufferStr(q, fmtId(sortfamily));
12977                 }
12978
12979                 if (strcmp(amopreqcheck, "t") == 0)
12980                         appendPQExpBufferStr(q, " RECHECK");
12981
12982                 needComma = true;
12983         }
12984
12985         PQclear(res);
12986
12987         /*
12988          * Now fetch and print the FUNCTION entries (pg_amproc rows).
12989          *
12990          * Print only those opfamily members that are tied to the opclass by
12991          * pg_depend entries.
12992          *
12993          * We print the amproclefttype/amprocrighttype even though in most cases
12994          * the backend could deduce the right values, because of the corner case
12995          * of a btree sort support function for a cross-type comparison.  That's
12996          * only allowed in 9.2 and later, but for simplicity print them in all
12997          * versions that have the columns.
12998          */
12999         resetPQExpBuffer(query);
13000
13001         if (fout->remoteVersion >= 80300)
13002         {
13003                 appendPQExpBuffer(query, "SELECT amprocnum, "
13004                                                   "amproc::pg_catalog.regprocedure, "
13005                                                   "amproclefttype::pg_catalog.regtype, "
13006                                                   "amprocrighttype::pg_catalog.regtype "
13007                                                   "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
13008                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
13009                                                   "AND refobjid = '%u'::pg_catalog.oid "
13010                                                   "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
13011                                                   "AND objid = ap.oid "
13012                                                   "ORDER BY amprocnum",
13013                                                   opcinfo->dobj.catId.oid);
13014         }
13015         else
13016         {
13017                 appendPQExpBuffer(query, "SELECT amprocnum, "
13018                                                   "amproc::pg_catalog.regprocedure, "
13019                                                   "'' AS amproclefttype, "
13020                                                   "'' AS amprocrighttype "
13021                                                   "FROM pg_catalog.pg_amproc "
13022                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
13023                                                   "ORDER BY amprocnum",
13024                                                   opcinfo->dobj.catId.oid);
13025         }
13026
13027         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13028
13029         ntups = PQntuples(res);
13030
13031         i_amprocnum = PQfnumber(res, "amprocnum");
13032         i_amproc = PQfnumber(res, "amproc");
13033         i_amproclefttype = PQfnumber(res, "amproclefttype");
13034         i_amprocrighttype = PQfnumber(res, "amprocrighttype");
13035
13036         for (i = 0; i < ntups; i++)
13037         {
13038                 amprocnum = PQgetvalue(res, i, i_amprocnum);
13039                 amproc = PQgetvalue(res, i, i_amproc);
13040                 amproclefttype = PQgetvalue(res, i, i_amproclefttype);
13041                 amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
13042
13043                 if (needComma)
13044                         appendPQExpBufferStr(q, " ,\n    ");
13045
13046                 appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
13047
13048                 if (*amproclefttype && *amprocrighttype)
13049                         appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
13050
13051                 appendPQExpBuffer(q, " %s", amproc);
13052
13053                 needComma = true;
13054         }
13055
13056         PQclear(res);
13057
13058         /*
13059          * If needComma is still false it means we haven't added anything after
13060          * the AS keyword.  To avoid printing broken SQL, append a dummy STORAGE
13061          * clause with the same datatype.  This isn't sanctioned by the
13062          * documentation, but actually DefineOpClass will treat it as a no-op.
13063          */
13064         if (!needComma)
13065                 appendPQExpBuffer(q, "STORAGE %s", opcintype);
13066
13067         appendPQExpBufferStr(q, ";\n");
13068
13069         appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
13070         appendPQExpBuffer(nameusing, " USING %s",
13071                                           fmtId(amname));
13072
13073         if (dopt->binary_upgrade)
13074                 binary_upgrade_extension_member(q, &opcinfo->dobj,
13075                                                                                 "OPERATOR CLASS", nameusing->data,
13076                                                                                 opcinfo->dobj.namespace->dobj.name);
13077
13078         if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13079                 ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
13080                                          ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
13081                                                                   .namespace = opcinfo->dobj.namespace->dobj.name,
13082                                                                   .owner = opcinfo->rolname,
13083                                                                   .description = "OPERATOR CLASS",
13084                                                                   .section = SECTION_PRE_DATA,
13085                                                                   .createStmt = q->data,
13086                                                                   .dropStmt = delq->data));
13087
13088         /* Dump Operator Class Comments */
13089         if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13090                 dumpComment(fout, "OPERATOR CLASS", nameusing->data,
13091                                         opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
13092                                         opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
13093
13094         free(opcintype);
13095         free(opcfamily);
13096         free(amname);
13097         destroyPQExpBuffer(query);
13098         destroyPQExpBuffer(q);
13099         destroyPQExpBuffer(delq);
13100         destroyPQExpBuffer(nameusing);
13101 }
13102
13103 /*
13104  * dumpOpfamily
13105  *        write out a single operator family definition
13106  *
13107  * Note: this also dumps any "loose" operator members that aren't bound to a
13108  * specific opclass within the opfamily.
13109  */
13110 static void
13111 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
13112 {
13113         DumpOptions *dopt = fout->dopt;
13114         PQExpBuffer query;
13115         PQExpBuffer q;
13116         PQExpBuffer delq;
13117         PQExpBuffer nameusing;
13118         PGresult   *res;
13119         PGresult   *res_ops;
13120         PGresult   *res_procs;
13121         int                     ntups;
13122         int                     i_amname;
13123         int                     i_amopstrategy;
13124         int                     i_amopreqcheck;
13125         int                     i_amopopr;
13126         int                     i_sortfamily;
13127         int                     i_sortfamilynsp;
13128         int                     i_amprocnum;
13129         int                     i_amproc;
13130         int                     i_amproclefttype;
13131         int                     i_amprocrighttype;
13132         char       *amname;
13133         char       *amopstrategy;
13134         char       *amopreqcheck;
13135         char       *amopopr;
13136         char       *sortfamily;
13137         char       *sortfamilynsp;
13138         char       *amprocnum;
13139         char       *amproc;
13140         char       *amproclefttype;
13141         char       *amprocrighttype;
13142         bool            needComma;
13143         int                     i;
13144
13145         /* Skip if not to be dumped */
13146         if (!opfinfo->dobj.dump || dopt->dataOnly)
13147                 return;
13148
13149         query = createPQExpBuffer();
13150         q = createPQExpBuffer();
13151         delq = createPQExpBuffer();
13152         nameusing = createPQExpBuffer();
13153
13154         /*
13155          * Fetch only those opfamily members that are tied directly to the
13156          * opfamily by pg_depend entries.
13157          *
13158          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
13159          * older server's opclass in which it is used.  This is to avoid
13160          * hard-to-detect breakage if a newer pg_dump is used to dump from an
13161          * older server and then reload into that old version.  This can go away
13162          * once 8.3 is so old as to not be of interest to anyone.
13163          */
13164         if (fout->remoteVersion >= 90100)
13165         {
13166                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
13167                                                   "amopopr::pg_catalog.regoperator, "
13168                                                   "opfname AS sortfamily, "
13169                                                   "nspname AS sortfamilynsp "
13170                                                   "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
13171                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
13172                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
13173                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
13174                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13175                                                   "AND refobjid = '%u'::pg_catalog.oid "
13176                                                   "AND amopfamily = '%u'::pg_catalog.oid "
13177                                                   "ORDER BY amopstrategy",
13178                                                   opfinfo->dobj.catId.oid,
13179                                                   opfinfo->dobj.catId.oid);
13180         }
13181         else if (fout->remoteVersion >= 80400)
13182         {
13183                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
13184                                                   "amopopr::pg_catalog.regoperator, "
13185                                                   "NULL AS sortfamily, "
13186                                                   "NULL AS sortfamilynsp "
13187                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
13188                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13189                                                   "AND refobjid = '%u'::pg_catalog.oid "
13190                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
13191                                                   "AND objid = ao.oid "
13192                                                   "ORDER BY amopstrategy",
13193                                                   opfinfo->dobj.catId.oid);
13194         }
13195         else
13196         {
13197                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
13198                                                   "amopopr::pg_catalog.regoperator, "
13199                                                   "NULL AS sortfamily, "
13200                                                   "NULL AS sortfamilynsp "
13201                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
13202                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13203                                                   "AND refobjid = '%u'::pg_catalog.oid "
13204                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
13205                                                   "AND objid = ao.oid "
13206                                                   "ORDER BY amopstrategy",
13207                                                   opfinfo->dobj.catId.oid);
13208         }
13209
13210         res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13211
13212         resetPQExpBuffer(query);
13213
13214         appendPQExpBuffer(query, "SELECT amprocnum, "
13215                                           "amproc::pg_catalog.regprocedure, "
13216                                           "amproclefttype::pg_catalog.regtype, "
13217                                           "amprocrighttype::pg_catalog.regtype "
13218                                           "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
13219                                           "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13220                                           "AND refobjid = '%u'::pg_catalog.oid "
13221                                           "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
13222                                           "AND objid = ap.oid "
13223                                           "ORDER BY amprocnum",
13224                                           opfinfo->dobj.catId.oid);
13225
13226         res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13227
13228         /* Get additional fields from the pg_opfamily row */
13229         resetPQExpBuffer(query);
13230
13231         appendPQExpBuffer(query, "SELECT "
13232                                           "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
13233                                           "FROM pg_catalog.pg_opfamily "
13234                                           "WHERE oid = '%u'::pg_catalog.oid",
13235                                           opfinfo->dobj.catId.oid);
13236
13237         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13238
13239         i_amname = PQfnumber(res, "amname");
13240
13241         /* amname will still be needed after we PQclear res */
13242         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
13243
13244         appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
13245                                           fmtQualifiedDumpable(opfinfo));
13246         appendPQExpBuffer(delq, " USING %s;\n",
13247                                           fmtId(amname));
13248
13249         /* Build the fixed portion of the CREATE command */
13250         appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
13251                                           fmtQualifiedDumpable(opfinfo));
13252         appendPQExpBuffer(q, " USING %s;\n",
13253                                           fmtId(amname));
13254
13255         PQclear(res);
13256
13257         /* Do we need an ALTER to add loose members? */
13258         if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
13259         {
13260                 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
13261                                                   fmtQualifiedDumpable(opfinfo));
13262                 appendPQExpBuffer(q, " USING %s ADD\n    ",
13263                                                   fmtId(amname));
13264
13265                 needComma = false;
13266
13267                 /*
13268                  * Now fetch and print the OPERATOR entries (pg_amop rows).
13269                  */
13270                 ntups = PQntuples(res_ops);
13271
13272                 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
13273                 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
13274                 i_amopopr = PQfnumber(res_ops, "amopopr");
13275                 i_sortfamily = PQfnumber(res_ops, "sortfamily");
13276                 i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
13277
13278                 for (i = 0; i < ntups; i++)
13279                 {
13280                         amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
13281                         amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
13282                         amopopr = PQgetvalue(res_ops, i, i_amopopr);
13283                         sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
13284                         sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
13285
13286                         if (needComma)
13287                                 appendPQExpBufferStr(q, " ,\n    ");
13288
13289                         appendPQExpBuffer(q, "OPERATOR %s %s",
13290                                                           amopstrategy, amopopr);
13291
13292                         if (strlen(sortfamily) > 0)
13293                         {
13294                                 appendPQExpBufferStr(q, " FOR ORDER BY ");
13295                                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
13296                                 appendPQExpBufferStr(q, fmtId(sortfamily));
13297                         }
13298
13299                         if (strcmp(amopreqcheck, "t") == 0)
13300                                 appendPQExpBufferStr(q, " RECHECK");
13301
13302                         needComma = true;
13303                 }
13304
13305                 /*
13306                  * Now fetch and print the FUNCTION entries (pg_amproc rows).
13307                  */
13308                 ntups = PQntuples(res_procs);
13309
13310                 i_amprocnum = PQfnumber(res_procs, "amprocnum");
13311                 i_amproc = PQfnumber(res_procs, "amproc");
13312                 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
13313                 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
13314
13315                 for (i = 0; i < ntups; i++)
13316                 {
13317                         amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
13318                         amproc = PQgetvalue(res_procs, i, i_amproc);
13319                         amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
13320                         amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
13321
13322                         if (needComma)
13323                                 appendPQExpBufferStr(q, " ,\n    ");
13324
13325                         appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
13326                                                           amprocnum, amproclefttype, amprocrighttype,
13327                                                           amproc);
13328
13329                         needComma = true;
13330                 }
13331
13332                 appendPQExpBufferStr(q, ";\n");
13333         }
13334
13335         appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
13336         appendPQExpBuffer(nameusing, " USING %s",
13337                                           fmtId(amname));
13338
13339         if (dopt->binary_upgrade)
13340                 binary_upgrade_extension_member(q, &opfinfo->dobj,
13341                                                                                 "OPERATOR FAMILY", nameusing->data,
13342                                                                                 opfinfo->dobj.namespace->dobj.name);
13343
13344         if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13345                 ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
13346                                          ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
13347                                                                   .namespace = opfinfo->dobj.namespace->dobj.name,
13348                                                                   .owner = opfinfo->rolname,
13349                                                                   .description = "OPERATOR FAMILY",
13350                                                                   .section = SECTION_PRE_DATA,
13351                                                                   .createStmt = q->data,
13352                                                                   .dropStmt = delq->data));
13353
13354         /* Dump Operator Family Comments */
13355         if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13356                 dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
13357                                         opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
13358                                         opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
13359
13360         free(amname);
13361         PQclear(res_ops);
13362         PQclear(res_procs);
13363         destroyPQExpBuffer(query);
13364         destroyPQExpBuffer(q);
13365         destroyPQExpBuffer(delq);
13366         destroyPQExpBuffer(nameusing);
13367 }
13368
13369 /*
13370  * dumpCollation
13371  *        write out a single collation definition
13372  */
13373 static void
13374 dumpCollation(Archive *fout, CollInfo *collinfo)
13375 {
13376         DumpOptions *dopt = fout->dopt;
13377         PQExpBuffer query;
13378         PQExpBuffer q;
13379         PQExpBuffer delq;
13380         char       *qcollname;
13381         PGresult   *res;
13382         int                     i_collprovider;
13383         int                     i_collisdeterministic;
13384         int                     i_collcollate;
13385         int                     i_collctype;
13386         const char *collprovider;
13387         const char *collcollate;
13388         const char *collctype;
13389
13390         /* Skip if not to be dumped */
13391         if (!collinfo->dobj.dump || dopt->dataOnly)
13392                 return;
13393
13394         query = createPQExpBuffer();
13395         q = createPQExpBuffer();
13396         delq = createPQExpBuffer();
13397
13398         qcollname = pg_strdup(fmtId(collinfo->dobj.name));
13399
13400         /* Get collation-specific details */
13401         appendPQExpBuffer(query, "SELECT ");
13402
13403         if (fout->remoteVersion >= 100000)
13404                 appendPQExpBuffer(query,
13405                                                   "collprovider, "
13406                                                   "collversion, ");
13407         else
13408                 appendPQExpBuffer(query,
13409                                                   "'c' AS collprovider, "
13410                                                   "NULL AS collversion, ");
13411
13412         if (fout->remoteVersion >= 120000)
13413                 appendPQExpBuffer(query,
13414                                                   "collisdeterministic, ");
13415         else
13416                 appendPQExpBuffer(query,
13417                                                   "true AS collisdeterministic, ");
13418
13419         appendPQExpBuffer(query,
13420                                           "collcollate, "
13421                                           "collctype "
13422                                           "FROM pg_catalog.pg_collation c "
13423                                           "WHERE c.oid = '%u'::pg_catalog.oid",
13424                                           collinfo->dobj.catId.oid);
13425
13426         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13427
13428         i_collprovider = PQfnumber(res, "collprovider");
13429         i_collisdeterministic = PQfnumber(res, "collisdeterministic");
13430         i_collcollate = PQfnumber(res, "collcollate");
13431         i_collctype = PQfnumber(res, "collctype");
13432
13433         collprovider = PQgetvalue(res, 0, i_collprovider);
13434         collcollate = PQgetvalue(res, 0, i_collcollate);
13435         collctype = PQgetvalue(res, 0, i_collctype);
13436
13437         appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
13438                                           fmtQualifiedDumpable(collinfo));
13439
13440         appendPQExpBuffer(q, "CREATE COLLATION %s (",
13441                                           fmtQualifiedDumpable(collinfo));
13442
13443         appendPQExpBufferStr(q, "provider = ");
13444         if (collprovider[0] == 'c')
13445                 appendPQExpBufferStr(q, "libc");
13446         else if (collprovider[0] == 'i')
13447                 appendPQExpBufferStr(q, "icu");
13448         else if (collprovider[0] == 'd')
13449                 /* to allow dumping pg_catalog; not accepted on input */
13450                 appendPQExpBufferStr(q, "default");
13451         else
13452                 fatal("unrecognized collation provider: %s\n",
13453                                           collprovider);
13454
13455         if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
13456                 appendPQExpBufferStr(q, ", deterministic = false");
13457
13458         if (strcmp(collcollate, collctype) == 0)
13459         {
13460                 appendPQExpBufferStr(q, ", locale = ");
13461                 appendStringLiteralAH(q, collcollate, fout);
13462         }
13463         else
13464         {
13465                 appendPQExpBufferStr(q, ", lc_collate = ");
13466                 appendStringLiteralAH(q, collcollate, fout);
13467                 appendPQExpBufferStr(q, ", lc_ctype = ");
13468                 appendStringLiteralAH(q, collctype, fout);
13469         }
13470
13471         /*
13472          * For binary upgrade, carry over the collation version.  For normal
13473          * dump/restore, omit the version, so that it is computed upon restore.
13474          */
13475         if (dopt->binary_upgrade)
13476         {
13477                 int                     i_collversion;
13478
13479                 i_collversion = PQfnumber(res, "collversion");
13480                 if (!PQgetisnull(res, 0, i_collversion))
13481                 {
13482                         appendPQExpBufferStr(q, ", version = ");
13483                         appendStringLiteralAH(q,
13484                                                                   PQgetvalue(res, 0, i_collversion),
13485                                                                   fout);
13486                 }
13487         }
13488
13489         appendPQExpBufferStr(q, ");\n");
13490
13491         if (dopt->binary_upgrade)
13492                 binary_upgrade_extension_member(q, &collinfo->dobj,
13493                                                                                 "COLLATION", qcollname,
13494                                                                                 collinfo->dobj.namespace->dobj.name);
13495
13496         if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13497                 ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
13498                                          ARCHIVE_OPTS(.tag = collinfo->dobj.name,
13499                                                                   .namespace = collinfo->dobj.namespace->dobj.name,
13500                                                                   .owner = collinfo->rolname,
13501                                                                   .description = "COLLATION",
13502                                                                   .section = SECTION_PRE_DATA,
13503                                                                   .createStmt = q->data,
13504                                                                   .dropStmt = delq->data));
13505
13506         /* Dump Collation Comments */
13507         if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13508                 dumpComment(fout, "COLLATION", qcollname,
13509                                         collinfo->dobj.namespace->dobj.name, collinfo->rolname,
13510                                         collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
13511
13512         PQclear(res);
13513
13514         destroyPQExpBuffer(query);
13515         destroyPQExpBuffer(q);
13516         destroyPQExpBuffer(delq);
13517         free(qcollname);
13518 }
13519
13520 /*
13521  * dumpConversion
13522  *        write out a single conversion definition
13523  */
13524 static void
13525 dumpConversion(Archive *fout, ConvInfo *convinfo)
13526 {
13527         DumpOptions *dopt = fout->dopt;
13528         PQExpBuffer query;
13529         PQExpBuffer q;
13530         PQExpBuffer delq;
13531         char       *qconvname;
13532         PGresult   *res;
13533         int                     i_conforencoding;
13534         int                     i_contoencoding;
13535         int                     i_conproc;
13536         int                     i_condefault;
13537         const char *conforencoding;
13538         const char *contoencoding;
13539         const char *conproc;
13540         bool            condefault;
13541
13542         /* Skip if not to be dumped */
13543         if (!convinfo->dobj.dump || dopt->dataOnly)
13544                 return;
13545
13546         query = createPQExpBuffer();
13547         q = createPQExpBuffer();
13548         delq = createPQExpBuffer();
13549
13550         qconvname = pg_strdup(fmtId(convinfo->dobj.name));
13551
13552         /* Get conversion-specific details */
13553         appendPQExpBuffer(query, "SELECT "
13554                                           "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
13555                                           "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
13556                                           "conproc, condefault "
13557                                           "FROM pg_catalog.pg_conversion c "
13558                                           "WHERE c.oid = '%u'::pg_catalog.oid",
13559                                           convinfo->dobj.catId.oid);
13560
13561         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13562
13563         i_conforencoding = PQfnumber(res, "conforencoding");
13564         i_contoencoding = PQfnumber(res, "contoencoding");
13565         i_conproc = PQfnumber(res, "conproc");
13566         i_condefault = PQfnumber(res, "condefault");
13567
13568         conforencoding = PQgetvalue(res, 0, i_conforencoding);
13569         contoencoding = PQgetvalue(res, 0, i_contoencoding);
13570         conproc = PQgetvalue(res, 0, i_conproc);
13571         condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
13572
13573         appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
13574                                           fmtQualifiedDumpable(convinfo));
13575
13576         appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
13577                                           (condefault) ? "DEFAULT " : "",
13578                                           fmtQualifiedDumpable(convinfo));
13579         appendStringLiteralAH(q, conforencoding, fout);
13580         appendPQExpBufferStr(q, " TO ");
13581         appendStringLiteralAH(q, contoencoding, fout);
13582         /* regproc output is already sufficiently quoted */
13583         appendPQExpBuffer(q, " FROM %s;\n", conproc);
13584
13585         if (dopt->binary_upgrade)
13586                 binary_upgrade_extension_member(q, &convinfo->dobj,
13587                                                                                 "CONVERSION", qconvname,
13588                                                                                 convinfo->dobj.namespace->dobj.name);
13589
13590         if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13591                 ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
13592                                          ARCHIVE_OPTS(.tag = convinfo->dobj.name,
13593                                                                   .namespace = convinfo->dobj.namespace->dobj.name,
13594                                                                   .owner = convinfo->rolname,
13595                                                                   .description = "CONVERSION",
13596                                                                   .section = SECTION_PRE_DATA,
13597                                                                   .createStmt = q->data,
13598                                                                   .dropStmt = delq->data));
13599
13600         /* Dump Conversion Comments */
13601         if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13602                 dumpComment(fout, "CONVERSION", qconvname,
13603                                         convinfo->dobj.namespace->dobj.name, convinfo->rolname,
13604                                         convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
13605
13606         PQclear(res);
13607
13608         destroyPQExpBuffer(query);
13609         destroyPQExpBuffer(q);
13610         destroyPQExpBuffer(delq);
13611         free(qconvname);
13612 }
13613
13614 /*
13615  * format_aggregate_signature: generate aggregate name and argument list
13616  *
13617  * The argument type names are qualified if needed.  The aggregate name
13618  * is never qualified.
13619  */
13620 static char *
13621 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
13622 {
13623         PQExpBufferData buf;
13624         int                     j;
13625
13626         initPQExpBuffer(&buf);
13627         if (honor_quotes)
13628                 appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
13629         else
13630                 appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
13631
13632         if (agginfo->aggfn.nargs == 0)
13633                 appendPQExpBuffer(&buf, "(*)");
13634         else
13635         {
13636                 appendPQExpBufferChar(&buf, '(');
13637                 for (j = 0; j < agginfo->aggfn.nargs; j++)
13638                 {
13639                         char       *typname;
13640
13641                         typname = getFormattedTypeName(fout, agginfo->aggfn.argtypes[j],
13642                                                                                    zeroAsOpaque);
13643
13644                         appendPQExpBuffer(&buf, "%s%s",
13645                                                           (j > 0) ? ", " : "",
13646                                                           typname);
13647                         free(typname);
13648                 }
13649                 appendPQExpBufferChar(&buf, ')');
13650         }
13651         return buf.data;
13652 }
13653
13654 /*
13655  * dumpAgg
13656  *        write out a single aggregate definition
13657  */
13658 static void
13659 dumpAgg(Archive *fout, AggInfo *agginfo)
13660 {
13661         DumpOptions *dopt = fout->dopt;
13662         PQExpBuffer query;
13663         PQExpBuffer q;
13664         PQExpBuffer delq;
13665         PQExpBuffer details;
13666         char       *aggsig;                     /* identity signature */
13667         char       *aggfullsig = NULL;  /* full signature */
13668         char       *aggsig_tag;
13669         PGresult   *res;
13670         int                     i_aggtransfn;
13671         int                     i_aggfinalfn;
13672         int                     i_aggcombinefn;
13673         int                     i_aggserialfn;
13674         int                     i_aggdeserialfn;
13675         int                     i_aggmtransfn;
13676         int                     i_aggminvtransfn;
13677         int                     i_aggmfinalfn;
13678         int                     i_aggfinalextra;
13679         int                     i_aggmfinalextra;
13680         int                     i_aggfinalmodify;
13681         int                     i_aggmfinalmodify;
13682         int                     i_aggsortop;
13683         int                     i_aggkind;
13684         int                     i_aggtranstype;
13685         int                     i_aggtransspace;
13686         int                     i_aggmtranstype;
13687         int                     i_aggmtransspace;
13688         int                     i_agginitval;
13689         int                     i_aggminitval;
13690         int                     i_convertok;
13691         int                     i_proparallel;
13692         const char *aggtransfn;
13693         const char *aggfinalfn;
13694         const char *aggcombinefn;
13695         const char *aggserialfn;
13696         const char *aggdeserialfn;
13697         const char *aggmtransfn;
13698         const char *aggminvtransfn;
13699         const char *aggmfinalfn;
13700         bool            aggfinalextra;
13701         bool            aggmfinalextra;
13702         char            aggfinalmodify;
13703         char            aggmfinalmodify;
13704         const char *aggsortop;
13705         char       *aggsortconvop;
13706         char            aggkind;
13707         const char *aggtranstype;
13708         const char *aggtransspace;
13709         const char *aggmtranstype;
13710         const char *aggmtransspace;
13711         const char *agginitval;
13712         const char *aggminitval;
13713         bool            convertok;
13714         const char *proparallel;
13715         char            defaultfinalmodify;
13716
13717         /* Skip if not to be dumped */
13718         if (!agginfo->aggfn.dobj.dump || dopt->dataOnly)
13719                 return;
13720
13721         query = createPQExpBuffer();
13722         q = createPQExpBuffer();
13723         delq = createPQExpBuffer();
13724         details = createPQExpBuffer();
13725
13726         /* Get aggregate-specific details */
13727         if (fout->remoteVersion >= 110000)
13728         {
13729                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13730                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13731                                                   "aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
13732                                                   "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13733                                                   "aggfinalextra, aggmfinalextra, "
13734                                                   "aggfinalmodify, aggmfinalmodify, "
13735                                                   "aggsortop, "
13736                                                   "aggkind, "
13737                                                   "aggtransspace, agginitval, "
13738                                                   "aggmtransspace, aggminitval, "
13739                                                   "true AS convertok, "
13740                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13741                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs, "
13742                                                   "p.proparallel "
13743                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13744                                                   "WHERE a.aggfnoid = p.oid "
13745                                                   "AND p.oid = '%u'::pg_catalog.oid",
13746                                                   agginfo->aggfn.dobj.catId.oid);
13747         }
13748         else if (fout->remoteVersion >= 90600)
13749         {
13750                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13751                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13752                                                   "aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
13753                                                   "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13754                                                   "aggfinalextra, aggmfinalextra, "
13755                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13756                                                   "aggsortop, "
13757                                                   "aggkind, "
13758                                                   "aggtransspace, agginitval, "
13759                                                   "aggmtransspace, aggminitval, "
13760                                                   "true AS convertok, "
13761                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13762                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs, "
13763                                                   "p.proparallel "
13764                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13765                                                   "WHERE a.aggfnoid = p.oid "
13766                                                   "AND p.oid = '%u'::pg_catalog.oid",
13767                                                   agginfo->aggfn.dobj.catId.oid);
13768         }
13769         else if (fout->remoteVersion >= 90400)
13770         {
13771                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13772                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13773                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13774                                                   "'-' AS aggdeserialfn, aggmtransfn, aggminvtransfn, "
13775                                                   "aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13776                                                   "aggfinalextra, aggmfinalextra, "
13777                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13778                                                   "aggsortop, "
13779                                                   "aggkind, "
13780                                                   "aggtransspace, agginitval, "
13781                                                   "aggmtransspace, aggminitval, "
13782                                                   "true AS convertok, "
13783                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13784                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
13785                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13786                                                   "WHERE a.aggfnoid = p.oid "
13787                                                   "AND p.oid = '%u'::pg_catalog.oid",
13788                                                   agginfo->aggfn.dobj.catId.oid);
13789         }
13790         else if (fout->remoteVersion >= 80400)
13791         {
13792                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13793                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13794                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13795                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13796                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13797                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13798                                                   "false AS aggmfinalextra, "
13799                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13800                                                   "aggsortop, "
13801                                                   "'n' AS aggkind, "
13802                                                   "0 AS aggtransspace, agginitval, "
13803                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13804                                                   "true AS convertok, "
13805                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13806                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
13807                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13808                                                   "WHERE a.aggfnoid = p.oid "
13809                                                   "AND p.oid = '%u'::pg_catalog.oid",
13810                                                   agginfo->aggfn.dobj.catId.oid);
13811         }
13812         else if (fout->remoteVersion >= 80100)
13813         {
13814                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13815                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13816                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13817                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13818                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13819                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13820                                                   "false AS aggmfinalextra, "
13821                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13822                                                   "aggsortop, "
13823                                                   "'n' AS aggkind, "
13824                                                   "0 AS aggtransspace, agginitval, "
13825                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13826                                                   "true AS convertok "
13827                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13828                                                   "WHERE a.aggfnoid = p.oid "
13829                                                   "AND p.oid = '%u'::pg_catalog.oid",
13830                                                   agginfo->aggfn.dobj.catId.oid);
13831         }
13832         else
13833         {
13834                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13835                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13836                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13837                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13838                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13839                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13840                                                   "false AS aggmfinalextra, "
13841                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13842                                                   "0 AS aggsortop, "
13843                                                   "'n' AS aggkind, "
13844                                                   "0 AS aggtransspace, agginitval, "
13845                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13846                                                   "true AS convertok "
13847                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13848                                                   "WHERE a.aggfnoid = p.oid "
13849                                                   "AND p.oid = '%u'::pg_catalog.oid",
13850                                                   agginfo->aggfn.dobj.catId.oid);
13851         }
13852
13853         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13854
13855         i_aggtransfn = PQfnumber(res, "aggtransfn");
13856         i_aggfinalfn = PQfnumber(res, "aggfinalfn");
13857         i_aggcombinefn = PQfnumber(res, "aggcombinefn");
13858         i_aggserialfn = PQfnumber(res, "aggserialfn");
13859         i_aggdeserialfn = PQfnumber(res, "aggdeserialfn");
13860         i_aggmtransfn = PQfnumber(res, "aggmtransfn");
13861         i_aggminvtransfn = PQfnumber(res, "aggminvtransfn");
13862         i_aggmfinalfn = PQfnumber(res, "aggmfinalfn");
13863         i_aggfinalextra = PQfnumber(res, "aggfinalextra");
13864         i_aggmfinalextra = PQfnumber(res, "aggmfinalextra");
13865         i_aggfinalmodify = PQfnumber(res, "aggfinalmodify");
13866         i_aggmfinalmodify = PQfnumber(res, "aggmfinalmodify");
13867         i_aggsortop = PQfnumber(res, "aggsortop");
13868         i_aggkind = PQfnumber(res, "aggkind");
13869         i_aggtranstype = PQfnumber(res, "aggtranstype");
13870         i_aggtransspace = PQfnumber(res, "aggtransspace");
13871         i_aggmtranstype = PQfnumber(res, "aggmtranstype");
13872         i_aggmtransspace = PQfnumber(res, "aggmtransspace");
13873         i_agginitval = PQfnumber(res, "agginitval");
13874         i_aggminitval = PQfnumber(res, "aggminitval");
13875         i_convertok = PQfnumber(res, "convertok");
13876         i_proparallel = PQfnumber(res, "proparallel");
13877
13878         aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
13879         aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
13880         aggcombinefn = PQgetvalue(res, 0, i_aggcombinefn);
13881         aggserialfn = PQgetvalue(res, 0, i_aggserialfn);
13882         aggdeserialfn = PQgetvalue(res, 0, i_aggdeserialfn);
13883         aggmtransfn = PQgetvalue(res, 0, i_aggmtransfn);
13884         aggminvtransfn = PQgetvalue(res, 0, i_aggminvtransfn);
13885         aggmfinalfn = PQgetvalue(res, 0, i_aggmfinalfn);
13886         aggfinalextra = (PQgetvalue(res, 0, i_aggfinalextra)[0] == 't');
13887         aggmfinalextra = (PQgetvalue(res, 0, i_aggmfinalextra)[0] == 't');
13888         aggfinalmodify = PQgetvalue(res, 0, i_aggfinalmodify)[0];
13889         aggmfinalmodify = PQgetvalue(res, 0, i_aggmfinalmodify)[0];
13890         aggsortop = PQgetvalue(res, 0, i_aggsortop);
13891         aggkind = PQgetvalue(res, 0, i_aggkind)[0];
13892         aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
13893         aggtransspace = PQgetvalue(res, 0, i_aggtransspace);
13894         aggmtranstype = PQgetvalue(res, 0, i_aggmtranstype);
13895         aggmtransspace = PQgetvalue(res, 0, i_aggmtransspace);
13896         agginitval = PQgetvalue(res, 0, i_agginitval);
13897         aggminitval = PQgetvalue(res, 0, i_aggminitval);
13898         convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
13899
13900         if (fout->remoteVersion >= 80400)
13901         {
13902                 /* 8.4 or later; we rely on server-side code for most of the work */
13903                 char       *funcargs;
13904                 char       *funciargs;
13905
13906                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
13907                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
13908                 aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
13909                 aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
13910         }
13911         else
13912                 /* pre-8.4, do it ourselves */
13913                 aggsig = format_aggregate_signature(agginfo, fout, true);
13914
13915         aggsig_tag = format_aggregate_signature(agginfo, fout, false);
13916
13917         if (i_proparallel != -1)
13918                 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
13919         else
13920                 proparallel = NULL;
13921
13922         if (!convertok)
13923         {
13924                 pg_log_warning("aggregate function %s could not be dumped correctly for this database version; ignored",
13925                                   aggsig);
13926
13927                 if (aggfullsig)
13928                         free(aggfullsig);
13929
13930                 free(aggsig);
13931
13932                 return;
13933         }
13934
13935         /* identify default modify flag for aggkind (must match DefineAggregate) */
13936         defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
13937         /* replace omitted flags for old versions */
13938         if (aggfinalmodify == '0')
13939                 aggfinalmodify = defaultfinalmodify;
13940         if (aggmfinalmodify == '0')
13941                 aggmfinalmodify = defaultfinalmodify;
13942
13943         /* regproc and regtype output is already sufficiently quoted */
13944         appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
13945                                           aggtransfn, aggtranstype);
13946
13947         if (strcmp(aggtransspace, "0") != 0)
13948         {
13949                 appendPQExpBuffer(details, ",\n    SSPACE = %s",
13950                                                   aggtransspace);
13951         }
13952
13953         if (!PQgetisnull(res, 0, i_agginitval))
13954         {
13955                 appendPQExpBufferStr(details, ",\n    INITCOND = ");
13956                 appendStringLiteralAH(details, agginitval, fout);
13957         }
13958
13959         if (strcmp(aggfinalfn, "-") != 0)
13960         {
13961                 appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
13962                                                   aggfinalfn);
13963                 if (aggfinalextra)
13964                         appendPQExpBufferStr(details, ",\n    FINALFUNC_EXTRA");
13965                 if (aggfinalmodify != defaultfinalmodify)
13966                 {
13967                         switch (aggfinalmodify)
13968                         {
13969                                 case AGGMODIFY_READ_ONLY:
13970                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_ONLY");
13971                                         break;
13972                                 case AGGMODIFY_SHAREABLE:
13973                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = SHAREABLE");
13974                                         break;
13975                                 case AGGMODIFY_READ_WRITE:
13976                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_WRITE");
13977                                         break;
13978                                 default:
13979                                         fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
13980                                                                   agginfo->aggfn.dobj.name);
13981                                         break;
13982                         }
13983                 }
13984         }
13985
13986         if (strcmp(aggcombinefn, "-") != 0)
13987                 appendPQExpBuffer(details, ",\n    COMBINEFUNC = %s", aggcombinefn);
13988
13989         if (strcmp(aggserialfn, "-") != 0)
13990                 appendPQExpBuffer(details, ",\n    SERIALFUNC = %s", aggserialfn);
13991
13992         if (strcmp(aggdeserialfn, "-") != 0)
13993                 appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s", aggdeserialfn);
13994
13995         if (strcmp(aggmtransfn, "-") != 0)
13996         {
13997                 appendPQExpBuffer(details, ",\n    MSFUNC = %s,\n    MINVFUNC = %s,\n    MSTYPE = %s",
13998                                                   aggmtransfn,
13999                                                   aggminvtransfn,
14000                                                   aggmtranstype);
14001         }
14002
14003         if (strcmp(aggmtransspace, "0") != 0)
14004         {
14005                 appendPQExpBuffer(details, ",\n    MSSPACE = %s",
14006                                                   aggmtransspace);
14007         }
14008
14009         if (!PQgetisnull(res, 0, i_aggminitval))
14010         {
14011                 appendPQExpBufferStr(details, ",\n    MINITCOND = ");
14012                 appendStringLiteralAH(details, aggminitval, fout);
14013         }
14014
14015         if (strcmp(aggmfinalfn, "-") != 0)
14016         {
14017                 appendPQExpBuffer(details, ",\n    MFINALFUNC = %s",
14018                                                   aggmfinalfn);
14019                 if (aggmfinalextra)
14020                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_EXTRA");
14021                 if (aggmfinalmodify != defaultfinalmodify)
14022                 {
14023                         switch (aggmfinalmodify)
14024                         {
14025                                 case AGGMODIFY_READ_ONLY:
14026                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_ONLY");
14027                                         break;
14028                                 case AGGMODIFY_SHAREABLE:
14029                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = SHAREABLE");
14030                                         break;
14031                                 case AGGMODIFY_READ_WRITE:
14032                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_WRITE");
14033                                         break;
14034                                 default:
14035                                         fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
14036                                                                   agginfo->aggfn.dobj.name);
14037                                         break;
14038                         }
14039                 }
14040         }
14041
14042         aggsortconvop = getFormattedOperatorName(fout, aggsortop);
14043         if (aggsortconvop)
14044         {
14045                 appendPQExpBuffer(details, ",\n    SORTOP = %s",
14046                                                   aggsortconvop);
14047                 free(aggsortconvop);
14048         }
14049
14050         if (aggkind == AGGKIND_HYPOTHETICAL)
14051                 appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
14052
14053         if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
14054         {
14055                 if (proparallel[0] == PROPARALLEL_SAFE)
14056                         appendPQExpBufferStr(details, ",\n    PARALLEL = safe");
14057                 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
14058                         appendPQExpBufferStr(details, ",\n    PARALLEL = restricted");
14059                 else if (proparallel[0] != PROPARALLEL_UNSAFE)
14060                         fatal("unrecognized proparallel value for function \"%s\"",
14061                                                   agginfo->aggfn.dobj.name);
14062         }
14063
14064         appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
14065                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
14066                                           aggsig);
14067
14068         appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
14069                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
14070                                           aggfullsig ? aggfullsig : aggsig, details->data);
14071
14072         if (dopt->binary_upgrade)
14073                 binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
14074                                                                                 "AGGREGATE", aggsig,
14075                                                                                 agginfo->aggfn.dobj.namespace->dobj.name);
14076
14077         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
14078                 ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
14079                                          agginfo->aggfn.dobj.dumpId,
14080                                          ARCHIVE_OPTS(.tag = aggsig_tag,
14081                                                                   .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
14082                                                                   .owner = agginfo->aggfn.rolname,
14083                                                                   .description = "AGGREGATE",
14084                                                                   .section = SECTION_PRE_DATA,
14085                                                                   .createStmt = q->data,
14086                                                                   .dropStmt = delq->data));
14087
14088         /* Dump Aggregate Comments */
14089         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
14090                 dumpComment(fout, "AGGREGATE", aggsig,
14091                                         agginfo->aggfn.dobj.namespace->dobj.name,
14092                                         agginfo->aggfn.rolname,
14093                                         agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
14094
14095         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
14096                 dumpSecLabel(fout, "AGGREGATE", aggsig,
14097                                          agginfo->aggfn.dobj.namespace->dobj.name,
14098                                          agginfo->aggfn.rolname,
14099                                          agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
14100
14101         /*
14102          * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
14103          * command look like a function's GRANT; in particular this affects the
14104          * syntax for zero-argument aggregates and ordered-set aggregates.
14105          */
14106         free(aggsig);
14107
14108         aggsig = format_function_signature(fout, &agginfo->aggfn, true);
14109
14110         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
14111                 dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
14112                                 "FUNCTION", aggsig, NULL,
14113                                 agginfo->aggfn.dobj.namespace->dobj.name,
14114                                 agginfo->aggfn.rolname, agginfo->aggfn.proacl,
14115                                 agginfo->aggfn.rproacl,
14116                                 agginfo->aggfn.initproacl, agginfo->aggfn.initrproacl);
14117
14118         free(aggsig);
14119         if (aggfullsig)
14120                 free(aggfullsig);
14121         free(aggsig_tag);
14122
14123         PQclear(res);
14124
14125         destroyPQExpBuffer(query);
14126         destroyPQExpBuffer(q);
14127         destroyPQExpBuffer(delq);
14128         destroyPQExpBuffer(details);
14129 }
14130
14131 /*
14132  * dumpTSParser
14133  *        write out a single text search parser
14134  */
14135 static void
14136 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
14137 {
14138         DumpOptions *dopt = fout->dopt;
14139         PQExpBuffer q;
14140         PQExpBuffer delq;
14141         char       *qprsname;
14142
14143         /* Skip if not to be dumped */
14144         if (!prsinfo->dobj.dump || dopt->dataOnly)
14145                 return;
14146
14147         q = createPQExpBuffer();
14148         delq = createPQExpBuffer();
14149
14150         qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
14151
14152         appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
14153                                           fmtQualifiedDumpable(prsinfo));
14154
14155         appendPQExpBuffer(q, "    START = %s,\n",
14156                                           convertTSFunction(fout, prsinfo->prsstart));
14157         appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
14158                                           convertTSFunction(fout, prsinfo->prstoken));
14159         appendPQExpBuffer(q, "    END = %s,\n",
14160                                           convertTSFunction(fout, prsinfo->prsend));
14161         if (prsinfo->prsheadline != InvalidOid)
14162                 appendPQExpBuffer(q, "    HEADLINE = %s,\n",
14163                                                   convertTSFunction(fout, prsinfo->prsheadline));
14164         appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
14165                                           convertTSFunction(fout, prsinfo->prslextype));
14166
14167         appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
14168                                           fmtQualifiedDumpable(prsinfo));
14169
14170         if (dopt->binary_upgrade)
14171                 binary_upgrade_extension_member(q, &prsinfo->dobj,
14172                                                                                 "TEXT SEARCH PARSER", qprsname,
14173                                                                                 prsinfo->dobj.namespace->dobj.name);
14174
14175         if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14176                 ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
14177                                          ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
14178                                                                   .namespace = prsinfo->dobj.namespace->dobj.name,
14179                                                                   .description = "TEXT SEARCH PARSER",
14180                                                                   .section = SECTION_PRE_DATA,
14181                                                                   .createStmt = q->data,
14182                                                                   .dropStmt = delq->data));
14183
14184         /* Dump Parser Comments */
14185         if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14186                 dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
14187                                         prsinfo->dobj.namespace->dobj.name, "",
14188                                         prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
14189
14190         destroyPQExpBuffer(q);
14191         destroyPQExpBuffer(delq);
14192         free(qprsname);
14193 }
14194
14195 /*
14196  * dumpTSDictionary
14197  *        write out a single text search dictionary
14198  */
14199 static void
14200 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
14201 {
14202         DumpOptions *dopt = fout->dopt;
14203         PQExpBuffer q;
14204         PQExpBuffer delq;
14205         PQExpBuffer query;
14206         char       *qdictname;
14207         PGresult   *res;
14208         char       *nspname;
14209         char       *tmplname;
14210
14211         /* Skip if not to be dumped */
14212         if (!dictinfo->dobj.dump || dopt->dataOnly)
14213                 return;
14214
14215         q = createPQExpBuffer();
14216         delq = createPQExpBuffer();
14217         query = createPQExpBuffer();
14218
14219         qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
14220
14221         /* Fetch name and namespace of the dictionary's template */
14222         appendPQExpBuffer(query, "SELECT nspname, tmplname "
14223                                           "FROM pg_ts_template p, pg_namespace n "
14224                                           "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
14225                                           dictinfo->dicttemplate);
14226         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14227         nspname = PQgetvalue(res, 0, 0);
14228         tmplname = PQgetvalue(res, 0, 1);
14229
14230         appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
14231                                           fmtQualifiedDumpable(dictinfo));
14232
14233         appendPQExpBufferStr(q, "    TEMPLATE = ");
14234         appendPQExpBuffer(q, "%s.", fmtId(nspname));
14235         appendPQExpBufferStr(q, fmtId(tmplname));
14236
14237         PQclear(res);
14238
14239         /* the dictinitoption can be dumped straight into the command */
14240         if (dictinfo->dictinitoption)
14241                 appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
14242
14243         appendPQExpBufferStr(q, " );\n");
14244
14245         appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
14246                                           fmtQualifiedDumpable(dictinfo));
14247
14248         if (dopt->binary_upgrade)
14249                 binary_upgrade_extension_member(q, &dictinfo->dobj,
14250                                                                                 "TEXT SEARCH DICTIONARY", qdictname,
14251                                                                                 dictinfo->dobj.namespace->dobj.name);
14252
14253         if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14254                 ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
14255                                          ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
14256                                                                   .namespace = dictinfo->dobj.namespace->dobj.name,
14257                                                                   .owner = dictinfo->rolname,
14258                                                                   .description = "TEXT SEARCH DICTIONARY",
14259                                                                   .section = SECTION_PRE_DATA,
14260                                                                   .createStmt = q->data,
14261                                                                   .dropStmt = delq->data));
14262
14263         /* Dump Dictionary Comments */
14264         if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14265                 dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
14266                                         dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
14267                                         dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
14268
14269         destroyPQExpBuffer(q);
14270         destroyPQExpBuffer(delq);
14271         destroyPQExpBuffer(query);
14272         free(qdictname);
14273 }
14274
14275 /*
14276  * dumpTSTemplate
14277  *        write out a single text search template
14278  */
14279 static void
14280 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
14281 {
14282         DumpOptions *dopt = fout->dopt;
14283         PQExpBuffer q;
14284         PQExpBuffer delq;
14285         char       *qtmplname;
14286
14287         /* Skip if not to be dumped */
14288         if (!tmplinfo->dobj.dump || dopt->dataOnly)
14289                 return;
14290
14291         q = createPQExpBuffer();
14292         delq = createPQExpBuffer();
14293
14294         qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
14295
14296         appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
14297                                           fmtQualifiedDumpable(tmplinfo));
14298
14299         if (tmplinfo->tmplinit != InvalidOid)
14300                 appendPQExpBuffer(q, "    INIT = %s,\n",
14301                                                   convertTSFunction(fout, tmplinfo->tmplinit));
14302         appendPQExpBuffer(q, "    LEXIZE = %s );\n",
14303                                           convertTSFunction(fout, tmplinfo->tmpllexize));
14304
14305         appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
14306                                           fmtQualifiedDumpable(tmplinfo));
14307
14308         if (dopt->binary_upgrade)
14309                 binary_upgrade_extension_member(q, &tmplinfo->dobj,
14310                                                                                 "TEXT SEARCH TEMPLATE", qtmplname,
14311                                                                                 tmplinfo->dobj.namespace->dobj.name);
14312
14313         if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14314                 ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
14315                                          ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
14316                                                                   .namespace = tmplinfo->dobj.namespace->dobj.name,
14317                                                                   .description = "TEXT SEARCH TEMPLATE",
14318                                                                   .section = SECTION_PRE_DATA,
14319                                                                   .createStmt = q->data,
14320                                                                   .dropStmt = delq->data));
14321
14322         /* Dump Template Comments */
14323         if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14324                 dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
14325                                         tmplinfo->dobj.namespace->dobj.name, "",
14326                                         tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
14327
14328         destroyPQExpBuffer(q);
14329         destroyPQExpBuffer(delq);
14330         free(qtmplname);
14331 }
14332
14333 /*
14334  * dumpTSConfig
14335  *        write out a single text search configuration
14336  */
14337 static void
14338 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
14339 {
14340         DumpOptions *dopt = fout->dopt;
14341         PQExpBuffer q;
14342         PQExpBuffer delq;
14343         PQExpBuffer query;
14344         char       *qcfgname;
14345         PGresult   *res;
14346         char       *nspname;
14347         char       *prsname;
14348         int                     ntups,
14349                                 i;
14350         int                     i_tokenname;
14351         int                     i_dictname;
14352
14353         /* Skip if not to be dumped */
14354         if (!cfginfo->dobj.dump || dopt->dataOnly)
14355                 return;
14356
14357         q = createPQExpBuffer();
14358         delq = createPQExpBuffer();
14359         query = createPQExpBuffer();
14360
14361         qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
14362
14363         /* Fetch name and namespace of the config's parser */
14364         appendPQExpBuffer(query, "SELECT nspname, prsname "
14365                                           "FROM pg_ts_parser p, pg_namespace n "
14366                                           "WHERE p.oid = '%u' AND n.oid = prsnamespace",
14367                                           cfginfo->cfgparser);
14368         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14369         nspname = PQgetvalue(res, 0, 0);
14370         prsname = PQgetvalue(res, 0, 1);
14371
14372         appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
14373                                           fmtQualifiedDumpable(cfginfo));
14374
14375         appendPQExpBuffer(q, "    PARSER = %s.", fmtId(nspname));
14376         appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
14377
14378         PQclear(res);
14379
14380         resetPQExpBuffer(query);
14381         appendPQExpBuffer(query,
14382                                           "SELECT\n"
14383                                           "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
14384                                           "    WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
14385                                           "  m.mapdict::pg_catalog.regdictionary AS dictname\n"
14386                                           "FROM pg_catalog.pg_ts_config_map AS m\n"
14387                                           "WHERE m.mapcfg = '%u'\n"
14388                                           "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
14389                                           cfginfo->cfgparser, cfginfo->dobj.catId.oid);
14390
14391         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14392         ntups = PQntuples(res);
14393
14394         i_tokenname = PQfnumber(res, "tokenname");
14395         i_dictname = PQfnumber(res, "dictname");
14396
14397         for (i = 0; i < ntups; i++)
14398         {
14399                 char       *tokenname = PQgetvalue(res, i, i_tokenname);
14400                 char       *dictname = PQgetvalue(res, i, i_dictname);
14401
14402                 if (i == 0 ||
14403                         strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
14404                 {
14405                         /* starting a new token type, so start a new command */
14406                         if (i > 0)
14407                                 appendPQExpBufferStr(q, ";\n");
14408                         appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
14409                                                           fmtQualifiedDumpable(cfginfo));
14410                         /* tokenname needs quoting, dictname does NOT */
14411                         appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
14412                                                           fmtId(tokenname), dictname);
14413                 }
14414                 else
14415                         appendPQExpBuffer(q, ", %s", dictname);
14416         }
14417
14418         if (ntups > 0)
14419                 appendPQExpBufferStr(q, ";\n");
14420
14421         PQclear(res);
14422
14423         appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
14424                                           fmtQualifiedDumpable(cfginfo));
14425
14426         if (dopt->binary_upgrade)
14427                 binary_upgrade_extension_member(q, &cfginfo->dobj,
14428                                                                                 "TEXT SEARCH CONFIGURATION", qcfgname,
14429                                                                                 cfginfo->dobj.namespace->dobj.name);
14430
14431         if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14432                 ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
14433                                          ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
14434                                                                   .namespace = cfginfo->dobj.namespace->dobj.name,
14435                                                                   .owner = cfginfo->rolname,
14436                                                                   .description = "TEXT SEARCH CONFIGURATION",
14437                                                                   .section = SECTION_PRE_DATA,
14438                                                                   .createStmt = q->data,
14439                                                                   .dropStmt = delq->data));
14440
14441         /* Dump Configuration Comments */
14442         if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14443                 dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
14444                                         cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
14445                                         cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
14446
14447         destroyPQExpBuffer(q);
14448         destroyPQExpBuffer(delq);
14449         destroyPQExpBuffer(query);
14450         free(qcfgname);
14451 }
14452
14453 /*
14454  * dumpForeignDataWrapper
14455  *        write out a single foreign-data wrapper definition
14456  */
14457 static void
14458 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
14459 {
14460         DumpOptions *dopt = fout->dopt;
14461         PQExpBuffer q;
14462         PQExpBuffer delq;
14463         char       *qfdwname;
14464
14465         /* Skip if not to be dumped */
14466         if (!fdwinfo->dobj.dump || dopt->dataOnly)
14467                 return;
14468
14469         q = createPQExpBuffer();
14470         delq = createPQExpBuffer();
14471
14472         qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
14473
14474         appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
14475                                           qfdwname);
14476
14477         if (strcmp(fdwinfo->fdwhandler, "-") != 0)
14478                 appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
14479
14480         if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
14481                 appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
14482
14483         if (strlen(fdwinfo->fdwoptions) > 0)
14484                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
14485
14486         appendPQExpBufferStr(q, ";\n");
14487
14488         appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
14489                                           qfdwname);
14490
14491         if (dopt->binary_upgrade)
14492                 binary_upgrade_extension_member(q, &fdwinfo->dobj,
14493                                                                                 "FOREIGN DATA WRAPPER", qfdwname,
14494                                                                                 NULL);
14495
14496         if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14497                 ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14498                                          ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
14499                                                                   .owner = fdwinfo->rolname,
14500                                                                   .description = "FOREIGN DATA WRAPPER",
14501                                                                   .section = SECTION_PRE_DATA,
14502                                                                   .createStmt = q->data,
14503                                                                   .dropStmt = delq->data));
14504
14505         /* Dump Foreign Data Wrapper Comments */
14506         if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14507                 dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
14508                                         NULL, fdwinfo->rolname,
14509                                         fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
14510
14511         /* Handle the ACL */
14512         if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
14513                 dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14514                                 "FOREIGN DATA WRAPPER", qfdwname, NULL,
14515                                 NULL, fdwinfo->rolname,
14516                                 fdwinfo->fdwacl, fdwinfo->rfdwacl,
14517                                 fdwinfo->initfdwacl, fdwinfo->initrfdwacl);
14518
14519         free(qfdwname);
14520
14521         destroyPQExpBuffer(q);
14522         destroyPQExpBuffer(delq);
14523 }
14524
14525 /*
14526  * dumpForeignServer
14527  *        write out a foreign server definition
14528  */
14529 static void
14530 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
14531 {
14532         DumpOptions *dopt = fout->dopt;
14533         PQExpBuffer q;
14534         PQExpBuffer delq;
14535         PQExpBuffer query;
14536         PGresult   *res;
14537         char       *qsrvname;
14538         char       *fdwname;
14539
14540         /* Skip if not to be dumped */
14541         if (!srvinfo->dobj.dump || dopt->dataOnly)
14542                 return;
14543
14544         q = createPQExpBuffer();
14545         delq = createPQExpBuffer();
14546         query = createPQExpBuffer();
14547
14548         qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
14549
14550         /* look up the foreign-data wrapper */
14551         appendPQExpBuffer(query, "SELECT fdwname "
14552                                           "FROM pg_foreign_data_wrapper w "
14553                                           "WHERE w.oid = '%u'",
14554                                           srvinfo->srvfdw);
14555         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14556         fdwname = PQgetvalue(res, 0, 0);
14557
14558         appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
14559         if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
14560         {
14561                 appendPQExpBufferStr(q, " TYPE ");
14562                 appendStringLiteralAH(q, srvinfo->srvtype, fout);
14563         }
14564         if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
14565         {
14566                 appendPQExpBufferStr(q, " VERSION ");
14567                 appendStringLiteralAH(q, srvinfo->srvversion, fout);
14568         }
14569
14570         appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
14571         appendPQExpBufferStr(q, fmtId(fdwname));
14572
14573         if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
14574                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
14575
14576         appendPQExpBufferStr(q, ";\n");
14577
14578         appendPQExpBuffer(delq, "DROP SERVER %s;\n",
14579                                           qsrvname);
14580
14581         if (dopt->binary_upgrade)
14582                 binary_upgrade_extension_member(q, &srvinfo->dobj,
14583                                                                                 "SERVER", qsrvname, NULL);
14584
14585         if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14586                 ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14587                                          ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
14588                                                                   .owner = srvinfo->rolname,
14589                                                                   .description = "SERVER",
14590                                                                   .section = SECTION_PRE_DATA,
14591                                                                   .createStmt = q->data,
14592                                                                   .dropStmt = delq->data));
14593
14594         /* Dump Foreign Server Comments */
14595         if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14596                 dumpComment(fout, "SERVER", qsrvname,
14597                                         NULL, srvinfo->rolname,
14598                                         srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
14599
14600         /* Handle the ACL */
14601         if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
14602                 dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14603                                 "FOREIGN SERVER", qsrvname, NULL,
14604                                 NULL, srvinfo->rolname,
14605                                 srvinfo->srvacl, srvinfo->rsrvacl,
14606                                 srvinfo->initsrvacl, srvinfo->initrsrvacl);
14607
14608         /* Dump user mappings */
14609         if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
14610                 dumpUserMappings(fout,
14611                                                  srvinfo->dobj.name, NULL,
14612                                                  srvinfo->rolname,
14613                                                  srvinfo->dobj.catId, srvinfo->dobj.dumpId);
14614
14615         free(qsrvname);
14616
14617         destroyPQExpBuffer(q);
14618         destroyPQExpBuffer(delq);
14619         destroyPQExpBuffer(query);
14620 }
14621
14622 /*
14623  * dumpUserMappings
14624  *
14625  * This routine is used to dump any user mappings associated with the
14626  * server handed to this routine. Should be called after ArchiveEntry()
14627  * for the server.
14628  */
14629 static void
14630 dumpUserMappings(Archive *fout,
14631                                  const char *servername, const char *namespace,
14632                                  const char *owner,
14633                                  CatalogId catalogId, DumpId dumpId)
14634 {
14635         PQExpBuffer q;
14636         PQExpBuffer delq;
14637         PQExpBuffer query;
14638         PQExpBuffer tag;
14639         PGresult   *res;
14640         int                     ntups;
14641         int                     i_usename;
14642         int                     i_umoptions;
14643         int                     i;
14644
14645         q = createPQExpBuffer();
14646         tag = createPQExpBuffer();
14647         delq = createPQExpBuffer();
14648         query = createPQExpBuffer();
14649
14650         /*
14651          * We read from the publicly accessible view pg_user_mappings, so as not
14652          * to fail if run by a non-superuser.  Note that the view will show
14653          * umoptions as null if the user hasn't got privileges for the associated
14654          * server; this means that pg_dump will dump such a mapping, but with no
14655          * OPTIONS clause.  A possible alternative is to skip such mappings
14656          * altogether, but it's not clear that that's an improvement.
14657          */
14658         appendPQExpBuffer(query,
14659                                           "SELECT usename, "
14660                                           "array_to_string(ARRAY("
14661                                           "SELECT quote_ident(option_name) || ' ' || "
14662                                           "quote_literal(option_value) "
14663                                           "FROM pg_options_to_table(umoptions) "
14664                                           "ORDER BY option_name"
14665                                           "), E',\n    ') AS umoptions "
14666                                           "FROM pg_user_mappings "
14667                                           "WHERE srvid = '%u' "
14668                                           "ORDER BY usename",
14669                                           catalogId.oid);
14670
14671         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14672
14673         ntups = PQntuples(res);
14674         i_usename = PQfnumber(res, "usename");
14675         i_umoptions = PQfnumber(res, "umoptions");
14676
14677         for (i = 0; i < ntups; i++)
14678         {
14679                 char       *usename;
14680                 char       *umoptions;
14681
14682                 usename = PQgetvalue(res, i, i_usename);
14683                 umoptions = PQgetvalue(res, i, i_umoptions);
14684
14685                 resetPQExpBuffer(q);
14686                 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
14687                 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
14688
14689                 if (umoptions && strlen(umoptions) > 0)
14690                         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
14691
14692                 appendPQExpBufferStr(q, ";\n");
14693
14694                 resetPQExpBuffer(delq);
14695                 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
14696                 appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
14697
14698                 resetPQExpBuffer(tag);
14699                 appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
14700                                                   usename, servername);
14701
14702                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14703                                          ARCHIVE_OPTS(.tag = tag->data,
14704                                                                   .namespace = namespace,
14705                                                                   .owner = owner,
14706                                                                   .description = "USER MAPPING",
14707                                                                   .section = SECTION_PRE_DATA,
14708                                                                   .createStmt = q->data,
14709                                                                   .dropStmt = delq->data));
14710         }
14711
14712         PQclear(res);
14713
14714         destroyPQExpBuffer(query);
14715         destroyPQExpBuffer(delq);
14716         destroyPQExpBuffer(tag);
14717         destroyPQExpBuffer(q);
14718 }
14719
14720 /*
14721  * Write out default privileges information
14722  */
14723 static void
14724 dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
14725 {
14726         DumpOptions *dopt = fout->dopt;
14727         PQExpBuffer q;
14728         PQExpBuffer tag;
14729         const char *type;
14730
14731         /* Skip if not to be dumped */
14732         if (!daclinfo->dobj.dump || dopt->dataOnly || dopt->aclsSkip)
14733                 return;
14734
14735         q = createPQExpBuffer();
14736         tag = createPQExpBuffer();
14737
14738         switch (daclinfo->defaclobjtype)
14739         {
14740                 case DEFACLOBJ_RELATION:
14741                         type = "TABLES";
14742                         break;
14743                 case DEFACLOBJ_SEQUENCE:
14744                         type = "SEQUENCES";
14745                         break;
14746                 case DEFACLOBJ_FUNCTION:
14747                         type = "FUNCTIONS";
14748                         break;
14749                 case DEFACLOBJ_TYPE:
14750                         type = "TYPES";
14751                         break;
14752                 case DEFACLOBJ_NAMESPACE:
14753                         type = "SCHEMAS";
14754                         break;
14755                 default:
14756                         /* shouldn't get here */
14757                         fatal("unrecognized object type in default privileges: %d",
14758                                                   (int) daclinfo->defaclobjtype);
14759                         type = "";                      /* keep compiler quiet */
14760         }
14761
14762         appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
14763
14764         /* build the actual command(s) for this tuple */
14765         if (!buildDefaultACLCommands(type,
14766                                                                  daclinfo->dobj.namespace != NULL ?
14767                                                                  daclinfo->dobj.namespace->dobj.name : NULL,
14768                                                                  daclinfo->defaclacl,
14769                                                                  daclinfo->rdefaclacl,
14770                                                                  daclinfo->initdefaclacl,
14771                                                                  daclinfo->initrdefaclacl,
14772                                                                  daclinfo->defaclrole,
14773                                                                  fout->remoteVersion,
14774                                                                  q))
14775                 fatal("could not parse default ACL list (%s)",
14776                                           daclinfo->defaclacl);
14777
14778         if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
14779                 ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
14780                                          ARCHIVE_OPTS(.tag = tag->data,
14781                                                                   .namespace = daclinfo->dobj.namespace ?
14782                                                                   daclinfo->dobj.namespace->dobj.name : NULL,
14783                                                                   .owner = daclinfo->defaclrole,
14784                                                                   .description = "DEFAULT ACL",
14785                                                                   .section = SECTION_POST_DATA,
14786                                                                   .createStmt = q->data));
14787
14788         destroyPQExpBuffer(tag);
14789         destroyPQExpBuffer(q);
14790 }
14791
14792 /*----------
14793  * Write out grant/revoke information
14794  *
14795  * 'objCatId' is the catalog ID of the underlying object.
14796  * 'objDumpId' is the dump ID of the underlying object.
14797  * 'type' must be one of
14798  *              TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
14799  *              FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
14800  * 'name' is the formatted name of the object.  Must be quoted etc. already.
14801  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
14802  *              (Currently we assume that subname is only provided for table columns.)
14803  * 'nspname' is the namespace the object is in (NULL if none).
14804  * 'owner' is the owner, NULL if there is no owner (for languages).
14805  * 'acls' contains the ACL string of the object from the appropriate system
14806  *              catalog field; it will be passed to buildACLCommands for building the
14807  *              appropriate GRANT commands.
14808  * 'racls' contains the ACL string of any initial-but-now-revoked ACLs of the
14809  *              object; it will be passed to buildACLCommands for building the
14810  *              appropriate REVOKE commands.
14811  * 'initacls' In binary-upgrade mode, ACL string of the object's initial
14812  *              privileges, to be recorded into pg_init_privs
14813  * 'initracls' In binary-upgrade mode, ACL string of the object's
14814  *              revoked-from-default privileges, to be recorded into pg_init_privs
14815  *
14816  * NB: initacls/initracls are needed because extensions can set privileges on
14817  * an object during the extension's script file and we record those into
14818  * pg_init_privs as that object's initial privileges.
14819  *----------
14820  */
14821 static void
14822 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
14823                 const char *type, const char *name, const char *subname,
14824                 const char *nspname, const char *owner,
14825                 const char *acls, const char *racls,
14826                 const char *initacls, const char *initracls)
14827 {
14828         DumpOptions *dopt = fout->dopt;
14829         PQExpBuffer sql;
14830
14831         /* Do nothing if ACL dump is not enabled */
14832         if (dopt->aclsSkip)
14833                 return;
14834
14835         /* --data-only skips ACLs *except* BLOB ACLs */
14836         if (dopt->dataOnly && strcmp(type, "LARGE OBJECT") != 0)
14837                 return;
14838
14839         sql = createPQExpBuffer();
14840
14841         /*
14842          * Check to see if this object has had any initial ACLs included for it.
14843          * If so, we are in binary upgrade mode and these are the ACLs to turn
14844          * into GRANT and REVOKE statements to set and record the initial
14845          * privileges for an extension object.  Let the backend know that these
14846          * are to be recorded by calling binary_upgrade_set_record_init_privs()
14847          * before and after.
14848          */
14849         if (strlen(initacls) != 0 || strlen(initracls) != 0)
14850         {
14851                 appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
14852                 if (!buildACLCommands(name, subname, nspname, type,
14853                                                           initacls, initracls, owner,
14854                                                           "", fout->remoteVersion, sql))
14855                         fatal("could not parse initial GRANT ACL list (%s) or initial REVOKE ACL list (%s) for object \"%s\" (%s)",
14856                                                   initacls, initracls, name, type);
14857                 appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
14858         }
14859
14860         if (!buildACLCommands(name, subname, nspname, type,
14861                                                   acls, racls, owner,
14862                                                   "", fout->remoteVersion, sql))
14863                 fatal("could not parse GRANT ACL list (%s) or REVOKE ACL list (%s) for object \"%s\" (%s)",
14864                                           acls, racls, name, type);
14865
14866         if (sql->len > 0)
14867         {
14868                 PQExpBuffer tag = createPQExpBuffer();
14869
14870                 if (subname)
14871                         appendPQExpBuffer(tag, "COLUMN %s.%s", name, subname);
14872                 else
14873                         appendPQExpBuffer(tag, "%s %s", type, name);
14874
14875                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14876                                          ARCHIVE_OPTS(.tag = tag->data,
14877                                                                   .namespace = nspname,
14878                                                                   .owner = owner,
14879                                                                   .description = "ACL",
14880                                                                   .section = SECTION_NONE,
14881                                                                   .createStmt = sql->data,
14882                                                                   .deps = &objDumpId,
14883                                                                   .nDeps = 1));
14884                 destroyPQExpBuffer(tag);
14885         }
14886
14887         destroyPQExpBuffer(sql);
14888 }
14889
14890 /*
14891  * dumpSecLabel
14892  *
14893  * This routine is used to dump any security labels associated with the
14894  * object handed to this routine. The routine takes the object type
14895  * and object name (ready to print, except for schema decoration), plus
14896  * the namespace and owner of the object (for labeling the ArchiveEntry),
14897  * plus catalog ID and subid which are the lookup key for pg_seclabel,
14898  * plus the dump ID for the object (for setting a dependency).
14899  * If a matching pg_seclabel entry is found, it is dumped.
14900  *
14901  * Note: although this routine takes a dumpId for dependency purposes,
14902  * that purpose is just to mark the dependency in the emitted dump file
14903  * for possible future use by pg_restore.  We do NOT use it for determining
14904  * ordering of the label in the dump file, because this routine is called
14905  * after dependency sorting occurs.  This routine should be called just after
14906  * calling ArchiveEntry() for the specified object.
14907  */
14908 static void
14909 dumpSecLabel(Archive *fout, const char *type, const char *name,
14910                          const char *namespace, const char *owner,
14911                          CatalogId catalogId, int subid, DumpId dumpId)
14912 {
14913         DumpOptions *dopt = fout->dopt;
14914         SecLabelItem *labels;
14915         int                     nlabels;
14916         int                     i;
14917         PQExpBuffer query;
14918
14919         /* do nothing, if --no-security-labels is supplied */
14920         if (dopt->no_security_labels)
14921                 return;
14922
14923         /* Security labels are schema not data ... except blob labels are data */
14924         if (strcmp(type, "LARGE OBJECT") != 0)
14925         {
14926                 if (dopt->dataOnly)
14927                         return;
14928         }
14929         else
14930         {
14931                 /* We do dump blob security labels in binary-upgrade mode */
14932                 if (dopt->schemaOnly && !dopt->binary_upgrade)
14933                         return;
14934         }
14935
14936         /* Search for security labels associated with catalogId, using table */
14937         nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
14938
14939         query = createPQExpBuffer();
14940
14941         for (i = 0; i < nlabels; i++)
14942         {
14943                 /*
14944                  * Ignore label entries for which the subid doesn't match.
14945                  */
14946                 if (labels[i].objsubid != subid)
14947                         continue;
14948
14949                 appendPQExpBuffer(query,
14950                                                   "SECURITY LABEL FOR %s ON %s ",
14951                                                   fmtId(labels[i].provider), type);
14952                 if (namespace && *namespace)
14953                         appendPQExpBuffer(query, "%s.", fmtId(namespace));
14954                 appendPQExpBuffer(query, "%s IS ", name);
14955                 appendStringLiteralAH(query, labels[i].label, fout);
14956                 appendPQExpBufferStr(query, ";\n");
14957         }
14958
14959         if (query->len > 0)
14960         {
14961                 PQExpBuffer tag = createPQExpBuffer();
14962
14963                 appendPQExpBuffer(tag, "%s %s", type, name);
14964                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14965                                          ARCHIVE_OPTS(.tag = tag->data,
14966                                                                   .namespace = namespace,
14967                                                                   .owner = owner,
14968                                                                   .description = "SECURITY LABEL",
14969                                                                   .section = SECTION_NONE,
14970                                                                   .createStmt = query->data,
14971                                                                   .deps = &dumpId,
14972                                                                   .nDeps = 1));
14973                 destroyPQExpBuffer(tag);
14974         }
14975
14976         destroyPQExpBuffer(query);
14977 }
14978
14979 /*
14980  * dumpTableSecLabel
14981  *
14982  * As above, but dump security label for both the specified table (or view)
14983  * and its columns.
14984  */
14985 static void
14986 dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
14987 {
14988         DumpOptions *dopt = fout->dopt;
14989         SecLabelItem *labels;
14990         int                     nlabels;
14991         int                     i;
14992         PQExpBuffer query;
14993         PQExpBuffer target;
14994
14995         /* do nothing, if --no-security-labels is supplied */
14996         if (dopt->no_security_labels)
14997                 return;
14998
14999         /* SecLabel are SCHEMA not data */
15000         if (dopt->dataOnly)
15001                 return;
15002
15003         /* Search for comments associated with relation, using table */
15004         nlabels = findSecLabels(fout,
15005                                                         tbinfo->dobj.catId.tableoid,
15006                                                         tbinfo->dobj.catId.oid,
15007                                                         &labels);
15008
15009         /* If security labels exist, build SECURITY LABEL statements */
15010         if (nlabels <= 0)
15011                 return;
15012
15013         query = createPQExpBuffer();
15014         target = createPQExpBuffer();
15015
15016         for (i = 0; i < nlabels; i++)
15017         {
15018                 const char *colname;
15019                 const char *provider = labels[i].provider;
15020                 const char *label = labels[i].label;
15021                 int                     objsubid = labels[i].objsubid;
15022
15023                 resetPQExpBuffer(target);
15024                 if (objsubid == 0)
15025                 {
15026                         appendPQExpBuffer(target, "%s %s", reltypename,
15027                                                           fmtQualifiedDumpable(tbinfo));
15028                 }
15029                 else
15030                 {
15031                         colname = getAttrName(objsubid, tbinfo);
15032                         /* first fmtXXX result must be consumed before calling again */
15033                         appendPQExpBuffer(target, "COLUMN %s",
15034                                                           fmtQualifiedDumpable(tbinfo));
15035                         appendPQExpBuffer(target, ".%s", fmtId(colname));
15036                 }
15037                 appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
15038                                                   fmtId(provider), target->data);
15039                 appendStringLiteralAH(query, label, fout);
15040                 appendPQExpBufferStr(query, ";\n");
15041         }
15042         if (query->len > 0)
15043         {
15044                 resetPQExpBuffer(target);
15045                 appendPQExpBuffer(target, "%s %s", reltypename,
15046                                                   fmtId(tbinfo->dobj.name));
15047                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
15048                                          ARCHIVE_OPTS(.tag = target->data,
15049                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
15050                                                                   .owner = tbinfo->rolname,
15051                                                                   .description = "SECURITY LABEL",
15052                                                                   .section = SECTION_NONE,
15053                                                                   .createStmt = query->data,
15054                                                                   .deps = &(tbinfo->dobj.dumpId),
15055                                                                   .nDeps = 1));
15056         }
15057         destroyPQExpBuffer(query);
15058         destroyPQExpBuffer(target);
15059 }
15060
15061 /*
15062  * findSecLabels
15063  *
15064  * Find the security label(s), if any, associated with the given object.
15065  * All the objsubid values associated with the given classoid/objoid are
15066  * found with one search.
15067  */
15068 static int
15069 findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
15070 {
15071         /* static storage for table of security labels */
15072         static SecLabelItem *labels = NULL;
15073         static int      nlabels = -1;
15074
15075         SecLabelItem *middle = NULL;
15076         SecLabelItem *low;
15077         SecLabelItem *high;
15078         int                     nmatch;
15079
15080         /* Get security labels if we didn't already */
15081         if (nlabels < 0)
15082                 nlabels = collectSecLabels(fout, &labels);
15083
15084         if (nlabels <= 0)                       /* no labels, so no match is possible */
15085         {
15086                 *items = NULL;
15087                 return 0;
15088         }
15089
15090         /*
15091          * Do binary search to find some item matching the object.
15092          */
15093         low = &labels[0];
15094         high = &labels[nlabels - 1];
15095         while (low <= high)
15096         {
15097                 middle = low + (high - low) / 2;
15098
15099                 if (classoid < middle->classoid)
15100                         high = middle - 1;
15101                 else if (classoid > middle->classoid)
15102                         low = middle + 1;
15103                 else if (objoid < middle->objoid)
15104                         high = middle - 1;
15105                 else if (objoid > middle->objoid)
15106                         low = middle + 1;
15107                 else
15108                         break;                          /* found a match */
15109         }
15110
15111         if (low > high)                         /* no matches */
15112         {
15113                 *items = NULL;
15114                 return 0;
15115         }
15116
15117         /*
15118          * Now determine how many items match the object.  The search loop
15119          * invariant still holds: only items between low and high inclusive could
15120          * match.
15121          */
15122         nmatch = 1;
15123         while (middle > low)
15124         {
15125                 if (classoid != middle[-1].classoid ||
15126                         objoid != middle[-1].objoid)
15127                         break;
15128                 middle--;
15129                 nmatch++;
15130         }
15131
15132         *items = middle;
15133
15134         middle += nmatch;
15135         while (middle <= high)
15136         {
15137                 if (classoid != middle->classoid ||
15138                         objoid != middle->objoid)
15139                         break;
15140                 middle++;
15141                 nmatch++;
15142         }
15143
15144         return nmatch;
15145 }
15146
15147 /*
15148  * collectSecLabels
15149  *
15150  * Construct a table of all security labels available for database objects.
15151  * It's much faster to pull them all at once.
15152  *
15153  * The table is sorted by classoid/objid/objsubid for speed in lookup.
15154  */
15155 static int
15156 collectSecLabels(Archive *fout, SecLabelItem **items)
15157 {
15158         PGresult   *res;
15159         PQExpBuffer query;
15160         int                     i_label;
15161         int                     i_provider;
15162         int                     i_classoid;
15163         int                     i_objoid;
15164         int                     i_objsubid;
15165         int                     ntups;
15166         int                     i;
15167         SecLabelItem *labels;
15168
15169         query = createPQExpBuffer();
15170
15171         appendPQExpBufferStr(query,
15172                                                  "SELECT label, provider, classoid, objoid, objsubid "
15173                                                  "FROM pg_catalog.pg_seclabel "
15174                                                  "ORDER BY classoid, objoid, objsubid");
15175
15176         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15177
15178         /* Construct lookup table containing OIDs in numeric form */
15179         i_label = PQfnumber(res, "label");
15180         i_provider = PQfnumber(res, "provider");
15181         i_classoid = PQfnumber(res, "classoid");
15182         i_objoid = PQfnumber(res, "objoid");
15183         i_objsubid = PQfnumber(res, "objsubid");
15184
15185         ntups = PQntuples(res);
15186
15187         labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
15188
15189         for (i = 0; i < ntups; i++)
15190         {
15191                 labels[i].label = PQgetvalue(res, i, i_label);
15192                 labels[i].provider = PQgetvalue(res, i, i_provider);
15193                 labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
15194                 labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
15195                 labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
15196         }
15197
15198         /* Do NOT free the PGresult since we are keeping pointers into it */
15199         destroyPQExpBuffer(query);
15200
15201         *items = labels;
15202         return ntups;
15203 }
15204
15205 /*
15206  * dumpTable
15207  *        write out to fout the declarations (not data) of a user-defined table
15208  */
15209 static void
15210 dumpTable(Archive *fout, TableInfo *tbinfo)
15211 {
15212         DumpOptions *dopt = fout->dopt;
15213         char       *namecopy;
15214
15215         /*
15216          * noop if we are not dumping anything about this table, or if we are
15217          * doing a data-only dump
15218          */
15219         if (!tbinfo->dobj.dump || dopt->dataOnly)
15220                 return;
15221
15222         if (tbinfo->relkind == RELKIND_SEQUENCE)
15223                 dumpSequence(fout, tbinfo);
15224         else
15225                 dumpTableSchema(fout, tbinfo);
15226
15227         /* Handle the ACL here */
15228         namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
15229         if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15230         {
15231                 const char *objtype =
15232                 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
15233
15234                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
15235                                 objtype, namecopy, NULL,
15236                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15237                                 tbinfo->relacl, tbinfo->rrelacl,
15238                                 tbinfo->initrelacl, tbinfo->initrrelacl);
15239         }
15240
15241         /*
15242          * Handle column ACLs, if any.  Note: we pull these with a separate query
15243          * rather than trying to fetch them during getTableAttrs, so that we won't
15244          * miss ACLs on system columns.
15245          */
15246         if (fout->remoteVersion >= 80400 && tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15247         {
15248                 PQExpBuffer query = createPQExpBuffer();
15249                 PGresult   *res;
15250                 int                     i;
15251
15252                 if (fout->remoteVersion >= 90600)
15253                 {
15254                         PQExpBuffer acl_subquery = createPQExpBuffer();
15255                         PQExpBuffer racl_subquery = createPQExpBuffer();
15256                         PQExpBuffer initacl_subquery = createPQExpBuffer();
15257                         PQExpBuffer initracl_subquery = createPQExpBuffer();
15258
15259                         buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
15260                                                         initracl_subquery, "at.attacl", "c.relowner", "'c'",
15261                                                         dopt->binary_upgrade);
15262
15263                         appendPQExpBuffer(query,
15264                                                           "SELECT at.attname, "
15265                                                           "%s AS attacl, "
15266                                                           "%s AS rattacl, "
15267                                                           "%s AS initattacl, "
15268                                                           "%s AS initrattacl "
15269                                                           "FROM pg_catalog.pg_attribute at "
15270                                                           "JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
15271                                                           "LEFT JOIN pg_catalog.pg_init_privs pip ON "
15272                                                           "(at.attrelid = pip.objoid "
15273                                                           "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
15274                                                           "AND at.attnum = pip.objsubid) "
15275                                                           "WHERE at.attrelid = '%u'::pg_catalog.oid AND "
15276                                                           "NOT at.attisdropped "
15277                                                           "AND ("
15278                                                           "%s IS NOT NULL OR "
15279                                                           "%s IS NOT NULL OR "
15280                                                           "%s IS NOT NULL OR "
15281                                                           "%s IS NOT NULL)"
15282                                                           "ORDER BY at.attnum",
15283                                                           acl_subquery->data,
15284                                                           racl_subquery->data,
15285                                                           initacl_subquery->data,
15286                                                           initracl_subquery->data,
15287                                                           tbinfo->dobj.catId.oid,
15288                                                           acl_subquery->data,
15289                                                           racl_subquery->data,
15290                                                           initacl_subquery->data,
15291                                                           initracl_subquery->data);
15292
15293                         destroyPQExpBuffer(acl_subquery);
15294                         destroyPQExpBuffer(racl_subquery);
15295                         destroyPQExpBuffer(initacl_subquery);
15296                         destroyPQExpBuffer(initracl_subquery);
15297                 }
15298                 else
15299                 {
15300                         appendPQExpBuffer(query,
15301                                                           "SELECT attname, attacl, NULL as rattacl, "
15302                                                           "NULL AS initattacl, NULL AS initrattacl "
15303                                                           "FROM pg_catalog.pg_attribute "
15304                                                           "WHERE attrelid = '%u'::pg_catalog.oid AND NOT attisdropped "
15305                                                           "AND attacl IS NOT NULL "
15306                                                           "ORDER BY attnum",
15307                                                           tbinfo->dobj.catId.oid);
15308                 }
15309
15310                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15311
15312                 for (i = 0; i < PQntuples(res); i++)
15313                 {
15314                         char       *attname = PQgetvalue(res, i, 0);
15315                         char       *attacl = PQgetvalue(res, i, 1);
15316                         char       *rattacl = PQgetvalue(res, i, 2);
15317                         char       *initattacl = PQgetvalue(res, i, 3);
15318                         char       *initrattacl = PQgetvalue(res, i, 4);
15319                         char       *attnamecopy;
15320
15321                         attnamecopy = pg_strdup(fmtId(attname));
15322                         /* Column's GRANT type is always TABLE */
15323                         dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
15324                                         "TABLE", namecopy, attnamecopy,
15325                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15326                                         attacl, rattacl, initattacl, initrattacl);
15327                         free(attnamecopy);
15328                 }
15329                 PQclear(res);
15330                 destroyPQExpBuffer(query);
15331         }
15332
15333         free(namecopy);
15334
15335         return;
15336 }
15337
15338 /*
15339  * Create the AS clause for a view or materialized view. The semicolon is
15340  * stripped because a materialized view must add a WITH NO DATA clause.
15341  *
15342  * This returns a new buffer which must be freed by the caller.
15343  */
15344 static PQExpBuffer
15345 createViewAsClause(Archive *fout, TableInfo *tbinfo)
15346 {
15347         PQExpBuffer query = createPQExpBuffer();
15348         PQExpBuffer result = createPQExpBuffer();
15349         PGresult   *res;
15350         int                     len;
15351
15352         /* Fetch the view definition */
15353         appendPQExpBuffer(query,
15354                                           "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
15355                                           tbinfo->dobj.catId.oid);
15356
15357         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15358
15359         if (PQntuples(res) != 1)
15360         {
15361                 if (PQntuples(res) < 1)
15362                         fatal("query to obtain definition of view \"%s\" returned no data",
15363                                                   tbinfo->dobj.name);
15364                 else
15365                         fatal("query to obtain definition of view \"%s\" returned more than one definition",
15366                                                   tbinfo->dobj.name);
15367         }
15368
15369         len = PQgetlength(res, 0, 0);
15370
15371         if (len == 0)
15372                 fatal("definition of view \"%s\" appears to be empty (length zero)",
15373                                           tbinfo->dobj.name);
15374
15375         /* Strip off the trailing semicolon so that other things may follow. */
15376         Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
15377         appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
15378
15379         PQclear(res);
15380         destroyPQExpBuffer(query);
15381
15382         return result;
15383 }
15384
15385 /*
15386  * Create a dummy AS clause for a view.  This is used when the real view
15387  * definition has to be postponed because of circular dependencies.
15388  * We must duplicate the view's external properties -- column names and types
15389  * (including collation) -- so that it works for subsequent references.
15390  *
15391  * This returns a new buffer which must be freed by the caller.
15392  */
15393 static PQExpBuffer
15394 createDummyViewAsClause(Archive *fout, TableInfo *tbinfo)
15395 {
15396         PQExpBuffer result = createPQExpBuffer();
15397         int                     j;
15398
15399         appendPQExpBufferStr(result, "SELECT");
15400
15401         for (j = 0; j < tbinfo->numatts; j++)
15402         {
15403                 if (j > 0)
15404                         appendPQExpBufferChar(result, ',');
15405                 appendPQExpBufferStr(result, "\n    ");
15406
15407                 appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
15408
15409                 /*
15410                  * Must add collation if not default for the type, because CREATE OR
15411                  * REPLACE VIEW won't change it
15412                  */
15413                 if (OidIsValid(tbinfo->attcollation[j]))
15414                 {
15415                         CollInfo   *coll;
15416
15417                         coll = findCollationByOid(tbinfo->attcollation[j]);
15418                         if (coll)
15419                                 appendPQExpBuffer(result, " COLLATE %s",
15420                                                                   fmtQualifiedDumpable(coll));
15421                 }
15422
15423                 appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
15424         }
15425
15426         return result;
15427 }
15428
15429 /*
15430  * dumpTableSchema
15431  *        write the declaration (not data) of one user-defined table or view
15432  */
15433 static void
15434 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
15435 {
15436         DumpOptions *dopt = fout->dopt;
15437         PQExpBuffer q = createPQExpBuffer();
15438         PQExpBuffer delq = createPQExpBuffer();
15439         char       *qrelname;
15440         char       *qualrelname;
15441         int                     numParents;
15442         TableInfo **parents;
15443         int                     actual_atts;    /* number of attrs in this CREATE statement */
15444         const char *reltypename;
15445         char       *storage;
15446         int                     j,
15447                                 k;
15448
15449         qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
15450         qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
15451
15452
15453         if (tbinfo->hasoids)
15454                 pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
15455                                   qrelname);
15456
15457         if (dopt->binary_upgrade)
15458                 binary_upgrade_set_type_oids_by_rel_oid(fout, q,
15459                                                                                                 tbinfo->dobj.catId.oid);
15460
15461         /* Is it a table or a view? */
15462         if (tbinfo->relkind == RELKIND_VIEW)
15463         {
15464                 PQExpBuffer result;
15465
15466                 /*
15467                  * Note: keep this code in sync with the is_view case in dumpRule()
15468                  */
15469
15470                 reltypename = "VIEW";
15471
15472                 appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
15473
15474                 if (dopt->binary_upgrade)
15475                         binary_upgrade_set_pg_class_oids(fout, q,
15476                                                                                          tbinfo->dobj.catId.oid, false);
15477
15478                 appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
15479
15480                 if (tbinfo->dummy_view)
15481                         result = createDummyViewAsClause(fout, tbinfo);
15482                 else
15483                 {
15484                         if (nonemptyReloptions(tbinfo->reloptions))
15485                         {
15486                                 appendPQExpBufferStr(q, " WITH (");
15487                                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15488                                 appendPQExpBufferChar(q, ')');
15489                         }
15490                         result = createViewAsClause(fout, tbinfo);
15491                 }
15492                 appendPQExpBuffer(q, " AS\n%s", result->data);
15493                 destroyPQExpBuffer(result);
15494
15495                 if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
15496                         appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
15497                 appendPQExpBufferStr(q, ";\n");
15498         }
15499         else
15500         {
15501                 char       *ftoptions = NULL;
15502                 char       *srvname = NULL;
15503
15504                 switch (tbinfo->relkind)
15505                 {
15506                         case RELKIND_FOREIGN_TABLE:
15507                                 {
15508                                         PQExpBuffer query = createPQExpBuffer();
15509                                         PGresult   *res;
15510                                         int                     i_srvname;
15511                                         int                     i_ftoptions;
15512
15513                                         reltypename = "FOREIGN TABLE";
15514
15515                                         /* retrieve name of foreign server and generic options */
15516                                         appendPQExpBuffer(query,
15517                                                                           "SELECT fs.srvname, "
15518                                                                           "pg_catalog.array_to_string(ARRAY("
15519                                                                           "SELECT pg_catalog.quote_ident(option_name) || "
15520                                                                           "' ' || pg_catalog.quote_literal(option_value) "
15521                                                                           "FROM pg_catalog.pg_options_to_table(ftoptions) "
15522                                                                           "ORDER BY option_name"
15523                                                                           "), E',\n    ') AS ftoptions "
15524                                                                           "FROM pg_catalog.pg_foreign_table ft "
15525                                                                           "JOIN pg_catalog.pg_foreign_server fs "
15526                                                                           "ON (fs.oid = ft.ftserver) "
15527                                                                           "WHERE ft.ftrelid = '%u'",
15528                                                                           tbinfo->dobj.catId.oid);
15529                                         res = ExecuteSqlQueryForSingleRow(fout, query->data);
15530                                         i_srvname = PQfnumber(res, "srvname");
15531                                         i_ftoptions = PQfnumber(res, "ftoptions");
15532                                         srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
15533                                         ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
15534                                         PQclear(res);
15535                                         destroyPQExpBuffer(query);
15536                                         break;
15537                                 }
15538                         case RELKIND_MATVIEW:
15539                                 reltypename = "MATERIALIZED VIEW";
15540                                 break;
15541                         default:
15542                                 reltypename = "TABLE";
15543                 }
15544
15545                 numParents = tbinfo->numParents;
15546                 parents = tbinfo->parents;
15547
15548                 appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
15549
15550                 if (dopt->binary_upgrade)
15551                         binary_upgrade_set_pg_class_oids(fout, q,
15552                                                                                          tbinfo->dobj.catId.oid, false);
15553
15554                 appendPQExpBuffer(q, "CREATE %s%s %s",
15555                                                   tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
15556                                                   "UNLOGGED " : "",
15557                                                   reltypename,
15558                                                   qualrelname);
15559
15560                 /*
15561                  * Attach to type, if reloftype; except in case of a binary upgrade,
15562                  * we dump the table normally and attach it to the type afterward.
15563                  */
15564                 if (tbinfo->reloftype && !dopt->binary_upgrade)
15565                         appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
15566
15567                 /*
15568                  * If the table is a partition, dump it as such; except in the case of
15569                  * a binary upgrade, we dump the table normally and attach it to the
15570                  * parent afterward.
15571                  */
15572                 if (tbinfo->ispartition && !dopt->binary_upgrade)
15573                 {
15574                         TableInfo  *parentRel = tbinfo->parents[0];
15575
15576                         /*
15577                          * With partitions, unlike inheritance, there can only be one
15578                          * parent.
15579                          */
15580                         if (tbinfo->numParents != 1)
15581                                 fatal("invalid number of parents %d for table \"%s\"",
15582                                                           tbinfo->numParents, tbinfo->dobj.name);
15583
15584                         appendPQExpBuffer(q, " PARTITION OF %s",
15585                                                           fmtQualifiedDumpable(parentRel));
15586                 }
15587
15588                 if (tbinfo->relkind != RELKIND_MATVIEW)
15589                 {
15590                         /* Dump the attributes */
15591                         actual_atts = 0;
15592                         for (j = 0; j < tbinfo->numatts; j++)
15593                         {
15594                                 /*
15595                                  * Normally, dump if it's locally defined in this table, and
15596                                  * not dropped.  But for binary upgrade, we'll dump all the
15597                                  * columns, and then fix up the dropped and nonlocal cases
15598                                  * below.
15599                                  */
15600                                 if (shouldPrintColumn(dopt, tbinfo, j))
15601                                 {
15602                                         /*
15603                                          * Default value --- suppress if to be printed separately.
15604                                          */
15605                                         bool            has_default = (tbinfo->attrdefs[j] != NULL &&
15606                                                                                            !tbinfo->attrdefs[j]->separate);
15607
15608                                         /*
15609                                          * Not Null constraint --- suppress if inherited, except
15610                                          * in binary-upgrade case where that won't work.
15611                                          */
15612                                         bool            has_notnull = (tbinfo->notnull[j] &&
15613                                                                                            (!tbinfo->inhNotNull[j] ||
15614                                                                                                 dopt->binary_upgrade));
15615
15616                                         /*
15617                                          * Skip column if fully defined by reloftype or the
15618                                          * partition parent.
15619                                          */
15620                                         if ((tbinfo->reloftype || tbinfo->ispartition) &&
15621                                                 !has_default && !has_notnull && !dopt->binary_upgrade)
15622                                                 continue;
15623
15624                                         /* Format properly if not first attr */
15625                                         if (actual_atts == 0)
15626                                                 appendPQExpBufferStr(q, " (");
15627                                         else
15628                                                 appendPQExpBufferChar(q, ',');
15629                                         appendPQExpBufferStr(q, "\n    ");
15630                                         actual_atts++;
15631
15632                                         /* Attribute name */
15633                                         appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
15634
15635                                         if (tbinfo->attisdropped[j])
15636                                         {
15637                                                 /*
15638                                                  * ALTER TABLE DROP COLUMN clears
15639                                                  * pg_attribute.atttypid, so we will not have gotten a
15640                                                  * valid type name; insert INTEGER as a stopgap. We'll
15641                                                  * clean things up later.
15642                                                  */
15643                                                 appendPQExpBufferStr(q, " INTEGER /* dummy */");
15644                                                 /* Skip all the rest, too */
15645                                                 continue;
15646                                         }
15647
15648                                         /*
15649                                          * Attribute type
15650                                          *
15651                                          * In binary-upgrade mode, we always include the type. If
15652                                          * we aren't in binary-upgrade mode, then we skip the type
15653                                          * when creating a typed table ('OF type_name') or a
15654                                          * partition ('PARTITION OF'), since the type comes from
15655                                          * the parent/partitioned table.
15656                                          */
15657                                         if (dopt->binary_upgrade || (!tbinfo->reloftype && !tbinfo->ispartition))
15658                                         {
15659                                                 appendPQExpBuffer(q, " %s",
15660                                                                                   tbinfo->atttypnames[j]);
15661                                         }
15662
15663                                         if (has_default)
15664                                         {
15665                                                 if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
15666                                                         appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
15667                                                                                           tbinfo->attrdefs[j]->adef_expr);
15668                                                 else
15669                                                         appendPQExpBuffer(q, " DEFAULT %s",
15670                                                                                           tbinfo->attrdefs[j]->adef_expr);
15671                                         }
15672
15673
15674                                         if (has_notnull)
15675                                                 appendPQExpBufferStr(q, " NOT NULL");
15676
15677                                         /* Add collation if not default for the type */
15678                                         if (OidIsValid(tbinfo->attcollation[j]))
15679                                         {
15680                                                 CollInfo   *coll;
15681
15682                                                 coll = findCollationByOid(tbinfo->attcollation[j]);
15683                                                 if (coll)
15684                                                         appendPQExpBuffer(q, " COLLATE %s",
15685                                                                                           fmtQualifiedDumpable(coll));
15686                                         }
15687                                 }
15688                         }
15689
15690                         /*
15691                          * Add non-inherited CHECK constraints, if any.
15692                          */
15693                         for (j = 0; j < tbinfo->ncheck; j++)
15694                         {
15695                                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
15696
15697                                 if (constr->separate || !constr->conislocal)
15698                                         continue;
15699
15700                                 if (actual_atts == 0)
15701                                         appendPQExpBufferStr(q, " (\n    ");
15702                                 else
15703                                         appendPQExpBufferStr(q, ",\n    ");
15704
15705                                 appendPQExpBuffer(q, "CONSTRAINT %s ",
15706                                                                   fmtId(constr->dobj.name));
15707                                 appendPQExpBufferStr(q, constr->condef);
15708
15709                                 actual_atts++;
15710                         }
15711
15712                         if (actual_atts)
15713                                 appendPQExpBufferStr(q, "\n)");
15714                         else if (!((tbinfo->reloftype || tbinfo->ispartition) &&
15715                                            !dopt->binary_upgrade))
15716                         {
15717                                 /*
15718                                  * We must have a parenthesized attribute list, even though
15719                                  * empty, when not using the OF TYPE or PARTITION OF syntax.
15720                                  */
15721                                 appendPQExpBufferStr(q, " (\n)");
15722                         }
15723
15724                         if (tbinfo->ispartition && !dopt->binary_upgrade)
15725                         {
15726                                 appendPQExpBufferChar(q, '\n');
15727                                 appendPQExpBufferStr(q, tbinfo->partbound);
15728                         }
15729
15730                         /* Emit the INHERITS clause, except if this is a partition. */
15731                         if (numParents > 0 &&
15732                                 !tbinfo->ispartition &&
15733                                 !dopt->binary_upgrade)
15734                         {
15735                                 appendPQExpBufferStr(q, "\nINHERITS (");
15736                                 for (k = 0; k < numParents; k++)
15737                                 {
15738                                         TableInfo  *parentRel = parents[k];
15739
15740                                         if (k > 0)
15741                                                 appendPQExpBufferStr(q, ", ");
15742                                         appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
15743                                 }
15744                                 appendPQExpBufferChar(q, ')');
15745                         }
15746
15747                         if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15748                                 appendPQExpBuffer(q, "\nPARTITION BY %s", tbinfo->partkeydef);
15749
15750                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
15751                                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
15752                 }
15753
15754                 if (nonemptyReloptions(tbinfo->reloptions) ||
15755                         nonemptyReloptions(tbinfo->toast_reloptions))
15756                 {
15757                         bool            addcomma = false;
15758
15759                         appendPQExpBufferStr(q, "\nWITH (");
15760                         if (nonemptyReloptions(tbinfo->reloptions))
15761                         {
15762                                 addcomma = true;
15763                                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15764                         }
15765                         if (nonemptyReloptions(tbinfo->toast_reloptions))
15766                         {
15767                                 if (addcomma)
15768                                         appendPQExpBufferStr(q, ", ");
15769                                 appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
15770                                                                                 fout);
15771                         }
15772                         appendPQExpBufferChar(q, ')');
15773                 }
15774
15775                 /* Dump generic options if any */
15776                 if (ftoptions && ftoptions[0])
15777                         appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
15778
15779                 /*
15780                  * For materialized views, create the AS clause just like a view. At
15781                  * this point, we always mark the view as not populated.
15782                  */
15783                 if (tbinfo->relkind == RELKIND_MATVIEW)
15784                 {
15785                         PQExpBuffer result;
15786
15787                         result = createViewAsClause(fout, tbinfo);
15788                         appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
15789                                                           result->data);
15790                         destroyPQExpBuffer(result);
15791                 }
15792                 else
15793                         appendPQExpBufferStr(q, ";\n");
15794
15795                 /*
15796                  * in binary upgrade mode, update the catalog with any missing values
15797                  * that might be present.
15798                  */
15799                 if (dopt->binary_upgrade)
15800                 {
15801                         for (j = 0; j < tbinfo->numatts; j++)
15802                         {
15803                                 if (tbinfo->attmissingval[j][0] != '\0')
15804                                 {
15805                                         appendPQExpBufferStr(q, "\n-- set missing value.\n");
15806                                         appendPQExpBufferStr(q,
15807                                                                                  "SELECT pg_catalog.binary_upgrade_set_missing_value(");
15808                                         appendStringLiteralAH(q, qualrelname, fout);
15809                                         appendPQExpBufferStr(q, "::pg_catalog.regclass,");
15810                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15811                                         appendPQExpBufferStr(q, ",");
15812                                         appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
15813                                         appendPQExpBufferStr(q, ");\n\n");
15814                                 }
15815                         }
15816                 }
15817
15818                 /*
15819                  * To create binary-compatible heap files, we have to ensure the same
15820                  * physical column order, including dropped columns, as in the
15821                  * original.  Therefore, we create dropped columns above and drop them
15822                  * here, also updating their attlen/attalign values so that the
15823                  * dropped column can be skipped properly.  (We do not bother with
15824                  * restoring the original attbyval setting.)  Also, inheritance
15825                  * relationships are set up by doing ALTER TABLE INHERIT rather than
15826                  * using an INHERITS clause --- the latter would possibly mess up the
15827                  * column order.  That also means we have to take care about setting
15828                  * attislocal correctly, plus fix up any inherited CHECK constraints.
15829                  * Analogously, we set up typed tables using ALTER TABLE / OF here.
15830                  *
15831                  * We process foreign and partitioned tables here, even though they
15832                  * lack heap storage, because they can participate in inheritance
15833                  * relationships and we want this stuff to be consistent across the
15834                  * inheritance tree.  We can exclude indexes, toast tables, sequences
15835                  * and matviews, even though they have storage, because we don't
15836                  * support altering or dropping columns in them, nor can they be part
15837                  * of inheritance trees.
15838                  */
15839                 if (dopt->binary_upgrade &&
15840                         (tbinfo->relkind == RELKIND_RELATION ||
15841                          tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
15842                          tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
15843                 {
15844                         for (j = 0; j < tbinfo->numatts; j++)
15845                         {
15846                                 if (tbinfo->attisdropped[j])
15847                                 {
15848                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
15849                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
15850                                                                           "SET attlen = %d, "
15851                                                                           "attalign = '%c', attbyval = false\n"
15852                                                                           "WHERE attname = ",
15853                                                                           tbinfo->attlen[j],
15854                                                                           tbinfo->attalign[j]);
15855                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15856                                         appendPQExpBufferStr(q, "\n  AND attrelid = ");
15857                                         appendStringLiteralAH(q, qualrelname, fout);
15858                                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15859
15860                                         if (tbinfo->relkind == RELKIND_RELATION ||
15861                                                 tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15862                                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15863                                                                                   qualrelname);
15864                                         else
15865                                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE ONLY %s ",
15866                                                                                   qualrelname);
15867                                         appendPQExpBuffer(q, "DROP COLUMN %s;\n",
15868                                                                           fmtId(tbinfo->attnames[j]));
15869                                 }
15870                                 else if (!tbinfo->attislocal[j])
15871                                 {
15872                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
15873                                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
15874                                                                                  "SET attislocal = false\n"
15875                                                                                  "WHERE attname = ");
15876                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15877                                         appendPQExpBufferStr(q, "\n  AND attrelid = ");
15878                                         appendStringLiteralAH(q, qualrelname, fout);
15879                                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15880                                 }
15881                         }
15882
15883                         for (k = 0; k < tbinfo->ncheck; k++)
15884                         {
15885                                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
15886
15887                                 if (constr->separate || constr->conislocal)
15888                                         continue;
15889
15890                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
15891                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15892                                                                   qualrelname);
15893                                 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
15894                                                                   fmtId(constr->dobj.name));
15895                                 appendPQExpBuffer(q, "%s;\n", constr->condef);
15896                                 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
15897                                                                          "SET conislocal = false\n"
15898                                                                          "WHERE contype = 'c' AND conname = ");
15899                                 appendStringLiteralAH(q, constr->dobj.name, fout);
15900                                 appendPQExpBufferStr(q, "\n  AND conrelid = ");
15901                                 appendStringLiteralAH(q, qualrelname, fout);
15902                                 appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15903                         }
15904
15905                         if (numParents > 0)
15906                         {
15907                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance and partitioning this way.\n");
15908                                 for (k = 0; k < numParents; k++)
15909                                 {
15910                                         TableInfo  *parentRel = parents[k];
15911
15912                                         /* In the partitioning case, we alter the parent */
15913                                         if (tbinfo->ispartition)
15914                                                 appendPQExpBuffer(q,
15915                                                                                   "ALTER TABLE ONLY %s ATTACH PARTITION ",
15916                                                                                   fmtQualifiedDumpable(parentRel));
15917                                         else
15918                                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
15919                                                                                   qualrelname);
15920
15921                                         /* Partition needs specifying the bounds */
15922                                         if (tbinfo->ispartition)
15923                                                 appendPQExpBuffer(q, "%s %s;\n",
15924                                                                                   qualrelname,
15925                                                                                   tbinfo->partbound);
15926                                         else
15927                                                 appendPQExpBuffer(q, "%s;\n",
15928                                                                                   fmtQualifiedDumpable(parentRel));
15929                                 }
15930                         }
15931
15932                         if (tbinfo->reloftype)
15933                         {
15934                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
15935                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
15936                                                                   qualrelname,
15937                                                                   tbinfo->reloftype);
15938                         }
15939                 }
15940
15941                 /*
15942                  * In binary_upgrade mode, arrange to restore the old relfrozenxid and
15943                  * relminmxid of all vacuumable relations.  (While vacuum.c processes
15944                  * TOAST tables semi-independently, here we see them only as children
15945                  * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
15946                  * child toast table is handled below.)
15947                  */
15948                 if (dopt->binary_upgrade &&
15949                         (tbinfo->relkind == RELKIND_RELATION ||
15950                          tbinfo->relkind == RELKIND_MATVIEW))
15951                 {
15952                         appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
15953                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
15954                                                           "SET relfrozenxid = '%u', relminmxid = '%u'\n"
15955                                                           "WHERE oid = ",
15956                                                           tbinfo->frozenxid, tbinfo->minmxid);
15957                         appendStringLiteralAH(q, qualrelname, fout);
15958                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15959
15960                         if (tbinfo->toast_oid)
15961                         {
15962                                 /*
15963                                  * The toast table will have the same OID at restore, so we
15964                                  * can safely target it by OID.
15965                                  */
15966                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
15967                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
15968                                                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
15969                                                                   "WHERE oid = '%u';\n",
15970                                                                   tbinfo->toast_frozenxid,
15971                                                                   tbinfo->toast_minmxid, tbinfo->toast_oid);
15972                         }
15973                 }
15974
15975                 /*
15976                  * In binary_upgrade mode, restore matviews' populated status by
15977                  * poking pg_class directly.  This is pretty ugly, but we can't use
15978                  * REFRESH MATERIALIZED VIEW since it's possible that some underlying
15979                  * matview is not populated even though this matview is; in any case,
15980                  * we want to transfer the matview's heap storage, not run REFRESH.
15981                  */
15982                 if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
15983                         tbinfo->relispopulated)
15984                 {
15985                         appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
15986                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
15987                                                                  "SET relispopulated = 't'\n"
15988                                                                  "WHERE oid = ");
15989                         appendStringLiteralAH(q, qualrelname, fout);
15990                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15991                 }
15992
15993                 /*
15994                  * Dump additional per-column properties that we can't handle in the
15995                  * main CREATE TABLE command.
15996                  */
15997                 for (j = 0; j < tbinfo->numatts; j++)
15998                 {
15999                         /* None of this applies to dropped columns */
16000                         if (tbinfo->attisdropped[j])
16001                                 continue;
16002
16003                         /*
16004                          * If we didn't dump the column definition explicitly above, and
16005                          * it is NOT NULL and did not inherit that property from a parent,
16006                          * we have to mark it separately.
16007                          */
16008                         if (!shouldPrintColumn(dopt, tbinfo, j) &&
16009                                 tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
16010                         {
16011                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16012                                                                   qualrelname);
16013                                 appendPQExpBuffer(q, "ALTER COLUMN %s SET NOT NULL;\n",
16014                                                                   fmtId(tbinfo->attnames[j]));
16015                         }
16016
16017                         /*
16018                          * Dump per-column statistics information. We only issue an ALTER
16019                          * TABLE statement if the attstattarget entry for this column is
16020                          * non-negative (i.e. it's not the default value)
16021                          */
16022                         if (tbinfo->attstattarget[j] >= 0)
16023                         {
16024                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16025                                                                   qualrelname);
16026                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
16027                                                                   fmtId(tbinfo->attnames[j]));
16028                                 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
16029                                                                   tbinfo->attstattarget[j]);
16030                         }
16031
16032                         /*
16033                          * Dump per-column storage information.  The statement is only
16034                          * dumped if the storage has been changed from the type's default.
16035                          */
16036                         if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
16037                         {
16038                                 switch (tbinfo->attstorage[j])
16039                                 {
16040                                         case 'p':
16041                                                 storage = "PLAIN";
16042                                                 break;
16043                                         case 'e':
16044                                                 storage = "EXTERNAL";
16045                                                 break;
16046                                         case 'm':
16047                                                 storage = "MAIN";
16048                                                 break;
16049                                         case 'x':
16050                                                 storage = "EXTENDED";
16051                                                 break;
16052                                         default:
16053                                                 storage = NULL;
16054                                 }
16055
16056                                 /*
16057                                  * Only dump the statement if it's a storage type we recognize
16058                                  */
16059                                 if (storage != NULL)
16060                                 {
16061                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16062                                                                           qualrelname);
16063                                         appendPQExpBuffer(q, "ALTER COLUMN %s ",
16064                                                                           fmtId(tbinfo->attnames[j]));
16065                                         appendPQExpBuffer(q, "SET STORAGE %s;\n",
16066                                                                           storage);
16067                                 }
16068                         }
16069
16070                         /*
16071                          * Dump per-column attributes.
16072                          */
16073                         if (tbinfo->attoptions[j][0] != '\0')
16074                         {
16075                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16076                                                                   qualrelname);
16077                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
16078                                                                   fmtId(tbinfo->attnames[j]));
16079                                 appendPQExpBuffer(q, "SET (%s);\n",
16080                                                                   tbinfo->attoptions[j]);
16081                         }
16082
16083                         /*
16084                          * Dump per-column fdw options.
16085                          */
16086                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
16087                                 tbinfo->attfdwoptions[j][0] != '\0')
16088                         {
16089                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
16090                                                                   qualrelname);
16091                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
16092                                                                   fmtId(tbinfo->attnames[j]));
16093                                 appendPQExpBuffer(q, "OPTIONS (\n    %s\n);\n",
16094                                                                   tbinfo->attfdwoptions[j]);
16095                         }
16096                 }
16097
16098                 if (ftoptions)
16099                         free(ftoptions);
16100                 if (srvname)
16101                         free(srvname);
16102         }
16103
16104         /*
16105          * dump properties we only have ALTER TABLE syntax for
16106          */
16107         if ((tbinfo->relkind == RELKIND_RELATION ||
16108                  tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
16109                  tbinfo->relkind == RELKIND_MATVIEW) &&
16110                 tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
16111         {
16112                 if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
16113                 {
16114                         /* nothing to do, will be set when the index is dumped */
16115                 }
16116                 else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
16117                 {
16118                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
16119                                                           qualrelname);
16120                 }
16121                 else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
16122                 {
16123                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
16124                                                           qualrelname);
16125                 }
16126         }
16127
16128         if (tbinfo->forcerowsec)
16129                 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
16130                                                   qualrelname);
16131
16132         if (dopt->binary_upgrade)
16133                 binary_upgrade_extension_member(q, &tbinfo->dobj,
16134                                                                                 reltypename, qrelname,
16135                                                                                 tbinfo->dobj.namespace->dobj.name);
16136
16137         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16138         {
16139                 char *tableam = NULL;
16140
16141                 if (tbinfo->relkind == RELKIND_RELATION ||
16142                         tbinfo->relkind == RELKIND_MATVIEW)
16143                         tableam = tbinfo->amname;
16144
16145                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
16146                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
16147                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
16148                                                                   .tablespace = (tbinfo->relkind == RELKIND_VIEW) ?
16149                                                                   NULL : tbinfo->reltablespace,
16150                                                                   .tableam = tableam,
16151                                                                   .owner = tbinfo->rolname,
16152                                                                   .description = reltypename,
16153                                                                   .section = tbinfo->postponed_def ?
16154                                                                   SECTION_POST_DATA : SECTION_PRE_DATA,
16155                                                                   .createStmt = q->data,
16156                                                                   .dropStmt = delq->data));
16157         }
16158
16159         /* Dump Table Comments */
16160         if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16161                 dumpTableComment(fout, tbinfo, reltypename);
16162
16163         /* Dump Table Security Labels */
16164         if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
16165                 dumpTableSecLabel(fout, tbinfo, reltypename);
16166
16167         /* Dump comments on inlined table constraints */
16168         for (j = 0; j < tbinfo->ncheck; j++)
16169         {
16170                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
16171
16172                 if (constr->separate || !constr->conislocal)
16173                         continue;
16174
16175                 if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16176                         dumpTableConstraintComment(fout, constr);
16177         }
16178
16179         destroyPQExpBuffer(q);
16180         destroyPQExpBuffer(delq);
16181         free(qrelname);
16182         free(qualrelname);
16183 }
16184
16185 /*
16186  * dumpAttrDef --- dump an attribute's default-value declaration
16187  */
16188 static void
16189 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
16190 {
16191         DumpOptions *dopt = fout->dopt;
16192         TableInfo  *tbinfo = adinfo->adtable;
16193         int                     adnum = adinfo->adnum;
16194         PQExpBuffer q;
16195         PQExpBuffer delq;
16196         char       *qualrelname;
16197         char       *tag;
16198
16199         /* Skip if table definition not to be dumped */
16200         if (!tbinfo->dobj.dump || dopt->dataOnly)
16201                 return;
16202
16203         /* Skip if not "separate"; it was dumped in the table's definition */
16204         if (!adinfo->separate)
16205                 return;
16206
16207         q = createPQExpBuffer();
16208         delq = createPQExpBuffer();
16209
16210         qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
16211
16212         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16213                                           qualrelname);
16214         appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
16215                                           fmtId(tbinfo->attnames[adnum - 1]),
16216                                           adinfo->adef_expr);
16217
16218         appendPQExpBuffer(delq, "ALTER TABLE %s ",
16219                                           qualrelname);
16220         appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
16221                                           fmtId(tbinfo->attnames[adnum - 1]));
16222
16223         tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
16224
16225         if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16226                 ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
16227                                          ARCHIVE_OPTS(.tag = tag,
16228                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
16229                                                                   .owner = tbinfo->rolname,
16230                                                                   .description = "DEFAULT",
16231                                                                   .section = SECTION_PRE_DATA,
16232                                                                   .createStmt = q->data,
16233                                                                   .dropStmt = delq->data));
16234
16235         free(tag);
16236         destroyPQExpBuffer(q);
16237         destroyPQExpBuffer(delq);
16238         free(qualrelname);
16239 }
16240
16241 /*
16242  * getAttrName: extract the correct name for an attribute
16243  *
16244  * The array tblInfo->attnames[] only provides names of user attributes;
16245  * if a system attribute number is supplied, we have to fake it.
16246  * We also do a little bit of bounds checking for safety's sake.
16247  */
16248 static const char *
16249 getAttrName(int attrnum, TableInfo *tblInfo)
16250 {
16251         if (attrnum > 0 && attrnum <= tblInfo->numatts)
16252                 return tblInfo->attnames[attrnum - 1];
16253         switch (attrnum)
16254         {
16255                 case SelfItemPointerAttributeNumber:
16256                         return "ctid";
16257                 case MinTransactionIdAttributeNumber:
16258                         return "xmin";
16259                 case MinCommandIdAttributeNumber:
16260                         return "cmin";
16261                 case MaxTransactionIdAttributeNumber:
16262                         return "xmax";
16263                 case MaxCommandIdAttributeNumber:
16264                         return "cmax";
16265                 case TableOidAttributeNumber:
16266                         return "tableoid";
16267         }
16268         fatal("invalid column number %d for table \"%s\"",
16269                                   attrnum, tblInfo->dobj.name);
16270         return NULL;                            /* keep compiler quiet */
16271 }
16272
16273 /*
16274  * dumpIndex
16275  *        write out to fout a user-defined index
16276  */
16277 static void
16278 dumpIndex(Archive *fout, IndxInfo *indxinfo)
16279 {
16280         DumpOptions *dopt = fout->dopt;
16281         TableInfo  *tbinfo = indxinfo->indextable;
16282         bool            is_constraint = (indxinfo->indexconstraint != 0);
16283         PQExpBuffer q;
16284         PQExpBuffer delq;
16285         char       *qindxname;
16286
16287         if (dopt->dataOnly)
16288                 return;
16289
16290         q = createPQExpBuffer();
16291         delq = createPQExpBuffer();
16292
16293         qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
16294
16295         /*
16296          * If there's an associated constraint, don't dump the index per se, but
16297          * do dump any comment for it.  (This is safe because dependency ordering
16298          * will have ensured the constraint is emitted first.)  Note that the
16299          * emitted comment has to be shown as depending on the constraint, not the
16300          * index, in such cases.
16301          */
16302         if (!is_constraint)
16303         {
16304                 char       *indstatcols = indxinfo->indstatcols;
16305                 char       *indstatvals = indxinfo->indstatvals;
16306                 char      **indstatcolsarray = NULL;
16307                 char      **indstatvalsarray = NULL;
16308                 int                     nstatcols;
16309                 int                     nstatvals;
16310
16311                 if (dopt->binary_upgrade)
16312                         binary_upgrade_set_pg_class_oids(fout, q,
16313                                                                                          indxinfo->dobj.catId.oid, true);
16314
16315                 /* Plain secondary index */
16316                 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
16317
16318                 /*
16319                  * Append ALTER TABLE commands as needed to set properties that we
16320                  * only have ALTER TABLE syntax for.  Keep this in sync with the
16321                  * similar code in dumpConstraint!
16322                  */
16323
16324                 /* If the index is clustered, we need to record that. */
16325                 if (indxinfo->indisclustered)
16326                 {
16327                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16328                                                           fmtQualifiedDumpable(tbinfo));
16329                         /* index name is not qualified in this syntax */
16330                         appendPQExpBuffer(q, " ON %s;\n",
16331                                                           qindxname);
16332                 }
16333
16334                 /*
16335                  * If the index has any statistics on some of its columns, generate
16336                  * the associated ALTER INDEX queries.
16337                  */
16338                 if (parsePGArray(indstatcols, &indstatcolsarray, &nstatcols) &&
16339                         parsePGArray(indstatvals, &indstatvalsarray, &nstatvals) &&
16340                         nstatcols == nstatvals)
16341                 {
16342                         int                     j;
16343
16344                         for (j = 0; j < nstatcols; j++)
16345                         {
16346                                 appendPQExpBuffer(q, "ALTER INDEX %s ",
16347                                                                   fmtQualifiedDumpable(indxinfo));
16348
16349                                 /*
16350                                  * Note that this is a column number, so no quotes should be
16351                                  * used.
16352                                  */
16353                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
16354                                                                   indstatcolsarray[j]);
16355                                 appendPQExpBuffer(q, "SET STATISTICS %s;\n",
16356                                                                   indstatvalsarray[j]);
16357                         }
16358                 }
16359
16360                 /* If the index defines identity, we need to record that. */
16361                 if (indxinfo->indisreplident)
16362                 {
16363                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
16364                                                           fmtQualifiedDumpable(tbinfo));
16365                         /* index name is not qualified in this syntax */
16366                         appendPQExpBuffer(q, " INDEX %s;\n",
16367                                                           qindxname);
16368                 }
16369
16370                 appendPQExpBuffer(delq, "DROP INDEX %s;\n",
16371                                                   fmtQualifiedDumpable(indxinfo));
16372
16373                 if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16374                         ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
16375                                                  ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
16376                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
16377                                                                           .tablespace = indxinfo->tablespace,
16378                                                                           .owner = tbinfo->rolname,
16379                                                                           .description = "INDEX",
16380                                                                           .section = SECTION_POST_DATA,
16381                                                                           .createStmt = q->data,
16382                                                                           .dropStmt = delq->data));
16383
16384                 if (indstatcolsarray)
16385                         free(indstatcolsarray);
16386                 if (indstatvalsarray)
16387                         free(indstatvalsarray);
16388         }
16389
16390         /* Dump Index Comments */
16391         if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16392                 dumpComment(fout, "INDEX", qindxname,
16393                                         tbinfo->dobj.namespace->dobj.name,
16394                                         tbinfo->rolname,
16395                                         indxinfo->dobj.catId, 0,
16396                                         is_constraint ? indxinfo->indexconstraint :
16397                                         indxinfo->dobj.dumpId);
16398
16399         destroyPQExpBuffer(q);
16400         destroyPQExpBuffer(delq);
16401         free(qindxname);
16402 }
16403
16404 /*
16405  * dumpIndexAttach
16406  *        write out to fout a partitioned-index attachment clause
16407  */
16408 static void
16409 dumpIndexAttach(Archive *fout, IndexAttachInfo *attachinfo)
16410 {
16411         if (fout->dopt->dataOnly)
16412                 return;
16413
16414         if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
16415         {
16416                 PQExpBuffer q = createPQExpBuffer();
16417
16418                 appendPQExpBuffer(q, "ALTER INDEX %s ",
16419                                                   fmtQualifiedDumpable(attachinfo->parentIdx));
16420                 appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
16421                                                   fmtQualifiedDumpable(attachinfo->partitionIdx));
16422
16423                 ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
16424                                          ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
16425                                                                   .namespace = attachinfo->dobj.namespace->dobj.name,
16426                                                                   .description = "INDEX ATTACH",
16427                                                                   .section = SECTION_POST_DATA,
16428                                                                   .createStmt = q->data));
16429
16430                 destroyPQExpBuffer(q);
16431         }
16432 }
16433
16434 /*
16435  * dumpStatisticsExt
16436  *        write out to fout an extended statistics object
16437  */
16438 static void
16439 dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo)
16440 {
16441         DumpOptions *dopt = fout->dopt;
16442         PQExpBuffer q;
16443         PQExpBuffer delq;
16444         PQExpBuffer query;
16445         char       *qstatsextname;
16446         PGresult   *res;
16447         char       *stxdef;
16448
16449         /* Skip if not to be dumped */
16450         if (!statsextinfo->dobj.dump || dopt->dataOnly)
16451                 return;
16452
16453         q = createPQExpBuffer();
16454         delq = createPQExpBuffer();
16455         query = createPQExpBuffer();
16456
16457         qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
16458
16459         appendPQExpBuffer(query, "SELECT "
16460                                           "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
16461                                           statsextinfo->dobj.catId.oid);
16462
16463         res = ExecuteSqlQueryForSingleRow(fout, query->data);
16464
16465         stxdef = PQgetvalue(res, 0, 0);
16466
16467         /* Result of pg_get_statisticsobjdef is complete except for semicolon */
16468         appendPQExpBuffer(q, "%s;\n", stxdef);
16469
16470         appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
16471                                           fmtQualifiedDumpable(statsextinfo));
16472
16473         if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16474                 ArchiveEntry(fout, statsextinfo->dobj.catId,
16475                                          statsextinfo->dobj.dumpId,
16476                                          ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
16477                                                                   .namespace = statsextinfo->dobj.namespace->dobj.name,
16478                                                                   .owner = statsextinfo->rolname,
16479                                                                   .description = "STATISTICS",
16480                                                                   .section = SECTION_POST_DATA,
16481                                                                   .createStmt = q->data,
16482                                                                   .dropStmt = delq->data));
16483
16484         /* Dump Statistics Comments */
16485         if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16486                 dumpComment(fout, "STATISTICS", qstatsextname,
16487                                         statsextinfo->dobj.namespace->dobj.name,
16488                                         statsextinfo->rolname,
16489                                         statsextinfo->dobj.catId, 0,
16490                                         statsextinfo->dobj.dumpId);
16491
16492         PQclear(res);
16493         destroyPQExpBuffer(q);
16494         destroyPQExpBuffer(delq);
16495         destroyPQExpBuffer(query);
16496         free(qstatsextname);
16497 }
16498
16499 /*
16500  * dumpConstraint
16501  *        write out to fout a user-defined constraint
16502  */
16503 static void
16504 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
16505 {
16506         DumpOptions *dopt = fout->dopt;
16507         TableInfo  *tbinfo = coninfo->contable;
16508         PQExpBuffer q;
16509         PQExpBuffer delq;
16510         char       *tag = NULL;
16511
16512         /* Skip if not to be dumped */
16513         if (!coninfo->dobj.dump || dopt->dataOnly)
16514                 return;
16515
16516         q = createPQExpBuffer();
16517         delq = createPQExpBuffer();
16518
16519         if (coninfo->contype == 'p' ||
16520                 coninfo->contype == 'u' ||
16521                 coninfo->contype == 'x')
16522         {
16523                 /* Index-related constraint */
16524                 IndxInfo   *indxinfo;
16525                 int                     k;
16526
16527                 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
16528
16529                 if (indxinfo == NULL)
16530                         fatal("missing index for constraint \"%s\"",
16531                                                   coninfo->dobj.name);
16532
16533                 if (dopt->binary_upgrade)
16534                         binary_upgrade_set_pg_class_oids(fout, q,
16535                                                                                          indxinfo->dobj.catId.oid, true);
16536
16537                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
16538                                                   fmtQualifiedDumpable(tbinfo));
16539                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
16540                                                   fmtId(coninfo->dobj.name));
16541
16542                 if (coninfo->condef)
16543                 {
16544                         /* pg_get_constraintdef should have provided everything */
16545                         appendPQExpBuffer(q, "%s;\n", coninfo->condef);
16546                 }
16547                 else
16548                 {
16549                         appendPQExpBuffer(q, "%s (",
16550                                                           coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
16551                         for (k = 0; k < indxinfo->indnkeyattrs; k++)
16552                         {
16553                                 int                     indkey = (int) indxinfo->indkeys[k];
16554                                 const char *attname;
16555
16556                                 if (indkey == InvalidAttrNumber)
16557                                         break;
16558                                 attname = getAttrName(indkey, tbinfo);
16559
16560                                 appendPQExpBuffer(q, "%s%s",
16561                                                                   (k == 0) ? "" : ", ",
16562                                                                   fmtId(attname));
16563                         }
16564
16565                         if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
16566                                 appendPQExpBuffer(q, ") INCLUDE (");
16567
16568                         for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
16569                         {
16570                                 int                     indkey = (int) indxinfo->indkeys[k];
16571                                 const char *attname;
16572
16573                                 if (indkey == InvalidAttrNumber)
16574                                         break;
16575                                 attname = getAttrName(indkey, tbinfo);
16576
16577                                 appendPQExpBuffer(q, "%s%s",
16578                                                                   (k == indxinfo->indnkeyattrs) ? "" : ", ",
16579                                                                   fmtId(attname));
16580                         }
16581
16582                         appendPQExpBufferChar(q, ')');
16583
16584                         if (nonemptyReloptions(indxinfo->indreloptions))
16585                         {
16586                                 appendPQExpBufferStr(q, " WITH (");
16587                                 appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
16588                                 appendPQExpBufferChar(q, ')');
16589                         }
16590
16591                         if (coninfo->condeferrable)
16592                         {
16593                                 appendPQExpBufferStr(q, " DEFERRABLE");
16594                                 if (coninfo->condeferred)
16595                                         appendPQExpBufferStr(q, " INITIALLY DEFERRED");
16596                         }
16597
16598                         appendPQExpBufferStr(q, ";\n");
16599                 }
16600
16601                 /*
16602                  * Append ALTER TABLE commands as needed to set properties that we
16603                  * only have ALTER TABLE syntax for.  Keep this in sync with the
16604                  * similar code in dumpIndex!
16605                  */
16606
16607                 /* If the index is clustered, we need to record that. */
16608                 if (indxinfo->indisclustered)
16609                 {
16610                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16611                                                           fmtQualifiedDumpable(tbinfo));
16612                         /* index name is not qualified in this syntax */
16613                         appendPQExpBuffer(q, " ON %s;\n",
16614                                                           fmtId(indxinfo->dobj.name));
16615                 }
16616
16617                 /* If the index defines identity, we need to record that. */
16618                 if (indxinfo->indisreplident)
16619                 {
16620                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
16621                                                           fmtQualifiedDumpable(tbinfo));
16622                         /* index name is not qualified in this syntax */
16623                         appendPQExpBuffer(q, " INDEX %s;\n",
16624                                                           fmtId(indxinfo->dobj.name));
16625                 }
16626
16627                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s ",
16628                                                   fmtQualifiedDumpable(tbinfo));
16629                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16630                                                   fmtId(coninfo->dobj.name));
16631
16632                 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16633
16634                 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16635                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16636                                                  ARCHIVE_OPTS(.tag = tag,
16637                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
16638                                                                           .tablespace = indxinfo->tablespace,
16639                                                                           .owner = tbinfo->rolname,
16640                                                                           .description = "CONSTRAINT",
16641                                                                           .section = SECTION_POST_DATA,
16642                                                                           .createStmt = q->data,
16643                                                                           .dropStmt = delq->data));
16644         }
16645         else if (coninfo->contype == 'f')
16646         {
16647                 char       *only;
16648
16649                 /*
16650                  * Foreign keys on partitioned tables are always declared as
16651                  * inheriting to partitions; for all other cases, emit them as
16652                  * applying ONLY directly to the named table, because that's how they
16653                  * work for regular inherited tables.
16654                  */
16655                 only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
16656
16657                 /*
16658                  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
16659                  * current table data is not processed
16660                  */
16661                 appendPQExpBuffer(q, "ALTER TABLE %s%s\n",
16662                                                   only, fmtQualifiedDumpable(tbinfo));
16663                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16664                                                   fmtId(coninfo->dobj.name),
16665                                                   coninfo->condef);
16666
16667                 appendPQExpBuffer(delq, "ALTER TABLE %s%s ",
16668                                                   only, fmtQualifiedDumpable(tbinfo));
16669                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16670                                                   fmtId(coninfo->dobj.name));
16671
16672                 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16673
16674                 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16675                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16676                                                  ARCHIVE_OPTS(.tag = tag,
16677                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
16678                                                                           .owner = tbinfo->rolname,
16679                                                                           .description = "FK CONSTRAINT",
16680                                                                           .section = SECTION_POST_DATA,
16681                                                                           .createStmt = q->data,
16682                                                                           .dropStmt = delq->data));
16683         }
16684         else if (coninfo->contype == 'c' && tbinfo)
16685         {
16686                 /* CHECK constraint on a table */
16687
16688                 /* Ignore if not to be dumped separately, or if it was inherited */
16689                 if (coninfo->separate && coninfo->conislocal)
16690                 {
16691                         /* not ONLY since we want it to propagate to children */
16692                         appendPQExpBuffer(q, "ALTER TABLE %s\n",
16693                                                           fmtQualifiedDumpable(tbinfo));
16694                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16695                                                           fmtId(coninfo->dobj.name),
16696                                                           coninfo->condef);
16697
16698                         appendPQExpBuffer(delq, "ALTER TABLE %s ",
16699                                                           fmtQualifiedDumpable(tbinfo));
16700                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16701                                                           fmtId(coninfo->dobj.name));
16702
16703                         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16704
16705                         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16706                                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16707                                                          ARCHIVE_OPTS(.tag = tag,
16708                                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
16709                                                                                   .owner = tbinfo->rolname,
16710                                                                                   .description = "CHECK CONSTRAINT",
16711                                                                                   .section = SECTION_POST_DATA,
16712                                                                                   .createStmt = q->data,
16713                                                                                   .dropStmt = delq->data));
16714                 }
16715         }
16716         else if (coninfo->contype == 'c' && tbinfo == NULL)
16717         {
16718                 /* CHECK constraint on a domain */
16719                 TypeInfo   *tyinfo = coninfo->condomain;
16720
16721                 /* Ignore if not to be dumped separately */
16722                 if (coninfo->separate)
16723                 {
16724                         appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
16725                                                           fmtQualifiedDumpable(tyinfo));
16726                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16727                                                           fmtId(coninfo->dobj.name),
16728                                                           coninfo->condef);
16729
16730                         appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
16731                                                           fmtQualifiedDumpable(tyinfo));
16732                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16733                                                           fmtId(coninfo->dobj.name));
16734
16735                         tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
16736
16737                         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16738                                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16739                                                          ARCHIVE_OPTS(.tag = tag,
16740                                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
16741                                                                                   .owner = tyinfo->rolname,
16742                                                                                   .description = "CHECK CONSTRAINT",
16743                                                                                   .section = SECTION_POST_DATA,
16744                                                                                   .createStmt = q->data,
16745                                                                                   .dropStmt = delq->data));
16746                 }
16747         }
16748         else
16749         {
16750                 fatal("unrecognized constraint type: %c",
16751                                           coninfo->contype);
16752         }
16753
16754         /* Dump Constraint Comments --- only works for table constraints */
16755         if (tbinfo && coninfo->separate &&
16756                 coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16757                 dumpTableConstraintComment(fout, coninfo);
16758
16759         free(tag);
16760         destroyPQExpBuffer(q);
16761         destroyPQExpBuffer(delq);
16762 }
16763
16764 /*
16765  * dumpTableConstraintComment --- dump a constraint's comment if any
16766  *
16767  * This is split out because we need the function in two different places
16768  * depending on whether the constraint is dumped as part of CREATE TABLE
16769  * or as a separate ALTER command.
16770  */
16771 static void
16772 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
16773 {
16774         TableInfo  *tbinfo = coninfo->contable;
16775         PQExpBuffer conprefix = createPQExpBuffer();
16776         char       *qtabname;
16777
16778         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
16779
16780         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
16781                                           fmtId(coninfo->dobj.name));
16782
16783         if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16784                 dumpComment(fout, conprefix->data, qtabname,
16785                                         tbinfo->dobj.namespace->dobj.name,
16786                                         tbinfo->rolname,
16787                                         coninfo->dobj.catId, 0,
16788                                         coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
16789
16790         destroyPQExpBuffer(conprefix);
16791         free(qtabname);
16792 }
16793
16794 /*
16795  * findLastBuiltinOid_V71 -
16796  *
16797  * find the last built in oid
16798  *
16799  * For 7.1 through 8.0, we do this by retrieving datlastsysoid from the
16800  * pg_database entry for the current database.  (Note: current_database()
16801  * requires 7.3; pg_dump requires 8.0 now.)
16802  */
16803 static Oid
16804 findLastBuiltinOid_V71(Archive *fout)
16805 {
16806         PGresult   *res;
16807         Oid                     last_oid;
16808
16809         res = ExecuteSqlQueryForSingleRow(fout,
16810                                                                           "SELECT datlastsysoid FROM pg_database WHERE datname = current_database()");
16811         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
16812         PQclear(res);
16813
16814         return last_oid;
16815 }
16816
16817 /*
16818  * dumpSequence
16819  *        write the declaration (not data) of one user-defined sequence
16820  */
16821 static void
16822 dumpSequence(Archive *fout, TableInfo *tbinfo)
16823 {
16824         DumpOptions *dopt = fout->dopt;
16825         PGresult   *res;
16826         char       *startv,
16827                            *incby,
16828                            *maxv,
16829                            *minv,
16830                            *cache,
16831                            *seqtype;
16832         bool            cycled;
16833         bool            is_ascending;
16834         int64           default_minv,
16835                                 default_maxv;
16836         char            bufm[32],
16837                                 bufx[32];
16838         PQExpBuffer query = createPQExpBuffer();
16839         PQExpBuffer delqry = createPQExpBuffer();
16840         char       *qseqname;
16841
16842         qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
16843
16844         if (fout->remoteVersion >= 100000)
16845         {
16846                 appendPQExpBuffer(query,
16847                                                   "SELECT format_type(seqtypid, NULL), "
16848                                                   "seqstart, seqincrement, "
16849                                                   "seqmax, seqmin, "
16850                                                   "seqcache, seqcycle "
16851                                                   "FROM pg_catalog.pg_sequence "
16852                                                   "WHERE seqrelid = '%u'::oid",
16853                                                   tbinfo->dobj.catId.oid);
16854         }
16855         else if (fout->remoteVersion >= 80400)
16856         {
16857                 /*
16858                  * Before PostgreSQL 10, sequence metadata is in the sequence itself.
16859                  *
16860                  * Note: it might seem that 'bigint' potentially needs to be
16861                  * schema-qualified, but actually that's a keyword.
16862                  */
16863                 appendPQExpBuffer(query,
16864                                                   "SELECT 'bigint' AS sequence_type, "
16865                                                   "start_value, increment_by, max_value, min_value, "
16866                                                   "cache_value, is_cycled FROM %s",
16867                                                   fmtQualifiedDumpable(tbinfo));
16868         }
16869         else
16870         {
16871                 appendPQExpBuffer(query,
16872                                                   "SELECT 'bigint' AS sequence_type, "
16873                                                   "0 AS start_value, increment_by, max_value, min_value, "
16874                                                   "cache_value, is_cycled FROM %s",
16875                                                   fmtQualifiedDumpable(tbinfo));
16876         }
16877
16878         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16879
16880         if (PQntuples(res) != 1)
16881         {
16882                 pg_log_error(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
16883                                                           "query to get data of sequence \"%s\" returned %d rows (expected 1)",
16884                                                                  PQntuples(res)),
16885                                   tbinfo->dobj.name, PQntuples(res));
16886                 exit_nicely(1);
16887         }
16888
16889         seqtype = PQgetvalue(res, 0, 0);
16890         startv = PQgetvalue(res, 0, 1);
16891         incby = PQgetvalue(res, 0, 2);
16892         maxv = PQgetvalue(res, 0, 3);
16893         minv = PQgetvalue(res, 0, 4);
16894         cache = PQgetvalue(res, 0, 5);
16895         cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
16896
16897         /* Calculate default limits for a sequence of this type */
16898         is_ascending = (incby[0] != '-');
16899         if (strcmp(seqtype, "smallint") == 0)
16900         {
16901                 default_minv = is_ascending ? 1 : PG_INT16_MIN;
16902                 default_maxv = is_ascending ? PG_INT16_MAX : -1;
16903         }
16904         else if (strcmp(seqtype, "integer") == 0)
16905         {
16906                 default_minv = is_ascending ? 1 : PG_INT32_MIN;
16907                 default_maxv = is_ascending ? PG_INT32_MAX : -1;
16908         }
16909         else if (strcmp(seqtype, "bigint") == 0)
16910         {
16911                 default_minv = is_ascending ? 1 : PG_INT64_MIN;
16912                 default_maxv = is_ascending ? PG_INT64_MAX : -1;
16913         }
16914         else
16915         {
16916                 fatal("unrecognized sequence type: %s", seqtype);
16917                 default_minv = default_maxv = 0;        /* keep compiler quiet */
16918         }
16919
16920         /*
16921          * 64-bit strtol() isn't very portable, so convert the limits to strings
16922          * and compare that way.
16923          */
16924         snprintf(bufm, sizeof(bufm), INT64_FORMAT, default_minv);
16925         snprintf(bufx, sizeof(bufx), INT64_FORMAT, default_maxv);
16926
16927         /* Don't print minv/maxv if they match the respective default limit */
16928         if (strcmp(minv, bufm) == 0)
16929                 minv = NULL;
16930         if (strcmp(maxv, bufx) == 0)
16931                 maxv = NULL;
16932
16933         /*
16934          * Identity sequences are not to be dropped separately.
16935          */
16936         if (!tbinfo->is_identity_sequence)
16937         {
16938                 appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
16939                                                   fmtQualifiedDumpable(tbinfo));
16940         }
16941
16942         resetPQExpBuffer(query);
16943
16944         if (dopt->binary_upgrade)
16945         {
16946                 binary_upgrade_set_pg_class_oids(fout, query,
16947                                                                                  tbinfo->dobj.catId.oid, false);
16948                 binary_upgrade_set_type_oids_by_rel_oid(fout, query,
16949                                                                                                 tbinfo->dobj.catId.oid);
16950         }
16951
16952         if (tbinfo->is_identity_sequence)
16953         {
16954                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
16955
16956                 appendPQExpBuffer(query,
16957                                                   "ALTER TABLE %s ",
16958                                                   fmtQualifiedDumpable(owning_tab));
16959                 appendPQExpBuffer(query,
16960                                                   "ALTER COLUMN %s ADD GENERATED ",
16961                                                   fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
16962                 if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
16963                         appendPQExpBuffer(query, "ALWAYS");
16964                 else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
16965                         appendPQExpBuffer(query, "BY DEFAULT");
16966                 appendPQExpBuffer(query, " AS IDENTITY (\n    SEQUENCE NAME %s\n",
16967                                                   fmtQualifiedDumpable(tbinfo));
16968         }
16969         else
16970         {
16971                 appendPQExpBuffer(query,
16972                                                   "CREATE SEQUENCE %s\n",
16973                                                   fmtQualifiedDumpable(tbinfo));
16974
16975                 if (strcmp(seqtype, "bigint") != 0)
16976                         appendPQExpBuffer(query, "    AS %s\n", seqtype);
16977         }
16978
16979         if (fout->remoteVersion >= 80400)
16980                 appendPQExpBuffer(query, "    START WITH %s\n", startv);
16981
16982         appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
16983
16984         if (minv)
16985                 appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
16986         else
16987                 appendPQExpBufferStr(query, "    NO MINVALUE\n");
16988
16989         if (maxv)
16990                 appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
16991         else
16992                 appendPQExpBufferStr(query, "    NO MAXVALUE\n");
16993
16994         appendPQExpBuffer(query,
16995                                           "    CACHE %s%s",
16996                                           cache, (cycled ? "\n    CYCLE" : ""));
16997
16998         if (tbinfo->is_identity_sequence)
16999                 appendPQExpBufferStr(query, "\n);\n");
17000         else
17001                 appendPQExpBufferStr(query, ";\n");
17002
17003         /* binary_upgrade:      no need to clear TOAST table oid */
17004
17005         if (dopt->binary_upgrade)
17006                 binary_upgrade_extension_member(query, &tbinfo->dobj,
17007                                                                                 "SEQUENCE", qseqname,
17008                                                                                 tbinfo->dobj.namespace->dobj.name);
17009
17010         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17011                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
17012                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17013                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17014                                                                   .owner = tbinfo->rolname,
17015                                                                   .description = "SEQUENCE",
17016                                                                   .section = SECTION_PRE_DATA,
17017                                                                   .createStmt = query->data,
17018                                                                   .dropStmt = delqry->data));
17019
17020         /*
17021          * If the sequence is owned by a table column, emit the ALTER for it as a
17022          * separate TOC entry immediately following the sequence's own entry. It's
17023          * OK to do this rather than using full sorting logic, because the
17024          * dependency that tells us it's owned will have forced the table to be
17025          * created first.  We can't just include the ALTER in the TOC entry
17026          * because it will fail if we haven't reassigned the sequence owner to
17027          * match the table's owner.
17028          *
17029          * We need not schema-qualify the table reference because both sequence
17030          * and table must be in the same schema.
17031          */
17032         if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
17033         {
17034                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
17035
17036                 if (owning_tab == NULL)
17037                         fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
17038                                                   tbinfo->owning_tab, tbinfo->dobj.catId.oid);
17039
17040                 if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
17041                 {
17042                         resetPQExpBuffer(query);
17043                         appendPQExpBuffer(query, "ALTER SEQUENCE %s",
17044                                                           fmtQualifiedDumpable(tbinfo));
17045                         appendPQExpBuffer(query, " OWNED BY %s",
17046                                                           fmtQualifiedDumpable(owning_tab));
17047                         appendPQExpBuffer(query, ".%s;\n",
17048                                                           fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
17049
17050                         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17051                                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
17052                                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17053                                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17054                                                                                   .owner = tbinfo->rolname,
17055                                                                                   .description = "SEQUENCE OWNED BY",
17056                                                                                   .section = SECTION_PRE_DATA,
17057                                                                                   .createStmt = query->data,
17058                                                                                   .deps = &(tbinfo->dobj.dumpId),
17059                                                                                   .nDeps = 1));
17060                 }
17061         }
17062
17063         /* Dump Sequence Comments and Security Labels */
17064         if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17065                 dumpComment(fout, "SEQUENCE", qseqname,
17066                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17067                                         tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
17068
17069         if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
17070                 dumpSecLabel(fout, "SEQUENCE", qseqname,
17071                                          tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17072                                          tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
17073
17074         PQclear(res);
17075
17076         destroyPQExpBuffer(query);
17077         destroyPQExpBuffer(delqry);
17078         free(qseqname);
17079 }
17080
17081 /*
17082  * dumpSequenceData
17083  *        write the data of one user-defined sequence
17084  */
17085 static void
17086 dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
17087 {
17088         TableInfo  *tbinfo = tdinfo->tdtable;
17089         PGresult   *res;
17090         char       *last;
17091         bool            called;
17092         PQExpBuffer query = createPQExpBuffer();
17093
17094         appendPQExpBuffer(query,
17095                                           "SELECT last_value, is_called FROM %s",
17096                                           fmtQualifiedDumpable(tbinfo));
17097
17098         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17099
17100         if (PQntuples(res) != 1)
17101         {
17102                 pg_log_error(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
17103                                                           "query to get data of sequence \"%s\" returned %d rows (expected 1)",
17104                                                                  PQntuples(res)),
17105                                   tbinfo->dobj.name, PQntuples(res));
17106                 exit_nicely(1);
17107         }
17108
17109         last = PQgetvalue(res, 0, 0);
17110         called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
17111
17112         resetPQExpBuffer(query);
17113         appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
17114         appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
17115         appendPQExpBuffer(query, ", %s, %s);\n",
17116                                           last, (called ? "true" : "false"));
17117
17118         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
17119                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
17120                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17121                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17122                                                                   .owner = tbinfo->rolname,
17123                                                                   .description = "SEQUENCE SET",
17124                                                                   .section = SECTION_DATA,
17125                                                                   .createStmt = query->data,
17126                                                                   .deps = &(tbinfo->dobj.dumpId),
17127                                                                   .nDeps = 1));
17128
17129         PQclear(res);
17130
17131         destroyPQExpBuffer(query);
17132 }
17133
17134 /*
17135  * dumpTrigger
17136  *        write the declaration of one user-defined table trigger
17137  */
17138 static void
17139 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
17140 {
17141         DumpOptions *dopt = fout->dopt;
17142         TableInfo  *tbinfo = tginfo->tgtable;
17143         PQExpBuffer query;
17144         PQExpBuffer delqry;
17145         PQExpBuffer trigprefix;
17146         char       *qtabname;
17147         char       *tgargs;
17148         size_t          lentgargs;
17149         const char *p;
17150         int                     findx;
17151         char       *tag;
17152
17153         /*
17154          * we needn't check dobj.dump because TriggerInfo wouldn't have been
17155          * created in the first place for non-dumpable triggers
17156          */
17157         if (dopt->dataOnly)
17158                 return;
17159
17160         query = createPQExpBuffer();
17161         delqry = createPQExpBuffer();
17162         trigprefix = createPQExpBuffer();
17163
17164         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17165
17166         appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
17167                                           fmtId(tginfo->dobj.name));
17168         appendPQExpBuffer(delqry, "ON %s;\n",
17169                                           fmtQualifiedDumpable(tbinfo));
17170
17171         if (tginfo->tgdef)
17172         {
17173                 appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
17174         }
17175         else
17176         {
17177                 if (tginfo->tgisconstraint)
17178                 {
17179                         appendPQExpBufferStr(query, "CREATE CONSTRAINT TRIGGER ");
17180                         appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
17181                 }
17182                 else
17183                 {
17184                         appendPQExpBufferStr(query, "CREATE TRIGGER ");
17185                         appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
17186                 }
17187                 appendPQExpBufferStr(query, "\n    ");
17188
17189                 /* Trigger type */
17190                 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
17191                         appendPQExpBufferStr(query, "BEFORE");
17192                 else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
17193                         appendPQExpBufferStr(query, "AFTER");
17194                 else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
17195                         appendPQExpBufferStr(query, "INSTEAD OF");
17196                 else
17197                 {
17198                         pg_log_error("unexpected tgtype value: %d", tginfo->tgtype);
17199                         exit_nicely(1);
17200                 }
17201
17202                 findx = 0;
17203                 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
17204                 {
17205                         appendPQExpBufferStr(query, " INSERT");
17206                         findx++;
17207                 }
17208                 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
17209                 {
17210                         if (findx > 0)
17211                                 appendPQExpBufferStr(query, " OR DELETE");
17212                         else
17213                                 appendPQExpBufferStr(query, " DELETE");
17214                         findx++;
17215                 }
17216                 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
17217                 {
17218                         if (findx > 0)
17219                                 appendPQExpBufferStr(query, " OR UPDATE");
17220                         else
17221                                 appendPQExpBufferStr(query, " UPDATE");
17222                         findx++;
17223                 }
17224                 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
17225                 {
17226                         if (findx > 0)
17227                                 appendPQExpBufferStr(query, " OR TRUNCATE");
17228                         else
17229                                 appendPQExpBufferStr(query, " TRUNCATE");
17230                         findx++;
17231                 }
17232                 appendPQExpBuffer(query, " ON %s\n",
17233                                                   fmtQualifiedDumpable(tbinfo));
17234
17235                 if (tginfo->tgisconstraint)
17236                 {
17237                         if (OidIsValid(tginfo->tgconstrrelid))
17238                         {
17239                                 /* regclass output is already quoted */
17240                                 appendPQExpBuffer(query, "    FROM %s\n    ",
17241                                                                   tginfo->tgconstrrelname);
17242                         }
17243                         if (!tginfo->tgdeferrable)
17244                                 appendPQExpBufferStr(query, "NOT ");
17245                         appendPQExpBufferStr(query, "DEFERRABLE INITIALLY ");
17246                         if (tginfo->tginitdeferred)
17247                                 appendPQExpBufferStr(query, "DEFERRED\n");
17248                         else
17249                                 appendPQExpBufferStr(query, "IMMEDIATE\n");
17250                 }
17251
17252                 if (TRIGGER_FOR_ROW(tginfo->tgtype))
17253                         appendPQExpBufferStr(query, "    FOR EACH ROW\n    ");
17254                 else
17255                         appendPQExpBufferStr(query, "    FOR EACH STATEMENT\n    ");
17256
17257                 /* regproc output is already sufficiently quoted */
17258                 appendPQExpBuffer(query, "EXECUTE FUNCTION %s(",
17259                                                   tginfo->tgfname);
17260
17261                 tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
17262                                                                                   &lentgargs);
17263                 p = tgargs;
17264                 for (findx = 0; findx < tginfo->tgnargs; findx++)
17265                 {
17266                         /* find the embedded null that terminates this trigger argument */
17267                         size_t          tlen = strlen(p);
17268
17269                         if (p + tlen >= tgargs + lentgargs)
17270                         {
17271                                 /* hm, not found before end of bytea value... */
17272                                 pg_log_error("invalid argument string (%s) for trigger \"%s\" on table \"%s\"",
17273                                                   tginfo->tgargs,
17274                                                   tginfo->dobj.name,
17275                                                   tbinfo->dobj.name);
17276                                 exit_nicely(1);
17277                         }
17278
17279                         if (findx > 0)
17280                                 appendPQExpBufferStr(query, ", ");
17281                         appendStringLiteralAH(query, p, fout);
17282                         p += tlen + 1;
17283                 }
17284                 free(tgargs);
17285                 appendPQExpBufferStr(query, ");\n");
17286         }
17287
17288         if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
17289         {
17290                 appendPQExpBuffer(query, "\nALTER TABLE %s ",
17291                                                   fmtQualifiedDumpable(tbinfo));
17292                 switch (tginfo->tgenabled)
17293                 {
17294                         case 'D':
17295                         case 'f':
17296                                 appendPQExpBufferStr(query, "DISABLE");
17297                                 break;
17298                         case 'A':
17299                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
17300                                 break;
17301                         case 'R':
17302                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
17303                                 break;
17304                         default:
17305                                 appendPQExpBufferStr(query, "ENABLE");
17306                                 break;
17307                 }
17308                 appendPQExpBuffer(query, " TRIGGER %s;\n",
17309                                                   fmtId(tginfo->dobj.name));
17310         }
17311
17312         appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
17313                                           fmtId(tginfo->dobj.name));
17314
17315         tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
17316
17317         if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17318                 ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
17319                                          ARCHIVE_OPTS(.tag = tag,
17320                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17321                                                                   .owner = tbinfo->rolname,
17322                                                                   .description = "TRIGGER",
17323                                                                   .section = SECTION_POST_DATA,
17324                                                                   .createStmt = query->data,
17325                                                                   .dropStmt = delqry->data));
17326
17327         if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17328                 dumpComment(fout, trigprefix->data, qtabname,
17329                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17330                                         tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
17331
17332         free(tag);
17333         destroyPQExpBuffer(query);
17334         destroyPQExpBuffer(delqry);
17335         destroyPQExpBuffer(trigprefix);
17336         free(qtabname);
17337 }
17338
17339 /*
17340  * dumpEventTrigger
17341  *        write the declaration of one user-defined event trigger
17342  */
17343 static void
17344 dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
17345 {
17346         DumpOptions *dopt = fout->dopt;
17347         PQExpBuffer query;
17348         PQExpBuffer delqry;
17349         char       *qevtname;
17350
17351         /* Skip if not to be dumped */
17352         if (!evtinfo->dobj.dump || dopt->dataOnly)
17353                 return;
17354
17355         query = createPQExpBuffer();
17356         delqry = createPQExpBuffer();
17357
17358         qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
17359
17360         appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
17361         appendPQExpBufferStr(query, qevtname);
17362         appendPQExpBufferStr(query, " ON ");
17363         appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
17364
17365         if (strcmp("", evtinfo->evttags) != 0)
17366         {
17367                 appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
17368                 appendPQExpBufferStr(query, evtinfo->evttags);
17369                 appendPQExpBufferChar(query, ')');
17370         }
17371
17372         appendPQExpBufferStr(query, "\n   EXECUTE FUNCTION ");
17373         appendPQExpBufferStr(query, evtinfo->evtfname);
17374         appendPQExpBufferStr(query, "();\n");
17375
17376         if (evtinfo->evtenabled != 'O')
17377         {
17378                 appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
17379                                                   qevtname);
17380                 switch (evtinfo->evtenabled)
17381                 {
17382                         case 'D':
17383                                 appendPQExpBufferStr(query, "DISABLE");
17384                                 break;
17385                         case 'A':
17386                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
17387                                 break;
17388                         case 'R':
17389                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
17390                                 break;
17391                         default:
17392                                 appendPQExpBufferStr(query, "ENABLE");
17393                                 break;
17394                 }
17395                 appendPQExpBufferStr(query, ";\n");
17396         }
17397
17398         appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
17399                                           qevtname);
17400
17401         if (dopt->binary_upgrade)
17402                 binary_upgrade_extension_member(query, &evtinfo->dobj,
17403                                                                                 "EVENT TRIGGER", qevtname, NULL);
17404
17405         if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17406                 ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
17407                                          ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
17408                                                                   .owner = evtinfo->evtowner,
17409                                                                   .description = "EVENT TRIGGER",
17410                                                                   .section = SECTION_POST_DATA,
17411                                                                   .createStmt = query->data,
17412                                                                   .dropStmt = delqry->data));
17413
17414         if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17415                 dumpComment(fout, "EVENT TRIGGER", qevtname,
17416                                         NULL, evtinfo->evtowner,
17417                                         evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
17418
17419         destroyPQExpBuffer(query);
17420         destroyPQExpBuffer(delqry);
17421         free(qevtname);
17422 }
17423
17424 /*
17425  * dumpRule
17426  *              Dump a rule
17427  */
17428 static void
17429 dumpRule(Archive *fout, RuleInfo *rinfo)
17430 {
17431         DumpOptions *dopt = fout->dopt;
17432         TableInfo  *tbinfo = rinfo->ruletable;
17433         bool            is_view;
17434         PQExpBuffer query;
17435         PQExpBuffer cmd;
17436         PQExpBuffer delcmd;
17437         PQExpBuffer ruleprefix;
17438         char       *qtabname;
17439         PGresult   *res;
17440         char       *tag;
17441
17442         /* Skip if not to be dumped */
17443         if (!rinfo->dobj.dump || dopt->dataOnly)
17444                 return;
17445
17446         /*
17447          * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
17448          * we do not want to dump it as a separate object.
17449          */
17450         if (!rinfo->separate)
17451                 return;
17452
17453         /*
17454          * If it's an ON SELECT rule, we want to print it as a view definition,
17455          * instead of a rule.
17456          */
17457         is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
17458
17459         query = createPQExpBuffer();
17460         cmd = createPQExpBuffer();
17461         delcmd = createPQExpBuffer();
17462         ruleprefix = createPQExpBuffer();
17463
17464         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17465
17466         if (is_view)
17467         {
17468                 PQExpBuffer result;
17469
17470                 /*
17471                  * We need OR REPLACE here because we'll be replacing a dummy view.
17472                  * Otherwise this should look largely like the regular view dump code.
17473                  */
17474                 appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
17475                                                   fmtQualifiedDumpable(tbinfo));
17476                 if (nonemptyReloptions(tbinfo->reloptions))
17477                 {
17478                         appendPQExpBufferStr(cmd, " WITH (");
17479                         appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
17480                         appendPQExpBufferChar(cmd, ')');
17481                 }
17482                 result = createViewAsClause(fout, tbinfo);
17483                 appendPQExpBuffer(cmd, " AS\n%s", result->data);
17484                 destroyPQExpBuffer(result);
17485                 if (tbinfo->checkoption != NULL)
17486                         appendPQExpBuffer(cmd, "\n  WITH %s CHECK OPTION",
17487                                                           tbinfo->checkoption);
17488                 appendPQExpBufferStr(cmd, ";\n");
17489         }
17490         else
17491         {
17492                 /* In the rule case, just print pg_get_ruledef's result verbatim */
17493                 appendPQExpBuffer(query,
17494                                                   "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
17495                                                   rinfo->dobj.catId.oid);
17496
17497                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17498
17499                 if (PQntuples(res) != 1)
17500                 {
17501                         pg_log_error("query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
17502                                           rinfo->dobj.name, tbinfo->dobj.name);
17503                         exit_nicely(1);
17504                 }
17505
17506                 printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
17507
17508                 PQclear(res);
17509         }
17510
17511         /*
17512          * Add the command to alter the rules replication firing semantics if it
17513          * differs from the default.
17514          */
17515         if (rinfo->ev_enabled != 'O')
17516         {
17517                 appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
17518                 switch (rinfo->ev_enabled)
17519                 {
17520                         case 'A':
17521                                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
17522                                                                   fmtId(rinfo->dobj.name));
17523                                 break;
17524                         case 'R':
17525                                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
17526                                                                   fmtId(rinfo->dobj.name));
17527                                 break;
17528                         case 'D':
17529                                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
17530                                                                   fmtId(rinfo->dobj.name));
17531                                 break;
17532                 }
17533         }
17534
17535         if (is_view)
17536         {
17537                 /*
17538                  * We can't DROP a view's ON SELECT rule.  Instead, use CREATE OR
17539                  * REPLACE VIEW to replace the rule with something with minimal
17540                  * dependencies.
17541                  */
17542                 PQExpBuffer result;
17543
17544                 appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
17545                                                   fmtQualifiedDumpable(tbinfo));
17546                 result = createDummyViewAsClause(fout, tbinfo);
17547                 appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
17548                 destroyPQExpBuffer(result);
17549         }
17550         else
17551         {
17552                 appendPQExpBuffer(delcmd, "DROP RULE %s ",
17553                                                   fmtId(rinfo->dobj.name));
17554                 appendPQExpBuffer(delcmd, "ON %s;\n",
17555                                                   fmtQualifiedDumpable(tbinfo));
17556         }
17557
17558         appendPQExpBuffer(ruleprefix, "RULE %s ON",
17559                                           fmtId(rinfo->dobj.name));
17560
17561         tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
17562
17563         if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17564                 ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
17565                                          ARCHIVE_OPTS(.tag = tag,
17566                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17567                                                                   .owner = tbinfo->rolname,
17568                                                                   .description = "RULE",
17569                                                                   .section = SECTION_POST_DATA,
17570                                                                   .createStmt = cmd->data,
17571                                                                   .dropStmt = delcmd->data));
17572
17573         /* Dump rule comments */
17574         if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17575                 dumpComment(fout, ruleprefix->data, qtabname,
17576                                         tbinfo->dobj.namespace->dobj.name,
17577                                         tbinfo->rolname,
17578                                         rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
17579
17580         free(tag);
17581         destroyPQExpBuffer(query);
17582         destroyPQExpBuffer(cmd);
17583         destroyPQExpBuffer(delcmd);
17584         destroyPQExpBuffer(ruleprefix);
17585         free(qtabname);
17586 }
17587
17588 /*
17589  * getExtensionMembership --- obtain extension membership data
17590  *
17591  * We need to identify objects that are extension members as soon as they're
17592  * loaded, so that we can correctly determine whether they need to be dumped.
17593  * Generally speaking, extension member objects will get marked as *not* to
17594  * be dumped, as they will be recreated by the single CREATE EXTENSION
17595  * command.  However, in binary upgrade mode we still need to dump the members
17596  * individually.
17597  */
17598 void
17599 getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
17600                                            int numExtensions)
17601 {
17602         PQExpBuffer query;
17603         PGresult   *res;
17604         int                     ntups,
17605                                 nextmembers,
17606                                 i;
17607         int                     i_classid,
17608                                 i_objid,
17609                                 i_refobjid;
17610         ExtensionMemberId *extmembers;
17611         ExtensionInfo *ext;
17612
17613         /* Nothing to do if no extensions */
17614         if (numExtensions == 0)
17615                 return;
17616
17617         query = createPQExpBuffer();
17618
17619         /* refclassid constraint is redundant but may speed the search */
17620         appendPQExpBufferStr(query, "SELECT "
17621                                                  "classid, objid, refobjid "
17622                                                  "FROM pg_depend "
17623                                                  "WHERE refclassid = 'pg_extension'::regclass "
17624                                                  "AND deptype = 'e' "
17625                                                  "ORDER BY 3");
17626
17627         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17628
17629         ntups = PQntuples(res);
17630
17631         i_classid = PQfnumber(res, "classid");
17632         i_objid = PQfnumber(res, "objid");
17633         i_refobjid = PQfnumber(res, "refobjid");
17634
17635         extmembers = (ExtensionMemberId *) pg_malloc(ntups * sizeof(ExtensionMemberId));
17636         nextmembers = 0;
17637
17638         /*
17639          * Accumulate data into extmembers[].
17640          *
17641          * Since we ordered the SELECT by referenced ID, we can expect that
17642          * multiple entries for the same extension will appear together; this
17643          * saves on searches.
17644          */
17645         ext = NULL;
17646
17647         for (i = 0; i < ntups; i++)
17648         {
17649                 CatalogId       objId;
17650                 Oid                     extId;
17651
17652                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17653                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
17654                 extId = atooid(PQgetvalue(res, i, i_refobjid));
17655
17656                 if (ext == NULL ||
17657                         ext->dobj.catId.oid != extId)
17658                         ext = findExtensionByOid(extId);
17659
17660                 if (ext == NULL)
17661                 {
17662                         /* shouldn't happen */
17663                         pg_log_warning("could not find referenced extension %u", extId);
17664                         continue;
17665                 }
17666
17667                 extmembers[nextmembers].catId = objId;
17668                 extmembers[nextmembers].ext = ext;
17669                 nextmembers++;
17670         }
17671
17672         PQclear(res);
17673
17674         /* Remember the data for use later */
17675         setExtensionMembership(extmembers, nextmembers);
17676
17677         destroyPQExpBuffer(query);
17678 }
17679
17680 /*
17681  * processExtensionTables --- deal with extension configuration tables
17682  *
17683  * There are two parts to this process:
17684  *
17685  * 1. Identify and create dump records for extension configuration tables.
17686  *
17687  *        Extensions can mark tables as "configuration", which means that the user
17688  *        is able and expected to modify those tables after the extension has been
17689  *        loaded.  For these tables, we dump out only the data- the structure is
17690  *        expected to be handled at CREATE EXTENSION time, including any indexes or
17691  *        foreign keys, which brings us to-
17692  *
17693  * 2. Record FK dependencies between configuration tables.
17694  *
17695  *        Due to the FKs being created at CREATE EXTENSION time and therefore before
17696  *        the data is loaded, we have to work out what the best order for reloading
17697  *        the data is, to avoid FK violations when the tables are restored.  This is
17698  *        not perfect- we can't handle circular dependencies and if any exist they
17699  *        will cause an invalid dump to be produced (though at least all of the data
17700  *        is included for a user to manually restore).  This is currently documented
17701  *        but perhaps we can provide a better solution in the future.
17702  */
17703 void
17704 processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
17705                                            int numExtensions)
17706 {
17707         DumpOptions *dopt = fout->dopt;
17708         PQExpBuffer query;
17709         PGresult   *res;
17710         int                     ntups,
17711                                 i;
17712         int                     i_conrelid,
17713                                 i_confrelid;
17714
17715         /* Nothing to do if no extensions */
17716         if (numExtensions == 0)
17717                 return;
17718
17719         /*
17720          * Identify extension configuration tables and create TableDataInfo
17721          * objects for them, ensuring their data will be dumped even though the
17722          * tables themselves won't be.
17723          *
17724          * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
17725          * user data in a configuration table is treated like schema data. This
17726          * seems appropriate since system data in a config table would get
17727          * reloaded by CREATE EXTENSION.
17728          */
17729         for (i = 0; i < numExtensions; i++)
17730         {
17731                 ExtensionInfo *curext = &(extinfo[i]);
17732                 char       *extconfig = curext->extconfig;
17733                 char       *extcondition = curext->extcondition;
17734                 char      **extconfigarray = NULL;
17735                 char      **extconditionarray = NULL;
17736                 int                     nconfigitems;
17737                 int                     nconditionitems;
17738
17739                 if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
17740                         parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
17741                         nconfigitems == nconditionitems)
17742                 {
17743                         int                     j;
17744
17745                         for (j = 0; j < nconfigitems; j++)
17746                         {
17747                                 TableInfo  *configtbl;
17748                                 Oid                     configtbloid = atooid(extconfigarray[j]);
17749                                 bool            dumpobj =
17750                                 curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
17751
17752                                 configtbl = findTableByOid(configtbloid);
17753                                 if (configtbl == NULL)
17754                                         continue;
17755
17756                                 /*
17757                                  * Tables of not-to-be-dumped extensions shouldn't be dumped
17758                                  * unless the table or its schema is explicitly included
17759                                  */
17760                                 if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
17761                                 {
17762                                         /* check table explicitly requested */
17763                                         if (table_include_oids.head != NULL &&
17764                                                 simple_oid_list_member(&table_include_oids,
17765                                                                                            configtbloid))
17766                                                 dumpobj = true;
17767
17768                                         /* check table's schema explicitly requested */
17769                                         if (configtbl->dobj.namespace->dobj.dump &
17770                                                 DUMP_COMPONENT_DATA)
17771                                                 dumpobj = true;
17772                                 }
17773
17774                                 /* check table excluded by an exclusion switch */
17775                                 if (table_exclude_oids.head != NULL &&
17776                                         simple_oid_list_member(&table_exclude_oids,
17777                                                                                    configtbloid))
17778                                         dumpobj = false;
17779
17780                                 /* check schema excluded by an exclusion switch */
17781                                 if (simple_oid_list_member(&schema_exclude_oids,
17782                                                                                    configtbl->dobj.namespace->dobj.catId.oid))
17783                                         dumpobj = false;
17784
17785                                 if (dumpobj)
17786                                 {
17787                                         makeTableDataInfo(dopt, configtbl);
17788                                         if (configtbl->dataObj != NULL)
17789                                         {
17790                                                 if (strlen(extconditionarray[j]) > 0)
17791                                                         configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
17792                                         }
17793                                 }
17794                         }
17795                 }
17796                 if (extconfigarray)
17797                         free(extconfigarray);
17798                 if (extconditionarray)
17799                         free(extconditionarray);
17800         }
17801
17802         /*
17803          * Now that all the TableInfoData objects have been created for all the
17804          * extensions, check their FK dependencies and register them to try and
17805          * dump the data out in an order that they can be restored in.
17806          *
17807          * Note that this is not a problem for user tables as their FKs are
17808          * recreated after the data has been loaded.
17809          */
17810
17811         query = createPQExpBuffer();
17812
17813         printfPQExpBuffer(query,
17814                                           "SELECT conrelid, confrelid "
17815                                           "FROM pg_constraint "
17816                                           "JOIN pg_depend ON (objid = confrelid) "
17817                                           "WHERE contype = 'f' "
17818                                           "AND refclassid = 'pg_extension'::regclass "
17819                                           "AND classid = 'pg_class'::regclass;");
17820
17821         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17822         ntups = PQntuples(res);
17823
17824         i_conrelid = PQfnumber(res, "conrelid");
17825         i_confrelid = PQfnumber(res, "confrelid");
17826
17827         /* Now get the dependencies and register them */
17828         for (i = 0; i < ntups; i++)
17829         {
17830                 Oid                     conrelid,
17831                                         confrelid;
17832                 TableInfo  *reftable,
17833                                    *contable;
17834
17835                 conrelid = atooid(PQgetvalue(res, i, i_conrelid));
17836                 confrelid = atooid(PQgetvalue(res, i, i_confrelid));
17837                 contable = findTableByOid(conrelid);
17838                 reftable = findTableByOid(confrelid);
17839
17840                 if (reftable == NULL ||
17841                         reftable->dataObj == NULL ||
17842                         contable == NULL ||
17843                         contable->dataObj == NULL)
17844                         continue;
17845
17846                 /*
17847                  * Make referencing TABLE_DATA object depend on the referenced table's
17848                  * TABLE_DATA object.
17849                  */
17850                 addObjectDependency(&contable->dataObj->dobj,
17851                                                         reftable->dataObj->dobj.dumpId);
17852         }
17853         PQclear(res);
17854         destroyPQExpBuffer(query);
17855 }
17856
17857 /*
17858  * getDependencies --- obtain available dependency data
17859  */
17860 static void
17861 getDependencies(Archive *fout)
17862 {
17863         PQExpBuffer query;
17864         PGresult   *res;
17865         int                     ntups,
17866                                 i;
17867         int                     i_classid,
17868                                 i_objid,
17869                                 i_refclassid,
17870                                 i_refobjid,
17871                                 i_deptype;
17872         DumpableObject *dobj,
17873                            *refdobj;
17874
17875         pg_log_info("reading dependency data");
17876
17877         query = createPQExpBuffer();
17878
17879         /*
17880          * PIN dependencies aren't interesting, and EXTENSION dependencies were
17881          * already processed by getExtensionMembership.
17882          */
17883         appendPQExpBufferStr(query, "SELECT "
17884                                                  "classid, objid, refclassid, refobjid, deptype "
17885                                                  "FROM pg_depend "
17886                                                  "WHERE deptype != 'p' AND deptype != 'e' "
17887                                                  "ORDER BY 1,2");
17888
17889         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17890
17891         ntups = PQntuples(res);
17892
17893         i_classid = PQfnumber(res, "classid");
17894         i_objid = PQfnumber(res, "objid");
17895         i_refclassid = PQfnumber(res, "refclassid");
17896         i_refobjid = PQfnumber(res, "refobjid");
17897         i_deptype = PQfnumber(res, "deptype");
17898
17899         /*
17900          * Since we ordered the SELECT by referencing ID, we can expect that
17901          * multiple entries for the same object will appear together; this saves
17902          * on searches.
17903          */
17904         dobj = NULL;
17905
17906         for (i = 0; i < ntups; i++)
17907         {
17908                 CatalogId       objId;
17909                 CatalogId       refobjId;
17910                 char            deptype;
17911
17912                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17913                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
17914                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
17915                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
17916                 deptype = *(PQgetvalue(res, i, i_deptype));
17917
17918                 if (dobj == NULL ||
17919                         dobj->catId.tableoid != objId.tableoid ||
17920                         dobj->catId.oid != objId.oid)
17921                         dobj = findObjectByCatalogId(objId);
17922
17923                 /*
17924                  * Failure to find objects mentioned in pg_depend is not unexpected,
17925                  * since for example we don't collect info about TOAST tables.
17926                  */
17927                 if (dobj == NULL)
17928                 {
17929 #ifdef NOT_USED
17930                         pg_log_warning("no referencing object %u %u",
17931                                         objId.tableoid, objId.oid);
17932 #endif
17933                         continue;
17934                 }
17935
17936                 refdobj = findObjectByCatalogId(refobjId);
17937
17938                 if (refdobj == NULL)
17939                 {
17940 #ifdef NOT_USED
17941                         pg_log_warning("no referenced object %u %u",
17942                                         refobjId.tableoid, refobjId.oid);
17943 #endif
17944                         continue;
17945                 }
17946
17947                 /*
17948                  * Ordinarily, table rowtypes have implicit dependencies on their
17949                  * tables.  However, for a composite type the implicit dependency goes
17950                  * the other way in pg_depend; which is the right thing for DROP but
17951                  * it doesn't produce the dependency ordering we need. So in that one
17952                  * case, we reverse the direction of the dependency.
17953                  */
17954                 if (deptype == 'i' &&
17955                         dobj->objType == DO_TABLE &&
17956                         refdobj->objType == DO_TYPE)
17957                         addObjectDependency(refdobj, dobj->dumpId);
17958                 else
17959                         /* normal case */
17960                         addObjectDependency(dobj, refdobj->dumpId);
17961         }
17962
17963         PQclear(res);
17964
17965         destroyPQExpBuffer(query);
17966 }
17967
17968
17969 /*
17970  * createBoundaryObjects - create dummy DumpableObjects to represent
17971  * dump section boundaries.
17972  */
17973 static DumpableObject *
17974 createBoundaryObjects(void)
17975 {
17976         DumpableObject *dobjs;
17977
17978         dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
17979
17980         dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
17981         dobjs[0].catId = nilCatalogId;
17982         AssignDumpId(dobjs + 0);
17983         dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
17984
17985         dobjs[1].objType = DO_POST_DATA_BOUNDARY;
17986         dobjs[1].catId = nilCatalogId;
17987         AssignDumpId(dobjs + 1);
17988         dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
17989
17990         return dobjs;
17991 }
17992
17993 /*
17994  * addBoundaryDependencies - add dependencies as needed to enforce the dump
17995  * section boundaries.
17996  */
17997 static void
17998 addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
17999                                                 DumpableObject *boundaryObjs)
18000 {
18001         DumpableObject *preDataBound = boundaryObjs + 0;
18002         DumpableObject *postDataBound = boundaryObjs + 1;
18003         int                     i;
18004
18005         for (i = 0; i < numObjs; i++)
18006         {
18007                 DumpableObject *dobj = dobjs[i];
18008
18009                 /*
18010                  * The classification of object types here must match the SECTION_xxx
18011                  * values assigned during subsequent ArchiveEntry calls!
18012                  */
18013                 switch (dobj->objType)
18014                 {
18015                         case DO_NAMESPACE:
18016                         case DO_EXTENSION:
18017                         case DO_TYPE:
18018                         case DO_SHELL_TYPE:
18019                         case DO_FUNC:
18020                         case DO_AGG:
18021                         case DO_OPERATOR:
18022                         case DO_ACCESS_METHOD:
18023                         case DO_OPCLASS:
18024                         case DO_OPFAMILY:
18025                         case DO_COLLATION:
18026                         case DO_CONVERSION:
18027                         case DO_TABLE:
18028                         case DO_ATTRDEF:
18029                         case DO_PROCLANG:
18030                         case DO_CAST:
18031                         case DO_DUMMY_TYPE:
18032                         case DO_TSPARSER:
18033                         case DO_TSDICT:
18034                         case DO_TSTEMPLATE:
18035                         case DO_TSCONFIG:
18036                         case DO_FDW:
18037                         case DO_FOREIGN_SERVER:
18038                         case DO_TRANSFORM:
18039                         case DO_BLOB:
18040                                 /* Pre-data objects: must come before the pre-data boundary */
18041                                 addObjectDependency(preDataBound, dobj->dumpId);
18042                                 break;
18043                         case DO_TABLE_DATA:
18044                         case DO_SEQUENCE_SET:
18045                         case DO_BLOB_DATA:
18046                                 /* Data objects: must come between the boundaries */
18047                                 addObjectDependency(dobj, preDataBound->dumpId);
18048                                 addObjectDependency(postDataBound, dobj->dumpId);
18049                                 break;
18050                         case DO_INDEX:
18051                         case DO_INDEX_ATTACH:
18052                         case DO_STATSEXT:
18053                         case DO_REFRESH_MATVIEW:
18054                         case DO_TRIGGER:
18055                         case DO_EVENT_TRIGGER:
18056                         case DO_DEFAULT_ACL:
18057                         case DO_POLICY:
18058                         case DO_PUBLICATION:
18059                         case DO_PUBLICATION_REL:
18060                         case DO_SUBSCRIPTION:
18061                                 /* Post-data objects: must come after the post-data boundary */
18062                                 addObjectDependency(dobj, postDataBound->dumpId);
18063                                 break;
18064                         case DO_RULE:
18065                                 /* Rules are post-data, but only if dumped separately */
18066                                 if (((RuleInfo *) dobj)->separate)
18067                                         addObjectDependency(dobj, postDataBound->dumpId);
18068                                 break;
18069                         case DO_CONSTRAINT:
18070                         case DO_FK_CONSTRAINT:
18071                                 /* Constraints are post-data, but only if dumped separately */
18072                                 if (((ConstraintInfo *) dobj)->separate)
18073                                         addObjectDependency(dobj, postDataBound->dumpId);
18074                                 break;
18075                         case DO_PRE_DATA_BOUNDARY:
18076                                 /* nothing to do */
18077                                 break;
18078                         case DO_POST_DATA_BOUNDARY:
18079                                 /* must come after the pre-data boundary */
18080                                 addObjectDependency(dobj, preDataBound->dumpId);
18081                                 break;
18082                 }
18083         }
18084 }
18085
18086
18087 /*
18088  * BuildArchiveDependencies - create dependency data for archive TOC entries
18089  *
18090  * The raw dependency data obtained by getDependencies() is not terribly
18091  * useful in an archive dump, because in many cases there are dependency
18092  * chains linking through objects that don't appear explicitly in the dump.
18093  * For example, a view will depend on its _RETURN rule while the _RETURN rule
18094  * will depend on other objects --- but the rule will not appear as a separate
18095  * object in the dump.  We need to adjust the view's dependencies to include
18096  * whatever the rule depends on that is included in the dump.
18097  *
18098  * Just to make things more complicated, there are also "special" dependencies
18099  * such as the dependency of a TABLE DATA item on its TABLE, which we must
18100  * not rearrange because pg_restore knows that TABLE DATA only depends on
18101  * its table.  In these cases we must leave the dependencies strictly as-is
18102  * even if they refer to not-to-be-dumped objects.
18103  *
18104  * To handle this, the convention is that "special" dependencies are created
18105  * during ArchiveEntry calls, and an archive TOC item that has any such
18106  * entries will not be touched here.  Otherwise, we recursively search the
18107  * DumpableObject data structures to build the correct dependencies for each
18108  * archive TOC item.
18109  */
18110 static void
18111 BuildArchiveDependencies(Archive *fout)
18112 {
18113         ArchiveHandle *AH = (ArchiveHandle *) fout;
18114         TocEntry   *te;
18115
18116         /* Scan all TOC entries in the archive */
18117         for (te = AH->toc->next; te != AH->toc; te = te->next)
18118         {
18119                 DumpableObject *dobj;
18120                 DumpId     *dependencies;
18121                 int                     nDeps;
18122                 int                     allocDeps;
18123
18124                 /* No need to process entries that will not be dumped */
18125                 if (te->reqs == 0)
18126                         continue;
18127                 /* Ignore entries that already have "special" dependencies */
18128                 if (te->nDeps > 0)
18129                         continue;
18130                 /* Otherwise, look up the item's original DumpableObject, if any */
18131                 dobj = findObjectByDumpId(te->dumpId);
18132                 if (dobj == NULL)
18133                         continue;
18134                 /* No work if it has no dependencies */
18135                 if (dobj->nDeps <= 0)
18136                         continue;
18137                 /* Set up work array */
18138                 allocDeps = 64;
18139                 dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
18140                 nDeps = 0;
18141                 /* Recursively find all dumpable dependencies */
18142                 findDumpableDependencies(AH, dobj,
18143                                                                  &dependencies, &nDeps, &allocDeps);
18144                 /* And save 'em ... */
18145                 if (nDeps > 0)
18146                 {
18147                         dependencies = (DumpId *) pg_realloc(dependencies,
18148                                                                                                  nDeps * sizeof(DumpId));
18149                         te->dependencies = dependencies;
18150                         te->nDeps = nDeps;
18151                 }
18152                 else
18153                         free(dependencies);
18154         }
18155 }
18156
18157 /* Recursive search subroutine for BuildArchiveDependencies */
18158 static void
18159 findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
18160                                                  DumpId **dependencies, int *nDeps, int *allocDeps)
18161 {
18162         int                     i;
18163
18164         /*
18165          * Ignore section boundary objects: if we search through them, we'll
18166          * report lots of bogus dependencies.
18167          */
18168         if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
18169                 dobj->objType == DO_POST_DATA_BOUNDARY)
18170                 return;
18171
18172         for (i = 0; i < dobj->nDeps; i++)
18173         {
18174                 DumpId          depid = dobj->dependencies[i];
18175
18176                 if (TocIDRequired(AH, depid) != 0)
18177                 {
18178                         /* Object will be dumped, so just reference it as a dependency */
18179                         if (*nDeps >= *allocDeps)
18180                         {
18181                                 *allocDeps *= 2;
18182                                 *dependencies = (DumpId *) pg_realloc(*dependencies,
18183                                                                                                           *allocDeps * sizeof(DumpId));
18184                         }
18185                         (*dependencies)[*nDeps] = depid;
18186                         (*nDeps)++;
18187                 }
18188                 else
18189                 {
18190                         /*
18191                          * Object will not be dumped, so recursively consider its deps. We
18192                          * rely on the assumption that sortDumpableObjects already broke
18193                          * any dependency loops, else we might recurse infinitely.
18194                          */
18195                         DumpableObject *otherdobj = findObjectByDumpId(depid);
18196
18197                         if (otherdobj)
18198                                 findDumpableDependencies(AH, otherdobj,
18199                                                                                  dependencies, nDeps, allocDeps);
18200                 }
18201         }
18202 }
18203
18204
18205 /*
18206  * getFormattedTypeName - retrieve a nicely-formatted type name for the
18207  * given type OID.
18208  *
18209  * This does not guarantee to schema-qualify the output, so it should not
18210  * be used to create the target object name for CREATE or ALTER commands.
18211  *
18212  * TODO: there might be some value in caching the results.
18213  */
18214 static char *
18215 getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
18216 {
18217         char       *result;
18218         PQExpBuffer query;
18219         PGresult   *res;
18220
18221         if (oid == 0)
18222         {
18223                 if ((opts & zeroAsOpaque) != 0)
18224                         return pg_strdup(g_opaque_type);
18225                 else if ((opts & zeroAsAny) != 0)
18226                         return pg_strdup("'any'");
18227                 else if ((opts & zeroAsStar) != 0)
18228                         return pg_strdup("*");
18229                 else if ((opts & zeroAsNone) != 0)
18230                         return pg_strdup("NONE");
18231         }
18232
18233         query = createPQExpBuffer();
18234         appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
18235                                           oid);
18236
18237         res = ExecuteSqlQueryForSingleRow(fout, query->data);
18238
18239         /* result of format_type is already quoted */
18240         result = pg_strdup(PQgetvalue(res, 0, 0));
18241
18242         PQclear(res);
18243         destroyPQExpBuffer(query);
18244
18245         return result;
18246 }
18247
18248 /*
18249  * Return a column list clause for the given relation.
18250  *
18251  * Special case: if there are no undropped columns in the relation, return
18252  * "", not an invalid "()" column list.
18253  */
18254 static const char *
18255 fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
18256 {
18257         int                     numatts = ti->numatts;
18258         char      **attnames = ti->attnames;
18259         bool       *attisdropped = ti->attisdropped;
18260         char       *attgenerated = ti->attgenerated;
18261         bool            needComma;
18262         int                     i;
18263
18264         appendPQExpBufferChar(buffer, '(');
18265         needComma = false;
18266         for (i = 0; i < numatts; i++)
18267         {
18268                 if (attisdropped[i])
18269                         continue;
18270                 if (attgenerated[i])
18271                         continue;
18272                 if (needComma)
18273                         appendPQExpBufferStr(buffer, ", ");
18274                 appendPQExpBufferStr(buffer, fmtId(attnames[i]));
18275                 needComma = true;
18276         }
18277
18278         if (!needComma)
18279                 return "";                              /* no undropped columns */
18280
18281         appendPQExpBufferChar(buffer, ')');
18282         return buffer->data;
18283 }
18284
18285 /*
18286  * Check if a reloptions array is nonempty.
18287  */
18288 static bool
18289 nonemptyReloptions(const char *reloptions)
18290 {
18291         /* Don't want to print it if it's just "{}" */
18292         return (reloptions != NULL && strlen(reloptions) > 2);
18293 }
18294
18295 /*
18296  * Format a reloptions array and append it to the given buffer.
18297  *
18298  * "prefix" is prepended to the option names; typically it's "" or "toast.".
18299  */
18300 static void
18301 appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
18302                                                 const char *prefix, Archive *fout)
18303 {
18304         bool            res;
18305
18306         res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
18307                                                                 fout->std_strings);
18308         if (!res)
18309                 pg_log_warning("could not parse reloptions array");
18310 }