]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_dump.c
Fix some typos
[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/logging.h"
67 #include "fe_utils/string_utils.h"
68
69
70 typedef struct
71 {
72         const char *descr;                      /* comment for an object */
73         Oid                     classoid;               /* object class (catalog OID) */
74         Oid                     objoid;                 /* object OID */
75         int                     objsubid;               /* subobject (table column #) */
76 } CommentItem;
77
78 typedef struct
79 {
80         const char *provider;           /* label provider of this security label */
81         const char *label;                      /* security label for an object */
82         Oid                     classoid;               /* object class (catalog OID) */
83         Oid                     objoid;                 /* object OID */
84         int                     objsubid;               /* subobject (table column #) */
85 } SecLabelItem;
86
87 typedef enum OidOptions
88 {
89         zeroAsOpaque = 1,
90         zeroAsAny = 2,
91         zeroAsStar = 4,
92         zeroAsNone = 8
93 } OidOptions;
94
95 /* global decls */
96 static bool dosync = true;              /* Issue fsync() to make dump durable on disk. */
97
98 /* subquery used to convert user ID (eg, datdba) to user name */
99 static const char *username_subquery;
100
101 /*
102  * For 8.0 and earlier servers, pulled from pg_database, for 8.1+ we use
103  * FirstNormalObjectId - 1.
104  */
105 static Oid      g_last_builtin_oid; /* value of the last builtin oid */
106
107 /* The specified names/patterns should to match at least one entity */
108 static int      strict_names = 0;
109
110 /*
111  * Object inclusion/exclusion lists
112  *
113  * The string lists record the patterns given by command-line switches,
114  * which we then convert to lists of OIDs of matching objects.
115  */
116 static SimpleStringList schema_include_patterns = {NULL, NULL};
117 static SimpleOidList schema_include_oids = {NULL, NULL};
118 static SimpleStringList schema_exclude_patterns = {NULL, NULL};
119 static SimpleOidList schema_exclude_oids = {NULL, NULL};
120
121 static SimpleStringList table_include_patterns = {NULL, NULL};
122 static SimpleOidList table_include_oids = {NULL, NULL};
123 static SimpleStringList table_exclude_patterns = {NULL, NULL};
124 static SimpleOidList table_exclude_oids = {NULL, NULL};
125 static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
126 static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
127
128
129 char            g_opaque_type[10];      /* name for the opaque type */
130
131 /* placeholders for the delimiters for comments */
132 char            g_comment_start[10];
133 char            g_comment_end[10];
134
135 static const CatalogId nilCatalogId = {0, 0};
136
137 /* override for standard extra_float_digits setting */
138 static bool have_extra_float_digits = false;
139 static int extra_float_digits;
140
141 /*
142  * The default number of rows per INSERT when
143  * --inserts is specified without --rows-per-insert
144  */
145 #define DUMP_DEFAULT_ROWS_PER_INSERT 1
146
147 /*
148  * Macro for producing quoted, schema-qualified name of a dumpable object.
149  */
150 #define fmtQualifiedDumpable(obj) \
151         fmtQualifiedId((obj)->dobj.namespace->dobj.name, \
152                                    (obj)->dobj.name)
153
154 static void help(const char *progname);
155 static void setup_connection(Archive *AH,
156                                  const char *dumpencoding, const char *dumpsnapshot,
157                                  char *use_role);
158 static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
159 static void expand_schema_name_patterns(Archive *fout,
160                                                         SimpleStringList *patterns,
161                                                         SimpleOidList *oids,
162                                                         bool strict_names);
163 static void expand_table_name_patterns(Archive *fout,
164                                                    SimpleStringList *patterns,
165                                                    SimpleOidList *oids,
166                                                    bool strict_names);
167 static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid);
168 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
169 static void refreshMatViewData(Archive *fout, TableDataInfo *tdinfo);
170 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
171 static void dumpComment(Archive *fout, const char *type, const char *name,
172                         const char *namespace, const char *owner,
173                         CatalogId catalogId, int subid, DumpId dumpId);
174 static int findComments(Archive *fout, Oid classoid, Oid objoid,
175                          CommentItem **items);
176 static int      collectComments(Archive *fout, CommentItem **items);
177 static void dumpSecLabel(Archive *fout, const char *type, const char *name,
178                          const char *namespace, const char *owner,
179                          CatalogId catalogId, int subid, DumpId dumpId);
180 static int findSecLabels(Archive *fout, Oid classoid, Oid objoid,
181                           SecLabelItem **items);
182 static int      collectSecLabels(Archive *fout, SecLabelItem **items);
183 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
184 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
185 static void dumpExtension(Archive *fout, ExtensionInfo *extinfo);
186 static void dumpType(Archive *fout, TypeInfo *tyinfo);
187 static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
188 static void dumpEnumType(Archive *fout, TypeInfo *tyinfo);
189 static void dumpRangeType(Archive *fout, TypeInfo *tyinfo);
190 static void dumpUndefinedType(Archive *fout, TypeInfo *tyinfo);
191 static void dumpDomain(Archive *fout, TypeInfo *tyinfo);
192 static void dumpCompositeType(Archive *fout, TypeInfo *tyinfo);
193 static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
194 static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
195 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
196 static void dumpFunc(Archive *fout, FuncInfo *finfo);
197 static void dumpCast(Archive *fout, CastInfo *cast);
198 static void dumpTransform(Archive *fout, TransformInfo *transform);
199 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
200 static void dumpAccessMethod(Archive *fout, AccessMethodInfo *oprinfo);
201 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
202 static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
203 static void dumpCollation(Archive *fout, CollInfo *collinfo);
204 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
205 static void dumpRule(Archive *fout, RuleInfo *rinfo);
206 static void dumpAgg(Archive *fout, AggInfo *agginfo);
207 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
208 static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
209 static void dumpTable(Archive *fout, TableInfo *tbinfo);
210 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
211 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
212 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
213 static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo);
214 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
215 static void dumpIndexAttach(Archive *fout, IndexAttachInfo *attachinfo);
216 static void dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo);
217 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
218 static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
219 static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
220 static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
221 static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
222 static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
223 static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
224 static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
225 static void dumpUserMappings(Archive *fout,
226                                  const char *servername, const char *namespace,
227                                  const char *owner, CatalogId catalogId, DumpId dumpId);
228 static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
229
230 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
231                 const char *type, const char *name, const char *subname,
232                 const char *nspname, const char *owner,
233                 const char *acls, const char *racls,
234                 const char *initacls, const char *initracls);
235
236 static void getDependencies(Archive *fout);
237 static void BuildArchiveDependencies(Archive *fout);
238 static void findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
239                                                  DumpId **dependencies, int *nDeps, int *allocDeps);
240
241 static DumpableObject *createBoundaryObjects(void);
242 static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
243                                                 DumpableObject *boundaryObjs);
244
245 static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
246 static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind);
247 static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo);
248 static void buildMatViewRefreshDependencies(Archive *fout);
249 static void getTableDataFKConstraints(void);
250 static char *format_function_arguments(FuncInfo *finfo, char *funcargs,
251                                                   bool is_agg);
252 static char *format_function_arguments_old(Archive *fout,
253                                                           FuncInfo *finfo, int nallargs,
254                                                           char **allargtypes,
255                                                           char **argmodes,
256                                                           char **argnames);
257 static char *format_function_signature(Archive *fout,
258                                                   FuncInfo *finfo, bool honor_quotes);
259 static char *convertRegProcReference(Archive *fout,
260                                                 const char *proc);
261 static char *getFormattedOperatorName(Archive *fout, const char *oproid);
262 static char *convertTSFunction(Archive *fout, Oid funcOid);
263 static Oid      findLastBuiltinOid_V71(Archive *fout);
264 static char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
265 static void getBlobs(Archive *fout);
266 static void dumpBlob(Archive *fout, BlobInfo *binfo);
267 static int      dumpBlobs(Archive *fout, void *arg);
268 static void dumpPolicy(Archive *fout, PolicyInfo *polinfo);
269 static void dumpPublication(Archive *fout, PublicationInfo *pubinfo);
270 static void dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo);
271 static void dumpSubscription(Archive *fout, SubscriptionInfo *subinfo);
272 static void dumpDatabase(Archive *AH);
273 static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
274                                    const char *dbname, Oid dboid);
275 static void dumpEncoding(Archive *AH);
276 static void dumpStdStrings(Archive *AH);
277 static void dumpSearchPath(Archive *AH);
278 static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
279                                                                                  PQExpBuffer upgrade_buffer,
280                                                                                  Oid pg_type_oid,
281                                                                                  bool force_array_type);
282 static bool binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
283                                                                                 PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
284 static void binary_upgrade_set_pg_class_oids(Archive *fout,
285                                                                  PQExpBuffer upgrade_buffer,
286                                                                  Oid pg_class_oid, bool is_index);
287 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
288                                                                 DumpableObject *dobj,
289                                                                 const char *objtype,
290                                                                 const char *objname,
291                                                                 const char *objnamespace);
292 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
293 static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
294 static bool nonemptyReloptions(const char *reloptions);
295 static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
296                                                 const char *prefix, Archive *fout);
297 static char *get_synchronized_snapshot(Archive *fout);
298 static void setupDumpWorker(Archive *AHX);
299 static TableInfo *getRootTableInfo(TableInfo *tbinfo);
300
301
302 int
303 main(int argc, char **argv)
304 {
305         int                     c;
306         const char *filename = NULL;
307         const char *format = "p";
308         TableInfo  *tblinfo;
309         int                     numTables;
310         DumpableObject **dobjs;
311         int                     numObjs;
312         DumpableObject *boundaryObjs;
313         int                     i;
314         int                     optindex;
315         char       *endptr;
316         RestoreOptions *ropt;
317         Archive    *fout;                       /* the script file */
318         bool            g_verbose = false;
319         const char *dumpencoding = NULL;
320         const char *dumpsnapshot = NULL;
321         char       *use_role = NULL;
322         long            rowsPerInsert;
323         int                     numWorkers = 1;
324         trivalue        prompt_password = TRI_DEFAULT;
325         int                     compressLevel = -1;
326         int                     plainText = 0;
327         ArchiveFormat archiveFormat = archUnknown;
328         ArchiveMode archiveMode;
329
330         static DumpOptions dopt;
331
332         static struct option long_options[] = {
333                 {"data-only", no_argument, NULL, 'a'},
334                 {"blobs", no_argument, NULL, 'b'},
335                 {"no-blobs", no_argument, NULL, 'B'},
336                 {"clean", no_argument, NULL, 'c'},
337                 {"create", no_argument, NULL, 'C'},
338                 {"dbname", required_argument, NULL, 'd'},
339                 {"file", required_argument, NULL, 'f'},
340                 {"format", required_argument, NULL, 'F'},
341                 {"host", required_argument, NULL, 'h'},
342                 {"jobs", 1, NULL, 'j'},
343                 {"no-reconnect", no_argument, NULL, 'R'},
344                 {"no-owner", no_argument, NULL, 'O'},
345                 {"port", required_argument, NULL, 'p'},
346                 {"schema", required_argument, NULL, 'n'},
347                 {"exclude-schema", required_argument, NULL, 'N'},
348                 {"schema-only", no_argument, NULL, 's'},
349                 {"superuser", required_argument, NULL, 'S'},
350                 {"table", required_argument, NULL, 't'},
351                 {"exclude-table", required_argument, NULL, 'T'},
352                 {"no-password", no_argument, NULL, 'w'},
353                 {"password", no_argument, NULL, 'W'},
354                 {"username", required_argument, NULL, 'U'},
355                 {"verbose", no_argument, NULL, 'v'},
356                 {"no-privileges", no_argument, NULL, 'x'},
357                 {"no-acl", no_argument, NULL, 'x'},
358                 {"compress", required_argument, NULL, 'Z'},
359                 {"encoding", required_argument, NULL, 'E'},
360                 {"help", no_argument, NULL, '?'},
361                 {"version", no_argument, NULL, 'V'},
362
363                 /*
364                  * the following options don't have an equivalent short option letter
365                  */
366                 {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
367                 {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
368                 {"column-inserts", no_argument, &dopt.column_inserts, 1},
369                 {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
370                 {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
371                 {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
372                 {"exclude-table-data", required_argument, NULL, 4},
373                 {"extra-float-digits", required_argument, NULL, 8},
374                 {"if-exists", no_argument, &dopt.if_exists, 1},
375                 {"inserts", no_argument, NULL, 9},
376                 {"lock-wait-timeout", required_argument, NULL, 2},
377                 {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
378                 {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
379                 {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
380                 {"role", required_argument, NULL, 3},
381                 {"section", required_argument, NULL, 5},
382                 {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
383                 {"snapshot", required_argument, NULL, 6},
384                 {"strict-names", no_argument, &strict_names, 1},
385                 {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
386                 {"no-comments", no_argument, &dopt.no_comments, 1},
387                 {"no-publications", no_argument, &dopt.no_publications, 1},
388                 {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
389                 {"no-synchronized-snapshots", no_argument, &dopt.no_synchronized_snapshots, 1},
390                 {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
391                 {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
392                 {"no-sync", no_argument, NULL, 7},
393                 {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
394                 {"rows-per-insert", required_argument, NULL, 10},
395
396                 {NULL, 0, NULL, 0}
397         };
398
399         pg_logging_init(argv[0]);
400         pg_logging_set_level(PG_LOG_WARNING);
401         set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
402
403         /*
404          * Initialize what we need for parallel execution, especially for thread
405          * support on Windows.
406          */
407         init_parallel_dump_utils();
408
409         strcpy(g_comment_start, "-- ");
410         g_comment_end[0] = '\0';
411         strcpy(g_opaque_type, "opaque");
412
413         progname = get_progname(argv[0]);
414
415         if (argc > 1)
416         {
417                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
418                 {
419                         help(progname);
420                         exit_nicely(0);
421                 }
422                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
423                 {
424                         puts("pg_dump (PostgreSQL) " PG_VERSION);
425                         exit_nicely(0);
426                 }
427         }
428
429         InitDumpOptions(&dopt);
430
431         while ((c = getopt_long(argc, argv, "abBcCd:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxZ:",
432                                                         long_options, &optindex)) != -1)
433         {
434                 switch (c)
435                 {
436                         case 'a':                       /* Dump data only */
437                                 dopt.dataOnly = true;
438                                 break;
439
440                         case 'b':                       /* Dump blobs */
441                                 dopt.outputBlobs = true;
442                                 break;
443
444                         case 'B':                       /* Don't dump blobs */
445                                 dopt.dontOutputBlobs = true;
446                                 break;
447
448                         case 'c':                       /* clean (i.e., drop) schema prior to create */
449                                 dopt.outputClean = 1;
450                                 break;
451
452                         case 'C':                       /* Create DB */
453                                 dopt.outputCreateDB = 1;
454                                 break;
455
456                         case 'd':                       /* database name */
457                                 dopt.dbname = pg_strdup(optarg);
458                                 break;
459
460                         case 'E':                       /* Dump encoding */
461                                 dumpencoding = pg_strdup(optarg);
462                                 break;
463
464                         case 'f':
465                                 filename = pg_strdup(optarg);
466                                 break;
467
468                         case 'F':
469                                 format = pg_strdup(optarg);
470                                 break;
471
472                         case 'h':                       /* server host */
473                                 dopt.pghost = pg_strdup(optarg);
474                                 break;
475
476                         case 'j':                       /* number of dump jobs */
477                                 numWorkers = atoi(optarg);
478                                 break;
479
480                         case 'n':                       /* include schema(s) */
481                                 simple_string_list_append(&schema_include_patterns, optarg);
482                                 dopt.include_everything = false;
483                                 break;
484
485                         case 'N':                       /* exclude schema(s) */
486                                 simple_string_list_append(&schema_exclude_patterns, optarg);
487                                 break;
488
489                         case 'O':                       /* Don't reconnect to match owner */
490                                 dopt.outputNoOwner = 1;
491                                 break;
492
493                         case 'p':                       /* server port */
494                                 dopt.pgport = pg_strdup(optarg);
495                                 break;
496
497                         case 'R':
498                                 /* no-op, still accepted for backwards compatibility */
499                                 break;
500
501                         case 's':                       /* dump schema only */
502                                 dopt.schemaOnly = true;
503                                 break;
504
505                         case 'S':                       /* Username for superuser in plain text output */
506                                 dopt.outputSuperuser = pg_strdup(optarg);
507                                 break;
508
509                         case 't':                       /* include table(s) */
510                                 simple_string_list_append(&table_include_patterns, optarg);
511                                 dopt.include_everything = false;
512                                 break;
513
514                         case 'T':                       /* exclude table(s) */
515                                 simple_string_list_append(&table_exclude_patterns, optarg);
516                                 break;
517
518                         case 'U':
519                                 dopt.username = pg_strdup(optarg);
520                                 break;
521
522                         case 'v':                       /* verbose */
523                                 g_verbose = true;
524                                 pg_logging_set_level(PG_LOG_INFO);
525                                 break;
526
527                         case 'w':
528                                 prompt_password = TRI_NO;
529                                 break;
530
531                         case 'W':
532                                 prompt_password = TRI_YES;
533                                 break;
534
535                         case 'x':                       /* skip ACL dump */
536                                 dopt.aclsSkip = true;
537                                 break;
538
539                         case 'Z':                       /* Compression Level */
540                                 compressLevel = atoi(optarg);
541                                 if (compressLevel < 0 || compressLevel > 9)
542                                 {
543                                         pg_log_error("compression level must be in range 0..9");
544                                         exit_nicely(1);
545                                 }
546                                 break;
547
548                         case 0:
549                                 /* This covers the long options. */
550                                 break;
551
552                         case 2:                         /* lock-wait-timeout */
553                                 dopt.lockWaitTimeout = pg_strdup(optarg);
554                                 break;
555
556                         case 3:                         /* SET ROLE */
557                                 use_role = pg_strdup(optarg);
558                                 break;
559
560                         case 4:                         /* exclude table(s) data */
561                                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
562                                 break;
563
564                         case 5:                         /* section */
565                                 set_dump_section(optarg, &dopt.dumpSections);
566                                 break;
567
568                         case 6:                         /* snapshot */
569                                 dumpsnapshot = pg_strdup(optarg);
570                                 break;
571
572                         case 7:                         /* no-sync */
573                                 dosync = false;
574                                 break;
575
576                         case 8:
577                                 have_extra_float_digits = true;
578                                 extra_float_digits = atoi(optarg);
579                                 if (extra_float_digits < -15 || extra_float_digits > 3)
580                                 {
581                                         pg_log_error("extra_float_digits must be in range -15..3");
582                                         exit_nicely(1);
583                                 }
584                                 break;
585
586                         case 9:                         /* inserts */
587
588                                 /*
589                                  * dump_inserts also stores --rows-per-insert, careful not to
590                                  * overwrite that.
591                                  */
592                                 if (dopt.dump_inserts == 0)
593                                         dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
594                                 break;
595
596                         case 10:                        /* rows per insert */
597                                 errno = 0;
598                                 rowsPerInsert = strtol(optarg, &endptr, 10);
599
600                                 if (endptr == optarg || *endptr != '\0' ||
601                                         rowsPerInsert <= 0 || rowsPerInsert > INT_MAX ||
602                                         errno == ERANGE)
603                                 {
604                                         pg_log_error("rows-per-insert must be in range %d..%d",
605                                                           1, INT_MAX);
606                                         exit_nicely(1);
607                                 }
608                                 dopt.dump_inserts = (int) rowsPerInsert;
609                                 break;
610
611                         default:
612                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
613                                 exit_nicely(1);
614                 }
615         }
616
617         /*
618          * Non-option argument specifies database name as long as it wasn't
619          * already specified with -d / --dbname
620          */
621         if (optind < argc && dopt.dbname == NULL)
622                 dopt.dbname = argv[optind++];
623
624         /* Complain if any arguments remain */
625         if (optind < argc)
626         {
627                 pg_log_error("too many command-line arguments (first is \"%s\")",
628                                          argv[optind]);
629                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
630                                 progname);
631                 exit_nicely(1);
632         }
633
634         /* --column-inserts implies --inserts */
635         if (dopt.column_inserts && dopt.dump_inserts == 0)
636                 dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
637
638         /*
639          * Binary upgrade mode implies dumping sequence data even in schema-only
640          * mode.  This is not exposed as a separate option, but kept separate
641          * internally for clarity.
642          */
643         if (dopt.binary_upgrade)
644                 dopt.sequence_data = 1;
645
646         if (dopt.dataOnly && dopt.schemaOnly)
647         {
648                 pg_log_error("options -s/--schema-only and -a/--data-only cannot be used together");
649                 exit_nicely(1);
650         }
651
652         if (dopt.dataOnly && dopt.outputClean)
653         {
654                 pg_log_error("options -c/--clean and -a/--data-only cannot be used together");
655                 exit_nicely(1);
656         }
657
658         if (dopt.if_exists && !dopt.outputClean)
659                 fatal("option --if-exists requires option -c/--clean");
660
661         /*
662          * --inserts are already implied above if --column-inserts or
663          * --rows-per-insert were specified.
664          */
665         if (dopt.do_nothing && dopt.dump_inserts == 0)
666                 fatal("option --on-conflict-do-nothing requires option --inserts, --rows-per-insert or --column-inserts");
667
668         /* Identify archive format to emit */
669         archiveFormat = parseArchiveFormat(format, &archiveMode);
670
671         /* archiveFormat specific setup */
672         if (archiveFormat == archNull)
673                 plainText = 1;
674
675         /* Custom and directory formats are compressed by default, others not */
676         if (compressLevel == -1)
677         {
678 #ifdef HAVE_LIBZ
679                 if (archiveFormat == archCustom || archiveFormat == archDirectory)
680                         compressLevel = Z_DEFAULT_COMPRESSION;
681                 else
682 #endif
683                         compressLevel = 0;
684         }
685
686 #ifndef HAVE_LIBZ
687         if (compressLevel != 0)
688                 pg_log_warning("requested compression not available in this installation -- archive will be uncompressed");
689         compressLevel = 0;
690 #endif
691
692         /*
693          * If emitting an archive format, we always want to emit a DATABASE item,
694          * in case --create is specified at pg_restore time.
695          */
696         if (!plainText)
697                 dopt.outputCreateDB = 1;
698
699         /*
700          * On Windows we can only have at most MAXIMUM_WAIT_OBJECTS (= 64 usually)
701          * parallel jobs because that's the maximum limit for the
702          * WaitForMultipleObjects() call.
703          */
704         if (numWorkers <= 0
705 #ifdef WIN32
706                 || numWorkers > MAXIMUM_WAIT_OBJECTS
707 #endif
708                 )
709                 fatal("invalid number of parallel jobs");
710
711         /* Parallel backup only in the directory archive format so far */
712         if (archiveFormat != archDirectory && numWorkers > 1)
713                 fatal("parallel backup only supported by the directory format");
714
715         /* Open the output file */
716         fout = CreateArchive(filename, archiveFormat, compressLevel, dosync,
717                                                  archiveMode, setupDumpWorker);
718
719         /* Make dump options accessible right away */
720         SetArchiveOptions(fout, &dopt, NULL);
721
722         /* Register the cleanup hook */
723         on_exit_close_archive(fout);
724
725         /* Let the archiver know how noisy to be */
726         fout->verbose = g_verbose;
727
728
729         /*
730          * We allow the server to be back to 8.0, and up to any minor release of
731          * our own major version.  (See also version check in pg_dumpall.c.)
732          */
733         fout->minRemoteVersion = 80000;
734         fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
735
736         fout->numWorkers = numWorkers;
737
738         /*
739          * Open the database using the Archiver, so it knows about it. Errors mean
740          * death.
741          */
742         ConnectDatabase(fout, dopt.dbname, dopt.pghost, dopt.pgport, dopt.username, prompt_password);
743         setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
744
745         /*
746          * Disable security label support if server version < v9.1.x (prevents
747          * access to nonexistent pg_seclabel catalog)
748          */
749         if (fout->remoteVersion < 90100)
750                 dopt.no_security_labels = 1;
751
752         /*
753          * On hot standbys, never try to dump unlogged table data, since it will
754          * just throw an error.
755          */
756         if (fout->isStandby)
757                 dopt.no_unlogged_table_data = true;
758
759         /* Select the appropriate subquery to convert user IDs to names */
760         if (fout->remoteVersion >= 80100)
761                 username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
762         else
763                 username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
764
765         /* check the version for the synchronized snapshots feature */
766         if (numWorkers > 1 && fout->remoteVersion < 90200
767                 && !dopt.no_synchronized_snapshots)
768                 fatal("Synchronized snapshots are not supported by this server version.\n"
769                           "Run with --no-synchronized-snapshots instead if you do not need\n"
770                           "synchronized snapshots.");
771
772         /* check the version when a snapshot is explicitly specified by user */
773         if (dumpsnapshot && fout->remoteVersion < 90200)
774                 fatal("Exported snapshots are not supported by this server version.");
775
776         /*
777          * Find the last built-in OID, if needed (prior to 8.1)
778          *
779          * With 8.1 and above, we can just use FirstNormalObjectId - 1.
780          */
781         if (fout->remoteVersion < 80100)
782                 g_last_builtin_oid = findLastBuiltinOid_V71(fout);
783         else
784                 g_last_builtin_oid = FirstNormalObjectId - 1;
785
786         pg_log_info("last built-in OID is %u", g_last_builtin_oid);
787
788         /* Expand schema selection patterns into OID lists */
789         if (schema_include_patterns.head != NULL)
790         {
791                 expand_schema_name_patterns(fout, &schema_include_patterns,
792                                                                         &schema_include_oids,
793                                                                         strict_names);
794                 if (schema_include_oids.head == NULL)
795                         fatal("no matching schemas were found");
796         }
797         expand_schema_name_patterns(fout, &schema_exclude_patterns,
798                                                                 &schema_exclude_oids,
799                                                                 false);
800         /* non-matching exclusion patterns aren't an error */
801
802         /* Expand table selection patterns into OID lists */
803         if (table_include_patterns.head != NULL)
804         {
805                 expand_table_name_patterns(fout, &table_include_patterns,
806                                                                    &table_include_oids,
807                                                                    strict_names);
808                 if (table_include_oids.head == NULL)
809                         fatal("no matching tables were found");
810         }
811         expand_table_name_patterns(fout, &table_exclude_patterns,
812                                                            &table_exclude_oids,
813                                                            false);
814
815         expand_table_name_patterns(fout, &tabledata_exclude_patterns,
816                                                            &tabledata_exclude_oids,
817                                                            false);
818
819         /* non-matching exclusion patterns aren't an error */
820
821         /*
822          * Dumping blobs is the default for dumps where an inclusion switch is not
823          * used (an "include everything" dump).  -B can be used to exclude blobs
824          * from those dumps.  -b can be used to include blobs even when an
825          * inclusion switch is used.
826          *
827          * -s means "schema only" and blobs are data, not schema, so we never
828          * include blobs when -s is used.
829          */
830         if (dopt.include_everything && !dopt.schemaOnly && !dopt.dontOutputBlobs)
831                 dopt.outputBlobs = true;
832
833         /*
834          * Now scan the database and create DumpableObject structs for all the
835          * objects we intend to dump.
836          */
837         tblinfo = getSchemaData(fout, &numTables);
838
839         if (fout->remoteVersion < 80400)
840                 guessConstraintInheritance(tblinfo, numTables);
841
842         if (!dopt.schemaOnly)
843         {
844                 getTableData(&dopt, tblinfo, numTables, 0);
845                 buildMatViewRefreshDependencies(fout);
846                 if (dopt.dataOnly)
847                         getTableDataFKConstraints();
848         }
849
850         if (dopt.schemaOnly && dopt.sequence_data)
851                 getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
852
853         /*
854          * In binary-upgrade mode, we do not have to worry about the actual blob
855          * data or the associated metadata that resides in the pg_largeobject and
856          * pg_largeobject_metadata tables, respectively.
857          *
858          * However, we do need to collect blob information as there may be
859          * comments or other information on blobs that we do need to dump out.
860          */
861         if (dopt.outputBlobs || dopt.binary_upgrade)
862                 getBlobs(fout);
863
864         /*
865          * Collect dependency data to assist in ordering the objects.
866          */
867         getDependencies(fout);
868
869         /* Lastly, create dummy objects to represent the section boundaries */
870         boundaryObjs = createBoundaryObjects();
871
872         /* Get pointers to all the known DumpableObjects */
873         getDumpableObjects(&dobjs, &numObjs);
874
875         /*
876          * Add dummy dependencies to enforce the dump section ordering.
877          */
878         addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
879
880         /*
881          * Sort the objects into a safe dump order (no forward references).
882          *
883          * We rely on dependency information to help us determine a safe order, so
884          * the initial sort is mostly for cosmetic purposes: we sort by name to
885          * ensure that logically identical schemas will dump identically.
886          */
887         sortDumpableObjectsByTypeName(dobjs, numObjs);
888
889         sortDumpableObjects(dobjs, numObjs,
890                                                 boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
891
892         /*
893          * Create archive TOC entries for all the objects to be dumped, in a safe
894          * order.
895          */
896
897         /* First the special ENCODING, STDSTRINGS, and SEARCHPATH entries. */
898         dumpEncoding(fout);
899         dumpStdStrings(fout);
900         dumpSearchPath(fout);
901
902         /* The database items are always next, unless we don't want them at all */
903         if (dopt.outputCreateDB)
904                 dumpDatabase(fout);
905
906         /* Now the rearrangeable objects. */
907         for (i = 0; i < numObjs; i++)
908                 dumpDumpableObject(fout, dobjs[i]);
909
910         /*
911          * Set up options info to ensure we dump what we want.
912          */
913         ropt = NewRestoreOptions();
914         ropt->filename = filename;
915
916         /* if you change this list, see dumpOptionsFromRestoreOptions */
917         ropt->dropSchema = dopt.outputClean;
918         ropt->dataOnly = dopt.dataOnly;
919         ropt->schemaOnly = dopt.schemaOnly;
920         ropt->if_exists = dopt.if_exists;
921         ropt->column_inserts = dopt.column_inserts;
922         ropt->dumpSections = dopt.dumpSections;
923         ropt->aclsSkip = dopt.aclsSkip;
924         ropt->superuser = dopt.outputSuperuser;
925         ropt->createDB = dopt.outputCreateDB;
926         ropt->noOwner = dopt.outputNoOwner;
927         ropt->noTablespace = dopt.outputNoTablespaces;
928         ropt->disable_triggers = dopt.disable_triggers;
929         ropt->use_setsessauth = dopt.use_setsessauth;
930         ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
931         ropt->dump_inserts = dopt.dump_inserts;
932         ropt->no_comments = dopt.no_comments;
933         ropt->no_publications = dopt.no_publications;
934         ropt->no_security_labels = dopt.no_security_labels;
935         ropt->no_subscriptions = dopt.no_subscriptions;
936         ropt->lockWaitTimeout = dopt.lockWaitTimeout;
937         ropt->include_everything = dopt.include_everything;
938         ropt->enable_row_security = dopt.enable_row_security;
939         ropt->sequence_data = dopt.sequence_data;
940         ropt->binary_upgrade = dopt.binary_upgrade;
941
942         if (compressLevel == -1)
943                 ropt->compression = 0;
944         else
945                 ropt->compression = compressLevel;
946
947         ropt->suppressDumpWarnings = true;      /* We've already shown them */
948
949         SetArchiveOptions(fout, &dopt, ropt);
950
951         /* Mark which entries should be output */
952         ProcessArchiveRestoreOptions(fout);
953
954         /*
955          * The archive's TOC entries are now marked as to which ones will actually
956          * be output, so we can set up their dependency lists properly. This isn't
957          * necessary for plain-text output, though.
958          */
959         if (!plainText)
960                 BuildArchiveDependencies(fout);
961
962         /*
963          * And finally we can do the actual output.
964          *
965          * Note: for non-plain-text output formats, the output file is written
966          * inside CloseArchive().  This is, um, bizarre; but not worth changing
967          * right now.
968          */
969         if (plainText)
970                 RestoreArchive(fout);
971
972         CloseArchive(fout);
973
974         exit_nicely(0);
975 }
976
977
978 static void
979 help(const char *progname)
980 {
981         printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
982         printf(_("Usage:\n"));
983         printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
984
985         printf(_("\nGeneral options:\n"));
986         printf(_("  -f, --file=FILENAME          output file or directory name\n"));
987         printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
988                          "                               plain text (default))\n"));
989         printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
990         printf(_("  -v, --verbose                verbose mode\n"));
991         printf(_("  -V, --version                output version information, then exit\n"));
992         printf(_("  -Z, --compress=0-9           compression level for compressed formats\n"));
993         printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
994         printf(_("  --no-sync                    do not wait for changes to be written safely to disk\n"));
995         printf(_("  -?, --help                   show this help, then exit\n"));
996
997         printf(_("\nOptions controlling the output content:\n"));
998         printf(_("  -a, --data-only              dump only the data, not the schema\n"));
999         printf(_("  -b, --blobs                  include large objects in dump\n"));
1000         printf(_("  -B, --no-blobs               exclude large objects in dump\n"));
1001         printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
1002         printf(_("  -C, --create                 include commands to create database in dump\n"));
1003         printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
1004         printf(_("  -n, --schema=SCHEMA          dump the named schema(s) only\n"));
1005         printf(_("  -N, --exclude-schema=SCHEMA  do NOT dump the named schema(s)\n"));
1006         printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
1007                          "                               plain-text format\n"));
1008         printf(_("  -s, --schema-only            dump only the schema, no data\n"));
1009         printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
1010         printf(_("  -t, --table=TABLE            dump the named table(s) only\n"));
1011         printf(_("  -T, --exclude-table=TABLE    do NOT dump the named table(s)\n"));
1012         printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
1013         printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
1014         printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
1015         printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
1016         printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
1017         printf(_("  --enable-row-security        enable row security (dump only content user has\n"
1018                          "                               access to)\n"));
1019         printf(_("  --exclude-table-data=TABLE   do NOT dump data for the named table(s)\n"));
1020         printf(_("  --extra-float-digits=NUM     override default setting for extra_float_digits\n"));
1021         printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
1022         printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
1023         printf(_("  --load-via-partition-root    load partitions via the root table\n"));
1024         printf(_("  --no-comments                do not dump comments\n"));
1025         printf(_("  --no-publications            do not dump publications\n"));
1026         printf(_("  --no-security-labels         do not dump security label assignments\n"));
1027         printf(_("  --no-subscriptions           do not dump subscriptions\n"));
1028         printf(_("  --no-synchronized-snapshots  do not use synchronized snapshots in parallel jobs\n"));
1029         printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
1030         printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
1031         printf(_("  --on-conflict-do-nothing     add ON CONFLICT DO NOTHING to INSERT commands\n"));
1032         printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
1033         printf(_("  --rows-per-insert=NROWS      number of rows per INSERT; implies --inserts\n"));
1034         printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
1035         printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
1036         printf(_("  --snapshot=SNAPSHOT          use given snapshot for the dump\n"));
1037         printf(_("  --strict-names               require table and/or schema include patterns to\n"
1038                          "                               match at least one entity each\n"));
1039         printf(_("  --use-set-session-authorization\n"
1040                          "                               use SET SESSION AUTHORIZATION commands instead of\n"
1041                          "                               ALTER OWNER commands to set ownership\n"));
1042
1043         printf(_("\nConnection options:\n"));
1044         printf(_("  -d, --dbname=DBNAME      database to dump\n"));
1045         printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
1046         printf(_("  -p, --port=PORT          database server port number\n"));
1047         printf(_("  -U, --username=NAME      connect as specified database user\n"));
1048         printf(_("  -w, --no-password        never prompt for password\n"));
1049         printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
1050         printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
1051
1052         printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
1053                          "variable value is used.\n\n"));
1054         printf(_("Report bugs to <pgsql-bugs@lists.postgresql.org>.\n"));
1055 }
1056
1057 static void
1058 setup_connection(Archive *AH, const char *dumpencoding,
1059                                  const char *dumpsnapshot, char *use_role)
1060 {
1061         DumpOptions *dopt = AH->dopt;
1062         PGconn     *conn = GetConnection(AH);
1063         const char *std_strings;
1064
1065         PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
1066
1067         /*
1068          * Set the client encoding if requested.
1069          */
1070         if (dumpencoding)
1071         {
1072                 if (PQsetClientEncoding(conn, dumpencoding) < 0)
1073                         fatal("invalid client encoding \"%s\" specified",
1074                                   dumpencoding);
1075         }
1076
1077         /*
1078          * Get the active encoding and the standard_conforming_strings setting, so
1079          * we know how to escape strings.
1080          */
1081         AH->encoding = PQclientEncoding(conn);
1082
1083         std_strings = PQparameterStatus(conn, "standard_conforming_strings");
1084         AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
1085
1086         /*
1087          * Set the role if requested.  In a parallel dump worker, we'll be passed
1088          * use_role == NULL, but AH->use_role is already set (if user specified it
1089          * originally) and we should use that.
1090          */
1091         if (!use_role && AH->use_role)
1092                 use_role = AH->use_role;
1093
1094         /* Set the role if requested */
1095         if (use_role && AH->remoteVersion >= 80100)
1096         {
1097                 PQExpBuffer query = createPQExpBuffer();
1098
1099                 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
1100                 ExecuteSqlStatement(AH, query->data);
1101                 destroyPQExpBuffer(query);
1102
1103                 /* save it for possible later use by parallel workers */
1104                 if (!AH->use_role)
1105                         AH->use_role = pg_strdup(use_role);
1106         }
1107
1108         /* Set the datestyle to ISO to ensure the dump's portability */
1109         ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
1110
1111         /* Likewise, avoid using sql_standard intervalstyle */
1112         if (AH->remoteVersion >= 80400)
1113                 ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
1114
1115         /*
1116          * Use an explicitly specified extra_float_digits if it has been
1117          * provided. Otherwise, set extra_float_digits so that we can dump float
1118          * data exactly (given correctly implemented float I/O code, anyway).
1119          */
1120         if (have_extra_float_digits)
1121         {
1122                 PQExpBuffer q = createPQExpBuffer();
1123                 appendPQExpBuffer(q, "SET extra_float_digits TO %d",
1124                                                   extra_float_digits);
1125                 ExecuteSqlStatement(AH, q->data);
1126                 destroyPQExpBuffer(q);
1127         }
1128         else if (AH->remoteVersion >= 90000)
1129                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
1130         else
1131                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 2");
1132
1133         /*
1134          * If synchronized scanning is supported, disable it, to prevent
1135          * unpredictable changes in row ordering across a dump and reload.
1136          */
1137         if (AH->remoteVersion >= 80300)
1138                 ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
1139
1140         /*
1141          * Disable timeouts if supported.
1142          */
1143         ExecuteSqlStatement(AH, "SET statement_timeout = 0");
1144         if (AH->remoteVersion >= 90300)
1145                 ExecuteSqlStatement(AH, "SET lock_timeout = 0");
1146         if (AH->remoteVersion >= 90600)
1147                 ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
1148
1149         /*
1150          * Quote all identifiers, if requested.
1151          */
1152         if (quote_all_identifiers && AH->remoteVersion >= 90100)
1153                 ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1154
1155         /*
1156          * Adjust row-security mode, if supported.
1157          */
1158         if (AH->remoteVersion >= 90500)
1159         {
1160                 if (dopt->enable_row_security)
1161                         ExecuteSqlStatement(AH, "SET row_security = on");
1162                 else
1163                         ExecuteSqlStatement(AH, "SET row_security = off");
1164         }
1165
1166         /*
1167          * Start transaction-snapshot mode transaction to dump consistent data.
1168          */
1169         ExecuteSqlStatement(AH, "BEGIN");
1170         if (AH->remoteVersion >= 90100)
1171         {
1172                 /*
1173                  * To support the combination of serializable_deferrable with the jobs
1174                  * option we use REPEATABLE READ for the worker connections that are
1175                  * passed a snapshot.  As long as the snapshot is acquired in a
1176                  * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
1177                  * REPEATABLE READ transaction provides the appropriate integrity
1178                  * guarantees.  This is a kluge, but safe for back-patching.
1179                  */
1180                 if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
1181                         ExecuteSqlStatement(AH,
1182                                                                 "SET TRANSACTION ISOLATION LEVEL "
1183                                                                 "SERIALIZABLE, READ ONLY, DEFERRABLE");
1184                 else
1185                         ExecuteSqlStatement(AH,
1186                                                                 "SET TRANSACTION ISOLATION LEVEL "
1187                                                                 "REPEATABLE READ, READ ONLY");
1188         }
1189         else
1190         {
1191                 ExecuteSqlStatement(AH,
1192                                                         "SET TRANSACTION ISOLATION LEVEL "
1193                                                         "SERIALIZABLE, READ ONLY");
1194         }
1195
1196         /*
1197          * If user specified a snapshot to use, select that.  In a parallel dump
1198          * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
1199          * is already set (if the server can handle it) and we should use that.
1200          */
1201         if (dumpsnapshot)
1202                 AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
1203
1204         if (AH->sync_snapshot_id)
1205         {
1206                 PQExpBuffer query = createPQExpBuffer();
1207
1208                 appendPQExpBuffer(query, "SET TRANSACTION SNAPSHOT ");
1209                 appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
1210                 ExecuteSqlStatement(AH, query->data);
1211                 destroyPQExpBuffer(query);
1212         }
1213         else if (AH->numWorkers > 1 &&
1214                          AH->remoteVersion >= 90200 &&
1215                          !dopt->no_synchronized_snapshots)
1216         {
1217                 if (AH->isStandby && AH->remoteVersion < 100000)
1218                         fatal("Synchronized snapshots on standby servers are not supported by this server version.\n"
1219                                   "Run with --no-synchronized-snapshots instead if you do not need\n"
1220                                   "synchronized snapshots.");
1221
1222
1223                 AH->sync_snapshot_id = get_synchronized_snapshot(AH);
1224         }
1225 }
1226
1227 /* Set up connection for a parallel worker process */
1228 static void
1229 setupDumpWorker(Archive *AH)
1230 {
1231         /*
1232          * We want to re-select all the same values the master connection is
1233          * using.  We'll have inherited directly-usable values in
1234          * AH->sync_snapshot_id and AH->use_role, but we need to translate the
1235          * inherited encoding value back to a string to pass to setup_connection.
1236          */
1237         setup_connection(AH,
1238                                          pg_encoding_to_char(AH->encoding),
1239                                          NULL,
1240                                          NULL);
1241 }
1242
1243 static char *
1244 get_synchronized_snapshot(Archive *fout)
1245 {
1246         char       *query = "SELECT pg_catalog.pg_export_snapshot()";
1247         char       *result;
1248         PGresult   *res;
1249
1250         res = ExecuteSqlQueryForSingleRow(fout, query);
1251         result = pg_strdup(PQgetvalue(res, 0, 0));
1252         PQclear(res);
1253
1254         return result;
1255 }
1256
1257 static ArchiveFormat
1258 parseArchiveFormat(const char *format, ArchiveMode *mode)
1259 {
1260         ArchiveFormat archiveFormat;
1261
1262         *mode = archModeWrite;
1263
1264         if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1265         {
1266                 /* This is used by pg_dumpall, and is not documented */
1267                 archiveFormat = archNull;
1268                 *mode = archModeAppend;
1269         }
1270         else if (pg_strcasecmp(format, "c") == 0)
1271                 archiveFormat = archCustom;
1272         else if (pg_strcasecmp(format, "custom") == 0)
1273                 archiveFormat = archCustom;
1274         else if (pg_strcasecmp(format, "d") == 0)
1275                 archiveFormat = archDirectory;
1276         else if (pg_strcasecmp(format, "directory") == 0)
1277                 archiveFormat = archDirectory;
1278         else if (pg_strcasecmp(format, "p") == 0)
1279                 archiveFormat = archNull;
1280         else if (pg_strcasecmp(format, "plain") == 0)
1281                 archiveFormat = archNull;
1282         else if (pg_strcasecmp(format, "t") == 0)
1283                 archiveFormat = archTar;
1284         else if (pg_strcasecmp(format, "tar") == 0)
1285                 archiveFormat = archTar;
1286         else
1287                 fatal("invalid output format \"%s\" specified", format);
1288         return archiveFormat;
1289 }
1290
1291 /*
1292  * Find the OIDs of all schemas matching the given list of patterns,
1293  * and append them to the given OID list.
1294  */
1295 static void
1296 expand_schema_name_patterns(Archive *fout,
1297                                                         SimpleStringList *patterns,
1298                                                         SimpleOidList *oids,
1299                                                         bool strict_names)
1300 {
1301         PQExpBuffer query;
1302         PGresult   *res;
1303         SimpleStringListCell *cell;
1304         int                     i;
1305
1306         if (patterns->head == NULL)
1307                 return;                                 /* nothing to do */
1308
1309         query = createPQExpBuffer();
1310
1311         /*
1312          * The loop below runs multiple SELECTs might sometimes result in
1313          * duplicate entries in the OID list, but we don't care.
1314          */
1315
1316         for (cell = patterns->head; cell; cell = cell->next)
1317         {
1318                 appendPQExpBuffer(query,
1319                                                   "SELECT oid FROM pg_catalog.pg_namespace n\n");
1320                 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1321                                                           false, NULL, "n.nspname", NULL, NULL);
1322
1323                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1324                 if (strict_names && PQntuples(res) == 0)
1325                         fatal("no matching schemas were found for pattern \"%s\"", cell->val);
1326
1327                 for (i = 0; i < PQntuples(res); i++)
1328                 {
1329                         simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1330                 }
1331
1332                 PQclear(res);
1333                 resetPQExpBuffer(query);
1334         }
1335
1336         destroyPQExpBuffer(query);
1337 }
1338
1339 /*
1340  * Find the OIDs of all tables matching the given list of patterns,
1341  * and append them to the given OID list. See also expand_dbname_patterns()
1342  * in pg_dumpall.c
1343  */
1344 static void
1345 expand_table_name_patterns(Archive *fout,
1346                                                    SimpleStringList *patterns, SimpleOidList *oids,
1347                                                    bool strict_names)
1348 {
1349         PQExpBuffer query;
1350         PGresult   *res;
1351         SimpleStringListCell *cell;
1352         int                     i;
1353
1354         if (patterns->head == NULL)
1355                 return;                                 /* nothing to do */
1356
1357         query = createPQExpBuffer();
1358
1359         /*
1360          * this might sometimes result in duplicate entries in the OID list, but
1361          * we don't care.
1362          */
1363
1364         for (cell = patterns->head; cell; cell = cell->next)
1365         {
1366                 /*
1367                  * Query must remain ABSOLUTELY devoid of unqualified names.  This
1368                  * would be unnecessary given a pg_table_is_visible() variant taking a
1369                  * search_path argument.
1370                  */
1371                 appendPQExpBuffer(query,
1372                                                   "SELECT c.oid"
1373                                                   "\nFROM pg_catalog.pg_class c"
1374                                                   "\n     LEFT JOIN pg_catalog.pg_namespace n"
1375                                                   "\n     ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
1376                                                   "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
1377                                                   "\n    (array['%c', '%c', '%c', '%c', '%c', '%c'])\n",
1378                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1379                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
1380                                                   RELKIND_PARTITIONED_TABLE);
1381                 processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1382                                                           false, "n.nspname", "c.relname", NULL,
1383                                                           "pg_catalog.pg_table_is_visible(c.oid)");
1384
1385                 ExecuteSqlStatement(fout, "RESET search_path");
1386                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1387                 PQclear(ExecuteSqlQueryForSingleRow(fout,
1388                                                                                         ALWAYS_SECURE_SEARCH_PATH_SQL));
1389                 if (strict_names && PQntuples(res) == 0)
1390                         fatal("no matching tables were found for pattern \"%s\"", cell->val);
1391
1392                 for (i = 0; i < PQntuples(res); i++)
1393                 {
1394                         simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1395                 }
1396
1397                 PQclear(res);
1398                 resetPQExpBuffer(query);
1399         }
1400
1401         destroyPQExpBuffer(query);
1402 }
1403
1404 /*
1405  * checkExtensionMembership
1406  *              Determine whether object is an extension member, and if so,
1407  *              record an appropriate dependency and set the object's dump flag.
1408  *
1409  * It's important to call this for each object that could be an extension
1410  * member.  Generally, we integrate this with determining the object's
1411  * to-be-dumped-ness, since extension membership overrides other rules for that.
1412  *
1413  * Returns true if object is an extension member, else false.
1414  */
1415 static bool
1416 checkExtensionMembership(DumpableObject *dobj, Archive *fout)
1417 {
1418         ExtensionInfo *ext = findOwningExtension(dobj->catId);
1419
1420         if (ext == NULL)
1421                 return false;
1422
1423         dobj->ext_member = true;
1424
1425         /* Record dependency so that getDependencies needn't deal with that */
1426         addObjectDependency(dobj, ext->dobj.dumpId);
1427
1428         /*
1429          * In 9.6 and above, mark the member object to have any non-initial ACL,
1430          * policies, and security labels dumped.
1431          *
1432          * Note that any initial ACLs (see pg_init_privs) will be removed when we
1433          * extract the information about the object.  We don't provide support for
1434          * initial policies and security labels and it seems unlikely for those to
1435          * ever exist, but we may have to revisit this later.
1436          *
1437          * Prior to 9.6, we do not include any extension member components.
1438          *
1439          * In binary upgrades, we still dump all components of the members
1440          * individually, since the idea is to exactly reproduce the database
1441          * contents rather than replace the extension contents with something
1442          * different.
1443          */
1444         if (fout->dopt->binary_upgrade)
1445                 dobj->dump = ext->dobj.dump;
1446         else
1447         {
1448                 if (fout->remoteVersion < 90600)
1449                         dobj->dump = DUMP_COMPONENT_NONE;
1450                 else
1451                         dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL |
1452                                                                                                         DUMP_COMPONENT_SECLABEL |
1453                                                                                                         DUMP_COMPONENT_POLICY);
1454         }
1455
1456         return true;
1457 }
1458
1459 /*
1460  * selectDumpableNamespace: policy-setting subroutine
1461  *              Mark a namespace as to be dumped or not
1462  */
1463 static void
1464 selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
1465 {
1466         /*
1467          * If specific tables are being dumped, do not dump any complete
1468          * namespaces. If specific namespaces are being dumped, dump just those
1469          * namespaces. Otherwise, dump all non-system namespaces.
1470          */
1471         if (table_include_oids.head != NULL)
1472                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1473         else if (schema_include_oids.head != NULL)
1474                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
1475                         simple_oid_list_member(&schema_include_oids,
1476                                                                    nsinfo->dobj.catId.oid) ?
1477                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1478         else if (fout->remoteVersion >= 90600 &&
1479                          strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
1480         {
1481                 /*
1482                  * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
1483                  * they are interesting (and not the original ACLs which were set at
1484                  * initdb time, see pg_init_privs).
1485                  */
1486                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1487         }
1488         else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1489                          strcmp(nsinfo->dobj.name, "information_schema") == 0)
1490         {
1491                 /* Other system schemas don't get dumped */
1492                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1493         }
1494         else if (strcmp(nsinfo->dobj.name, "public") == 0)
1495         {
1496                 /*
1497                  * The public schema is a strange beast that sits in a sort of
1498                  * no-mans-land between being a system object and a user object.  We
1499                  * don't want to dump creation or comment commands for it, because
1500                  * that complicates matters for non-superuser use of pg_dump.  But we
1501                  * should dump any ACL changes that have occurred for it, and of
1502                  * course we should dump contained objects.
1503                  */
1504                 nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1505                 nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
1506         }
1507         else
1508                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
1509
1510         /*
1511          * In any case, a namespace can be excluded by an exclusion switch
1512          */
1513         if (nsinfo->dobj.dump_contains &&
1514                 simple_oid_list_member(&schema_exclude_oids,
1515                                                            nsinfo->dobj.catId.oid))
1516                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1517
1518         /*
1519          * If the schema belongs to an extension, allow extension membership to
1520          * override the dump decision for the schema itself.  However, this does
1521          * not change dump_contains, so this won't change what we do with objects
1522          * within the schema.  (If they belong to the extension, they'll get
1523          * suppressed by it, otherwise not.)
1524          */
1525         (void) checkExtensionMembership(&nsinfo->dobj, fout);
1526 }
1527
1528 /*
1529  * selectDumpableTable: policy-setting subroutine
1530  *              Mark a table as to be dumped or not
1531  */
1532 static void
1533 selectDumpableTable(TableInfo *tbinfo, Archive *fout)
1534 {
1535         if (checkExtensionMembership(&tbinfo->dobj, fout))
1536                 return;                                 /* extension membership overrides all else */
1537
1538         /*
1539          * If specific tables are being dumped, dump just those tables; else, dump
1540          * according to the parent namespace's dump flag.
1541          */
1542         if (table_include_oids.head != NULL)
1543                 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1544                                                                                                    tbinfo->dobj.catId.oid) ?
1545                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1546         else
1547                 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
1548
1549         /*
1550          * In any case, a table can be excluded by an exclusion switch
1551          */
1552         if (tbinfo->dobj.dump &&
1553                 simple_oid_list_member(&table_exclude_oids,
1554                                                            tbinfo->dobj.catId.oid))
1555                 tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
1556 }
1557
1558 /*
1559  * selectDumpableType: policy-setting subroutine
1560  *              Mark a type as to be dumped or not
1561  *
1562  * If it's a table's rowtype or an autogenerated array type, we also apply a
1563  * special type code to facilitate sorting into the desired order.  (We don't
1564  * want to consider those to be ordinary types because that would bring tables
1565  * up into the datatype part of the dump order.)  We still set the object's
1566  * dump flag; that's not going to cause the dummy type to be dumped, but we
1567  * need it so that casts involving such types will be dumped correctly -- see
1568  * dumpCast.  This means the flag should be set the same as for the underlying
1569  * object (the table or base type).
1570  */
1571 static void
1572 selectDumpableType(TypeInfo *tyinfo, Archive *fout)
1573 {
1574         /* skip complex types, except for standalone composite types */
1575         if (OidIsValid(tyinfo->typrelid) &&
1576                 tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1577         {
1578                 TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
1579
1580                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1581                 if (tytable != NULL)
1582                         tyinfo->dobj.dump = tytable->dobj.dump;
1583                 else
1584                         tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
1585                 return;
1586         }
1587
1588         /* skip auto-generated array types */
1589         if (tyinfo->isArray)
1590         {
1591                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1592
1593                 /*
1594                  * Fall through to set the dump flag; we assume that the subsequent
1595                  * rules will do the same thing as they would for the array's base
1596                  * type.  (We cannot reliably look up the base type here, since
1597                  * getTypes may not have processed it yet.)
1598                  */
1599         }
1600
1601         if (checkExtensionMembership(&tyinfo->dobj, fout))
1602                 return;                                 /* extension membership overrides all else */
1603
1604         /* Dump based on if the contents of the namespace are being dumped */
1605         tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
1606 }
1607
1608 /*
1609  * selectDumpableDefaultACL: policy-setting subroutine
1610  *              Mark a default ACL as to be dumped or not
1611  *
1612  * For per-schema default ACLs, dump if the schema is to be dumped.
1613  * Otherwise dump if we are dumping "everything".  Note that dataOnly
1614  * and aclsSkip are checked separately.
1615  */
1616 static void
1617 selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
1618 {
1619         /* Default ACLs can't be extension members */
1620
1621         if (dinfo->dobj.namespace)
1622                 /* default ACLs are considered part of the namespace */
1623                 dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
1624         else
1625                 dinfo->dobj.dump = dopt->include_everything ?
1626                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1627 }
1628
1629 /*
1630  * selectDumpableCast: policy-setting subroutine
1631  *              Mark a cast as to be dumped or not
1632  *
1633  * Casts do not belong to any particular namespace (since they haven't got
1634  * names), nor do they have identifiable owners.  To distinguish user-defined
1635  * casts from built-in ones, we must resort to checking whether the cast's
1636  * OID is in the range reserved for initdb.
1637  */
1638 static void
1639 selectDumpableCast(CastInfo *cast, Archive *fout)
1640 {
1641         if (checkExtensionMembership(&cast->dobj, fout))
1642                 return;                                 /* extension membership overrides all else */
1643
1644         /*
1645          * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
1646          * support ACLs currently.
1647          */
1648         if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1649                 cast->dobj.dump = DUMP_COMPONENT_NONE;
1650         else
1651                 cast->dobj.dump = fout->dopt->include_everything ?
1652                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1653 }
1654
1655 /*
1656  * selectDumpableProcLang: policy-setting subroutine
1657  *              Mark a procedural language as to be dumped or not
1658  *
1659  * Procedural languages do not belong to any particular namespace.  To
1660  * identify built-in languages, we must resort to checking whether the
1661  * language's OID is in the range reserved for initdb.
1662  */
1663 static void
1664 selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
1665 {
1666         if (checkExtensionMembership(&plang->dobj, fout))
1667                 return;                                 /* extension membership overrides all else */
1668
1669         /*
1670          * Only include procedural languages when we are dumping everything.
1671          *
1672          * For from-initdb procedural languages, only include ACLs, as we do for
1673          * the pg_catalog namespace.  We need this because procedural languages do
1674          * not live in any namespace.
1675          */
1676         if (!fout->dopt->include_everything)
1677                 plang->dobj.dump = DUMP_COMPONENT_NONE;
1678         else
1679         {
1680                 if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1681                         plang->dobj.dump = fout->remoteVersion < 90600 ?
1682                                 DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
1683                 else
1684                         plang->dobj.dump = DUMP_COMPONENT_ALL;
1685         }
1686 }
1687
1688 /*
1689  * selectDumpableAccessMethod: policy-setting subroutine
1690  *              Mark an access method as to be dumped or not
1691  *
1692  * Access methods do not belong to any particular namespace.  To identify
1693  * built-in access methods, we must resort to checking whether the
1694  * method's OID is in the range reserved for initdb.
1695  */
1696 static void
1697 selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
1698 {
1699         if (checkExtensionMembership(&method->dobj, fout))
1700                 return;                                 /* extension membership overrides all else */
1701
1702         /*
1703          * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
1704          * they do not support ACLs currently.
1705          */
1706         if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1707                 method->dobj.dump = DUMP_COMPONENT_NONE;
1708         else
1709                 method->dobj.dump = fout->dopt->include_everything ?
1710                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1711 }
1712
1713 /*
1714  * selectDumpableExtension: policy-setting subroutine
1715  *              Mark an extension as to be dumped or not
1716  *
1717  * Built-in extensions should be skipped except for checking ACLs, since we
1718  * assume those will already be installed in the target database.  We identify
1719  * such extensions by their having OIDs in the range reserved for initdb.
1720  * We dump all user-added extensions by default, or none of them if
1721  * include_everything is false (i.e., a --schema or --table switch was given).
1722  */
1723 static void
1724 selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
1725 {
1726         /*
1727          * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
1728          * change permissions on their member objects, if they wish to, and have
1729          * those changes preserved.
1730          */
1731         if (extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1732                 extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
1733         else
1734                 extinfo->dobj.dump = extinfo->dobj.dump_contains =
1735                         dopt->include_everything ? DUMP_COMPONENT_ALL :
1736                         DUMP_COMPONENT_NONE;
1737 }
1738
1739 /*
1740  * selectDumpablePublicationTable: policy-setting subroutine
1741  *              Mark a publication table as to be dumped or not
1742  *
1743  * Publication tables have schemas, but those are ignored in decision making,
1744  * because publications are only dumped when we are dumping everything.
1745  */
1746 static void
1747 selectDumpablePublicationTable(DumpableObject *dobj, Archive *fout)
1748 {
1749         if (checkExtensionMembership(dobj, fout))
1750                 return;                                 /* extension membership overrides all else */
1751
1752         dobj->dump = fout->dopt->include_everything ?
1753                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1754 }
1755
1756 /*
1757  * selectDumpableObject: policy-setting subroutine
1758  *              Mark a generic dumpable object as to be dumped or not
1759  *
1760  * Use this only for object types without a special-case routine above.
1761  */
1762 static void
1763 selectDumpableObject(DumpableObject *dobj, Archive *fout)
1764 {
1765         if (checkExtensionMembership(dobj, fout))
1766                 return;                                 /* extension membership overrides all else */
1767
1768         /*
1769          * Default policy is to dump if parent namespace is dumpable, or for
1770          * non-namespace-associated items, dump if we're dumping "everything".
1771          */
1772         if (dobj->namespace)
1773                 dobj->dump = dobj->namespace->dobj.dump_contains;
1774         else
1775                 dobj->dump = fout->dopt->include_everything ?
1776                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1777 }
1778
1779 /*
1780  *      Dump a table's contents for loading using the COPY command
1781  *      - this routine is called by the Archiver when it wants the table
1782  *        to be dumped.
1783  */
1784
1785 static int
1786 dumpTableData_copy(Archive *fout, void *dcontext)
1787 {
1788         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1789         TableInfo  *tbinfo = tdinfo->tdtable;
1790         const char *classname = tbinfo->dobj.name;
1791         PQExpBuffer q = createPQExpBuffer();
1792
1793         /*
1794          * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
1795          * which uses it already.
1796          */
1797         PQExpBuffer clistBuf = createPQExpBuffer();
1798         PGconn     *conn = GetConnection(fout);
1799         PGresult   *res;
1800         int                     ret;
1801         char       *copybuf;
1802         const char *column_list;
1803
1804         pg_log_info("dumping contents of table \"%s.%s\"",
1805                                 tbinfo->dobj.namespace->dobj.name, classname);
1806
1807         /*
1808          * Specify the column list explicitly so that we have no possibility of
1809          * retrieving data in the wrong column order.  (The default column
1810          * ordering of COPY will not be what we want in certain corner cases
1811          * involving ADD COLUMN and inheritance.)
1812          */
1813         column_list = fmtCopyColumnList(tbinfo, clistBuf);
1814
1815         if (tdinfo->filtercond)
1816         {
1817                 /* Note: this syntax is only supported in 8.2 and up */
1818                 appendPQExpBufferStr(q, "COPY (SELECT ");
1819                 /* klugery to get rid of parens in column list */
1820                 if (strlen(column_list) > 2)
1821                 {
1822                         appendPQExpBufferStr(q, column_list + 1);
1823                         q->data[q->len - 1] = ' ';
1824                 }
1825                 else
1826                         appendPQExpBufferStr(q, "* ");
1827                 appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
1828                                                   fmtQualifiedDumpable(tbinfo),
1829                                                   tdinfo->filtercond);
1830         }
1831         else
1832         {
1833                 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1834                                                   fmtQualifiedDumpable(tbinfo),
1835                                                   column_list);
1836         }
1837         res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
1838         PQclear(res);
1839         destroyPQExpBuffer(clistBuf);
1840
1841         for (;;)
1842         {
1843                 ret = PQgetCopyData(conn, &copybuf, 0);
1844
1845                 if (ret < 0)
1846                         break;                          /* done or error */
1847
1848                 if (copybuf)
1849                 {
1850                         WriteData(fout, copybuf, ret);
1851                         PQfreemem(copybuf);
1852                 }
1853
1854                 /* ----------
1855                  * THROTTLE:
1856                  *
1857                  * There was considerable discussion in late July, 2000 regarding
1858                  * slowing down pg_dump when backing up large tables. Users with both
1859                  * slow & fast (multi-processor) machines experienced performance
1860                  * degradation when doing a backup.
1861                  *
1862                  * Initial attempts based on sleeping for a number of ms for each ms
1863                  * of work were deemed too complex, then a simple 'sleep in each loop'
1864                  * implementation was suggested. The latter failed because the loop
1865                  * was too tight. Finally, the following was implemented:
1866                  *
1867                  * If throttle is non-zero, then
1868                  *              See how long since the last sleep.
1869                  *              Work out how long to sleep (based on ratio).
1870                  *              If sleep is more than 100ms, then
1871                  *                      sleep
1872                  *                      reset timer
1873                  *              EndIf
1874                  * EndIf
1875                  *
1876                  * where the throttle value was the number of ms to sleep per ms of
1877                  * work. The calculation was done in each loop.
1878                  *
1879                  * Most of the hard work is done in the backend, and this solution
1880                  * still did not work particularly well: on slow machines, the ratio
1881                  * was 50:1, and on medium paced machines, 1:1, and on fast
1882                  * multi-processor machines, it had little or no effect, for reasons
1883                  * that were unclear.
1884                  *
1885                  * Further discussion ensued, and the proposal was dropped.
1886                  *
1887                  * For those people who want this feature, it can be implemented using
1888                  * gettimeofday in each loop, calculating the time since last sleep,
1889                  * multiplying that by the sleep ratio, then if the result is more
1890                  * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1891                  * function to sleep for a subsecond period ie.
1892                  *
1893                  * select(0, NULL, NULL, NULL, &tvi);
1894                  *
1895                  * This will return after the interval specified in the structure tvi.
1896                  * Finally, call gettimeofday again to save the 'last sleep time'.
1897                  * ----------
1898                  */
1899         }
1900         archprintf(fout, "\\.\n\n\n");
1901
1902         if (ret == -2)
1903         {
1904                 /* copy data transfer failed */
1905                 pg_log_error("Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.", classname);
1906                 pg_log_error("Error message from server: %s", PQerrorMessage(conn));
1907                 pg_log_error("The command was: %s", q->data);
1908                 exit_nicely(1);
1909         }
1910
1911         /* Check command status and return to normal libpq state */
1912         res = PQgetResult(conn);
1913         if (PQresultStatus(res) != PGRES_COMMAND_OK)
1914         {
1915                 pg_log_error("Dumping the contents of table \"%s\" failed: PQgetResult() failed.", classname);
1916                 pg_log_error("Error message from server: %s", PQerrorMessage(conn));
1917                 pg_log_error("The command was: %s", q->data);
1918                 exit_nicely(1);
1919         }
1920         PQclear(res);
1921
1922         /* Do this to ensure we've pumped libpq back to idle state */
1923         if (PQgetResult(conn) != NULL)
1924                 pg_log_warning("unexpected extra results during COPY of table \"%s\"",
1925                                   classname);
1926
1927         destroyPQExpBuffer(q);
1928         return 1;
1929 }
1930
1931 /*
1932  * Dump table data using INSERT commands.
1933  *
1934  * Caution: when we restore from an archive file direct to database, the
1935  * INSERT commands emitted by this function have to be parsed by
1936  * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
1937  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
1938  */
1939 static int
1940 dumpTableData_insert(Archive *fout, void *dcontext)
1941 {
1942         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1943         TableInfo  *tbinfo = tdinfo->tdtable;
1944         DumpOptions *dopt = fout->dopt;
1945         PQExpBuffer q = createPQExpBuffer();
1946         PQExpBuffer insertStmt = NULL;
1947         PGresult   *res;
1948         int                     nfields;
1949         int                     rows_per_statement = dopt->dump_inserts;
1950         int                     rows_this_statement = 0;
1951
1952         appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1953                                           "SELECT * FROM ONLY %s",
1954                                           fmtQualifiedDumpable(tbinfo));
1955         if (tdinfo->filtercond)
1956                 appendPQExpBuffer(q, " %s", tdinfo->filtercond);
1957
1958         ExecuteSqlStatement(fout, q->data);
1959
1960         while (1)
1961         {
1962                 res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
1963                                                           PGRES_TUPLES_OK);
1964                 nfields = PQnfields(res);
1965
1966                 /*
1967                  * First time through, we build as much of the INSERT statement as
1968                  * possible in "insertStmt", which we can then just print for each
1969                  * statement. If the table happens to have zero columns then this will
1970                  * be a complete statement, otherwise it will end in "VALUES" and be
1971                  * ready to have the row's column values printed.
1972                  */
1973                 if (insertStmt == NULL)
1974                 {
1975                         TableInfo  *targettab;
1976
1977                         insertStmt = createPQExpBuffer();
1978
1979                         /*
1980                          * When load-via-partition-root is set, get the root table name
1981                          * for the partition table, so that we can reload data through the
1982                          * root table.
1983                          */
1984                         if (dopt->load_via_partition_root && tbinfo->ispartition)
1985                                 targettab = getRootTableInfo(tbinfo);
1986                         else
1987                                 targettab = tbinfo;
1988
1989                         appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
1990                                                           fmtQualifiedDumpable(targettab));
1991
1992                         /* corner case for zero-column table */
1993                         if (nfields == 0)
1994                         {
1995                                 appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
1996                         }
1997                         else
1998                         {
1999                                 /* append the list of column names if required */
2000                                 if (dopt->column_inserts)
2001                                 {
2002                                         appendPQExpBufferChar(insertStmt, '(');
2003                                         for (int field = 0; field < nfields; field++)
2004                                         {
2005                                                 if (field > 0)
2006                                                         appendPQExpBufferStr(insertStmt, ", ");
2007                                                 appendPQExpBufferStr(insertStmt,
2008                                                                                          fmtId(PQfname(res, field)));
2009                                         }
2010                                         appendPQExpBufferStr(insertStmt, ") ");
2011                                 }
2012
2013                                 if (tbinfo->needs_override)
2014                                         appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
2015
2016                                 appendPQExpBufferStr(insertStmt, "VALUES");
2017                         }
2018                 }
2019
2020                 for (int tuple = 0; tuple < PQntuples(res); tuple++)
2021                 {
2022                         /* Write the INSERT if not in the middle of a multi-row INSERT. */
2023                         if (rows_this_statement == 0)
2024                                 archputs(insertStmt->data, fout);
2025
2026                         /*
2027                          * If it is zero-column table then we've already written the
2028                          * complete statement, which will mean we've disobeyed
2029                          * --rows-per-insert when it's set greater than 1.  We do support
2030                          * a way to make this multi-row with: SELECT UNION ALL SELECT
2031                          * UNION ALL ... but that's non-standard so we should avoid it
2032                          * given that using INSERTs is mostly only ever needed for
2033                          * cross-database exports.
2034                          */
2035                         if (nfields == 0)
2036                                 continue;
2037
2038                         /* Emit a row heading */
2039                         if (rows_per_statement == 1)
2040                                 archputs(" (", fout);
2041                         else if (rows_this_statement > 0)
2042                                 archputs(",\n\t(", fout);
2043                         else
2044                                 archputs("\n\t(", fout);
2045
2046                         for (int field = 0; field < nfields; field++)
2047                         {
2048                                 if (field > 0)
2049                                         archputs(", ", fout);
2050                                 if (tbinfo->attgenerated[field])
2051                                 {
2052                                         archputs("DEFAULT", fout);
2053                                         continue;
2054                                 }
2055                                 if (PQgetisnull(res, tuple, field))
2056                                 {
2057                                         archputs("NULL", fout);
2058                                         continue;
2059                                 }
2060
2061                                 /* XXX This code is partially duplicated in ruleutils.c */
2062                                 switch (PQftype(res, field))
2063                                 {
2064                                         case INT2OID:
2065                                         case INT4OID:
2066                                         case INT8OID:
2067                                         case OIDOID:
2068                                         case FLOAT4OID:
2069                                         case FLOAT8OID:
2070                                         case NUMERICOID:
2071                                                 {
2072                                                         /*
2073                                                          * These types are printed without quotes unless
2074                                                          * they contain values that aren't accepted by the
2075                                                          * scanner unquoted (e.g., 'NaN').  Note that
2076                                                          * strtod() and friends might accept NaN, so we
2077                                                          * can't use that to test.
2078                                                          *
2079                                                          * In reality we only need to defend against
2080                                                          * infinity and NaN, so we need not get too crazy
2081                                                          * about pattern matching here.
2082                                                          */
2083                                                         const char *s = PQgetvalue(res, tuple, field);
2084
2085                                                         if (strspn(s, "0123456789 +-eE.") == strlen(s))
2086                                                                 archputs(s, fout);
2087                                                         else
2088                                                                 archprintf(fout, "'%s'", s);
2089                                                 }
2090                                                 break;
2091
2092                                         case BITOID:
2093                                         case VARBITOID:
2094                                                 archprintf(fout, "B'%s'",
2095                                                                    PQgetvalue(res, tuple, field));
2096                                                 break;
2097
2098                                         case BOOLOID:
2099                                                 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
2100                                                         archputs("true", fout);
2101                                                 else
2102                                                         archputs("false", fout);
2103                                                 break;
2104
2105                                         default:
2106                                                 /* All other types are printed as string literals. */
2107                                                 resetPQExpBuffer(q);
2108                                                 appendStringLiteralAH(q,
2109                                                                                           PQgetvalue(res, tuple, field),
2110                                                                                           fout);
2111                                                 archputs(q->data, fout);
2112                                                 break;
2113                                 }
2114                         }
2115
2116                         /* Terminate the row ... */
2117                         archputs(")", fout);
2118
2119                         /* ... and the statement, if the target no. of rows is reached */
2120                         if (++rows_this_statement >= rows_per_statement)
2121                         {
2122                                 if (dopt->do_nothing)
2123                                         archputs(" ON CONFLICT DO NOTHING;\n", fout);
2124                                 else
2125                                         archputs(";\n", fout);
2126                                 /* Reset the row counter */
2127                                 rows_this_statement = 0;
2128                         }
2129                 }
2130
2131                 if (PQntuples(res) <= 0)
2132                 {
2133                         PQclear(res);
2134                         break;
2135                 }
2136                 PQclear(res);
2137         }
2138
2139         /* Terminate any statements that didn't make the row count. */
2140         if (rows_this_statement > 0)
2141         {
2142                 if (dopt->do_nothing)
2143                         archputs(" ON CONFLICT DO NOTHING;\n", fout);
2144                 else
2145                         archputs(";\n", fout);
2146         }
2147
2148         archputs("\n\n", fout);
2149
2150         ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
2151
2152         destroyPQExpBuffer(q);
2153         if (insertStmt != NULL)
2154                 destroyPQExpBuffer(insertStmt);
2155
2156         return 1;
2157 }
2158
2159 /*
2160  * getRootTableInfo:
2161  *     get the root TableInfo for the given partition table.
2162  */
2163 static TableInfo *
2164 getRootTableInfo(TableInfo *tbinfo)
2165 {
2166         TableInfo  *parentTbinfo;
2167
2168         Assert(tbinfo->ispartition);
2169         Assert(tbinfo->numParents == 1);
2170
2171         parentTbinfo = tbinfo->parents[0];
2172         while (parentTbinfo->ispartition)
2173         {
2174                 Assert(parentTbinfo->numParents == 1);
2175                 parentTbinfo = parentTbinfo->parents[0];
2176         }
2177
2178         return parentTbinfo;
2179 }
2180
2181 /*
2182  * dumpTableData -
2183  *        dump the contents of a single table
2184  *
2185  * Actually, this just makes an ArchiveEntry for the table contents.
2186  */
2187 static void
2188 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
2189 {
2190         DumpOptions *dopt = fout->dopt;
2191         TableInfo  *tbinfo = tdinfo->tdtable;
2192         PQExpBuffer copyBuf = createPQExpBuffer();
2193         PQExpBuffer clistBuf = createPQExpBuffer();
2194         DataDumperPtr dumpFn;
2195         char       *copyStmt;
2196         const char *copyFrom;
2197
2198         if (!dopt->dump_inserts)
2199         {
2200                 /* Dump/restore using COPY */
2201                 dumpFn = dumpTableData_copy;
2202
2203                 /*
2204                  * When load-via-partition-root is set, get the root table name for
2205                  * the partition table, so that we can reload data through the root
2206                  * table.
2207                  */
2208                 if (dopt->load_via_partition_root && tbinfo->ispartition)
2209                 {
2210                         TableInfo  *parentTbinfo;
2211
2212                         parentTbinfo = getRootTableInfo(tbinfo);
2213                         copyFrom = fmtQualifiedDumpable(parentTbinfo);
2214                 }
2215                 else
2216                         copyFrom = fmtQualifiedDumpable(tbinfo);
2217
2218                 /* must use 2 steps here 'cause fmtId is nonreentrant */
2219                 appendPQExpBuffer(copyBuf, "COPY %s ",
2220                                                   copyFrom);
2221                 appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
2222                                                   fmtCopyColumnList(tbinfo, clistBuf));
2223                 copyStmt = copyBuf->data;
2224         }
2225         else
2226         {
2227                 /* Restore using INSERT */
2228                 dumpFn = dumpTableData_insert;
2229                 copyStmt = NULL;
2230         }
2231
2232         /*
2233          * Note: although the TableDataInfo is a full DumpableObject, we treat its
2234          * dependency on its table as "special" and pass it to ArchiveEntry now.
2235          * See comments for BuildArchiveDependencies.
2236          */
2237         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2238         {
2239                 TocEntry   *te;
2240
2241                 te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
2242                                                   ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
2243                                                                            .namespace = tbinfo->dobj.namespace->dobj.name,
2244                                                                            .owner = tbinfo->rolname,
2245                                                                            .description = "TABLE DATA",
2246                                                                            .section = SECTION_DATA,
2247                                                                            .copyStmt = copyStmt,
2248                                                                            .deps = &(tbinfo->dobj.dumpId),
2249                                                                            .nDeps = 1,
2250                                                                            .dumpFn = dumpFn,
2251                                                                            .dumpArg = tdinfo));
2252
2253                 /*
2254                  * Set the TocEntry's dataLength in case we are doing a parallel dump
2255                  * and want to order dump jobs by table size.  We choose to measure
2256                  * dataLength in table pages during dump, so no scaling is needed.
2257                  * However, relpages is declared as "integer" in pg_class, and hence
2258                  * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
2259                  * Cast so that we get the right interpretation of table sizes
2260                  * exceeding INT_MAX pages.
2261                  */
2262                 te->dataLength = (BlockNumber) tbinfo->relpages;
2263         }
2264
2265         destroyPQExpBuffer(copyBuf);
2266         destroyPQExpBuffer(clistBuf);
2267 }
2268
2269 /*
2270  * refreshMatViewData -
2271  *        load or refresh the contents of a single materialized view
2272  *
2273  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
2274  * statement.
2275  */
2276 static void
2277 refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
2278 {
2279         TableInfo  *tbinfo = tdinfo->tdtable;
2280         PQExpBuffer q;
2281
2282         /* If the materialized view is not flagged as populated, skip this. */
2283         if (!tbinfo->relispopulated)
2284                 return;
2285
2286         q = createPQExpBuffer();
2287
2288         appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
2289                                           fmtQualifiedDumpable(tbinfo));
2290
2291         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2292                 ArchiveEntry(fout,
2293                                          tdinfo->dobj.catId,    /* catalog ID */
2294                                          tdinfo->dobj.dumpId,   /* dump ID */
2295                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
2296                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
2297                                                                   .owner = tbinfo->rolname,
2298                                                                   .description = "MATERIALIZED VIEW DATA",
2299                                                                   .section = SECTION_POST_DATA,
2300                                                                   .createStmt = q->data,
2301                                                                   .deps = tdinfo->dobj.dependencies,
2302                                                                   .nDeps = tdinfo->dobj.nDeps));
2303
2304         destroyPQExpBuffer(q);
2305 }
2306
2307 /*
2308  * getTableData -
2309  *        set up dumpable objects representing the contents of tables
2310  */
2311 static void
2312 getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
2313 {
2314         int                     i;
2315
2316         for (i = 0; i < numTables; i++)
2317         {
2318                 if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
2319                         (!relkind || tblinfo[i].relkind == relkind))
2320                         makeTableDataInfo(dopt, &(tblinfo[i]));
2321         }
2322 }
2323
2324 /*
2325  * Make a dumpable object for the data of this specific table
2326  *
2327  * Note: we make a TableDataInfo if and only if we are going to dump the
2328  * table data; the "dump" flag in such objects isn't used.
2329  */
2330 static void
2331 makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
2332 {
2333         TableDataInfo *tdinfo;
2334
2335         /*
2336          * Nothing to do if we already decided to dump the table.  This will
2337          * happen for "config" tables.
2338          */
2339         if (tbinfo->dataObj != NULL)
2340                 return;
2341
2342         /* Skip VIEWs (no data to dump) */
2343         if (tbinfo->relkind == RELKIND_VIEW)
2344                 return;
2345         /* Skip FOREIGN TABLEs (no data to dump) */
2346         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2347                 return;
2348         /* Skip partitioned tables (data in partitions) */
2349         if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
2350                 return;
2351
2352         /* Don't dump data in unlogged tables, if so requested */
2353         if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
2354                 dopt->no_unlogged_table_data)
2355                 return;
2356
2357         /* Check that the data is not explicitly excluded */
2358         if (simple_oid_list_member(&tabledata_exclude_oids,
2359                                                            tbinfo->dobj.catId.oid))
2360                 return;
2361
2362         /* OK, let's dump it */
2363         tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
2364
2365         if (tbinfo->relkind == RELKIND_MATVIEW)
2366                 tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
2367         else if (tbinfo->relkind == RELKIND_SEQUENCE)
2368                 tdinfo->dobj.objType = DO_SEQUENCE_SET;
2369         else
2370                 tdinfo->dobj.objType = DO_TABLE_DATA;
2371
2372         /*
2373          * Note: use tableoid 0 so that this object won't be mistaken for
2374          * something that pg_depend entries apply to.
2375          */
2376         tdinfo->dobj.catId.tableoid = 0;
2377         tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
2378         AssignDumpId(&tdinfo->dobj);
2379         tdinfo->dobj.name = tbinfo->dobj.name;
2380         tdinfo->dobj.namespace = tbinfo->dobj.namespace;
2381         tdinfo->tdtable = tbinfo;
2382         tdinfo->filtercond = NULL;      /* might get set later */
2383         addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
2384
2385         tbinfo->dataObj = tdinfo;
2386 }
2387
2388 /*
2389  * The refresh for a materialized view must be dependent on the refresh for
2390  * any materialized view that this one is dependent on.
2391  *
2392  * This must be called after all the objects are created, but before they are
2393  * sorted.
2394  */
2395 static void
2396 buildMatViewRefreshDependencies(Archive *fout)
2397 {
2398         PQExpBuffer query;
2399         PGresult   *res;
2400         int                     ntups,
2401                                 i;
2402         int                     i_classid,
2403                                 i_objid,
2404                                 i_refobjid;
2405
2406         /* No Mat Views before 9.3. */
2407         if (fout->remoteVersion < 90300)
2408                 return;
2409
2410         query = createPQExpBuffer();
2411
2412         appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
2413                                                  "( "
2414                                                  "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
2415                                                  "FROM pg_depend d1 "
2416                                                  "JOIN pg_class c1 ON c1.oid = d1.objid "
2417                                                  "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
2418                                                  " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
2419                                                  "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
2420                                                  "AND d2.objid = r1.oid "
2421                                                  "AND d2.refobjid <> d1.objid "
2422                                                  "JOIN pg_class c2 ON c2.oid = d2.refobjid "
2423                                                  "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2424                                                  CppAsString2(RELKIND_VIEW) ") "
2425                                                  "WHERE d1.classid = 'pg_class'::regclass "
2426                                                  "UNION "
2427                                                  "SELECT w.objid, d3.refobjid, c3.relkind "
2428                                                  "FROM w "
2429                                                  "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
2430                                                  "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
2431                                                  "AND d3.objid = r3.oid "
2432                                                  "AND d3.refobjid <> w.refobjid "
2433                                                  "JOIN pg_class c3 ON c3.oid = d3.refobjid "
2434                                                  "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2435                                                  CppAsString2(RELKIND_VIEW) ") "
2436                                                  ") "
2437                                                  "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
2438                                                  "FROM w "
2439                                                  "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
2440
2441         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2442
2443         ntups = PQntuples(res);
2444
2445         i_classid = PQfnumber(res, "classid");
2446         i_objid = PQfnumber(res, "objid");
2447         i_refobjid = PQfnumber(res, "refobjid");
2448
2449         for (i = 0; i < ntups; i++)
2450         {
2451                 CatalogId       objId;
2452                 CatalogId       refobjId;
2453                 DumpableObject *dobj;
2454                 DumpableObject *refdobj;
2455                 TableInfo  *tbinfo;
2456                 TableInfo  *reftbinfo;
2457
2458                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
2459                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
2460                 refobjId.tableoid = objId.tableoid;
2461                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
2462
2463                 dobj = findObjectByCatalogId(objId);
2464                 if (dobj == NULL)
2465                         continue;
2466
2467                 Assert(dobj->objType == DO_TABLE);
2468                 tbinfo = (TableInfo *) dobj;
2469                 Assert(tbinfo->relkind == RELKIND_MATVIEW);
2470                 dobj = (DumpableObject *) tbinfo->dataObj;
2471                 if (dobj == NULL)
2472                         continue;
2473                 Assert(dobj->objType == DO_REFRESH_MATVIEW);
2474
2475                 refdobj = findObjectByCatalogId(refobjId);
2476                 if (refdobj == NULL)
2477                         continue;
2478
2479                 Assert(refdobj->objType == DO_TABLE);
2480                 reftbinfo = (TableInfo *) refdobj;
2481                 Assert(reftbinfo->relkind == RELKIND_MATVIEW);
2482                 refdobj = (DumpableObject *) reftbinfo->dataObj;
2483                 if (refdobj == NULL)
2484                         continue;
2485                 Assert(refdobj->objType == DO_REFRESH_MATVIEW);
2486
2487                 addObjectDependency(dobj, refdobj->dumpId);
2488
2489                 if (!reftbinfo->relispopulated)
2490                         tbinfo->relispopulated = false;
2491         }
2492
2493         PQclear(res);
2494
2495         destroyPQExpBuffer(query);
2496 }
2497
2498 /*
2499  * getTableDataFKConstraints -
2500  *        add dump-order dependencies reflecting foreign key constraints
2501  *
2502  * This code is executed only in a data-only dump --- in schema+data dumps
2503  * we handle foreign key issues by not creating the FK constraints until
2504  * after the data is loaded.  In a data-only dump, however, we want to
2505  * order the table data objects in such a way that a table's referenced
2506  * tables are restored first.  (In the presence of circular references or
2507  * self-references this may be impossible; we'll detect and complain about
2508  * that during the dependency sorting step.)
2509  */
2510 static void
2511 getTableDataFKConstraints(void)
2512 {
2513         DumpableObject **dobjs;
2514         int                     numObjs;
2515         int                     i;
2516
2517         /* Search through all the dumpable objects for FK constraints */
2518         getDumpableObjects(&dobjs, &numObjs);
2519         for (i = 0; i < numObjs; i++)
2520         {
2521                 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
2522                 {
2523                         ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
2524                         TableInfo  *ftable;
2525
2526                         /* Not interesting unless both tables are to be dumped */
2527                         if (cinfo->contable == NULL ||
2528                                 cinfo->contable->dataObj == NULL)
2529                                 continue;
2530                         ftable = findTableByOid(cinfo->confrelid);
2531                         if (ftable == NULL ||
2532                                 ftable->dataObj == NULL)
2533                                 continue;
2534
2535                         /*
2536                          * Okay, make referencing table's TABLE_DATA object depend on the
2537                          * referenced table's TABLE_DATA object.
2538                          */
2539                         addObjectDependency(&cinfo->contable->dataObj->dobj,
2540                                                                 ftable->dataObj->dobj.dumpId);
2541                 }
2542         }
2543         free(dobjs);
2544 }
2545
2546
2547 /*
2548  * guessConstraintInheritance:
2549  *      In pre-8.4 databases, we can't tell for certain which constraints
2550  *      are inherited.  We assume a CHECK constraint is inherited if its name
2551  *      matches the name of any constraint in the parent.  Originally this code
2552  *      tried to compare the expression texts, but that can fail for various
2553  *      reasons --- for example, if the parent and child tables are in different
2554  *      schemas, reverse-listing of function calls may produce different text
2555  *      (schema-qualified or not) depending on search path.
2556  *
2557  *      In 8.4 and up we can rely on the conislocal field to decide which
2558  *      constraints must be dumped; much safer.
2559  *
2560  *      This function assumes all conislocal flags were initialized to true.
2561  *      It clears the flag on anything that seems to be inherited.
2562  */
2563 static void
2564 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
2565 {
2566         int                     i,
2567                                 j,
2568                                 k;
2569
2570         for (i = 0; i < numTables; i++)
2571         {
2572                 TableInfo  *tbinfo = &(tblinfo[i]);
2573                 int                     numParents;
2574                 TableInfo **parents;
2575                 TableInfo  *parent;
2576
2577                 /* Sequences and views never have parents */
2578                 if (tbinfo->relkind == RELKIND_SEQUENCE ||
2579                         tbinfo->relkind == RELKIND_VIEW)
2580                         continue;
2581
2582                 /* Don't bother computing anything for non-target tables, either */
2583                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
2584                         continue;
2585
2586                 numParents = tbinfo->numParents;
2587                 parents = tbinfo->parents;
2588
2589                 if (numParents == 0)
2590                         continue;                       /* nothing to see here, move along */
2591
2592                 /* scan for inherited CHECK constraints */
2593                 for (j = 0; j < tbinfo->ncheck; j++)
2594                 {
2595                         ConstraintInfo *constr;
2596
2597                         constr = &(tbinfo->checkexprs[j]);
2598
2599                         for (k = 0; k < numParents; k++)
2600                         {
2601                                 int                     l;
2602
2603                                 parent = parents[k];
2604                                 for (l = 0; l < parent->ncheck; l++)
2605                                 {
2606                                         ConstraintInfo *pconstr = &(parent->checkexprs[l]);
2607
2608                                         if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
2609                                         {
2610                                                 constr->conislocal = false;
2611                                                 break;
2612                                         }
2613                                 }
2614                                 if (!constr->conislocal)
2615                                         break;
2616                         }
2617                 }
2618         }
2619 }
2620
2621
2622 /*
2623  * dumpDatabase:
2624  *      dump the database definition
2625  */
2626 static void
2627 dumpDatabase(Archive *fout)
2628 {
2629         DumpOptions *dopt = fout->dopt;
2630         PQExpBuffer dbQry = createPQExpBuffer();
2631         PQExpBuffer delQry = createPQExpBuffer();
2632         PQExpBuffer creaQry = createPQExpBuffer();
2633         PQExpBuffer labelq = createPQExpBuffer();
2634         PGconn     *conn = GetConnection(fout);
2635         PGresult   *res;
2636         int                     i_tableoid,
2637                                 i_oid,
2638                                 i_datname,
2639                                 i_dba,
2640                                 i_encoding,
2641                                 i_collate,
2642                                 i_ctype,
2643                                 i_frozenxid,
2644                                 i_minmxid,
2645                                 i_datacl,
2646                                 i_rdatacl,
2647                                 i_datistemplate,
2648                                 i_datconnlimit,
2649                                 i_tablespace;
2650         CatalogId       dbCatId;
2651         DumpId          dbDumpId;
2652         const char *datname,
2653                            *dba,
2654                            *encoding,
2655                            *collate,
2656                            *ctype,
2657                            *datacl,
2658                            *rdatacl,
2659                            *datistemplate,
2660                            *datconnlimit,
2661                            *tablespace;
2662         uint32          frozenxid,
2663                                 minmxid;
2664         char       *qdatname;
2665
2666         pg_log_info("saving database definition");
2667
2668         /* Fetch the database-level properties for this database */
2669         if (fout->remoteVersion >= 90600)
2670         {
2671                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2672                                                   "(%s datdba) AS dba, "
2673                                                   "pg_encoding_to_char(encoding) AS encoding, "
2674                                                   "datcollate, datctype, datfrozenxid, datminmxid, "
2675                                                   "(SELECT array_agg(acl ORDER BY acl::text COLLATE \"C\") FROM ( "
2676                                                   "  SELECT unnest(coalesce(datacl,acldefault('d',datdba))) AS acl "
2677                                                   "  EXCEPT SELECT unnest(acldefault('d',datdba))) as datacls)"
2678                                                   " AS datacl, "
2679                                                   "(SELECT array_agg(acl ORDER BY acl::text COLLATE \"C\") FROM ( "
2680                                                   "  SELECT unnest(acldefault('d',datdba)) AS acl "
2681                                                   "  EXCEPT SELECT unnest(coalesce(datacl,acldefault('d',datdba)))) as rdatacls)"
2682                                                   " AS rdatacl, "
2683                                                   "datistemplate, datconnlimit, "
2684                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2685                                                   "shobj_description(oid, 'pg_database') AS description "
2686
2687                                                   "FROM pg_database "
2688                                                   "WHERE datname = current_database()",
2689                                                   username_subquery);
2690         }
2691         else if (fout->remoteVersion >= 90300)
2692         {
2693                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2694                                                   "(%s datdba) AS dba, "
2695                                                   "pg_encoding_to_char(encoding) AS encoding, "
2696                                                   "datcollate, datctype, datfrozenxid, datminmxid, "
2697                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2698                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2699                                                   "shobj_description(oid, 'pg_database') AS description "
2700
2701                                                   "FROM pg_database "
2702                                                   "WHERE datname = current_database()",
2703                                                   username_subquery);
2704         }
2705         else if (fout->remoteVersion >= 80400)
2706         {
2707                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2708                                                   "(%s datdba) AS dba, "
2709                                                   "pg_encoding_to_char(encoding) AS encoding, "
2710                                                   "datcollate, datctype, datfrozenxid, 0 AS datminmxid, "
2711                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2712                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2713                                                   "shobj_description(oid, 'pg_database') AS description "
2714
2715                                                   "FROM pg_database "
2716                                                   "WHERE datname = current_database()",
2717                                                   username_subquery);
2718         }
2719         else if (fout->remoteVersion >= 80200)
2720         {
2721                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2722                                                   "(%s datdba) AS dba, "
2723                                                   "pg_encoding_to_char(encoding) AS encoding, "
2724                                                   "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2725                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2726                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2727                                                   "shobj_description(oid, 'pg_database') AS description "
2728
2729                                                   "FROM pg_database "
2730                                                   "WHERE datname = current_database()",
2731                                                   username_subquery);
2732         }
2733         else
2734         {
2735                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2736                                                   "(%s datdba) AS dba, "
2737                                                   "pg_encoding_to_char(encoding) AS encoding, "
2738                                                   "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2739                                                   "datacl, '' as rdatacl, datistemplate, "
2740                                                   "-1 as datconnlimit, "
2741                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
2742                                                   "FROM pg_database "
2743                                                   "WHERE datname = current_database()",
2744                                                   username_subquery);
2745         }
2746
2747         res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
2748
2749         i_tableoid = PQfnumber(res, "tableoid");
2750         i_oid = PQfnumber(res, "oid");
2751         i_datname = PQfnumber(res, "datname");
2752         i_dba = PQfnumber(res, "dba");
2753         i_encoding = PQfnumber(res, "encoding");
2754         i_collate = PQfnumber(res, "datcollate");
2755         i_ctype = PQfnumber(res, "datctype");
2756         i_frozenxid = PQfnumber(res, "datfrozenxid");
2757         i_minmxid = PQfnumber(res, "datminmxid");
2758         i_datacl = PQfnumber(res, "datacl");
2759         i_rdatacl = PQfnumber(res, "rdatacl");
2760         i_datistemplate = PQfnumber(res, "datistemplate");
2761         i_datconnlimit = PQfnumber(res, "datconnlimit");
2762         i_tablespace = PQfnumber(res, "tablespace");
2763
2764         dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
2765         dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
2766         datname = PQgetvalue(res, 0, i_datname);
2767         dba = PQgetvalue(res, 0, i_dba);
2768         encoding = PQgetvalue(res, 0, i_encoding);
2769         collate = PQgetvalue(res, 0, i_collate);
2770         ctype = PQgetvalue(res, 0, i_ctype);
2771         frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
2772         minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
2773         datacl = PQgetvalue(res, 0, i_datacl);
2774         rdatacl = PQgetvalue(res, 0, i_rdatacl);
2775         datistemplate = PQgetvalue(res, 0, i_datistemplate);
2776         datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
2777         tablespace = PQgetvalue(res, 0, i_tablespace);
2778
2779         qdatname = pg_strdup(fmtId(datname));
2780
2781         /*
2782          * Prepare the CREATE DATABASE command.  We must specify encoding, locale,
2783          * and tablespace since those can't be altered later.  Other DB properties
2784          * are left to the DATABASE PROPERTIES entry, so that they can be applied
2785          * after reconnecting to the target DB.
2786          */
2787         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
2788                                           qdatname);
2789         if (strlen(encoding) > 0)
2790         {
2791                 appendPQExpBufferStr(creaQry, " ENCODING = ");
2792                 appendStringLiteralAH(creaQry, encoding, fout);
2793         }
2794         if (strlen(collate) > 0)
2795         {
2796                 appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
2797                 appendStringLiteralAH(creaQry, collate, fout);
2798         }
2799         if (strlen(ctype) > 0)
2800         {
2801                 appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
2802                 appendStringLiteralAH(creaQry, ctype, fout);
2803         }
2804
2805         /*
2806          * Note: looking at dopt->outputNoTablespaces here is completely the wrong
2807          * thing; the decision whether to specify a tablespace should be left till
2808          * pg_restore, so that pg_restore --no-tablespaces applies.  Ideally we'd
2809          * label the DATABASE entry with the tablespace and let the normal
2810          * tablespace selection logic work ... but CREATE DATABASE doesn't pay
2811          * attention to default_tablespace, so that won't work.
2812          */
2813         if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
2814                 !dopt->outputNoTablespaces)
2815                 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
2816                                                   fmtId(tablespace));
2817         appendPQExpBufferStr(creaQry, ";\n");
2818
2819         appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
2820                                           qdatname);
2821
2822         dbDumpId = createDumpId();
2823
2824         ArchiveEntry(fout,
2825                                  dbCatId,               /* catalog ID */
2826                                  dbDumpId,              /* dump ID */
2827                                  ARCHIVE_OPTS(.tag = datname,
2828                                                           .owner = dba,
2829                                                           .description = "DATABASE",
2830                                                           .section = SECTION_PRE_DATA,
2831                                                           .createStmt = creaQry->data,
2832                                                           .dropStmt = delQry->data));
2833
2834         /* Compute correct tag for archive entry */
2835         appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
2836
2837         /* Dump DB comment if any */
2838         if (fout->remoteVersion >= 80200)
2839         {
2840                 /*
2841                  * 8.2 and up keep comments on shared objects in a shared table, so we
2842                  * cannot use the dumpComment() code used for other database objects.
2843                  * Be careful that the ArchiveEntry parameters match that function.
2844                  */
2845                 char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
2846
2847                 if (comment && *comment && !dopt->no_comments)
2848                 {
2849                         resetPQExpBuffer(dbQry);
2850
2851                         /*
2852                          * Generates warning when loaded into a differently-named
2853                          * database.
2854                          */
2855                         appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
2856                         appendStringLiteralAH(dbQry, comment, fout);
2857                         appendPQExpBufferStr(dbQry, ";\n");
2858
2859                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2860                                                  ARCHIVE_OPTS(.tag = labelq->data,
2861                                                                           .owner = dba,
2862                                                                           .description = "COMMENT",
2863                                                                           .section = SECTION_NONE,
2864                                                                           .createStmt = dbQry->data,
2865                                                                           .deps = &dbDumpId,
2866                                                                           .nDeps = 1));
2867                 }
2868         }
2869         else
2870         {
2871                 dumpComment(fout, "DATABASE", qdatname, NULL, dba,
2872                                         dbCatId, 0, dbDumpId);
2873         }
2874
2875         /* Dump DB security label, if enabled */
2876         if (!dopt->no_security_labels && fout->remoteVersion >= 90200)
2877         {
2878                 PGresult   *shres;
2879                 PQExpBuffer seclabelQry;
2880
2881                 seclabelQry = createPQExpBuffer();
2882
2883                 buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
2884                 shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
2885                 resetPQExpBuffer(seclabelQry);
2886                 emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
2887                 if (seclabelQry->len > 0)
2888                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2889                                                  ARCHIVE_OPTS(.tag = labelq->data,
2890                                                                           .owner = dba,
2891                                                                           .description = "SECURITY LABEL",
2892                                                                           .section = SECTION_NONE,
2893                                                                           .createStmt = seclabelQry->data,
2894                                                                           .deps = &dbDumpId,
2895                                                                           .nDeps = 1));
2896                 destroyPQExpBuffer(seclabelQry);
2897                 PQclear(shres);
2898         }
2899
2900         /*
2901          * Dump ACL if any.  Note that we do not support initial privileges
2902          * (pg_init_privs) on databases.
2903          */
2904         dumpACL(fout, dbCatId, dbDumpId, "DATABASE",
2905                         qdatname, NULL, NULL,
2906                         dba, datacl, rdatacl, "", "");
2907
2908         /*
2909          * Now construct a DATABASE PROPERTIES archive entry to restore any
2910          * non-default database-level properties.  (The reason this must be
2911          * separate is that we cannot put any additional commands into the TOC
2912          * entry that has CREATE DATABASE.  pg_restore would execute such a group
2913          * in an implicit transaction block, and the backend won't allow CREATE
2914          * DATABASE in that context.)
2915          */
2916         resetPQExpBuffer(creaQry);
2917         resetPQExpBuffer(delQry);
2918
2919         if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
2920                 appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
2921                                                   qdatname, datconnlimit);
2922
2923         if (strcmp(datistemplate, "t") == 0)
2924         {
2925                 appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
2926                                                   qdatname);
2927
2928                 /*
2929                  * The backend won't accept DROP DATABASE on a template database.  We
2930                  * can deal with that by removing the template marking before the DROP
2931                  * gets issued.  We'd prefer to use ALTER DATABASE IF EXISTS here, but
2932                  * since no such command is currently supported, fake it with a direct
2933                  * UPDATE on pg_database.
2934                  */
2935                 appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
2936                                                          "SET datistemplate = false WHERE datname = ");
2937                 appendStringLiteralAH(delQry, datname, fout);
2938                 appendPQExpBufferStr(delQry, ";\n");
2939         }
2940
2941         /* Add database-specific SET options */
2942         dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
2943
2944         /*
2945          * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
2946          * entry, too, for lack of a better place.
2947          */
2948         if (dopt->binary_upgrade)
2949         {
2950                 appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
2951                 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
2952                                                   "SET datfrozenxid = '%u', datminmxid = '%u'\n"
2953                                                   "WHERE datname = ",
2954                                                   frozenxid, minmxid);
2955                 appendStringLiteralAH(creaQry, datname, fout);
2956                 appendPQExpBufferStr(creaQry, ";\n");
2957         }
2958
2959         if (creaQry->len > 0)
2960                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
2961                                          ARCHIVE_OPTS(.tag = datname,
2962                                                                   .owner = dba,
2963                                                                   .description = "DATABASE PROPERTIES",
2964                                                                   .section = SECTION_PRE_DATA,
2965                                                                   .createStmt = creaQry->data,
2966                                                                   .dropStmt = delQry->data,
2967                                                                   .deps = &dbDumpId));
2968
2969         /*
2970          * pg_largeobject comes from the old system intact, so set its
2971          * relfrozenxids and relminmxids.
2972          */
2973         if (dopt->binary_upgrade)
2974         {
2975                 PGresult   *lo_res;
2976                 PQExpBuffer loFrozenQry = createPQExpBuffer();
2977                 PQExpBuffer loOutQry = createPQExpBuffer();
2978                 int                     i_relfrozenxid,
2979                                         i_relminmxid;
2980
2981                 /*
2982                  * pg_largeobject
2983                  */
2984                 if (fout->remoteVersion >= 90300)
2985                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
2986                                                           "FROM pg_catalog.pg_class\n"
2987                                                           "WHERE oid = %u;\n",
2988                                                           LargeObjectRelationId);
2989                 else
2990                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
2991                                                           "FROM pg_catalog.pg_class\n"
2992                                                           "WHERE oid = %u;\n",
2993                                                           LargeObjectRelationId);
2994
2995                 lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2996
2997                 i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2998                 i_relminmxid = PQfnumber(lo_res, "relminmxid");
2999
3000                 appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
3001                 appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
3002                                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
3003                                                   "WHERE oid = %u;\n",
3004                                                   atooid(PQgetvalue(lo_res, 0, i_relfrozenxid)),
3005                                                   atooid(PQgetvalue(lo_res, 0, i_relminmxid)),
3006                                                   LargeObjectRelationId);
3007                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
3008                                          ARCHIVE_OPTS(.tag = "pg_largeobject",
3009                                                                   .description = "pg_largeobject",
3010                                                                   .section = SECTION_PRE_DATA,
3011                                                                   .createStmt = loOutQry->data));
3012
3013                 PQclear(lo_res);
3014
3015                 destroyPQExpBuffer(loFrozenQry);
3016                 destroyPQExpBuffer(loOutQry);
3017         }
3018
3019         PQclear(res);
3020
3021         free(qdatname);
3022         destroyPQExpBuffer(dbQry);
3023         destroyPQExpBuffer(delQry);
3024         destroyPQExpBuffer(creaQry);
3025         destroyPQExpBuffer(labelq);
3026 }
3027
3028 /*
3029  * Collect any database-specific or role-and-database-specific SET options
3030  * for this database, and append them to outbuf.
3031  */
3032 static void
3033 dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
3034                                    const char *dbname, Oid dboid)
3035 {
3036         PGconn     *conn = GetConnection(AH);
3037         PQExpBuffer buf = createPQExpBuffer();
3038         PGresult   *res;
3039         int                     count = 1;
3040
3041         /*
3042          * First collect database-specific options.  Pre-8.4 server versions lack
3043          * unnest(), so we do this the hard way by querying once per subscript.
3044          */
3045         for (;;)
3046         {
3047                 if (AH->remoteVersion >= 90000)
3048                         printfPQExpBuffer(buf, "SELECT setconfig[%d] FROM pg_db_role_setting "
3049                                                           "WHERE setrole = 0 AND setdatabase = '%u'::oid",
3050                                                           count, dboid);
3051                 else
3052                         printfPQExpBuffer(buf, "SELECT datconfig[%d] FROM pg_database WHERE oid = '%u'::oid", count, dboid);
3053
3054                 res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3055
3056                 if (PQntuples(res) == 1 &&
3057                         !PQgetisnull(res, 0, 0))
3058                 {
3059                         makeAlterConfigCommand(conn, PQgetvalue(res, 0, 0),
3060                                                                    "DATABASE", dbname, NULL, NULL,
3061                                                                    outbuf);
3062                         PQclear(res);
3063                         count++;
3064                 }
3065                 else
3066                 {
3067                         PQclear(res);
3068                         break;
3069                 }
3070         }
3071
3072         /* Now look for role-and-database-specific options */
3073         if (AH->remoteVersion >= 90000)
3074         {
3075                 /* Here we can assume we have unnest() */
3076                 printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
3077                                                   "FROM pg_db_role_setting s, pg_roles r "
3078                                                   "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
3079                                                   dboid);
3080
3081                 res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3082
3083                 if (PQntuples(res) > 0)
3084                 {
3085                         int                     i;
3086
3087                         for (i = 0; i < PQntuples(res); i++)
3088                                 makeAlterConfigCommand(conn, PQgetvalue(res, i, 1),
3089                                                                            "ROLE", PQgetvalue(res, i, 0),
3090                                                                            "DATABASE", dbname,
3091                                                                            outbuf);
3092                 }
3093
3094                 PQclear(res);
3095         }
3096
3097         destroyPQExpBuffer(buf);
3098 }
3099
3100 /*
3101  * dumpEncoding: put the correct encoding into the archive
3102  */
3103 static void
3104 dumpEncoding(Archive *AH)
3105 {
3106         const char *encname = pg_encoding_to_char(AH->encoding);
3107         PQExpBuffer qry = createPQExpBuffer();
3108
3109         pg_log_info("saving encoding = %s", encname);
3110
3111         appendPQExpBufferStr(qry, "SET client_encoding = ");
3112         appendStringLiteralAH(qry, encname, AH);
3113         appendPQExpBufferStr(qry, ";\n");
3114
3115         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3116                                  ARCHIVE_OPTS(.tag = "ENCODING",
3117                                                           .description = "ENCODING",
3118                                                           .section = SECTION_PRE_DATA,
3119                                                           .createStmt = qry->data));
3120
3121         destroyPQExpBuffer(qry);
3122 }
3123
3124
3125 /*
3126  * dumpStdStrings: put the correct escape string behavior into the archive
3127  */
3128 static void
3129 dumpStdStrings(Archive *AH)
3130 {
3131         const char *stdstrings = AH->std_strings ? "on" : "off";
3132         PQExpBuffer qry = createPQExpBuffer();
3133
3134         pg_log_info("saving standard_conforming_strings = %s",
3135                                 stdstrings);
3136
3137         appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
3138                                           stdstrings);
3139
3140         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3141                                  ARCHIVE_OPTS(.tag = "STDSTRINGS",
3142                                                           .description = "STDSTRINGS",
3143                                                           .section = SECTION_PRE_DATA,
3144                                                           .createStmt = qry->data));
3145
3146         destroyPQExpBuffer(qry);
3147 }
3148
3149 /*
3150  * dumpSearchPath: record the active search_path in the archive
3151  */
3152 static void
3153 dumpSearchPath(Archive *AH)
3154 {
3155         PQExpBuffer qry = createPQExpBuffer();
3156         PQExpBuffer path = createPQExpBuffer();
3157         PGresult   *res;
3158         char      **schemanames = NULL;
3159         int                     nschemanames = 0;
3160         int                     i;
3161
3162         /*
3163          * We use the result of current_schemas(), not the search_path GUC,
3164          * because that might contain wildcards such as "$user", which won't
3165          * necessarily have the same value during restore.  Also, this way avoids
3166          * listing schemas that may appear in search_path but not actually exist,
3167          * which seems like a prudent exclusion.
3168          */
3169         res = ExecuteSqlQueryForSingleRow(AH,
3170                                                                           "SELECT pg_catalog.current_schemas(false)");
3171
3172         if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
3173                 fatal("could not parse result of current_schemas()");
3174
3175         /*
3176          * We use set_config(), not a simple "SET search_path" command, because
3177          * the latter has less-clean behavior if the search path is empty.  While
3178          * that's likely to get fixed at some point, it seems like a good idea to
3179          * be as backwards-compatible as possible in what we put into archives.
3180          */
3181         for (i = 0; i < nschemanames; i++)
3182         {
3183                 if (i > 0)
3184                         appendPQExpBufferStr(path, ", ");
3185                 appendPQExpBufferStr(path, fmtId(schemanames[i]));
3186         }
3187
3188         appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
3189         appendStringLiteralAH(qry, path->data, AH);
3190         appendPQExpBufferStr(qry, ", false);\n");
3191
3192         pg_log_info("saving search_path = %s", path->data);
3193
3194         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3195                                  ARCHIVE_OPTS(.tag = "SEARCHPATH",
3196                                                           .description = "SEARCHPATH",
3197                                                           .section = SECTION_PRE_DATA,
3198                                                           .createStmt = qry->data));
3199
3200         /* Also save it in AH->searchpath, in case we're doing plain text dump */
3201         AH->searchpath = pg_strdup(qry->data);
3202
3203         if (schemanames)
3204                 free(schemanames);
3205         PQclear(res);
3206         destroyPQExpBuffer(qry);
3207         destroyPQExpBuffer(path);
3208 }
3209
3210
3211 /*
3212  * getBlobs:
3213  *      Collect schema-level data about large objects
3214  */
3215 static void
3216 getBlobs(Archive *fout)
3217 {
3218         DumpOptions *dopt = fout->dopt;
3219         PQExpBuffer blobQry = createPQExpBuffer();
3220         BlobInfo   *binfo;
3221         DumpableObject *bdata;
3222         PGresult   *res;
3223         int                     ntups;
3224         int                     i;
3225         int                     i_oid;
3226         int                     i_lomowner;
3227         int                     i_lomacl;
3228         int                     i_rlomacl;
3229         int                     i_initlomacl;
3230         int                     i_initrlomacl;
3231
3232         pg_log_info("reading large objects");
3233
3234         /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
3235         if (fout->remoteVersion >= 90600)
3236         {
3237                 PQExpBuffer acl_subquery = createPQExpBuffer();
3238                 PQExpBuffer racl_subquery = createPQExpBuffer();
3239                 PQExpBuffer init_acl_subquery = createPQExpBuffer();
3240                 PQExpBuffer init_racl_subquery = createPQExpBuffer();
3241
3242                 buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
3243                                                 init_racl_subquery, "l.lomacl", "l.lomowner", "'L'",
3244                                                 dopt->binary_upgrade);
3245
3246                 appendPQExpBuffer(blobQry,
3247                                                   "SELECT l.oid, (%s l.lomowner) AS rolname, "
3248                                                   "%s AS lomacl, "
3249                                                   "%s AS rlomacl, "
3250                                                   "%s AS initlomacl, "
3251                                                   "%s AS initrlomacl "
3252                                                   "FROM pg_largeobject_metadata l "
3253                                                   "LEFT JOIN pg_init_privs pip ON "
3254                                                   "(l.oid = pip.objoid "
3255                                                   "AND pip.classoid = 'pg_largeobject'::regclass "
3256                                                   "AND pip.objsubid = 0) ",
3257                                                   username_subquery,
3258                                                   acl_subquery->data,
3259                                                   racl_subquery->data,
3260                                                   init_acl_subquery->data,
3261                                                   init_racl_subquery->data);
3262
3263                 destroyPQExpBuffer(acl_subquery);
3264                 destroyPQExpBuffer(racl_subquery);
3265                 destroyPQExpBuffer(init_acl_subquery);
3266                 destroyPQExpBuffer(init_racl_subquery);
3267         }
3268         else if (fout->remoteVersion >= 90000)
3269                 appendPQExpBuffer(blobQry,
3270                                                   "SELECT oid, (%s lomowner) AS rolname, lomacl, "
3271                                                   "NULL AS rlomacl, NULL AS initlomacl, "
3272                                                   "NULL AS initrlomacl "
3273                                                   " FROM pg_largeobject_metadata",
3274                                                   username_subquery);
3275         else
3276                 appendPQExpBufferStr(blobQry,
3277                                                          "SELECT DISTINCT loid AS oid, "
3278                                                          "NULL::name AS rolname, NULL::oid AS lomacl, "
3279                                                          "NULL::oid AS rlomacl, NULL::oid AS initlomacl, "
3280                                                          "NULL::oid AS initrlomacl "
3281                                                          " FROM pg_largeobject");
3282
3283         res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
3284
3285         i_oid = PQfnumber(res, "oid");
3286         i_lomowner = PQfnumber(res, "rolname");
3287         i_lomacl = PQfnumber(res, "lomacl");
3288         i_rlomacl = PQfnumber(res, "rlomacl");
3289         i_initlomacl = PQfnumber(res, "initlomacl");
3290         i_initrlomacl = PQfnumber(res, "initrlomacl");
3291
3292         ntups = PQntuples(res);
3293
3294         /*
3295          * Each large object has its own BLOB archive entry.
3296          */
3297         binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
3298
3299         for (i = 0; i < ntups; i++)
3300         {
3301                 binfo[i].dobj.objType = DO_BLOB;
3302                 binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
3303                 binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3304                 AssignDumpId(&binfo[i].dobj);
3305
3306                 binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oid));
3307                 binfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_lomowner));
3308                 binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, i_lomacl));
3309                 binfo[i].rblobacl = pg_strdup(PQgetvalue(res, i, i_rlomacl));
3310                 binfo[i].initblobacl = pg_strdup(PQgetvalue(res, i, i_initlomacl));
3311                 binfo[i].initrblobacl = pg_strdup(PQgetvalue(res, i, i_initrlomacl));
3312
3313                 if (PQgetisnull(res, i, i_lomacl) &&
3314                         PQgetisnull(res, i, i_rlomacl) &&
3315                         PQgetisnull(res, i, i_initlomacl) &&
3316                         PQgetisnull(res, i, i_initrlomacl))
3317                         binfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
3318
3319                 /*
3320                  * In binary-upgrade mode for blobs, we do *not* dump out the blob
3321                  * data, as it will be copied by pg_upgrade, which simply copies the
3322                  * pg_largeobject table. We *do* however dump out anything but the
3323                  * data, as pg_upgrade copies just pg_largeobject, but not
3324                  * pg_largeobject_metadata, after the dump is restored.
3325                  */
3326                 if (dopt->binary_upgrade)
3327                         binfo[i].dobj.dump &= ~DUMP_COMPONENT_DATA;
3328         }
3329
3330         /*
3331          * If we have any large objects, a "BLOBS" archive entry is needed. This
3332          * is just a placeholder for sorting; it carries no data now.
3333          */
3334         if (ntups > 0)
3335         {
3336                 bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
3337                 bdata->objType = DO_BLOB_DATA;
3338                 bdata->catId = nilCatalogId;
3339                 AssignDumpId(bdata);
3340                 bdata->name = pg_strdup("BLOBS");
3341         }
3342
3343         PQclear(res);
3344         destroyPQExpBuffer(blobQry);
3345 }
3346
3347 /*
3348  * dumpBlob
3349  *
3350  * dump the definition (metadata) of the given large object
3351  */
3352 static void
3353 dumpBlob(Archive *fout, BlobInfo *binfo)
3354 {
3355         PQExpBuffer cquery = createPQExpBuffer();
3356         PQExpBuffer dquery = createPQExpBuffer();
3357
3358         appendPQExpBuffer(cquery,
3359                                           "SELECT pg_catalog.lo_create('%s');\n",
3360                                           binfo->dobj.name);
3361
3362         appendPQExpBuffer(dquery,
3363                                           "SELECT pg_catalog.lo_unlink('%s');\n",
3364                                           binfo->dobj.name);
3365
3366         if (binfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
3367                 ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
3368                                          ARCHIVE_OPTS(.tag = binfo->dobj.name,
3369                                                                   .owner = binfo->rolname,
3370                                                                   .description = "BLOB",
3371                                                                   .section = SECTION_PRE_DATA,
3372                                                                   .createStmt = cquery->data,
3373                                                                   .dropStmt = dquery->data));
3374
3375         /* Dump comment if any */
3376         if (binfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3377                 dumpComment(fout, "LARGE OBJECT", binfo->dobj.name,
3378                                         NULL, binfo->rolname,
3379                                         binfo->dobj.catId, 0, binfo->dobj.dumpId);
3380
3381         /* Dump security label if any */
3382         if (binfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3383                 dumpSecLabel(fout, "LARGE OBJECT", binfo->dobj.name,
3384                                          NULL, binfo->rolname,
3385                                          binfo->dobj.catId, 0, binfo->dobj.dumpId);
3386
3387         /* Dump ACL if any */
3388         if (binfo->blobacl && (binfo->dobj.dump & DUMP_COMPONENT_ACL))
3389                 dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
3390                                 binfo->dobj.name, NULL,
3391                                 NULL, binfo->rolname, binfo->blobacl, binfo->rblobacl,
3392                                 binfo->initblobacl, binfo->initrblobacl);
3393
3394         destroyPQExpBuffer(cquery);
3395         destroyPQExpBuffer(dquery);
3396 }
3397
3398 /*
3399  * dumpBlobs:
3400  *      dump the data contents of all large objects
3401  */
3402 static int
3403 dumpBlobs(Archive *fout, void *arg)
3404 {
3405         const char *blobQry;
3406         const char *blobFetchQry;
3407         PGconn     *conn = GetConnection(fout);
3408         PGresult   *res;
3409         char            buf[LOBBUFSIZE];
3410         int                     ntups;
3411         int                     i;
3412         int                     cnt;
3413
3414         pg_log_info("saving large objects");
3415
3416         /*
3417          * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
3418          * the already-in-memory dumpable objects instead...
3419          */
3420         if (fout->remoteVersion >= 90000)
3421                 blobQry =
3422                         "DECLARE bloboid CURSOR FOR "
3423                         "SELECT oid FROM pg_largeobject_metadata ORDER BY 1";
3424         else
3425                 blobQry =
3426                         "DECLARE bloboid CURSOR FOR "
3427                         "SELECT DISTINCT loid FROM pg_largeobject ORDER BY 1";
3428
3429         ExecuteSqlStatement(fout, blobQry);
3430
3431         /* Command to fetch from cursor */
3432         blobFetchQry = "FETCH 1000 IN bloboid";
3433
3434         do
3435         {
3436                 /* Do a fetch */
3437                 res = ExecuteSqlQuery(fout, blobFetchQry, PGRES_TUPLES_OK);
3438
3439                 /* Process the tuples, if any */
3440                 ntups = PQntuples(res);
3441                 for (i = 0; i < ntups; i++)
3442                 {
3443                         Oid                     blobOid;
3444                         int                     loFd;
3445
3446                         blobOid = atooid(PQgetvalue(res, i, 0));
3447                         /* Open the BLOB */
3448                         loFd = lo_open(conn, blobOid, INV_READ);
3449                         if (loFd == -1)
3450                                 fatal("could not open large object %u: %s",
3451                                                           blobOid, PQerrorMessage(conn));
3452
3453                         StartBlob(fout, blobOid);
3454
3455                         /* Now read it in chunks, sending data to archive */
3456                         do
3457                         {
3458                                 cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
3459                                 if (cnt < 0)
3460                                         fatal("error reading large object %u: %s",
3461                                                                   blobOid, PQerrorMessage(conn));
3462
3463                                 WriteData(fout, buf, cnt);
3464                         } while (cnt > 0);
3465
3466                         lo_close(conn, loFd);
3467
3468                         EndBlob(fout, blobOid);
3469                 }
3470
3471                 PQclear(res);
3472         } while (ntups > 0);
3473
3474         return 1;
3475 }
3476
3477 /*
3478  * getPolicies
3479  *        get information about policies on a dumpable table.
3480  */
3481 void
3482 getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
3483 {
3484         PQExpBuffer query;
3485         PGresult   *res;
3486         PolicyInfo *polinfo;
3487         int                     i_oid;
3488         int                     i_tableoid;
3489         int                     i_polname;
3490         int                     i_polcmd;
3491         int                     i_polpermissive;
3492         int                     i_polroles;
3493         int                     i_polqual;
3494         int                     i_polwithcheck;
3495         int                     i,
3496                                 j,
3497                                 ntups;
3498
3499         if (fout->remoteVersion < 90500)
3500                 return;
3501
3502         query = createPQExpBuffer();
3503
3504         for (i = 0; i < numTables; i++)
3505         {
3506                 TableInfo  *tbinfo = &tblinfo[i];
3507
3508                 /* Ignore row security on tables not to be dumped */
3509                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
3510                         continue;
3511
3512                 pg_log_info("reading row security enabled for table \"%s.%s\"",
3513                                         tbinfo->dobj.namespace->dobj.name,
3514                                         tbinfo->dobj.name);
3515
3516                 /*
3517                  * Get row security enabled information for the table. We represent
3518                  * RLS being enabled on a table by creating a PolicyInfo object with
3519                  * null polname.
3520                  */
3521                 if (tbinfo->rowsec)
3522                 {
3523                         /*
3524                          * Note: use tableoid 0 so that this object won't be mistaken for
3525                          * something that pg_depend entries apply to.
3526                          */
3527                         polinfo = pg_malloc(sizeof(PolicyInfo));
3528                         polinfo->dobj.objType = DO_POLICY;
3529                         polinfo->dobj.catId.tableoid = 0;
3530                         polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
3531                         AssignDumpId(&polinfo->dobj);
3532                         polinfo->dobj.namespace = tbinfo->dobj.namespace;
3533                         polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
3534                         polinfo->poltable = tbinfo;
3535                         polinfo->polname = NULL;
3536                         polinfo->polcmd = '\0';
3537                         polinfo->polpermissive = 0;
3538                         polinfo->polroles = NULL;
3539                         polinfo->polqual = NULL;
3540                         polinfo->polwithcheck = NULL;
3541                 }
3542
3543                 pg_log_info("reading policies for table \"%s.%s\"",
3544                                         tbinfo->dobj.namespace->dobj.name,
3545                                         tbinfo->dobj.name);
3546
3547                 resetPQExpBuffer(query);
3548
3549                 /* Get the policies for the table. */
3550                 if (fout->remoteVersion >= 100000)
3551                         appendPQExpBuffer(query,
3552                                                           "SELECT oid, tableoid, pol.polname, pol.polcmd, pol.polpermissive, "
3553                                                           "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3554                                                           "   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, "
3555                                                           "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3556                                                           "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3557                                                           "FROM pg_catalog.pg_policy pol "
3558                                                           "WHERE polrelid = '%u'",
3559                                                           tbinfo->dobj.catId.oid);
3560                 else
3561                         appendPQExpBuffer(query,
3562                                                           "SELECT oid, tableoid, pol.polname, pol.polcmd, 't' as polpermissive, "
3563                                                           "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3564                                                           "   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, "
3565                                                           "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3566                                                           "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3567                                                           "FROM pg_catalog.pg_policy pol "
3568                                                           "WHERE polrelid = '%u'",
3569                                                           tbinfo->dobj.catId.oid);
3570                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3571
3572                 ntups = PQntuples(res);
3573
3574                 if (ntups == 0)
3575                 {
3576                         /*
3577                          * No explicit policies to handle (only the default-deny policy,
3578                          * which is handled as part of the table definition).  Clean up
3579                          * and return.
3580                          */
3581                         PQclear(res);
3582                         continue;
3583                 }
3584
3585                 i_oid = PQfnumber(res, "oid");
3586                 i_tableoid = PQfnumber(res, "tableoid");
3587                 i_polname = PQfnumber(res, "polname");
3588                 i_polcmd = PQfnumber(res, "polcmd");
3589                 i_polpermissive = PQfnumber(res, "polpermissive");
3590                 i_polroles = PQfnumber(res, "polroles");
3591                 i_polqual = PQfnumber(res, "polqual");
3592                 i_polwithcheck = PQfnumber(res, "polwithcheck");
3593
3594                 polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
3595
3596                 for (j = 0; j < ntups; j++)
3597                 {
3598                         polinfo[j].dobj.objType = DO_POLICY;
3599                         polinfo[j].dobj.catId.tableoid =
3600                                 atooid(PQgetvalue(res, j, i_tableoid));
3601                         polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3602                         AssignDumpId(&polinfo[j].dobj);
3603                         polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3604                         polinfo[j].poltable = tbinfo;
3605                         polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
3606                         polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
3607
3608                         polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
3609                         polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
3610
3611                         if (PQgetisnull(res, j, i_polroles))
3612                                 polinfo[j].polroles = NULL;
3613                         else
3614                                 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
3615
3616                         if (PQgetisnull(res, j, i_polqual))
3617                                 polinfo[j].polqual = NULL;
3618                         else
3619                                 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
3620
3621                         if (PQgetisnull(res, j, i_polwithcheck))
3622                                 polinfo[j].polwithcheck = NULL;
3623                         else
3624                                 polinfo[j].polwithcheck
3625                                         = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
3626                 }
3627                 PQclear(res);
3628         }
3629         destroyPQExpBuffer(query);
3630 }
3631
3632 /*
3633  * dumpPolicy
3634  *        dump the definition of the given policy
3635  */
3636 static void
3637 dumpPolicy(Archive *fout, PolicyInfo *polinfo)
3638 {
3639         DumpOptions *dopt = fout->dopt;
3640         TableInfo  *tbinfo = polinfo->poltable;
3641         PQExpBuffer query;
3642         PQExpBuffer delqry;
3643         const char *cmd;
3644         char       *tag;
3645
3646         if (dopt->dataOnly)
3647                 return;
3648
3649         /*
3650          * If polname is NULL, then this record is just indicating that ROW LEVEL
3651          * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
3652          * ROW LEVEL SECURITY.
3653          */
3654         if (polinfo->polname == NULL)
3655         {
3656                 query = createPQExpBuffer();
3657
3658                 appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
3659                                                   fmtQualifiedDumpable(tbinfo));
3660
3661                 /*
3662                  * We must emit the ROW SECURITY object's dependency on its table
3663                  * explicitly, because it will not match anything in pg_depend (unlike
3664                  * the case for other PolicyInfo objects).
3665                  */
3666                 if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3667                         ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3668                                                  ARCHIVE_OPTS(.tag = polinfo->dobj.name,
3669                                                                           .namespace = polinfo->dobj.namespace->dobj.name,
3670                                                                           .owner = tbinfo->rolname,
3671                                                                           .description = "ROW SECURITY",
3672                                                                           .section = SECTION_POST_DATA,
3673                                                                           .createStmt = query->data,
3674                                                                           .deps = &(tbinfo->dobj.dumpId),
3675                                                                           .nDeps = 1));
3676
3677                 destroyPQExpBuffer(query);
3678                 return;
3679         }
3680
3681         if (polinfo->polcmd == '*')
3682                 cmd = "";
3683         else if (polinfo->polcmd == 'r')
3684                 cmd = " FOR SELECT";
3685         else if (polinfo->polcmd == 'a')
3686                 cmd = " FOR INSERT";
3687         else if (polinfo->polcmd == 'w')
3688                 cmd = " FOR UPDATE";
3689         else if (polinfo->polcmd == 'd')
3690                 cmd = " FOR DELETE";
3691         else
3692         {
3693                 pg_log_error("unexpected policy command type: %c",
3694                                   polinfo->polcmd);
3695                 exit_nicely(1);
3696         }
3697
3698         query = createPQExpBuffer();
3699         delqry = createPQExpBuffer();
3700
3701         appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
3702
3703         appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
3704                                           !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
3705
3706         if (polinfo->polroles != NULL)
3707                 appendPQExpBuffer(query, " TO %s", polinfo->polroles);
3708
3709         if (polinfo->polqual != NULL)
3710                 appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
3711
3712         if (polinfo->polwithcheck != NULL)
3713                 appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
3714
3715         appendPQExpBuffer(query, ";\n");
3716
3717         appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
3718         appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
3719
3720         tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
3721
3722         if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3723                 ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3724                                          ARCHIVE_OPTS(.tag = tag,
3725                                                                   .namespace = polinfo->dobj.namespace->dobj.name,
3726                                                                   .owner = tbinfo->rolname,
3727                                                                   .description = "POLICY",
3728                                                                   .section = SECTION_POST_DATA,
3729                                                                   .createStmt = query->data,
3730                                                                   .dropStmt = delqry->data));
3731
3732         free(tag);
3733         destroyPQExpBuffer(query);
3734         destroyPQExpBuffer(delqry);
3735 }
3736
3737 /*
3738  * getPublications
3739  *        get information about publications
3740  */
3741 void
3742 getPublications(Archive *fout)
3743 {
3744         DumpOptions *dopt = fout->dopt;
3745         PQExpBuffer query;
3746         PGresult   *res;
3747         PublicationInfo *pubinfo;
3748         int                     i_tableoid;
3749         int                     i_oid;
3750         int                     i_pubname;
3751         int                     i_rolname;
3752         int                     i_puballtables;
3753         int                     i_pubinsert;
3754         int                     i_pubupdate;
3755         int                     i_pubdelete;
3756         int                     i_pubtruncate;
3757         int                     i,
3758                                 ntups;
3759
3760         if (dopt->no_publications || fout->remoteVersion < 100000)
3761                 return;
3762
3763         query = createPQExpBuffer();
3764
3765         resetPQExpBuffer(query);
3766
3767         /* Get the publications. */
3768         if (fout->remoteVersion >= 110000)
3769                 appendPQExpBuffer(query,
3770                                                   "SELECT p.tableoid, p.oid, p.pubname, "
3771                                                   "(%s p.pubowner) AS rolname, "
3772                                                   "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, p.pubtruncate "
3773                                                   "FROM pg_publication p",
3774                                                   username_subquery);
3775         else
3776                 appendPQExpBuffer(query,
3777                                                   "SELECT p.tableoid, p.oid, p.pubname, "
3778                                                   "(%s p.pubowner) AS rolname, "
3779                                                   "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, false AS pubtruncate "
3780                                                   "FROM pg_publication p",
3781                                                   username_subquery);
3782
3783         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3784
3785         ntups = PQntuples(res);
3786
3787         i_tableoid = PQfnumber(res, "tableoid");
3788         i_oid = PQfnumber(res, "oid");
3789         i_pubname = PQfnumber(res, "pubname");
3790         i_rolname = PQfnumber(res, "rolname");
3791         i_puballtables = PQfnumber(res, "puballtables");
3792         i_pubinsert = PQfnumber(res, "pubinsert");
3793         i_pubupdate = PQfnumber(res, "pubupdate");
3794         i_pubdelete = PQfnumber(res, "pubdelete");
3795         i_pubtruncate = PQfnumber(res, "pubtruncate");
3796
3797         pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
3798
3799         for (i = 0; i < ntups; i++)
3800         {
3801                 pubinfo[i].dobj.objType = DO_PUBLICATION;
3802                 pubinfo[i].dobj.catId.tableoid =
3803                         atooid(PQgetvalue(res, i, i_tableoid));
3804                 pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3805                 AssignDumpId(&pubinfo[i].dobj);
3806                 pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
3807                 pubinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3808                 pubinfo[i].puballtables =
3809                         (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
3810                 pubinfo[i].pubinsert =
3811                         (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
3812                 pubinfo[i].pubupdate =
3813                         (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
3814                 pubinfo[i].pubdelete =
3815                         (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
3816                 pubinfo[i].pubtruncate =
3817                         (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
3818
3819                 if (strlen(pubinfo[i].rolname) == 0)
3820                         pg_log_warning("owner of publication \"%s\" appears to be invalid",
3821                                           pubinfo[i].dobj.name);
3822
3823                 /* Decide whether we want to dump it */
3824                 selectDumpableObject(&(pubinfo[i].dobj), fout);
3825         }
3826         PQclear(res);
3827
3828         destroyPQExpBuffer(query);
3829 }
3830
3831 /*
3832  * dumpPublication
3833  *        dump the definition of the given publication
3834  */
3835 static void
3836 dumpPublication(Archive *fout, PublicationInfo *pubinfo)
3837 {
3838         PQExpBuffer delq;
3839         PQExpBuffer query;
3840         char       *qpubname;
3841         bool            first = true;
3842
3843         if (!(pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3844                 return;
3845
3846         delq = createPQExpBuffer();
3847         query = createPQExpBuffer();
3848
3849         qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
3850
3851         appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
3852                                           qpubname);
3853
3854         appendPQExpBuffer(query, "CREATE PUBLICATION %s",
3855                                           qpubname);
3856
3857         if (pubinfo->puballtables)
3858                 appendPQExpBufferStr(query, " FOR ALL TABLES");
3859
3860         appendPQExpBufferStr(query, " WITH (publish = '");
3861         if (pubinfo->pubinsert)
3862         {
3863                 appendPQExpBufferStr(query, "insert");
3864                 first = false;
3865         }
3866
3867         if (pubinfo->pubupdate)
3868         {
3869                 if (!first)
3870                         appendPQExpBufferStr(query, ", ");
3871
3872                 appendPQExpBufferStr(query, "update");
3873                 first = false;
3874         }
3875
3876         if (pubinfo->pubdelete)
3877         {
3878                 if (!first)
3879                         appendPQExpBufferStr(query, ", ");
3880
3881                 appendPQExpBufferStr(query, "delete");
3882                 first = false;
3883         }
3884
3885         if (pubinfo->pubtruncate)
3886         {
3887                 if (!first)
3888                         appendPQExpBufferStr(query, ", ");
3889
3890                 appendPQExpBufferStr(query, "truncate");
3891                 first = false;
3892         }
3893
3894         appendPQExpBufferStr(query, "');\n");
3895
3896         ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
3897                                  ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
3898                                                           .owner = pubinfo->rolname,
3899                                                           .description = "PUBLICATION",
3900                                                           .section = SECTION_POST_DATA,
3901                                                           .createStmt = query->data,
3902                                                           .dropStmt = delq->data));
3903
3904         if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3905                 dumpComment(fout, "PUBLICATION", qpubname,
3906                                         NULL, pubinfo->rolname,
3907                                         pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
3908
3909         if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3910                 dumpSecLabel(fout, "PUBLICATION", qpubname,
3911                                          NULL, pubinfo->rolname,
3912                                          pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
3913
3914         destroyPQExpBuffer(delq);
3915         destroyPQExpBuffer(query);
3916         free(qpubname);
3917 }
3918
3919 /*
3920  * getPublicationTables
3921  *        get information about publication membership for dumpable tables.
3922  */
3923 void
3924 getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
3925 {
3926         PQExpBuffer query;
3927         PGresult   *res;
3928         PublicationRelInfo *pubrinfo;
3929         DumpOptions *dopt = fout->dopt;
3930         int                     i_tableoid;
3931         int                     i_oid;
3932         int                     i_pubname;
3933         int                     i,
3934                                 j,
3935                                 ntups;
3936
3937         if (dopt->no_publications || fout->remoteVersion < 100000)
3938                 return;
3939
3940         query = createPQExpBuffer();
3941
3942         for (i = 0; i < numTables; i++)
3943         {
3944                 TableInfo  *tbinfo = &tblinfo[i];
3945
3946                 /* Only plain tables can be aded to publications. */
3947                 if (tbinfo->relkind != RELKIND_RELATION)
3948                         continue;
3949
3950                 /*
3951                  * Ignore publication membership of tables whose definitions are not
3952                  * to be dumped.
3953                  */
3954                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3955                         continue;
3956
3957                 pg_log_info("reading publication membership for table \"%s.%s\"",
3958                                         tbinfo->dobj.namespace->dobj.name,
3959                                         tbinfo->dobj.name);
3960
3961                 resetPQExpBuffer(query);
3962
3963                 /* Get the publication membership for the table. */
3964                 appendPQExpBuffer(query,
3965                                                   "SELECT pr.tableoid, pr.oid, p.pubname "
3966                                                   "FROM pg_publication_rel pr, pg_publication p "
3967                                                   "WHERE pr.prrelid = '%u'"
3968                                                   "  AND p.oid = pr.prpubid",
3969                                                   tbinfo->dobj.catId.oid);
3970                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3971
3972                 ntups = PQntuples(res);
3973
3974                 if (ntups == 0)
3975                 {
3976                         /*
3977                          * Table is not member of any publications. Clean up and return.
3978                          */
3979                         PQclear(res);
3980                         continue;
3981                 }
3982
3983                 i_tableoid = PQfnumber(res, "tableoid");
3984                 i_oid = PQfnumber(res, "oid");
3985                 i_pubname = PQfnumber(res, "pubname");
3986
3987                 pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
3988
3989                 for (j = 0; j < ntups; j++)
3990                 {
3991                         pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
3992                         pubrinfo[j].dobj.catId.tableoid =
3993                                 atooid(PQgetvalue(res, j, i_tableoid));
3994                         pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3995                         AssignDumpId(&pubrinfo[j].dobj);
3996                         pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3997                         pubrinfo[j].dobj.name = tbinfo->dobj.name;
3998                         pubrinfo[j].pubname = pg_strdup(PQgetvalue(res, j, i_pubname));
3999                         pubrinfo[j].pubtable = tbinfo;
4000
4001                         /* Decide whether we want to dump it */
4002                         selectDumpablePublicationTable(&(pubrinfo[j].dobj), fout);
4003                 }
4004                 PQclear(res);
4005         }
4006         destroyPQExpBuffer(query);
4007 }
4008
4009 /*
4010  * dumpPublicationTable
4011  *        dump the definition of the given publication table mapping
4012  */
4013 static void
4014 dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo)
4015 {
4016         TableInfo  *tbinfo = pubrinfo->pubtable;
4017         PQExpBuffer query;
4018         char       *tag;
4019
4020         if (!(pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
4021                 return;
4022
4023         tag = psprintf("%s %s", pubrinfo->pubname, tbinfo->dobj.name);
4024
4025         query = createPQExpBuffer();
4026
4027         appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
4028                                           fmtId(pubrinfo->pubname));
4029         appendPQExpBuffer(query, " %s;\n",
4030                                           fmtQualifiedDumpable(tbinfo));
4031
4032         /*
4033          * There is no point in creating drop query as drop query as the drop is
4034          * done by table drop.
4035          */
4036         ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
4037                                  ARCHIVE_OPTS(.tag = tag,
4038                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
4039                                                           .description = "PUBLICATION TABLE",
4040                                                           .section = SECTION_POST_DATA,
4041                                                           .createStmt = query->data));
4042
4043         free(tag);
4044         destroyPQExpBuffer(query);
4045 }
4046
4047 /*
4048  * Is the currently connected user a superuser?
4049  */
4050 static bool
4051 is_superuser(Archive *fout)
4052 {
4053         ArchiveHandle *AH = (ArchiveHandle *) fout;
4054         const char *val;
4055
4056         val = PQparameterStatus(AH->connection, "is_superuser");
4057
4058         if (val && strcmp(val, "on") == 0)
4059                 return true;
4060
4061         return false;
4062 }
4063
4064 /*
4065  * getSubscriptions
4066  *        get information about subscriptions
4067  */
4068 void
4069 getSubscriptions(Archive *fout)
4070 {
4071         DumpOptions *dopt = fout->dopt;
4072         PQExpBuffer query;
4073         PGresult   *res;
4074         SubscriptionInfo *subinfo;
4075         int                     i_tableoid;
4076         int                     i_oid;
4077         int                     i_subname;
4078         int                     i_rolname;
4079         int                     i_subconninfo;
4080         int                     i_subslotname;
4081         int                     i_subsynccommit;
4082         int                     i_subpublications;
4083         int                     i,
4084                                 ntups;
4085
4086         if (dopt->no_subscriptions || fout->remoteVersion < 100000)
4087                 return;
4088
4089         if (!is_superuser(fout))
4090         {
4091                 int                     n;
4092
4093                 res = ExecuteSqlQuery(fout,
4094                                                           "SELECT count(*) FROM pg_subscription "
4095                                                           "WHERE subdbid = (SELECT oid FROM pg_database"
4096                                                           "                 WHERE datname = current_database())",
4097                                                           PGRES_TUPLES_OK);
4098                 n = atoi(PQgetvalue(res, 0, 0));
4099                 if (n > 0)
4100                         pg_log_warning("subscriptions not dumped because current user is not a superuser");
4101                 PQclear(res);
4102                 return;
4103         }
4104
4105         query = createPQExpBuffer();
4106
4107         resetPQExpBuffer(query);
4108
4109         /* Get the subscriptions in current database. */
4110         appendPQExpBuffer(query,
4111                                           "SELECT s.tableoid, s.oid, s.subname,"
4112                                           "(%s s.subowner) AS rolname, "
4113                                           " s.subconninfo, s.subslotname, s.subsynccommit, "
4114                                           " s.subpublications "
4115                                           "FROM pg_subscription s "
4116                                           "WHERE s.subdbid = (SELECT oid FROM pg_database"
4117                                           "                   WHERE datname = current_database())",
4118                                           username_subquery);
4119         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4120
4121         ntups = PQntuples(res);
4122
4123         i_tableoid = PQfnumber(res, "tableoid");
4124         i_oid = PQfnumber(res, "oid");
4125         i_subname = PQfnumber(res, "subname");
4126         i_rolname = PQfnumber(res, "rolname");
4127         i_subconninfo = PQfnumber(res, "subconninfo");
4128         i_subslotname = PQfnumber(res, "subslotname");
4129         i_subsynccommit = PQfnumber(res, "subsynccommit");
4130         i_subpublications = PQfnumber(res, "subpublications");
4131
4132         subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
4133
4134         for (i = 0; i < ntups; i++)
4135         {
4136                 subinfo[i].dobj.objType = DO_SUBSCRIPTION;
4137                 subinfo[i].dobj.catId.tableoid =
4138                         atooid(PQgetvalue(res, i, i_tableoid));
4139                 subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4140                 AssignDumpId(&subinfo[i].dobj);
4141                 subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
4142                 subinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4143                 subinfo[i].subconninfo = pg_strdup(PQgetvalue(res, i, i_subconninfo));
4144                 if (PQgetisnull(res, i, i_subslotname))
4145                         subinfo[i].subslotname = NULL;
4146                 else
4147                         subinfo[i].subslotname = pg_strdup(PQgetvalue(res, i, i_subslotname));
4148                 subinfo[i].subsynccommit =
4149                         pg_strdup(PQgetvalue(res, i, i_subsynccommit));
4150                 subinfo[i].subpublications =
4151                         pg_strdup(PQgetvalue(res, i, i_subpublications));
4152
4153                 if (strlen(subinfo[i].rolname) == 0)
4154                         pg_log_warning("owner of subscription \"%s\" appears to be invalid",
4155                                           subinfo[i].dobj.name);
4156
4157                 /* Decide whether we want to dump it */
4158                 selectDumpableObject(&(subinfo[i].dobj), fout);
4159         }
4160         PQclear(res);
4161
4162         destroyPQExpBuffer(query);
4163 }
4164
4165 /*
4166  * dumpSubscription
4167  *        dump the definition of the given subscription
4168  */
4169 static void
4170 dumpSubscription(Archive *fout, SubscriptionInfo *subinfo)
4171 {
4172         PQExpBuffer delq;
4173         PQExpBuffer query;
4174         PQExpBuffer publications;
4175         char       *qsubname;
4176         char      **pubnames = NULL;
4177         int                     npubnames = 0;
4178         int                     i;
4179
4180         if (!(subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
4181                 return;
4182
4183         delq = createPQExpBuffer();
4184         query = createPQExpBuffer();
4185
4186         qsubname = pg_strdup(fmtId(subinfo->dobj.name));
4187
4188         appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
4189                                           qsubname);
4190
4191         appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
4192                                           qsubname);
4193         appendStringLiteralAH(query, subinfo->subconninfo, fout);
4194
4195         /* Build list of quoted publications and append them to query. */
4196         if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
4197         {
4198                 pg_log_warning("could not parse subpublications array");
4199                 if (pubnames)
4200                         free(pubnames);
4201                 pubnames = NULL;
4202                 npubnames = 0;
4203         }
4204
4205         publications = createPQExpBuffer();
4206         for (i = 0; i < npubnames; i++)
4207         {
4208                 if (i > 0)
4209                         appendPQExpBufferStr(publications, ", ");
4210
4211                 appendPQExpBufferStr(publications, fmtId(pubnames[i]));
4212         }
4213
4214         appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
4215         if (subinfo->subslotname)
4216                 appendStringLiteralAH(query, subinfo->subslotname, fout);
4217         else
4218                 appendPQExpBufferStr(query, "NONE");
4219
4220         if (strcmp(subinfo->subsynccommit, "off") != 0)
4221                 appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
4222
4223         appendPQExpBufferStr(query, ");\n");
4224
4225         ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
4226                                  ARCHIVE_OPTS(.tag = subinfo->dobj.name,
4227                                                           .owner = subinfo->rolname,
4228                                                           .description = "SUBSCRIPTION",
4229                                                           .section = SECTION_POST_DATA,
4230                                                           .createStmt = query->data,
4231                                                           .dropStmt = delq->data));
4232
4233         if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4234                 dumpComment(fout, "SUBSCRIPTION", qsubname,
4235                                         NULL, subinfo->rolname,
4236                                         subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
4237
4238         if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
4239                 dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
4240                                          NULL, subinfo->rolname,
4241                                          subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
4242
4243         destroyPQExpBuffer(publications);
4244         if (pubnames)
4245                 free(pubnames);
4246
4247         destroyPQExpBuffer(delq);
4248         destroyPQExpBuffer(query);
4249         free(qsubname);
4250 }
4251
4252 static void
4253 binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
4254                                                                                  PQExpBuffer upgrade_buffer,
4255                                                                                  Oid pg_type_oid,
4256                                                                                  bool force_array_type)
4257 {
4258         PQExpBuffer upgrade_query = createPQExpBuffer();
4259         PGresult   *res;
4260         Oid                     pg_type_array_oid;
4261
4262         appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
4263         appendPQExpBuffer(upgrade_buffer,
4264                                           "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4265                                           pg_type_oid);
4266
4267         /* we only support old >= 8.3 for binary upgrades */
4268         appendPQExpBuffer(upgrade_query,
4269                                           "SELECT typarray "
4270                                           "FROM pg_catalog.pg_type "
4271                                           "WHERE oid = '%u'::pg_catalog.oid;",
4272                                           pg_type_oid);
4273
4274         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4275
4276         pg_type_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
4277
4278         PQclear(res);
4279
4280         if (!OidIsValid(pg_type_array_oid) && force_array_type)
4281         {
4282                 /*
4283                  * If the old version didn't assign an array type, but the new version
4284                  * does, we must select an unused type OID to assign.  This currently
4285                  * only happens for domains, when upgrading pre-v11 to v11 and up.
4286                  *
4287                  * Note: local state here is kind of ugly, but we must have some,
4288                  * since we mustn't choose the same unused OID more than once.
4289                  */
4290                 static Oid      next_possible_free_oid = FirstNormalObjectId;
4291                 bool            is_dup;
4292
4293                 do
4294                 {
4295                         ++next_possible_free_oid;
4296                         printfPQExpBuffer(upgrade_query,
4297                                                           "SELECT EXISTS(SELECT 1 "
4298                                                           "FROM pg_catalog.pg_type "
4299                                                           "WHERE oid = '%u'::pg_catalog.oid);",
4300                                                           next_possible_free_oid);
4301                         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4302                         is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
4303                         PQclear(res);
4304                 } while (is_dup);
4305
4306                 pg_type_array_oid = next_possible_free_oid;
4307         }
4308
4309         if (OidIsValid(pg_type_array_oid))
4310         {
4311                 appendPQExpBufferStr(upgrade_buffer,
4312                                                          "\n-- For binary upgrade, must preserve pg_type array oid\n");
4313                 appendPQExpBuffer(upgrade_buffer,
4314                                                   "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4315                                                   pg_type_array_oid);
4316         }
4317
4318         destroyPQExpBuffer(upgrade_query);
4319 }
4320
4321 static bool
4322 binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
4323                                                                                 PQExpBuffer upgrade_buffer,
4324                                                                                 Oid pg_rel_oid)
4325 {
4326         PQExpBuffer upgrade_query = createPQExpBuffer();
4327         PGresult   *upgrade_res;
4328         Oid                     pg_type_oid;
4329         bool            toast_set = false;
4330
4331         /*
4332          * We only support old >= 8.3 for binary upgrades.
4333          *
4334          * We purposefully ignore toast OIDs for partitioned tables; the reason is
4335          * that versions 10 and 11 have them, but 12 does not, so emitting them
4336          * causes the upgrade to fail.
4337          */
4338         appendPQExpBuffer(upgrade_query,
4339                                           "SELECT c.reltype AS crel, t.reltype AS trel "
4340                                           "FROM pg_catalog.pg_class c "
4341                                           "LEFT JOIN pg_catalog.pg_class t ON "
4342                                           "  (c.reltoastrelid = t.oid AND c.relkind <> '%c') "
4343                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
4344                                           RELKIND_PARTITIONED_TABLE, pg_rel_oid);
4345
4346         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4347
4348         pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
4349
4350         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
4351                                                                                          pg_type_oid, false);
4352
4353         if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
4354         {
4355                 /* Toast tables do not have pg_type array rows */
4356                 Oid                     pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
4357                                                                                                                   PQfnumber(upgrade_res, "trel")));
4358
4359                 appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
4360                 appendPQExpBuffer(upgrade_buffer,
4361                                                   "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4362                                                   pg_type_toast_oid);
4363
4364                 toast_set = true;
4365         }
4366
4367         PQclear(upgrade_res);
4368         destroyPQExpBuffer(upgrade_query);
4369
4370         return toast_set;
4371 }
4372
4373 static void
4374 binary_upgrade_set_pg_class_oids(Archive *fout,
4375                                                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid,
4376                                                                  bool is_index)
4377 {
4378         PQExpBuffer upgrade_query = createPQExpBuffer();
4379         PGresult   *upgrade_res;
4380         Oid                     pg_class_reltoastrelid;
4381         Oid                     pg_index_indexrelid;
4382
4383         appendPQExpBuffer(upgrade_query,
4384                                           "SELECT c.reltoastrelid, i.indexrelid "
4385                                           "FROM pg_catalog.pg_class c LEFT JOIN "
4386                                           "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
4387                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
4388                                           pg_class_oid);
4389
4390         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4391
4392         pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
4393         pg_index_indexrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "indexrelid")));
4394
4395         appendPQExpBufferStr(upgrade_buffer,
4396                                                  "\n-- For binary upgrade, must preserve pg_class oids\n");
4397
4398         if (!is_index)
4399         {
4400                 appendPQExpBuffer(upgrade_buffer,
4401                                                   "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
4402                                                   pg_class_oid);
4403                 /* only tables have toast tables, not indexes */
4404                 if (OidIsValid(pg_class_reltoastrelid))
4405                 {
4406                         /*
4407                          * One complexity is that the table definition might not require
4408                          * the creation of a TOAST table, and the TOAST table might have
4409                          * been created long after table creation, when the table was
4410                          * loaded with wide data.  By setting the TOAST oid we force
4411                          * creation of the TOAST heap and TOAST index by the backend so we
4412                          * can cleanly copy the files during binary upgrade.
4413                          */
4414
4415                         appendPQExpBuffer(upgrade_buffer,
4416                                                           "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
4417                                                           pg_class_reltoastrelid);
4418
4419                         /* every toast table has an index */
4420                         appendPQExpBuffer(upgrade_buffer,
4421                                                           "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
4422                                                           pg_index_indexrelid);
4423                 }
4424         }
4425         else
4426                 appendPQExpBuffer(upgrade_buffer,
4427                                                   "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
4428                                                   pg_class_oid);
4429
4430         appendPQExpBufferChar(upgrade_buffer, '\n');
4431
4432         PQclear(upgrade_res);
4433         destroyPQExpBuffer(upgrade_query);
4434 }
4435
4436 /*
4437  * If the DumpableObject is a member of an extension, add a suitable
4438  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
4439  *
4440  * For somewhat historical reasons, objname should already be quoted,
4441  * but not objnamespace (if any).
4442  */
4443 static void
4444 binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
4445                                                                 DumpableObject *dobj,
4446                                                                 const char *objtype,
4447                                                                 const char *objname,
4448                                                                 const char *objnamespace)
4449 {
4450         DumpableObject *extobj = NULL;
4451         int                     i;
4452
4453         if (!dobj->ext_member)
4454                 return;
4455
4456         /*
4457          * Find the parent extension.  We could avoid this search if we wanted to
4458          * add a link field to DumpableObject, but the space costs of that would
4459          * be considerable.  We assume that member objects could only have a
4460          * direct dependency on their own extension, not any others.
4461          */
4462         for (i = 0; i < dobj->nDeps; i++)
4463         {
4464                 extobj = findObjectByDumpId(dobj->dependencies[i]);
4465                 if (extobj && extobj->objType == DO_EXTENSION)
4466                         break;
4467                 extobj = NULL;
4468         }
4469         if (extobj == NULL)
4470                 fatal("could not find parent extension for %s %s",
4471                                           objtype, objname);
4472
4473         appendPQExpBufferStr(upgrade_buffer,
4474                                                  "\n-- For binary upgrade, handle extension membership the hard way\n");
4475         appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
4476                                           fmtId(extobj->name),
4477                                           objtype);
4478         if (objnamespace && *objnamespace)
4479                 appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
4480         appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
4481 }
4482
4483 /*
4484  * getNamespaces:
4485  *        read all namespaces in the system catalogs and return them in the
4486  * NamespaceInfo* structure
4487  *
4488  *      numNamespaces is set to the number of namespaces read in
4489  */
4490 NamespaceInfo *
4491 getNamespaces(Archive *fout, int *numNamespaces)
4492 {
4493         DumpOptions *dopt = fout->dopt;
4494         PGresult   *res;
4495         int                     ntups;
4496         int                     i;
4497         PQExpBuffer query;
4498         NamespaceInfo *nsinfo;
4499         int                     i_tableoid;
4500         int                     i_oid;
4501         int                     i_nspname;
4502         int                     i_rolname;
4503         int                     i_nspacl;
4504         int                     i_rnspacl;
4505         int                     i_initnspacl;
4506         int                     i_initrnspacl;
4507
4508         query = createPQExpBuffer();
4509
4510         /*
4511          * we fetch all namespaces including system ones, so that every object we
4512          * read in can be linked to a containing namespace.
4513          */
4514         if (fout->remoteVersion >= 90600)
4515         {
4516                 PQExpBuffer acl_subquery = createPQExpBuffer();
4517                 PQExpBuffer racl_subquery = createPQExpBuffer();
4518                 PQExpBuffer init_acl_subquery = createPQExpBuffer();
4519                 PQExpBuffer init_racl_subquery = createPQExpBuffer();
4520
4521                 buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
4522                                                 init_racl_subquery, "n.nspacl", "n.nspowner", "'n'",
4523                                                 dopt->binary_upgrade);
4524
4525                 appendPQExpBuffer(query, "SELECT n.tableoid, n.oid, n.nspname, "
4526                                                   "(%s nspowner) AS rolname, "
4527                                                   "%s as nspacl, "
4528                                                   "%s as rnspacl, "
4529                                                   "%s as initnspacl, "
4530                                                   "%s as initrnspacl "
4531                                                   "FROM pg_namespace n "
4532                                                   "LEFT JOIN pg_init_privs pip "
4533                                                   "ON (n.oid = pip.objoid "
4534                                                   "AND pip.classoid = 'pg_namespace'::regclass "
4535                                                   "AND pip.objsubid = 0",
4536                                                   username_subquery,
4537                                                   acl_subquery->data,
4538                                                   racl_subquery->data,
4539                                                   init_acl_subquery->data,
4540                                                   init_racl_subquery->data);
4541
4542                 appendPQExpBuffer(query, ") ");
4543
4544                 destroyPQExpBuffer(acl_subquery);
4545                 destroyPQExpBuffer(racl_subquery);
4546                 destroyPQExpBuffer(init_acl_subquery);
4547                 destroyPQExpBuffer(init_racl_subquery);
4548         }
4549         else
4550                 appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
4551                                                   "(%s nspowner) AS rolname, "
4552                                                   "nspacl, NULL as rnspacl, "
4553                                                   "NULL AS initnspacl, NULL as initrnspacl "
4554                                                   "FROM pg_namespace",
4555                                                   username_subquery);
4556
4557         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4558
4559         ntups = PQntuples(res);
4560
4561         nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
4562
4563         i_tableoid = PQfnumber(res, "tableoid");
4564         i_oid = PQfnumber(res, "oid");
4565         i_nspname = PQfnumber(res, "nspname");
4566         i_rolname = PQfnumber(res, "rolname");
4567         i_nspacl = PQfnumber(res, "nspacl");
4568         i_rnspacl = PQfnumber(res, "rnspacl");
4569         i_initnspacl = PQfnumber(res, "initnspacl");
4570         i_initrnspacl = PQfnumber(res, "initrnspacl");
4571
4572         for (i = 0; i < ntups; i++)
4573         {
4574                 nsinfo[i].dobj.objType = DO_NAMESPACE;
4575                 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4576                 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4577                 AssignDumpId(&nsinfo[i].dobj);
4578                 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
4579                 nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4580                 nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
4581                 nsinfo[i].rnspacl = pg_strdup(PQgetvalue(res, i, i_rnspacl));
4582                 nsinfo[i].initnspacl = pg_strdup(PQgetvalue(res, i, i_initnspacl));
4583                 nsinfo[i].initrnspacl = pg_strdup(PQgetvalue(res, i, i_initrnspacl));
4584
4585                 /* Decide whether to dump this namespace */
4586                 selectDumpableNamespace(&nsinfo[i], fout);
4587
4588                 /*
4589                  * Do not try to dump ACL if the ACL is empty or the default.
4590                  *
4591                  * This is useful because, for some schemas/objects, the only
4592                  * component we are going to try and dump is the ACL and if we can
4593                  * remove that then 'dump' goes to zero/false and we don't consider
4594                  * this object for dumping at all later on.
4595                  */
4596                 if (PQgetisnull(res, i, i_nspacl) && PQgetisnull(res, i, i_rnspacl) &&
4597                         PQgetisnull(res, i, i_initnspacl) &&
4598                         PQgetisnull(res, i, i_initrnspacl))
4599                         nsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4600
4601                 if (strlen(nsinfo[i].rolname) == 0)
4602                         pg_log_warning("owner of schema \"%s\" appears to be invalid",
4603                                           nsinfo[i].dobj.name);
4604         }
4605
4606         PQclear(res);
4607         destroyPQExpBuffer(query);
4608
4609         *numNamespaces = ntups;
4610
4611         return nsinfo;
4612 }
4613
4614 /*
4615  * findNamespace:
4616  *              given a namespace OID, look up the info read by getNamespaces
4617  */
4618 static NamespaceInfo *
4619 findNamespace(Archive *fout, Oid nsoid)
4620 {
4621         NamespaceInfo *nsinfo;
4622
4623         nsinfo = findNamespaceByOid(nsoid);
4624         if (nsinfo == NULL)
4625                 fatal("schema with OID %u does not exist", nsoid);
4626         return nsinfo;
4627 }
4628
4629 /*
4630  * getExtensions:
4631  *        read all extensions in the system catalogs and return them in the
4632  * ExtensionInfo* structure
4633  *
4634  *      numExtensions is set to the number of extensions read in
4635  */
4636 ExtensionInfo *
4637 getExtensions(Archive *fout, int *numExtensions)
4638 {
4639         DumpOptions *dopt = fout->dopt;
4640         PGresult   *res;
4641         int                     ntups;
4642         int                     i;
4643         PQExpBuffer query;
4644         ExtensionInfo *extinfo;
4645         int                     i_tableoid;
4646         int                     i_oid;
4647         int                     i_extname;
4648         int                     i_nspname;
4649         int                     i_extrelocatable;
4650         int                     i_extversion;
4651         int                     i_extconfig;
4652         int                     i_extcondition;
4653
4654         /*
4655          * Before 9.1, there are no extensions.
4656          */
4657         if (fout->remoteVersion < 90100)
4658         {
4659                 *numExtensions = 0;
4660                 return NULL;
4661         }
4662
4663         query = createPQExpBuffer();
4664
4665         appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
4666                                                  "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
4667                                                  "FROM pg_extension x "
4668                                                  "JOIN pg_namespace n ON n.oid = x.extnamespace");
4669
4670         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4671
4672         ntups = PQntuples(res);
4673
4674         extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
4675
4676         i_tableoid = PQfnumber(res, "tableoid");
4677         i_oid = PQfnumber(res, "oid");
4678         i_extname = PQfnumber(res, "extname");
4679         i_nspname = PQfnumber(res, "nspname");
4680         i_extrelocatable = PQfnumber(res, "extrelocatable");
4681         i_extversion = PQfnumber(res, "extversion");
4682         i_extconfig = PQfnumber(res, "extconfig");
4683         i_extcondition = PQfnumber(res, "extcondition");
4684
4685         for (i = 0; i < ntups; i++)
4686         {
4687                 extinfo[i].dobj.objType = DO_EXTENSION;
4688                 extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4689                 extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4690                 AssignDumpId(&extinfo[i].dobj);
4691                 extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
4692                 extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
4693                 extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
4694                 extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
4695                 extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
4696                 extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
4697
4698                 /* Decide whether we want to dump it */
4699                 selectDumpableExtension(&(extinfo[i]), dopt);
4700         }
4701
4702         PQclear(res);
4703         destroyPQExpBuffer(query);
4704
4705         *numExtensions = ntups;
4706
4707         return extinfo;
4708 }
4709
4710 /*
4711  * getTypes:
4712  *        read all types in the system catalogs and return them in the
4713  * TypeInfo* structure
4714  *
4715  *      numTypes is set to the number of types read in
4716  *
4717  * NB: this must run after getFuncs() because we assume we can do
4718  * findFuncByOid().
4719  */
4720 TypeInfo *
4721 getTypes(Archive *fout, int *numTypes)
4722 {
4723         DumpOptions *dopt = fout->dopt;
4724         PGresult   *res;
4725         int                     ntups;
4726         int                     i;
4727         PQExpBuffer query = createPQExpBuffer();
4728         TypeInfo   *tyinfo;
4729         ShellTypeInfo *stinfo;
4730         int                     i_tableoid;
4731         int                     i_oid;
4732         int                     i_typname;
4733         int                     i_typnamespace;
4734         int                     i_typacl;
4735         int                     i_rtypacl;
4736         int                     i_inittypacl;
4737         int                     i_initrtypacl;
4738         int                     i_rolname;
4739         int                     i_typelem;
4740         int                     i_typrelid;
4741         int                     i_typrelkind;
4742         int                     i_typtype;
4743         int                     i_typisdefined;
4744         int                     i_isarray;
4745
4746         /*
4747          * we include even the built-in types because those may be used as array
4748          * elements by user-defined types
4749          *
4750          * we filter out the built-in types when we dump out the types
4751          *
4752          * same approach for undefined (shell) types and array types
4753          *
4754          * Note: as of 8.3 we can reliably detect whether a type is an
4755          * auto-generated array type by checking the element type's typarray.
4756          * (Before that the test is capable of generating false positives.) We
4757          * still check for name beginning with '_', though, so as to avoid the
4758          * cost of the subselect probe for all standard types.  This would have to
4759          * be revisited if the backend ever allows renaming of array types.
4760          */
4761
4762         if (fout->remoteVersion >= 90600)
4763         {
4764                 PQExpBuffer acl_subquery = createPQExpBuffer();
4765                 PQExpBuffer racl_subquery = createPQExpBuffer();
4766                 PQExpBuffer initacl_subquery = createPQExpBuffer();
4767                 PQExpBuffer initracl_subquery = createPQExpBuffer();
4768
4769                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
4770                                                 initracl_subquery, "t.typacl", "t.typowner", "'T'",
4771                                                 dopt->binary_upgrade);
4772
4773                 appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, t.typname, "
4774                                                   "t.typnamespace, "
4775                                                   "%s AS typacl, "
4776                                                   "%s AS rtypacl, "
4777                                                   "%s AS inittypacl, "
4778                                                   "%s AS initrtypacl, "
4779                                                   "(%s t.typowner) AS rolname, "
4780                                                   "t.typelem, t.typrelid, "
4781                                                   "CASE WHEN t.typrelid = 0 THEN ' '::\"char\" "
4782                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = t.typrelid) END AS typrelkind, "
4783                                                   "t.typtype, t.typisdefined, "
4784                                                   "t.typname[0] = '_' AND t.typelem != 0 AND "
4785                                                   "(SELECT typarray FROM pg_type te WHERE oid = t.typelem) = t.oid AS isarray "
4786                                                   "FROM pg_type t "
4787                                                   "LEFT JOIN pg_init_privs pip ON "
4788                                                   "(t.oid = pip.objoid "
4789                                                   "AND pip.classoid = 'pg_type'::regclass "
4790                                                   "AND pip.objsubid = 0) ",
4791                                                   acl_subquery->data,
4792                                                   racl_subquery->data,
4793                                                   initacl_subquery->data,
4794                                                   initracl_subquery->data,
4795                                                   username_subquery);
4796
4797                 destroyPQExpBuffer(acl_subquery);
4798                 destroyPQExpBuffer(racl_subquery);
4799                 destroyPQExpBuffer(initacl_subquery);
4800                 destroyPQExpBuffer(initracl_subquery);
4801         }
4802         else if (fout->remoteVersion >= 90200)
4803         {
4804                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4805                                                   "typnamespace, typacl, NULL as rtypacl, "
4806                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4807                                                   "(%s typowner) AS rolname, "
4808                                                   "typelem, typrelid, "
4809                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4810                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4811                                                   "typtype, typisdefined, "
4812                                                   "typname[0] = '_' AND typelem != 0 AND "
4813                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4814                                                   "FROM pg_type",
4815                                                   username_subquery);
4816         }
4817         else if (fout->remoteVersion >= 80300)
4818         {
4819                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4820                                                   "typnamespace, NULL AS typacl, NULL as rtypacl, "
4821                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4822                                                   "(%s typowner) AS rolname, "
4823                                                   "typelem, typrelid, "
4824                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4825                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4826                                                   "typtype, typisdefined, "
4827                                                   "typname[0] = '_' AND typelem != 0 AND "
4828                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4829                                                   "FROM pg_type",
4830                                                   username_subquery);
4831         }
4832         else
4833         {
4834                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4835                                                   "typnamespace, NULL AS typacl, NULL as rtypacl, "
4836                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4837                                                   "(%s typowner) AS rolname, "
4838                                                   "typelem, typrelid, "
4839                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4840                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4841                                                   "typtype, typisdefined, "
4842                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
4843                                                   "FROM pg_type",
4844                                                   username_subquery);
4845         }
4846
4847         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4848
4849         ntups = PQntuples(res);
4850
4851         tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
4852
4853         i_tableoid = PQfnumber(res, "tableoid");
4854         i_oid = PQfnumber(res, "oid");
4855         i_typname = PQfnumber(res, "typname");
4856         i_typnamespace = PQfnumber(res, "typnamespace");
4857         i_typacl = PQfnumber(res, "typacl");
4858         i_rtypacl = PQfnumber(res, "rtypacl");
4859         i_inittypacl = PQfnumber(res, "inittypacl");
4860         i_initrtypacl = PQfnumber(res, "initrtypacl");
4861         i_rolname = PQfnumber(res, "rolname");
4862         i_typelem = PQfnumber(res, "typelem");
4863         i_typrelid = PQfnumber(res, "typrelid");
4864         i_typrelkind = PQfnumber(res, "typrelkind");
4865         i_typtype = PQfnumber(res, "typtype");
4866         i_typisdefined = PQfnumber(res, "typisdefined");
4867         i_isarray = PQfnumber(res, "isarray");
4868
4869         for (i = 0; i < ntups; i++)
4870         {
4871                 tyinfo[i].dobj.objType = DO_TYPE;
4872                 tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4873                 tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4874                 AssignDumpId(&tyinfo[i].dobj);
4875                 tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
4876                 tyinfo[i].dobj.namespace =
4877                         findNamespace(fout,
4878                                                   atooid(PQgetvalue(res, i, i_typnamespace)));
4879                 tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4880                 tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
4881                 tyinfo[i].rtypacl = pg_strdup(PQgetvalue(res, i, i_rtypacl));
4882                 tyinfo[i].inittypacl = pg_strdup(PQgetvalue(res, i, i_inittypacl));
4883                 tyinfo[i].initrtypacl = pg_strdup(PQgetvalue(res, i, i_initrtypacl));
4884                 tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
4885                 tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
4886                 tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
4887                 tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
4888                 tyinfo[i].shellType = NULL;
4889
4890                 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
4891                         tyinfo[i].isDefined = true;
4892                 else
4893                         tyinfo[i].isDefined = false;
4894
4895                 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
4896                         tyinfo[i].isArray = true;
4897                 else
4898                         tyinfo[i].isArray = false;
4899
4900                 /* Decide whether we want to dump it */
4901                 selectDumpableType(&tyinfo[i], fout);
4902
4903                 /* Do not try to dump ACL if no ACL exists. */
4904                 if (PQgetisnull(res, i, i_typacl) && PQgetisnull(res, i, i_rtypacl) &&
4905                         PQgetisnull(res, i, i_inittypacl) &&
4906                         PQgetisnull(res, i, i_initrtypacl))
4907                         tyinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4908
4909                 /*
4910                  * If it's a domain, fetch info about its constraints, if any
4911                  */
4912                 tyinfo[i].nDomChecks = 0;
4913                 tyinfo[i].domChecks = NULL;
4914                 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4915                         tyinfo[i].typtype == TYPTYPE_DOMAIN)
4916                         getDomainConstraints(fout, &(tyinfo[i]));
4917
4918                 /*
4919                  * If it's a base type, make a DumpableObject representing a shell
4920                  * definition of the type.  We will need to dump that ahead of the I/O
4921                  * functions for the type.  Similarly, range types need a shell
4922                  * definition in case they have a canonicalize function.
4923                  *
4924                  * Note: the shell type doesn't have a catId.  You might think it
4925                  * should copy the base type's catId, but then it might capture the
4926                  * pg_depend entries for the type, which we don't want.
4927                  */
4928                 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4929                         (tyinfo[i].typtype == TYPTYPE_BASE ||
4930                          tyinfo[i].typtype == TYPTYPE_RANGE))
4931                 {
4932                         stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
4933                         stinfo->dobj.objType = DO_SHELL_TYPE;
4934                         stinfo->dobj.catId = nilCatalogId;
4935                         AssignDumpId(&stinfo->dobj);
4936                         stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
4937                         stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
4938                         stinfo->baseType = &(tyinfo[i]);
4939                         tyinfo[i].shellType = stinfo;
4940
4941                         /*
4942                          * Initially mark the shell type as not to be dumped.  We'll only
4943                          * dump it if the I/O or canonicalize functions need to be dumped;
4944                          * this is taken care of while sorting dependencies.
4945                          */
4946                         stinfo->dobj.dump = DUMP_COMPONENT_NONE;
4947                 }
4948
4949                 if (strlen(tyinfo[i].rolname) == 0)
4950                         pg_log_warning("owner of data type \"%s\" appears to be invalid",
4951                                           tyinfo[i].dobj.name);
4952         }
4953
4954         *numTypes = ntups;
4955
4956         PQclear(res);
4957
4958         destroyPQExpBuffer(query);
4959
4960         return tyinfo;
4961 }
4962
4963 /*
4964  * getOperators:
4965  *        read all operators in the system catalogs and return them in the
4966  * OprInfo* structure
4967  *
4968  *      numOprs is set to the number of operators read in
4969  */
4970 OprInfo *
4971 getOperators(Archive *fout, int *numOprs)
4972 {
4973         PGresult   *res;
4974         int                     ntups;
4975         int                     i;
4976         PQExpBuffer query = createPQExpBuffer();
4977         OprInfo    *oprinfo;
4978         int                     i_tableoid;
4979         int                     i_oid;
4980         int                     i_oprname;
4981         int                     i_oprnamespace;
4982         int                     i_rolname;
4983         int                     i_oprkind;
4984         int                     i_oprcode;
4985
4986         /*
4987          * find all operators, including builtin operators; we filter out
4988          * system-defined operators at dump-out time.
4989          */
4990
4991         appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
4992                                           "oprnamespace, "
4993                                           "(%s oprowner) AS rolname, "
4994                                           "oprkind, "
4995                                           "oprcode::oid AS oprcode "
4996                                           "FROM pg_operator",
4997                                           username_subquery);
4998
4999         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5000
5001         ntups = PQntuples(res);
5002         *numOprs = ntups;
5003
5004         oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
5005
5006         i_tableoid = PQfnumber(res, "tableoid");
5007         i_oid = PQfnumber(res, "oid");
5008         i_oprname = PQfnumber(res, "oprname");
5009         i_oprnamespace = PQfnumber(res, "oprnamespace");
5010         i_rolname = PQfnumber(res, "rolname");
5011         i_oprkind = PQfnumber(res, "oprkind");
5012         i_oprcode = PQfnumber(res, "oprcode");
5013
5014         for (i = 0; i < ntups; i++)
5015         {
5016                 oprinfo[i].dobj.objType = DO_OPERATOR;
5017                 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5018                 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5019                 AssignDumpId(&oprinfo[i].dobj);
5020                 oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
5021                 oprinfo[i].dobj.namespace =
5022                         findNamespace(fout,
5023                                                   atooid(PQgetvalue(res, i, i_oprnamespace)));
5024                 oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5025                 oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
5026                 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
5027
5028                 /* Decide whether we want to dump it */
5029                 selectDumpableObject(&(oprinfo[i].dobj), fout);
5030
5031                 /* Operators do not currently have ACLs. */
5032                 oprinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5033
5034                 if (strlen(oprinfo[i].rolname) == 0)
5035                         pg_log_warning("owner of operator \"%s\" appears to be invalid",
5036                                           oprinfo[i].dobj.name);
5037         }
5038
5039         PQclear(res);
5040
5041         destroyPQExpBuffer(query);
5042
5043         return oprinfo;
5044 }
5045
5046 /*
5047  * getCollations:
5048  *        read all collations in the system catalogs and return them in the
5049  * CollInfo* structure
5050  *
5051  *      numCollations is set to the number of collations read in
5052  */
5053 CollInfo *
5054 getCollations(Archive *fout, int *numCollations)
5055 {
5056         PGresult   *res;
5057         int                     ntups;
5058         int                     i;
5059         PQExpBuffer query;
5060         CollInfo   *collinfo;
5061         int                     i_tableoid;
5062         int                     i_oid;
5063         int                     i_collname;
5064         int                     i_collnamespace;
5065         int                     i_rolname;
5066
5067         /* Collations didn't exist pre-9.1 */
5068         if (fout->remoteVersion < 90100)
5069         {
5070                 *numCollations = 0;
5071                 return NULL;
5072         }
5073
5074         query = createPQExpBuffer();
5075
5076         /*
5077          * find all collations, including builtin collations; we filter out
5078          * system-defined collations at dump-out time.
5079          */
5080
5081         appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
5082                                           "collnamespace, "
5083                                           "(%s collowner) AS rolname "
5084                                           "FROM pg_collation",
5085                                           username_subquery);
5086
5087         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5088
5089         ntups = PQntuples(res);
5090         *numCollations = ntups;
5091
5092         collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
5093
5094         i_tableoid = PQfnumber(res, "tableoid");
5095         i_oid = PQfnumber(res, "oid");
5096         i_collname = PQfnumber(res, "collname");
5097         i_collnamespace = PQfnumber(res, "collnamespace");
5098         i_rolname = PQfnumber(res, "rolname");
5099
5100         for (i = 0; i < ntups; i++)
5101         {
5102                 collinfo[i].dobj.objType = DO_COLLATION;
5103                 collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5104                 collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5105                 AssignDumpId(&collinfo[i].dobj);
5106                 collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
5107                 collinfo[i].dobj.namespace =
5108                         findNamespace(fout,
5109                                                   atooid(PQgetvalue(res, i, i_collnamespace)));
5110                 collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5111
5112                 /* Decide whether we want to dump it */
5113                 selectDumpableObject(&(collinfo[i].dobj), fout);
5114
5115                 /* Collations do not currently have ACLs. */
5116                 collinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5117         }
5118
5119         PQclear(res);
5120
5121         destroyPQExpBuffer(query);
5122
5123         return collinfo;
5124 }
5125
5126 /*
5127  * getConversions:
5128  *        read all conversions in the system catalogs and return them in the
5129  * ConvInfo* structure
5130  *
5131  *      numConversions is set to the number of conversions read in
5132  */
5133 ConvInfo *
5134 getConversions(Archive *fout, int *numConversions)
5135 {
5136         PGresult   *res;
5137         int                     ntups;
5138         int                     i;
5139         PQExpBuffer query;
5140         ConvInfo   *convinfo;
5141         int                     i_tableoid;
5142         int                     i_oid;
5143         int                     i_conname;
5144         int                     i_connamespace;
5145         int                     i_rolname;
5146
5147         query = createPQExpBuffer();
5148
5149         /*
5150          * find all conversions, including builtin conversions; we filter out
5151          * system-defined conversions at dump-out time.
5152          */
5153
5154         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5155                                           "connamespace, "
5156                                           "(%s conowner) AS rolname "
5157                                           "FROM pg_conversion",
5158                                           username_subquery);
5159
5160         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5161
5162         ntups = PQntuples(res);
5163         *numConversions = ntups;
5164
5165         convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
5166
5167         i_tableoid = PQfnumber(res, "tableoid");
5168         i_oid = PQfnumber(res, "oid");
5169         i_conname = PQfnumber(res, "conname");
5170         i_connamespace = PQfnumber(res, "connamespace");
5171         i_rolname = PQfnumber(res, "rolname");
5172
5173         for (i = 0; i < ntups; i++)
5174         {
5175                 convinfo[i].dobj.objType = DO_CONVERSION;
5176                 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5177                 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5178                 AssignDumpId(&convinfo[i].dobj);
5179                 convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
5180                 convinfo[i].dobj.namespace =
5181                         findNamespace(fout,
5182                                                   atooid(PQgetvalue(res, i, i_connamespace)));
5183                 convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5184
5185                 /* Decide whether we want to dump it */
5186                 selectDumpableObject(&(convinfo[i].dobj), fout);
5187
5188                 /* Conversions do not currently have ACLs. */
5189                 convinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5190         }
5191
5192         PQclear(res);
5193
5194         destroyPQExpBuffer(query);
5195
5196         return convinfo;
5197 }
5198
5199 /*
5200  * getAccessMethods:
5201  *        read all user-defined access methods in the system catalogs and return
5202  *        them in the AccessMethodInfo* structure
5203  *
5204  *      numAccessMethods is set to the number of access methods read in
5205  */
5206 AccessMethodInfo *
5207 getAccessMethods(Archive *fout, int *numAccessMethods)
5208 {
5209         PGresult   *res;
5210         int                     ntups;
5211         int                     i;
5212         PQExpBuffer query;
5213         AccessMethodInfo *aminfo;
5214         int                     i_tableoid;
5215         int                     i_oid;
5216         int                     i_amname;
5217         int                     i_amhandler;
5218         int                     i_amtype;
5219
5220         /* Before 9.6, there are no user-defined access methods */
5221         if (fout->remoteVersion < 90600)
5222         {
5223                 *numAccessMethods = 0;
5224                 return NULL;
5225         }
5226
5227         query = createPQExpBuffer();
5228
5229         /* Select all access methods from pg_am table */
5230         appendPQExpBuffer(query, "SELECT tableoid, oid, amname, amtype, "
5231                                           "amhandler::pg_catalog.regproc AS amhandler "
5232                                           "FROM pg_am");
5233
5234         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5235
5236         ntups = PQntuples(res);
5237         *numAccessMethods = ntups;
5238
5239         aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
5240
5241         i_tableoid = PQfnumber(res, "tableoid");
5242         i_oid = PQfnumber(res, "oid");
5243         i_amname = PQfnumber(res, "amname");
5244         i_amhandler = PQfnumber(res, "amhandler");
5245         i_amtype = PQfnumber(res, "amtype");
5246
5247         for (i = 0; i < ntups; i++)
5248         {
5249                 aminfo[i].dobj.objType = DO_ACCESS_METHOD;
5250                 aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5251                 aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5252                 AssignDumpId(&aminfo[i].dobj);
5253                 aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
5254                 aminfo[i].dobj.namespace = NULL;
5255                 aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
5256                 aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
5257
5258                 /* Decide whether we want to dump it */
5259                 selectDumpableAccessMethod(&(aminfo[i]), fout);
5260
5261                 /* Access methods do not currently have ACLs. */
5262                 aminfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5263         }
5264
5265         PQclear(res);
5266
5267         destroyPQExpBuffer(query);
5268
5269         return aminfo;
5270 }
5271
5272
5273 /*
5274  * getOpclasses:
5275  *        read all opclasses in the system catalogs and return them in the
5276  * OpclassInfo* structure
5277  *
5278  *      numOpclasses is set to the number of opclasses read in
5279  */
5280 OpclassInfo *
5281 getOpclasses(Archive *fout, int *numOpclasses)
5282 {
5283         PGresult   *res;
5284         int                     ntups;
5285         int                     i;
5286         PQExpBuffer query = createPQExpBuffer();
5287         OpclassInfo *opcinfo;
5288         int                     i_tableoid;
5289         int                     i_oid;
5290         int                     i_opcname;
5291         int                     i_opcnamespace;
5292         int                     i_rolname;
5293
5294         /*
5295          * find all opclasses, including builtin opclasses; we filter out
5296          * system-defined opclasses at dump-out time.
5297          */
5298
5299         appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
5300                                           "opcnamespace, "
5301                                           "(%s opcowner) AS rolname "
5302                                           "FROM pg_opclass",
5303                                           username_subquery);
5304
5305         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5306
5307         ntups = PQntuples(res);
5308         *numOpclasses = ntups;
5309
5310         opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
5311
5312         i_tableoid = PQfnumber(res, "tableoid");
5313         i_oid = PQfnumber(res, "oid");
5314         i_opcname = PQfnumber(res, "opcname");
5315         i_opcnamespace = PQfnumber(res, "opcnamespace");
5316         i_rolname = PQfnumber(res, "rolname");
5317
5318         for (i = 0; i < ntups; i++)
5319         {
5320                 opcinfo[i].dobj.objType = DO_OPCLASS;
5321                 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5322                 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5323                 AssignDumpId(&opcinfo[i].dobj);
5324                 opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
5325                 opcinfo[i].dobj.namespace =
5326                         findNamespace(fout,
5327                                                   atooid(PQgetvalue(res, i, i_opcnamespace)));
5328                 opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5329
5330                 /* Decide whether we want to dump it */
5331                 selectDumpableObject(&(opcinfo[i].dobj), fout);
5332
5333                 /* Op Classes do not currently have ACLs. */
5334                 opcinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5335
5336                 if (strlen(opcinfo[i].rolname) == 0)
5337                         pg_log_warning("owner of operator class \"%s\" appears to be invalid",
5338                                           opcinfo[i].dobj.name);
5339         }
5340
5341         PQclear(res);
5342
5343         destroyPQExpBuffer(query);
5344
5345         return opcinfo;
5346 }
5347
5348 /*
5349  * getOpfamilies:
5350  *        read all opfamilies in the system catalogs and return them in the
5351  * OpfamilyInfo* structure
5352  *
5353  *      numOpfamilies is set to the number of opfamilies read in
5354  */
5355 OpfamilyInfo *
5356 getOpfamilies(Archive *fout, int *numOpfamilies)
5357 {
5358         PGresult   *res;
5359         int                     ntups;
5360         int                     i;
5361         PQExpBuffer query;
5362         OpfamilyInfo *opfinfo;
5363         int                     i_tableoid;
5364         int                     i_oid;
5365         int                     i_opfname;
5366         int                     i_opfnamespace;
5367         int                     i_rolname;
5368
5369         /* Before 8.3, there is no separate concept of opfamilies */
5370         if (fout->remoteVersion < 80300)
5371         {
5372                 *numOpfamilies = 0;
5373                 return NULL;
5374         }
5375
5376         query = createPQExpBuffer();
5377
5378         /*
5379          * find all opfamilies, including builtin opfamilies; we filter out
5380          * system-defined opfamilies at dump-out time.
5381          */
5382
5383         appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
5384                                           "opfnamespace, "
5385                                           "(%s opfowner) AS rolname "
5386                                           "FROM pg_opfamily",
5387                                           username_subquery);
5388
5389         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5390
5391         ntups = PQntuples(res);
5392         *numOpfamilies = ntups;
5393
5394         opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
5395
5396         i_tableoid = PQfnumber(res, "tableoid");
5397         i_oid = PQfnumber(res, "oid");
5398         i_opfname = PQfnumber(res, "opfname");
5399         i_opfnamespace = PQfnumber(res, "opfnamespace");
5400         i_rolname = PQfnumber(res, "rolname");
5401
5402         for (i = 0; i < ntups; i++)
5403         {
5404                 opfinfo[i].dobj.objType = DO_OPFAMILY;
5405                 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5406                 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5407                 AssignDumpId(&opfinfo[i].dobj);
5408                 opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
5409                 opfinfo[i].dobj.namespace =
5410                         findNamespace(fout,
5411                                                   atooid(PQgetvalue(res, i, i_opfnamespace)));
5412                 opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5413
5414                 /* Decide whether we want to dump it */
5415                 selectDumpableObject(&(opfinfo[i].dobj), fout);
5416
5417                 /* Extensions do not currently have ACLs. */
5418                 opfinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5419
5420                 if (strlen(opfinfo[i].rolname) == 0)
5421                         pg_log_warning("owner of operator family \"%s\" appears to be invalid",
5422                                           opfinfo[i].dobj.name);
5423         }
5424
5425         PQclear(res);
5426
5427         destroyPQExpBuffer(query);
5428
5429         return opfinfo;
5430 }
5431
5432 /*
5433  * getAggregates:
5434  *        read all the user-defined aggregates in the system catalogs and
5435  * return them in the AggInfo* structure
5436  *
5437  * numAggs is set to the number of aggregates read in
5438  */
5439 AggInfo *
5440 getAggregates(Archive *fout, int *numAggs)
5441 {
5442         DumpOptions *dopt = fout->dopt;
5443         PGresult   *res;
5444         int                     ntups;
5445         int                     i;
5446         PQExpBuffer query = createPQExpBuffer();
5447         AggInfo    *agginfo;
5448         int                     i_tableoid;
5449         int                     i_oid;
5450         int                     i_aggname;
5451         int                     i_aggnamespace;
5452         int                     i_pronargs;
5453         int                     i_proargtypes;
5454         int                     i_rolname;
5455         int                     i_aggacl;
5456         int                     i_raggacl;
5457         int                     i_initaggacl;
5458         int                     i_initraggacl;
5459
5460         /*
5461          * Find all interesting aggregates.  See comment in getFuncs() for the
5462          * rationale behind the filtering logic.
5463          */
5464         if (fout->remoteVersion >= 90600)
5465         {
5466                 PQExpBuffer acl_subquery = createPQExpBuffer();
5467                 PQExpBuffer racl_subquery = createPQExpBuffer();
5468                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5469                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5470                 const char *agg_check;
5471
5472                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5473                                                 initracl_subquery, "p.proacl", "p.proowner", "'f'",
5474                                                 dopt->binary_upgrade);
5475
5476                 agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
5477                                          : "p.proisagg");
5478
5479                 appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
5480                                                   "p.proname AS aggname, "
5481                                                   "p.pronamespace AS aggnamespace, "
5482                                                   "p.pronargs, p.proargtypes, "
5483                                                   "(%s p.proowner) AS rolname, "
5484                                                   "%s AS aggacl, "
5485                                                   "%s AS raggacl, "
5486                                                   "%s AS initaggacl, "
5487                                                   "%s AS initraggacl "
5488                                                   "FROM pg_proc p "
5489                                                   "LEFT JOIN pg_init_privs pip ON "
5490                                                   "(p.oid = pip.objoid "
5491                                                   "AND pip.classoid = 'pg_proc'::regclass "
5492                                                   "AND pip.objsubid = 0) "
5493                                                   "WHERE %s AND ("
5494                                                   "p.pronamespace != "
5495                                                   "(SELECT oid FROM pg_namespace "
5496                                                   "WHERE nspname = 'pg_catalog') OR "
5497                                                   "p.proacl IS DISTINCT FROM pip.initprivs",
5498                                                   username_subquery,
5499                                                   acl_subquery->data,
5500                                                   racl_subquery->data,
5501                                                   initacl_subquery->data,
5502                                                   initracl_subquery->data,
5503                                                   agg_check);
5504                 if (dopt->binary_upgrade)
5505                         appendPQExpBufferStr(query,
5506                                                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5507                                                                  "classid = 'pg_proc'::regclass AND "
5508                                                                  "objid = p.oid AND "
5509                                                                  "refclassid = 'pg_extension'::regclass AND "
5510                                                                  "deptype = 'e')");
5511                 appendPQExpBufferChar(query, ')');
5512
5513                 destroyPQExpBuffer(acl_subquery);
5514                 destroyPQExpBuffer(racl_subquery);
5515                 destroyPQExpBuffer(initacl_subquery);
5516                 destroyPQExpBuffer(initracl_subquery);
5517         }
5518         else if (fout->remoteVersion >= 80200)
5519         {
5520                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
5521                                                   "pronamespace AS aggnamespace, "
5522                                                   "pronargs, proargtypes, "
5523                                                   "(%s proowner) AS rolname, "
5524                                                   "proacl AS aggacl, "
5525                                                   "NULL AS raggacl, "
5526                                                   "NULL AS initaggacl, NULL AS initraggacl "
5527                                                   "FROM pg_proc p "
5528                                                   "WHERE proisagg AND ("
5529                                                   "pronamespace != "
5530                                                   "(SELECT oid FROM pg_namespace "
5531                                                   "WHERE nspname = 'pg_catalog')",
5532                                                   username_subquery);
5533                 if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
5534                         appendPQExpBufferStr(query,
5535                                                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5536                                                                  "classid = 'pg_proc'::regclass AND "
5537                                                                  "objid = p.oid AND "
5538                                                                  "refclassid = 'pg_extension'::regclass AND "
5539                                                                  "deptype = 'e')");
5540                 appendPQExpBufferChar(query, ')');
5541         }
5542         else
5543         {
5544                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
5545                                                   "pronamespace AS aggnamespace, "
5546                                                   "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
5547                                                   "proargtypes, "
5548                                                   "(%s proowner) AS rolname, "
5549                                                   "proacl AS aggacl, "
5550                                                   "NULL AS raggacl, "
5551                                                   "NULL AS initaggacl, NULL AS initraggacl "
5552                                                   "FROM pg_proc "
5553                                                   "WHERE proisagg "
5554                                                   "AND pronamespace != "
5555                                                   "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
5556                                                   username_subquery);
5557         }
5558
5559         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5560
5561         ntups = PQntuples(res);
5562         *numAggs = ntups;
5563
5564         agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
5565
5566         i_tableoid = PQfnumber(res, "tableoid");
5567         i_oid = PQfnumber(res, "oid");
5568         i_aggname = PQfnumber(res, "aggname");
5569         i_aggnamespace = PQfnumber(res, "aggnamespace");
5570         i_pronargs = PQfnumber(res, "pronargs");
5571         i_proargtypes = PQfnumber(res, "proargtypes");
5572         i_rolname = PQfnumber(res, "rolname");
5573         i_aggacl = PQfnumber(res, "aggacl");
5574         i_raggacl = PQfnumber(res, "raggacl");
5575         i_initaggacl = PQfnumber(res, "initaggacl");
5576         i_initraggacl = PQfnumber(res, "initraggacl");
5577
5578         for (i = 0; i < ntups; i++)
5579         {
5580                 agginfo[i].aggfn.dobj.objType = DO_AGG;
5581                 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5582                 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5583                 AssignDumpId(&agginfo[i].aggfn.dobj);
5584                 agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
5585                 agginfo[i].aggfn.dobj.namespace =
5586                         findNamespace(fout,
5587                                                   atooid(PQgetvalue(res, i, i_aggnamespace)));
5588                 agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5589                 if (strlen(agginfo[i].aggfn.rolname) == 0)
5590                         pg_log_warning("owner of aggregate function \"%s\" appears to be invalid",
5591                                           agginfo[i].aggfn.dobj.name);
5592                 agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
5593                 agginfo[i].aggfn.prorettype = InvalidOid;       /* not saved */
5594                 agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
5595                 agginfo[i].aggfn.rproacl = pg_strdup(PQgetvalue(res, i, i_raggacl));
5596                 agginfo[i].aggfn.initproacl = pg_strdup(PQgetvalue(res, i, i_initaggacl));
5597                 agginfo[i].aggfn.initrproacl = pg_strdup(PQgetvalue(res, i, i_initraggacl));
5598                 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
5599                 if (agginfo[i].aggfn.nargs == 0)
5600                         agginfo[i].aggfn.argtypes = NULL;
5601                 else
5602                 {
5603                         agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
5604                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
5605                                                   agginfo[i].aggfn.argtypes,
5606                                                   agginfo[i].aggfn.nargs);
5607                 }
5608
5609                 /* Decide whether we want to dump it */
5610                 selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
5611
5612                 /* Do not try to dump ACL if no ACL exists. */
5613                 if (PQgetisnull(res, i, i_aggacl) && PQgetisnull(res, i, i_raggacl) &&
5614                         PQgetisnull(res, i, i_initaggacl) &&
5615                         PQgetisnull(res, i, i_initraggacl))
5616                         agginfo[i].aggfn.dobj.dump &= ~DUMP_COMPONENT_ACL;
5617         }
5618
5619         PQclear(res);
5620
5621         destroyPQExpBuffer(query);
5622
5623         return agginfo;
5624 }
5625
5626 /*
5627  * getFuncs:
5628  *        read all the user-defined functions in the system catalogs and
5629  * return them in the FuncInfo* structure
5630  *
5631  * numFuncs is set to the number of functions read in
5632  */
5633 FuncInfo *
5634 getFuncs(Archive *fout, int *numFuncs)
5635 {
5636         DumpOptions *dopt = fout->dopt;
5637         PGresult   *res;
5638         int                     ntups;
5639         int                     i;
5640         PQExpBuffer query = createPQExpBuffer();
5641         FuncInfo   *finfo;
5642         int                     i_tableoid;
5643         int                     i_oid;
5644         int                     i_proname;
5645         int                     i_pronamespace;
5646         int                     i_rolname;
5647         int                     i_prolang;
5648         int                     i_pronargs;
5649         int                     i_proargtypes;
5650         int                     i_prorettype;
5651         int                     i_proacl;
5652         int                     i_rproacl;
5653         int                     i_initproacl;
5654         int                     i_initrproacl;
5655
5656         /*
5657          * Find all interesting functions.  This is a bit complicated:
5658          *
5659          * 1. Always exclude aggregates; those are handled elsewhere.
5660          *
5661          * 2. Always exclude functions that are internally dependent on something
5662          * else, since presumably those will be created as a result of creating
5663          * the something else.  This currently acts only to suppress constructor
5664          * functions for range types (so we only need it in 9.2 and up).  Note
5665          * this is OK only because the constructors don't have any dependencies
5666          * the range type doesn't have; otherwise we might not get creation
5667          * ordering correct.
5668          *
5669          * 3. Otherwise, we normally exclude functions in pg_catalog.  However, if
5670          * they're members of extensions and we are in binary-upgrade mode then
5671          * include them, since we want to dump extension members individually in
5672          * that mode.  Also, if they are used by casts or transforms then we need
5673          * to gather the information about them, though they won't be dumped if
5674          * they are built-in.  Also, in 9.6 and up, include functions in
5675          * pg_catalog if they have an ACL different from what's shown in
5676          * pg_init_privs.
5677          */
5678         if (fout->remoteVersion >= 90600)
5679         {
5680                 PQExpBuffer acl_subquery = createPQExpBuffer();
5681                 PQExpBuffer racl_subquery = createPQExpBuffer();
5682                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5683                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5684                 const char *not_agg_check;
5685
5686                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5687                                                 initracl_subquery, "p.proacl", "p.proowner", "'f'",
5688                                                 dopt->binary_upgrade);
5689
5690                 not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
5691                                                  : "NOT p.proisagg");
5692
5693                 appendPQExpBuffer(query,
5694                                                   "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
5695                                                   "p.pronargs, p.proargtypes, p.prorettype, "
5696                                                   "%s AS proacl, "
5697                                                   "%s AS rproacl, "
5698                                                   "%s AS initproacl, "
5699                                                   "%s AS initrproacl, "
5700                                                   "p.pronamespace, "
5701                                                   "(%s p.proowner) AS rolname "
5702                                                   "FROM pg_proc p "
5703                                                   "LEFT JOIN pg_init_privs pip ON "
5704                                                   "(p.oid = pip.objoid "
5705                                                   "AND pip.classoid = 'pg_proc'::regclass "
5706                                                   "AND pip.objsubid = 0) "
5707                                                   "WHERE %s"
5708                                                   "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
5709                                                   "WHERE classid = 'pg_proc'::regclass AND "
5710                                                   "objid = p.oid AND deptype = 'i')"
5711                                                   "\n  AND ("
5712                                                   "\n  pronamespace != "
5713                                                   "(SELECT oid FROM pg_namespace "
5714                                                   "WHERE nspname = 'pg_catalog')"
5715                                                   "\n  OR EXISTS (SELECT 1 FROM pg_cast"
5716                                                   "\n  WHERE pg_cast.oid > %u "
5717                                                   "\n  AND p.oid = pg_cast.castfunc)"
5718                                                   "\n  OR EXISTS (SELECT 1 FROM pg_transform"
5719                                                   "\n  WHERE pg_transform.oid > %u AND "
5720                                                   "\n  (p.oid = pg_transform.trffromsql"
5721                                                   "\n  OR p.oid = pg_transform.trftosql))",
5722                                                   acl_subquery->data,
5723                                                   racl_subquery->data,
5724                                                   initacl_subquery->data,
5725                                                   initracl_subquery->data,
5726                                                   username_subquery,
5727                                                   not_agg_check,
5728                                                   g_last_builtin_oid,
5729                                                   g_last_builtin_oid);
5730                 if (dopt->binary_upgrade)
5731                         appendPQExpBufferStr(query,
5732                                                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5733                                                                  "classid = 'pg_proc'::regclass AND "
5734                                                                  "objid = p.oid AND "
5735                                                                  "refclassid = 'pg_extension'::regclass AND "
5736                                                                  "deptype = 'e')");
5737                 appendPQExpBufferStr(query,
5738                                                          "\n  OR p.proacl IS DISTINCT FROM pip.initprivs");
5739                 appendPQExpBufferChar(query, ')');
5740
5741                 destroyPQExpBuffer(acl_subquery);
5742                 destroyPQExpBuffer(racl_subquery);
5743                 destroyPQExpBuffer(initacl_subquery);
5744                 destroyPQExpBuffer(initracl_subquery);
5745         }
5746         else
5747         {
5748                 appendPQExpBuffer(query,
5749                                                   "SELECT tableoid, oid, proname, prolang, "
5750                                                   "pronargs, proargtypes, prorettype, proacl, "
5751                                                   "NULL as rproacl, "
5752                                                   "NULL as initproacl, NULL AS initrproacl, "
5753                                                   "pronamespace, "
5754                                                   "(%s proowner) AS rolname "
5755                                                   "FROM pg_proc p "
5756                                                   "WHERE NOT proisagg",
5757                                                   username_subquery);
5758                 if (fout->remoteVersion >= 90200)
5759                         appendPQExpBufferStr(query,
5760                                                                  "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
5761                                                                  "WHERE classid = 'pg_proc'::regclass AND "
5762                                                                  "objid = p.oid AND deptype = 'i')");
5763                 appendPQExpBuffer(query,
5764                                                   "\n  AND ("
5765                                                   "\n  pronamespace != "
5766                                                   "(SELECT oid FROM pg_namespace "
5767                                                   "WHERE nspname = 'pg_catalog')"
5768                                                   "\n  OR EXISTS (SELECT 1 FROM pg_cast"
5769                                                   "\n  WHERE pg_cast.oid > '%u'::oid"
5770                                                   "\n  AND p.oid = pg_cast.castfunc)",
5771                                                   g_last_builtin_oid);
5772
5773                 if (fout->remoteVersion >= 90500)
5774                         appendPQExpBuffer(query,
5775                                                           "\n  OR EXISTS (SELECT 1 FROM pg_transform"
5776                                                           "\n  WHERE pg_transform.oid > '%u'::oid"
5777                                                           "\n  AND (p.oid = pg_transform.trffromsql"
5778                                                           "\n  OR p.oid = pg_transform.trftosql))",
5779                                                           g_last_builtin_oid);
5780
5781                 if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
5782                         appendPQExpBufferStr(query,
5783                                                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5784                                                                  "classid = 'pg_proc'::regclass AND "
5785                                                                  "objid = p.oid AND "
5786                                                                  "refclassid = 'pg_extension'::regclass AND "
5787                                                                  "deptype = 'e')");
5788                 appendPQExpBufferChar(query, ')');
5789         }
5790
5791         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5792
5793         ntups = PQntuples(res);
5794
5795         *numFuncs = ntups;
5796
5797         finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
5798
5799         i_tableoid = PQfnumber(res, "tableoid");
5800         i_oid = PQfnumber(res, "oid");
5801         i_proname = PQfnumber(res, "proname");
5802         i_pronamespace = PQfnumber(res, "pronamespace");
5803         i_rolname = PQfnumber(res, "rolname");
5804         i_prolang = PQfnumber(res, "prolang");
5805         i_pronargs = PQfnumber(res, "pronargs");
5806         i_proargtypes = PQfnumber(res, "proargtypes");
5807         i_prorettype = PQfnumber(res, "prorettype");
5808         i_proacl = PQfnumber(res, "proacl");
5809         i_rproacl = PQfnumber(res, "rproacl");
5810         i_initproacl = PQfnumber(res, "initproacl");
5811         i_initrproacl = PQfnumber(res, "initrproacl");
5812
5813         for (i = 0; i < ntups; i++)
5814         {
5815                 finfo[i].dobj.objType = DO_FUNC;
5816                 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5817                 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5818                 AssignDumpId(&finfo[i].dobj);
5819                 finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
5820                 finfo[i].dobj.namespace =
5821                         findNamespace(fout,
5822                                                   atooid(PQgetvalue(res, i, i_pronamespace)));
5823                 finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5824                 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
5825                 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
5826                 finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
5827                 finfo[i].rproacl = pg_strdup(PQgetvalue(res, i, i_rproacl));
5828                 finfo[i].initproacl = pg_strdup(PQgetvalue(res, i, i_initproacl));
5829                 finfo[i].initrproacl = pg_strdup(PQgetvalue(res, i, i_initrproacl));
5830                 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
5831                 if (finfo[i].nargs == 0)
5832                         finfo[i].argtypes = NULL;
5833                 else
5834                 {
5835                         finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
5836                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
5837                                                   finfo[i].argtypes, finfo[i].nargs);
5838                 }
5839
5840                 /* Decide whether we want to dump it */
5841                 selectDumpableObject(&(finfo[i].dobj), fout);
5842
5843                 /* Do not try to dump ACL if no ACL exists. */
5844                 if (PQgetisnull(res, i, i_proacl) && PQgetisnull(res, i, i_rproacl) &&
5845                         PQgetisnull(res, i, i_initproacl) &&
5846                         PQgetisnull(res, i, i_initrproacl))
5847                         finfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5848
5849                 if (strlen(finfo[i].rolname) == 0)
5850                         pg_log_warning("owner of function \"%s\" appears to be invalid",
5851                                           finfo[i].dobj.name);
5852         }
5853
5854         PQclear(res);
5855
5856         destroyPQExpBuffer(query);
5857
5858         return finfo;
5859 }
5860
5861 /*
5862  * getTables
5863  *        read all the tables (no indexes)
5864  * in the system catalogs return them in the TableInfo* structure
5865  *
5866  * numTables is set to the number of tables read in
5867  */
5868 TableInfo *
5869 getTables(Archive *fout, int *numTables)
5870 {
5871         DumpOptions *dopt = fout->dopt;
5872         PGresult   *res;
5873         int                     ntups;
5874         int                     i;
5875         PQExpBuffer query = createPQExpBuffer();
5876         TableInfo  *tblinfo;
5877         int                     i_reltableoid;
5878         int                     i_reloid;
5879         int                     i_relname;
5880         int                     i_relnamespace;
5881         int                     i_relkind;
5882         int                     i_relacl;
5883         int                     i_rrelacl;
5884         int                     i_initrelacl;
5885         int                     i_initrrelacl;
5886         int                     i_rolname;
5887         int                     i_relchecks;
5888         int                     i_relhastriggers;
5889         int                     i_relhasindex;
5890         int                     i_relhasrules;
5891         int                     i_relrowsec;
5892         int                     i_relforcerowsec;
5893         int                     i_relhasoids;
5894         int                     i_relfrozenxid;
5895         int                     i_relminmxid;
5896         int                     i_toastoid;
5897         int                     i_toastfrozenxid;
5898         int                     i_toastminmxid;
5899         int                     i_relpersistence;
5900         int                     i_relispopulated;
5901         int                     i_relreplident;
5902         int                     i_owning_tab;
5903         int                     i_owning_col;
5904         int                     i_reltablespace;
5905         int                     i_reloptions;
5906         int                     i_checkoption;
5907         int                     i_toastreloptions;
5908         int                     i_reloftype;
5909         int                     i_relpages;
5910         int                     i_is_identity_sequence;
5911         int                     i_changed_acl;
5912         int                     i_partkeydef;
5913         int                     i_ispartition;
5914         int                     i_partbound;
5915         int                     i_amname;
5916
5917         /*
5918          * Find all the tables and table-like objects.
5919          *
5920          * We include system catalogs, so that we can work if a user table is
5921          * defined to inherit from a system catalog (pretty weird, but...)
5922          *
5923          * We ignore relations that are not ordinary tables, sequences, views,
5924          * materialized views, composite types, or foreign tables.
5925          *
5926          * Composite-type table entries won't be dumped as such, but we have to
5927          * make a DumpableObject for them so that we can track dependencies of the
5928          * composite type (pg_depend entries for columns of the composite type
5929          * link to the pg_class entry not the pg_type entry).
5930          *
5931          * Note: in this phase we should collect only a minimal amount of
5932          * information about each table, basically just enough to decide if it is
5933          * interesting. We must fetch all tables in this phase because otherwise
5934          * we cannot correctly identify inherited columns, owned sequences, etc.
5935          *
5936          * We purposefully ignore toast OIDs for partitioned tables; the reason is
5937          * that versions 10 and 11 have them, but 12 does not, so emitting them
5938          * causes the upgrade to fail.
5939          */
5940
5941         if (fout->remoteVersion >= 90600)
5942         {
5943                 char       *partkeydef = "NULL";
5944                 char       *ispartition = "false";
5945                 char       *partbound = "NULL";
5946                 char       *relhasoids = "c.relhasoids";
5947
5948                 PQExpBuffer acl_subquery = createPQExpBuffer();
5949                 PQExpBuffer racl_subquery = createPQExpBuffer();
5950                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5951                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5952
5953                 PQExpBuffer attacl_subquery = createPQExpBuffer();
5954                 PQExpBuffer attracl_subquery = createPQExpBuffer();
5955                 PQExpBuffer attinitacl_subquery = createPQExpBuffer();
5956                 PQExpBuffer attinitracl_subquery = createPQExpBuffer();
5957
5958                 /*
5959                  * Collect the information about any partitioned tables, which were
5960                  * added in PG10.
5961                  */
5962
5963                 if (fout->remoteVersion >= 100000)
5964                 {
5965                         partkeydef = "pg_get_partkeydef(c.oid)";
5966                         ispartition = "c.relispartition";
5967                         partbound = "pg_get_expr(c.relpartbound, c.oid)";
5968                 }
5969
5970                 /* In PG12 upwards WITH OIDS does not exist anymore. */
5971                 if (fout->remoteVersion >= 120000)
5972                         relhasoids = "'f'::bool";
5973
5974                 /*
5975                  * Left join to pick up dependency info linking sequences to their
5976                  * owning column, if any (note this dependency is AUTO as of 8.2)
5977                  *
5978                  * Left join to detect if any privileges are still as-set-at-init, in
5979                  * which case we won't dump out ACL commands for those.
5980                  */
5981
5982                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5983                                                 initracl_subquery, "c.relacl", "c.relowner",
5984                                                 "CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
5985                                                 " THEN 's' ELSE 'r' END::\"char\"",
5986                                                 dopt->binary_upgrade);
5987
5988                 buildACLQueries(attacl_subquery, attracl_subquery, attinitacl_subquery,
5989                                                 attinitracl_subquery, "at.attacl", "c.relowner", "'c'",
5990                                                 dopt->binary_upgrade);
5991
5992                 appendPQExpBuffer(query,
5993                                                   "SELECT c.tableoid, c.oid, c.relname, "
5994                                                   "%s AS relacl, %s as rrelacl, "
5995                                                   "%s AS initrelacl, %s as initrrelacl, "
5996                                                   "c.relkind, c.relnamespace, "
5997                                                   "(%s c.relowner) AS rolname, "
5998                                                   "c.relchecks, c.relhastriggers, "
5999                                                   "c.relhasindex, c.relhasrules, %s AS relhasoids, "
6000                                                   "c.relrowsecurity, c.relforcerowsecurity, "
6001                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6002                                                   "tc.relfrozenxid AS tfrozenxid, "
6003                                                   "tc.relminmxid AS tminmxid, "
6004                                                   "c.relpersistence, c.relispopulated, "
6005                                                   "c.relreplident, c.relpages, am.amname, "
6006                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6007                                                   "d.refobjid AS owning_tab, "
6008                                                   "d.refobjsubid AS owning_col, "
6009                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6010                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6011                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6012                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6013                                                   "tc.reloptions AS toast_reloptions, "
6014                                                   "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, "
6015                                                   "EXISTS (SELECT 1 FROM pg_attribute at LEFT JOIN pg_init_privs pip ON "
6016                                                   "(c.oid = pip.objoid "
6017                                                   "AND pip.classoid = 'pg_class'::regclass "
6018                                                   "AND pip.objsubid = at.attnum)"
6019                                                   "WHERE at.attrelid = c.oid AND ("
6020                                                   "%s IS NOT NULL "
6021                                                   "OR %s IS NOT NULL "
6022                                                   "OR %s IS NOT NULL "
6023                                                   "OR %s IS NOT NULL"
6024                                                   "))"
6025                                                   "AS changed_acl, "
6026                                                   "%s AS partkeydef, "
6027                                                   "%s AS ispartition, "
6028                                                   "%s AS partbound "
6029                                                   "FROM pg_class c "
6030                                                   "LEFT JOIN pg_depend d ON "
6031                                                   "(c.relkind = '%c' AND "
6032                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6033                                                   "d.objsubid = 0 AND "
6034                                                   "d.refclassid = c.tableoid AND d.deptype IN ('a', 'i')) "
6035                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid AND c.relkind <> '%c') "
6036                                                   "LEFT JOIN pg_am am ON (c.relam = am.oid) "
6037                                                   "LEFT JOIN pg_init_privs pip ON "
6038                                                   "(c.oid = pip.objoid "
6039                                                   "AND pip.classoid = 'pg_class'::regclass "
6040                                                   "AND pip.objsubid = 0) "
6041                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c', '%c') "
6042                                                   "ORDER BY c.oid",
6043                                                   acl_subquery->data,
6044                                                   racl_subquery->data,
6045                                                   initacl_subquery->data,
6046                                                   initracl_subquery->data,
6047                                                   username_subquery,
6048                                                   relhasoids,
6049                                                   RELKIND_SEQUENCE,
6050                                                   attacl_subquery->data,
6051                                                   attracl_subquery->data,
6052                                                   attinitacl_subquery->data,
6053                                                   attinitracl_subquery->data,
6054                                                   partkeydef,
6055                                                   ispartition,
6056                                                   partbound,
6057                                                   RELKIND_SEQUENCE,
6058                                                   RELKIND_PARTITIONED_TABLE,
6059                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6060                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6061                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
6062                                                   RELKIND_PARTITIONED_TABLE);
6063
6064                 destroyPQExpBuffer(acl_subquery);
6065                 destroyPQExpBuffer(racl_subquery);
6066                 destroyPQExpBuffer(initacl_subquery);
6067                 destroyPQExpBuffer(initracl_subquery);
6068
6069                 destroyPQExpBuffer(attacl_subquery);
6070                 destroyPQExpBuffer(attracl_subquery);
6071                 destroyPQExpBuffer(attinitacl_subquery);
6072                 destroyPQExpBuffer(attinitracl_subquery);
6073         }
6074         else if (fout->remoteVersion >= 90500)
6075         {
6076                 /*
6077                  * Left join to pick up dependency info linking sequences to their
6078                  * owning column, if any (note this dependency is AUTO as of 8.2)
6079                  */
6080                 appendPQExpBuffer(query,
6081                                                   "SELECT c.tableoid, c.oid, c.relname, "
6082                                                   "c.relacl, NULL as rrelacl, "
6083                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6084                                                   "c.relkind, "
6085                                                   "c.relnamespace, "
6086                                                   "(%s c.relowner) AS rolname, "
6087                                                   "c.relchecks, c.relhastriggers, "
6088                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6089                                                   "c.relrowsecurity, c.relforcerowsecurity, "
6090                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6091                                                   "tc.relfrozenxid AS tfrozenxid, "
6092                                                   "tc.relminmxid AS tminmxid, "
6093                                                   "c.relpersistence, c.relispopulated, "
6094                                                   "c.relreplident, c.relpages, "
6095                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6096                                                   "d.refobjid AS owning_tab, "
6097                                                   "d.refobjsubid AS owning_col, "
6098                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6099                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6100                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6101                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6102                                                   "tc.reloptions AS toast_reloptions, "
6103                                                   "NULL AS changed_acl, "
6104                                                   "NULL AS partkeydef, "
6105                                                   "false AS ispartition, "
6106                                                   "NULL AS partbound "
6107                                                   "FROM pg_class c "
6108                                                   "LEFT JOIN pg_depend d ON "
6109                                                   "(c.relkind = '%c' AND "
6110                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6111                                                   "d.objsubid = 0 AND "
6112                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6113                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6114                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6115                                                   "ORDER BY c.oid",
6116                                                   username_subquery,
6117                                                   RELKIND_SEQUENCE,
6118                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6119                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6120                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6121         }
6122         else if (fout->remoteVersion >= 90400)
6123         {
6124                 /*
6125                  * Left join to pick up dependency info linking sequences to their
6126                  * owning column, if any (note this dependency is AUTO as of 8.2)
6127                  */
6128                 appendPQExpBuffer(query,
6129                                                   "SELECT c.tableoid, c.oid, c.relname, "
6130                                                   "c.relacl, NULL as rrelacl, "
6131                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6132                                                   "c.relkind, "
6133                                                   "c.relnamespace, "
6134                                                   "(%s c.relowner) AS rolname, "
6135                                                   "c.relchecks, c.relhastriggers, "
6136                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6137                                                   "'f'::bool AS relrowsecurity, "
6138                                                   "'f'::bool AS relforcerowsecurity, "
6139                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6140                                                   "tc.relfrozenxid AS tfrozenxid, "
6141                                                   "tc.relminmxid AS tminmxid, "
6142                                                   "c.relpersistence, c.relispopulated, "
6143                                                   "c.relreplident, c.relpages, "
6144                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6145                                                   "d.refobjid AS owning_tab, "
6146                                                   "d.refobjsubid AS owning_col, "
6147                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6148                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6149                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6150                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6151                                                   "tc.reloptions AS toast_reloptions, "
6152                                                   "NULL AS changed_acl, "
6153                                                   "NULL AS partkeydef, "
6154                                                   "false AS ispartition, "
6155                                                   "NULL AS partbound "
6156                                                   "FROM pg_class c "
6157                                                   "LEFT JOIN pg_depend d ON "
6158                                                   "(c.relkind = '%c' AND "
6159                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6160                                                   "d.objsubid = 0 AND "
6161                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6162                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6163                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6164                                                   "ORDER BY c.oid",
6165                                                   username_subquery,
6166                                                   RELKIND_SEQUENCE,
6167                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6168                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6169                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6170         }
6171         else if (fout->remoteVersion >= 90300)
6172         {
6173                 /*
6174                  * Left join to pick up dependency info linking sequences to their
6175                  * owning column, if any (note this dependency is AUTO as of 8.2)
6176                  */
6177                 appendPQExpBuffer(query,
6178                                                   "SELECT c.tableoid, c.oid, c.relname, "
6179                                                   "c.relacl, NULL as rrelacl, "
6180                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6181                                                   "c.relkind, "
6182                                                   "c.relnamespace, "
6183                                                   "(%s c.relowner) AS rolname, "
6184                                                   "c.relchecks, c.relhastriggers, "
6185                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6186                                                   "'f'::bool AS relrowsecurity, "
6187                                                   "'f'::bool AS relforcerowsecurity, "
6188                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6189                                                   "tc.relfrozenxid AS tfrozenxid, "
6190                                                   "tc.relminmxid AS tminmxid, "
6191                                                   "c.relpersistence, c.relispopulated, "
6192                                                   "'d' AS relreplident, c.relpages, "
6193                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6194                                                   "d.refobjid AS owning_tab, "
6195                                                   "d.refobjsubid AS owning_col, "
6196                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6197                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6198                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6199                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6200                                                   "tc.reloptions AS toast_reloptions, "
6201                                                   "NULL AS changed_acl, "
6202                                                   "NULL AS partkeydef, "
6203                                                   "false AS ispartition, "
6204                                                   "NULL AS partbound "
6205                                                   "FROM pg_class c "
6206                                                   "LEFT JOIN pg_depend d ON "
6207                                                   "(c.relkind = '%c' AND "
6208                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6209                                                   "d.objsubid = 0 AND "
6210                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6211                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6212                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6213                                                   "ORDER BY c.oid",
6214                                                   username_subquery,
6215                                                   RELKIND_SEQUENCE,
6216                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6217                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6218                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6219         }
6220         else if (fout->remoteVersion >= 90100)
6221         {
6222                 /*
6223                  * Left join to pick up dependency info linking sequences to their
6224                  * owning column, if any (note this dependency is AUTO as of 8.2)
6225                  */
6226                 appendPQExpBuffer(query,
6227                                                   "SELECT c.tableoid, c.oid, c.relname, "
6228                                                   "c.relacl, NULL as rrelacl, "
6229                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6230                                                   "c.relkind, "
6231                                                   "c.relnamespace, "
6232                                                   "(%s c.relowner) AS rolname, "
6233                                                   "c.relchecks, c.relhastriggers, "
6234                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6235                                                   "'f'::bool AS relrowsecurity, "
6236                                                   "'f'::bool AS relforcerowsecurity, "
6237                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6238                                                   "tc.relfrozenxid AS tfrozenxid, "
6239                                                   "0 AS tminmxid, "
6240                                                   "c.relpersistence, 't' as relispopulated, "
6241                                                   "'d' AS relreplident, c.relpages, "
6242                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6243                                                   "d.refobjid AS owning_tab, "
6244                                                   "d.refobjsubid AS owning_col, "
6245                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6246                                                   "c.reloptions AS reloptions, "
6247                                                   "tc.reloptions AS toast_reloptions, "
6248                                                   "NULL AS changed_acl, "
6249                                                   "NULL AS partkeydef, "
6250                                                   "false AS ispartition, "
6251                                                   "NULL AS partbound "
6252                                                   "FROM pg_class c "
6253                                                   "LEFT JOIN pg_depend d ON "
6254                                                   "(c.relkind = '%c' AND "
6255                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6256                                                   "d.objsubid = 0 AND "
6257                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6258                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6259                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6260                                                   "ORDER BY c.oid",
6261                                                   username_subquery,
6262                                                   RELKIND_SEQUENCE,
6263                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6264                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6265                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6266         }
6267         else if (fout->remoteVersion >= 90000)
6268         {
6269                 /*
6270                  * Left join to pick up dependency info linking sequences to their
6271                  * owning column, if any (note this dependency is AUTO as of 8.2)
6272                  */
6273                 appendPQExpBuffer(query,
6274                                                   "SELECT c.tableoid, c.oid, c.relname, "
6275                                                   "c.relacl, NULL as rrelacl, "
6276                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6277                                                   "c.relkind, "
6278                                                   "c.relnamespace, "
6279                                                   "(%s c.relowner) AS rolname, "
6280                                                   "c.relchecks, c.relhastriggers, "
6281                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6282                                                   "'f'::bool AS relrowsecurity, "
6283                                                   "'f'::bool AS relforcerowsecurity, "
6284                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6285                                                   "tc.relfrozenxid AS tfrozenxid, "
6286                                                   "0 AS tminmxid, "
6287                                                   "'p' AS relpersistence, 't' as relispopulated, "
6288                                                   "'d' AS relreplident, c.relpages, "
6289                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6290                                                   "d.refobjid AS owning_tab, "
6291                                                   "d.refobjsubid AS owning_col, "
6292                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6293                                                   "c.reloptions AS reloptions, "
6294                                                   "tc.reloptions AS toast_reloptions, "
6295                                                   "NULL AS changed_acl, "
6296                                                   "NULL AS partkeydef, "
6297                                                   "false AS ispartition, "
6298                                                   "NULL AS partbound "
6299                                                   "FROM pg_class c "
6300                                                   "LEFT JOIN pg_depend d ON "
6301                                                   "(c.relkind = '%c' AND "
6302                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6303                                                   "d.objsubid = 0 AND "
6304                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6305                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6306                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6307                                                   "ORDER BY c.oid",
6308                                                   username_subquery,
6309                                                   RELKIND_SEQUENCE,
6310                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6311                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6312         }
6313         else if (fout->remoteVersion >= 80400)
6314         {
6315                 /*
6316                  * Left join to pick up dependency info linking sequences to their
6317                  * owning column, if any (note this dependency is AUTO as of 8.2)
6318                  */
6319                 appendPQExpBuffer(query,
6320                                                   "SELECT c.tableoid, c.oid, c.relname, "
6321                                                   "c.relacl, NULL as rrelacl, "
6322                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6323                                                   "c.relkind, "
6324                                                   "c.relnamespace, "
6325                                                   "(%s c.relowner) AS rolname, "
6326                                                   "c.relchecks, c.relhastriggers, "
6327                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6328                                                   "'f'::bool AS relrowsecurity, "
6329                                                   "'f'::bool AS relforcerowsecurity, "
6330                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6331                                                   "tc.relfrozenxid AS tfrozenxid, "
6332                                                   "0 AS tminmxid, "
6333                                                   "'p' AS relpersistence, 't' as relispopulated, "
6334                                                   "'d' AS relreplident, c.relpages, "
6335                                                   "NULL AS reloftype, "
6336                                                   "d.refobjid AS owning_tab, "
6337                                                   "d.refobjsubid AS owning_col, "
6338                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6339                                                   "c.reloptions AS reloptions, "
6340                                                   "tc.reloptions AS toast_reloptions, "
6341                                                   "NULL AS changed_acl, "
6342                                                   "NULL AS partkeydef, "
6343                                                   "false AS ispartition, "
6344                                                   "NULL AS partbound "
6345                                                   "FROM pg_class c "
6346                                                   "LEFT JOIN pg_depend d ON "
6347                                                   "(c.relkind = '%c' AND "
6348                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6349                                                   "d.objsubid = 0 AND "
6350                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6351                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6352                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6353                                                   "ORDER BY c.oid",
6354                                                   username_subquery,
6355                                                   RELKIND_SEQUENCE,
6356                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6357                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6358         }
6359         else if (fout->remoteVersion >= 80200)
6360         {
6361                 /*
6362                  * Left join to pick up dependency info linking sequences to their
6363                  * owning column, if any (note this dependency is AUTO as of 8.2)
6364                  */
6365                 appendPQExpBuffer(query,
6366                                                   "SELECT c.tableoid, c.oid, c.relname, "
6367                                                   "c.relacl, NULL as rrelacl, "
6368                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6369                                                   "c.relkind, "
6370                                                   "c.relnamespace, "
6371                                                   "(%s c.relowner) AS rolname, "
6372                                                   "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
6373                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6374                                                   "'f'::bool AS relrowsecurity, "
6375                                                   "'f'::bool AS relforcerowsecurity, "
6376                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6377                                                   "tc.relfrozenxid AS tfrozenxid, "
6378                                                   "0 AS tminmxid, "
6379                                                   "'p' AS relpersistence, 't' as relispopulated, "
6380                                                   "'d' AS relreplident, c.relpages, "
6381                                                   "NULL AS reloftype, "
6382                                                   "d.refobjid AS owning_tab, "
6383                                                   "d.refobjsubid AS owning_col, "
6384                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6385                                                   "c.reloptions AS reloptions, "
6386                                                   "NULL AS toast_reloptions, "
6387                                                   "NULL AS changed_acl, "
6388                                                   "NULL AS partkeydef, "
6389                                                   "false AS ispartition, "
6390                                                   "NULL AS partbound "
6391                                                   "FROM pg_class c "
6392                                                   "LEFT JOIN pg_depend d ON "
6393                                                   "(c.relkind = '%c' AND "
6394                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6395                                                   "d.objsubid = 0 AND "
6396                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6397                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6398                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6399                                                   "ORDER BY c.oid",
6400                                                   username_subquery,
6401                                                   RELKIND_SEQUENCE,
6402                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6403                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6404         }
6405         else
6406         {
6407                 /*
6408                  * Left join to pick up dependency info linking sequences to their
6409                  * owning column, if any
6410                  */
6411                 appendPQExpBuffer(query,
6412                                                   "SELECT c.tableoid, c.oid, relname, "
6413                                                   "relacl, NULL as rrelacl, "
6414                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6415                                                   "relkind, relnamespace, "
6416                                                   "(%s relowner) AS rolname, "
6417                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
6418                                                   "relhasindex, relhasrules, relhasoids, "
6419                                                   "'f'::bool AS relrowsecurity, "
6420                                                   "'f'::bool AS relforcerowsecurity, "
6421                                                   "0 AS relfrozenxid, 0 AS relminmxid,"
6422                                                   "0 AS toid, "
6423                                                   "0 AS tfrozenxid, 0 AS tminmxid,"
6424                                                   "'p' AS relpersistence, 't' as relispopulated, "
6425                                                   "'d' AS relreplident, relpages, "
6426                                                   "NULL AS reloftype, "
6427                                                   "d.refobjid AS owning_tab, "
6428                                                   "d.refobjsubid AS owning_col, "
6429                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6430                                                   "NULL AS reloptions, "
6431                                                   "NULL AS toast_reloptions, "
6432                                                   "NULL AS changed_acl, "
6433                                                   "NULL AS partkeydef, "
6434                                                   "false AS ispartition, "
6435                                                   "NULL AS partbound "
6436                                                   "FROM pg_class c "
6437                                                   "LEFT JOIN pg_depend d ON "
6438                                                   "(c.relkind = '%c' AND "
6439                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6440                                                   "d.objsubid = 0 AND "
6441                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
6442                                                   "WHERE relkind in ('%c', '%c', '%c', '%c') "
6443                                                   "ORDER BY c.oid",
6444                                                   username_subquery,
6445                                                   RELKIND_SEQUENCE,
6446                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6447                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6448         }
6449
6450         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6451
6452         ntups = PQntuples(res);
6453
6454         *numTables = ntups;
6455
6456         /*
6457          * Extract data from result and lock dumpable tables.  We do the locking
6458          * before anything else, to minimize the window wherein a table could
6459          * disappear under us.
6460          *
6461          * Note that we have to save info about all tables here, even when dumping
6462          * only one, because we don't yet know which tables might be inheritance
6463          * ancestors of the target table.
6464          */
6465         tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
6466
6467         i_reltableoid = PQfnumber(res, "tableoid");
6468         i_reloid = PQfnumber(res, "oid");
6469         i_relname = PQfnumber(res, "relname");
6470         i_relnamespace = PQfnumber(res, "relnamespace");
6471         i_relacl = PQfnumber(res, "relacl");
6472         i_rrelacl = PQfnumber(res, "rrelacl");
6473         i_initrelacl = PQfnumber(res, "initrelacl");
6474         i_initrrelacl = PQfnumber(res, "initrrelacl");
6475         i_relkind = PQfnumber(res, "relkind");
6476         i_rolname = PQfnumber(res, "rolname");
6477         i_relchecks = PQfnumber(res, "relchecks");
6478         i_relhastriggers = PQfnumber(res, "relhastriggers");
6479         i_relhasindex = PQfnumber(res, "relhasindex");
6480         i_relhasrules = PQfnumber(res, "relhasrules");
6481         i_relrowsec = PQfnumber(res, "relrowsecurity");
6482         i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
6483         i_relhasoids = PQfnumber(res, "relhasoids");
6484         i_relfrozenxid = PQfnumber(res, "relfrozenxid");
6485         i_relminmxid = PQfnumber(res, "relminmxid");
6486         i_toastoid = PQfnumber(res, "toid");
6487         i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
6488         i_toastminmxid = PQfnumber(res, "tminmxid");
6489         i_relpersistence = PQfnumber(res, "relpersistence");
6490         i_relispopulated = PQfnumber(res, "relispopulated");
6491         i_relreplident = PQfnumber(res, "relreplident");
6492         i_relpages = PQfnumber(res, "relpages");
6493         i_owning_tab = PQfnumber(res, "owning_tab");
6494         i_owning_col = PQfnumber(res, "owning_col");
6495         i_reltablespace = PQfnumber(res, "reltablespace");
6496         i_reloptions = PQfnumber(res, "reloptions");
6497         i_checkoption = PQfnumber(res, "checkoption");
6498         i_toastreloptions = PQfnumber(res, "toast_reloptions");
6499         i_reloftype = PQfnumber(res, "reloftype");
6500         i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
6501         i_changed_acl = PQfnumber(res, "changed_acl");
6502         i_partkeydef = PQfnumber(res, "partkeydef");
6503         i_ispartition = PQfnumber(res, "ispartition");
6504         i_partbound = PQfnumber(res, "partbound");
6505         i_amname = PQfnumber(res, "amname");
6506
6507         if (dopt->lockWaitTimeout)
6508         {
6509                 /*
6510                  * Arrange to fail instead of waiting forever for a table lock.
6511                  *
6512                  * NB: this coding assumes that the only queries issued within the
6513                  * following loop are LOCK TABLEs; else the timeout may be undesirably
6514                  * applied to other things too.
6515                  */
6516                 resetPQExpBuffer(query);
6517                 appendPQExpBufferStr(query, "SET statement_timeout = ");
6518                 appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
6519                 ExecuteSqlStatement(fout, query->data);
6520         }
6521
6522         for (i = 0; i < ntups; i++)
6523         {
6524                 tblinfo[i].dobj.objType = DO_TABLE;
6525                 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
6526                 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
6527                 AssignDumpId(&tblinfo[i].dobj);
6528                 tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
6529                 tblinfo[i].dobj.namespace =
6530                         findNamespace(fout,
6531                                                   atooid(PQgetvalue(res, i, i_relnamespace)));
6532                 tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6533                 tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
6534                 tblinfo[i].rrelacl = pg_strdup(PQgetvalue(res, i, i_rrelacl));
6535                 tblinfo[i].initrelacl = pg_strdup(PQgetvalue(res, i, i_initrelacl));
6536                 tblinfo[i].initrrelacl = pg_strdup(PQgetvalue(res, i, i_initrrelacl));
6537                 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
6538                 tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
6539                 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
6540                 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
6541                 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
6542                 tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
6543                 tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
6544                 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
6545                 tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
6546                 tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
6547                 tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
6548                 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
6549                 tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
6550                 tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
6551                 tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
6552                 tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
6553                 if (PQgetisnull(res, i, i_reloftype))
6554                         tblinfo[i].reloftype = NULL;
6555                 else
6556                         tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
6557                 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
6558                 if (PQgetisnull(res, i, i_owning_tab))
6559                 {
6560                         tblinfo[i].owning_tab = InvalidOid;
6561                         tblinfo[i].owning_col = 0;
6562                 }
6563                 else
6564                 {
6565                         tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
6566                         tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
6567                 }
6568                 tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
6569                 tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
6570                 if (i_checkoption == -1 || PQgetisnull(res, i, i_checkoption))
6571                         tblinfo[i].checkoption = NULL;
6572                 else
6573                         tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
6574                 tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
6575                 if (PQgetisnull(res, i, i_amname))
6576                         tblinfo[i].amname = NULL;
6577                 else
6578                         tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
6579
6580                 /* other fields were zeroed above */
6581
6582                 /*
6583                  * Decide whether we want to dump this table.
6584                  */
6585                 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
6586                         tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
6587                 else
6588                         selectDumpableTable(&tblinfo[i], fout);
6589
6590                 /*
6591                  * If the table-level and all column-level ACLs for this table are
6592                  * unchanged, then we don't need to worry about including the ACLs for
6593                  * this table.  If any column-level ACLs have been changed, the
6594                  * 'changed_acl' column from the query will indicate that.
6595                  *
6596                  * This can result in a significant performance improvement in cases
6597                  * where we are only looking to dump out the ACL (eg: pg_catalog).
6598                  */
6599                 if (PQgetisnull(res, i, i_relacl) && PQgetisnull(res, i, i_rrelacl) &&
6600                         PQgetisnull(res, i, i_initrelacl) &&
6601                         PQgetisnull(res, i, i_initrrelacl) &&
6602                         strcmp(PQgetvalue(res, i, i_changed_acl), "f") == 0)
6603                         tblinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
6604
6605                 tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
6606                 tblinfo[i].dummy_view = false;  /* might get set during sort */
6607                 tblinfo[i].postponed_def = false;       /* might get set during sort */
6608
6609                 tblinfo[i].is_identity_sequence = (i_is_identity_sequence >= 0 &&
6610                                                                                    strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
6611
6612                 /* Partition key string or NULL */
6613                 tblinfo[i].partkeydef = pg_strdup(PQgetvalue(res, i, i_partkeydef));
6614                 tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
6615                 tblinfo[i].partbound = pg_strdup(PQgetvalue(res, i, i_partbound));
6616
6617                 /*
6618                  * Read-lock target tables to make sure they aren't DROPPED or altered
6619                  * in schema before we get around to dumping them.
6620                  *
6621                  * Note that we don't explicitly lock parents of the target tables; we
6622                  * assume our lock on the child is enough to prevent schema
6623                  * alterations to parent tables.
6624                  *
6625                  * NOTE: it'd be kinda nice to lock other relations too, not only
6626                  * plain or partitioned tables, but the backend doesn't presently
6627                  * allow that.
6628                  *
6629                  * We only need to lock the table for certain components; see
6630                  * pg_dump.h
6631                  */
6632                 if (tblinfo[i].dobj.dump &&
6633                         (tblinfo[i].relkind == RELKIND_RELATION ||
6634                          tblinfo->relkind == RELKIND_PARTITIONED_TABLE) &&
6635                         (tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK))
6636                 {
6637                         resetPQExpBuffer(query);
6638                         appendPQExpBuffer(query,
6639                                                           "LOCK TABLE %s IN ACCESS SHARE MODE",
6640                                                           fmtQualifiedDumpable(&tblinfo[i]));
6641                         ExecuteSqlStatement(fout, query->data);
6642                 }
6643
6644                 /* Emit notice if join for owner failed */
6645                 if (strlen(tblinfo[i].rolname) == 0)
6646                         pg_log_warning("owner of table \"%s\" appears to be invalid",
6647                                           tblinfo[i].dobj.name);
6648         }
6649
6650         if (dopt->lockWaitTimeout)
6651         {
6652                 ExecuteSqlStatement(fout, "SET statement_timeout = 0");
6653         }
6654
6655         PQclear(res);
6656
6657         destroyPQExpBuffer(query);
6658
6659         return tblinfo;
6660 }
6661
6662 /*
6663  * getOwnedSeqs
6664  *        identify owned sequences and mark them as dumpable if owning table is
6665  *
6666  * We used to do this in getTables(), but it's better to do it after the
6667  * index used by findTableByOid() has been set up.
6668  */
6669 void
6670 getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
6671 {
6672         int                     i;
6673
6674         /*
6675          * Force sequences that are "owned" by table columns to be dumped whenever
6676          * their owning table is being dumped.
6677          */
6678         for (i = 0; i < numTables; i++)
6679         {
6680                 TableInfo  *seqinfo = &tblinfo[i];
6681                 TableInfo  *owning_tab;
6682
6683                 if (!OidIsValid(seqinfo->owning_tab))
6684                         continue;                       /* not an owned sequence */
6685
6686                 owning_tab = findTableByOid(seqinfo->owning_tab);
6687                 if (owning_tab == NULL)
6688                         fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
6689                                                   seqinfo->owning_tab, seqinfo->dobj.catId.oid);
6690
6691                 /*
6692                  * Only dump identity sequences if we're going to dump the table that
6693                  * it belongs to.
6694                  */
6695                 if (owning_tab->dobj.dump == DUMP_COMPONENT_NONE &&
6696                         seqinfo->is_identity_sequence)
6697                 {
6698                         seqinfo->dobj.dump = DUMP_COMPONENT_NONE;
6699                         continue;
6700                 }
6701
6702                 /*
6703                  * Otherwise we need to dump the components that are being dumped for
6704                  * the table and any components which the sequence is explicitly
6705                  * marked with.
6706                  *
6707                  * We can't simply use the set of components which are being dumped
6708                  * for the table as the table might be in an extension (and only the
6709                  * non-extension components, eg: ACLs if changed, security labels, and
6710                  * policies, are being dumped) while the sequence is not (and
6711                  * therefore the definition and other components should also be
6712                  * dumped).
6713                  *
6714                  * If the sequence is part of the extension then it should be properly
6715                  * marked by checkExtensionMembership() and this will be a no-op as
6716                  * the table will be equivalently marked.
6717                  */
6718                 seqinfo->dobj.dump = seqinfo->dobj.dump | owning_tab->dobj.dump;
6719
6720                 if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
6721                         seqinfo->interesting = true;
6722         }
6723 }
6724
6725 /*
6726  * getInherits
6727  *        read all the inheritance information
6728  * from the system catalogs return them in the InhInfo* structure
6729  *
6730  * numInherits is set to the number of pairs read in
6731  */
6732 InhInfo *
6733 getInherits(Archive *fout, int *numInherits)
6734 {
6735         PGresult   *res;
6736         int                     ntups;
6737         int                     i;
6738         PQExpBuffer query = createPQExpBuffer();
6739         InhInfo    *inhinfo;
6740
6741         int                     i_inhrelid;
6742         int                     i_inhparent;
6743
6744         /*
6745          * Find all the inheritance information, excluding implicit inheritance
6746          * via partitioning.  We handle that case using getPartitions(), because
6747          * we want more information about partitions than just the parent-child
6748          * relationship.
6749          */
6750         appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
6751
6752         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6753
6754         ntups = PQntuples(res);
6755
6756         *numInherits = ntups;
6757
6758         inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
6759
6760         i_inhrelid = PQfnumber(res, "inhrelid");
6761         i_inhparent = PQfnumber(res, "inhparent");
6762
6763         for (i = 0; i < ntups; i++)
6764         {
6765                 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
6766                 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
6767         }
6768
6769         PQclear(res);
6770
6771         destroyPQExpBuffer(query);
6772
6773         return inhinfo;
6774 }
6775
6776 /*
6777  * getIndexes
6778  *        get information about every index on a dumpable table
6779  *
6780  * Note: index data is not returned directly to the caller, but it
6781  * does get entered into the DumpableObject tables.
6782  */
6783 void
6784 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
6785 {
6786         int                     i,
6787                                 j;
6788         PQExpBuffer query = createPQExpBuffer();
6789         PGresult   *res;
6790         IndxInfo   *indxinfo;
6791         ConstraintInfo *constrinfo;
6792         int                     i_tableoid,
6793                                 i_oid,
6794                                 i_indexname,
6795                                 i_parentidx,
6796                                 i_indexdef,
6797                                 i_indnkeyatts,
6798                                 i_indnatts,
6799                                 i_indkey,
6800                                 i_indisclustered,
6801                                 i_indisreplident,
6802                                 i_contype,
6803                                 i_conname,
6804                                 i_condeferrable,
6805                                 i_condeferred,
6806                                 i_contableoid,
6807                                 i_conoid,
6808                                 i_condef,
6809                                 i_tablespace,
6810                                 i_indreloptions,
6811                                 i_indstatcols,
6812                                 i_indstatvals;
6813         int                     ntups;
6814
6815         for (i = 0; i < numTables; i++)
6816         {
6817                 TableInfo  *tbinfo = &tblinfo[i];
6818
6819                 if (!tbinfo->hasindex)
6820                         continue;
6821
6822                 /*
6823                  * Ignore indexes of tables whose definitions are not to be dumped.
6824                  *
6825                  * We also need indexes on partitioned tables which have partitions to
6826                  * be dumped, in order to dump the indexes on the partitions.
6827                  */
6828                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION) &&
6829                         !tbinfo->interesting)
6830                         continue;
6831
6832                 pg_log_info("reading indexes for table \"%s.%s\"",
6833                                         tbinfo->dobj.namespace->dobj.name,
6834                                         tbinfo->dobj.name);
6835
6836                 /*
6837                  * The point of the messy-looking outer join is to find a constraint
6838                  * that is related by an internal dependency link to the index. If we
6839                  * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
6840                  * assume an index won't have more than one internal dependency.
6841                  *
6842                  * As of 9.0 we don't need to look at pg_depend but can check for a
6843                  * match to pg_constraint.conindid.  The check on conrelid is
6844                  * redundant but useful because that column is indexed while conindid
6845                  * is not.
6846                  */
6847                 resetPQExpBuffer(query);
6848                 if (fout->remoteVersion >= 110000)
6849                 {
6850                         appendPQExpBuffer(query,
6851                                                           "SELECT t.tableoid, t.oid, "
6852                                                           "t.relname AS indexname, "
6853                                                           "inh.inhparent AS parentidx, "
6854                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6855                                                           "i.indnkeyatts AS indnkeyatts, "
6856                                                           "i.indnatts AS indnatts, "
6857                                                           "i.indkey, i.indisclustered, "
6858                                                           "i.indisreplident, "
6859                                                           "c.contype, c.conname, "
6860                                                           "c.condeferrable, c.condeferred, "
6861                                                           "c.tableoid AS contableoid, "
6862                                                           "c.oid AS conoid, "
6863                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6864                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6865                                                           "t.reloptions AS indreloptions, "
6866                                                           "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
6867                                                           "  FROM pg_catalog.pg_attribute "
6868                                                           "  WHERE attrelid = i.indexrelid AND "
6869                                                           "    attstattarget >= 0) AS indstatcols,"
6870                                                           "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
6871                                                           "  FROM pg_catalog.pg_attribute "
6872                                                           "  WHERE attrelid = i.indexrelid AND "
6873                                                           "    attstattarget >= 0) AS indstatvals "
6874                                                           "FROM pg_catalog.pg_index i "
6875                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6876                                                           "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
6877                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6878                                                           "ON (i.indrelid = c.conrelid AND "
6879                                                           "i.indexrelid = c.conindid AND "
6880                                                           "c.contype IN ('p','u','x')) "
6881                                                           "LEFT JOIN pg_catalog.pg_inherits inh "
6882                                                           "ON (inh.inhrelid = indexrelid) "
6883                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6884                                                           "AND (i.indisvalid OR t2.relkind = 'p') "
6885                                                           "AND i.indisready "
6886                                                           "ORDER BY indexname",
6887                                                           tbinfo->dobj.catId.oid);
6888                 }
6889                 else if (fout->remoteVersion >= 90400)
6890                 {
6891                         /*
6892                          * the test on indisready is necessary in 9.2, and harmless in
6893                          * earlier/later versions
6894                          */
6895                         appendPQExpBuffer(query,
6896                                                           "SELECT t.tableoid, t.oid, "
6897                                                           "t.relname AS indexname, "
6898                                                           "0 AS parentidx, "
6899                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6900                                                           "i.indnatts AS indnkeyatts, "
6901                                                           "i.indnatts AS indnatts, "
6902                                                           "i.indkey, i.indisclustered, "
6903                                                           "i.indisreplident, "
6904                                                           "c.contype, c.conname, "
6905                                                           "c.condeferrable, c.condeferred, "
6906                                                           "c.tableoid AS contableoid, "
6907                                                           "c.oid AS conoid, "
6908                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6909                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6910                                                           "t.reloptions AS indreloptions, "
6911                                                           "'' AS indstatcols, "
6912                                                           "'' AS indstatvals "
6913                                                           "FROM pg_catalog.pg_index i "
6914                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6915                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6916                                                           "ON (i.indrelid = c.conrelid AND "
6917                                                           "i.indexrelid = c.conindid AND "
6918                                                           "c.contype IN ('p','u','x')) "
6919                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6920                                                           "AND i.indisvalid AND i.indisready "
6921                                                           "ORDER BY indexname",
6922                                                           tbinfo->dobj.catId.oid);
6923                 }
6924                 else if (fout->remoteVersion >= 90000)
6925                 {
6926                         /*
6927                          * the test on indisready is necessary in 9.2, and harmless in
6928                          * earlier/later versions
6929                          */
6930                         appendPQExpBuffer(query,
6931                                                           "SELECT t.tableoid, t.oid, "
6932                                                           "t.relname AS indexname, "
6933                                                           "0 AS parentidx, "
6934                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6935                                                           "i.indnatts AS indnkeyatts, "
6936                                                           "i.indnatts AS indnatts, "
6937                                                           "i.indkey, i.indisclustered, "
6938                                                           "false AS indisreplident, "
6939                                                           "c.contype, c.conname, "
6940                                                           "c.condeferrable, c.condeferred, "
6941                                                           "c.tableoid AS contableoid, "
6942                                                           "c.oid AS conoid, "
6943                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6944                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6945                                                           "t.reloptions AS indreloptions, "
6946                                                           "'' AS indstatcols, "
6947                                                           "'' AS indstatvals "
6948                                                           "FROM pg_catalog.pg_index i "
6949                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6950                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6951                                                           "ON (i.indrelid = c.conrelid AND "
6952                                                           "i.indexrelid = c.conindid AND "
6953                                                           "c.contype IN ('p','u','x')) "
6954                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6955                                                           "AND i.indisvalid AND i.indisready "
6956                                                           "ORDER BY indexname",
6957                                                           tbinfo->dobj.catId.oid);
6958                 }
6959                 else if (fout->remoteVersion >= 80200)
6960                 {
6961                         appendPQExpBuffer(query,
6962                                                           "SELECT t.tableoid, t.oid, "
6963                                                           "t.relname AS indexname, "
6964                                                           "0 AS parentidx, "
6965                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6966                                                           "i.indnatts AS indnkeyatts, "
6967                                                           "i.indnatts AS indnatts, "
6968                                                           "i.indkey, i.indisclustered, "
6969                                                           "false AS indisreplident, "
6970                                                           "c.contype, c.conname, "
6971                                                           "c.condeferrable, c.condeferred, "
6972                                                           "c.tableoid AS contableoid, "
6973                                                           "c.oid AS conoid, "
6974                                                           "null AS condef, "
6975                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6976                                                           "t.reloptions AS indreloptions, "
6977                                                           "'' AS indstatcols, "
6978                                                           "'' AS indstatvals "
6979                                                           "FROM pg_catalog.pg_index i "
6980                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6981                                                           "LEFT JOIN pg_catalog.pg_depend d "
6982                                                           "ON (d.classid = t.tableoid "
6983                                                           "AND d.objid = t.oid "
6984                                                           "AND d.deptype = 'i') "
6985                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6986                                                           "ON (d.refclassid = c.tableoid "
6987                                                           "AND d.refobjid = c.oid) "
6988                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6989                                                           "AND i.indisvalid "
6990                                                           "ORDER BY indexname",
6991                                                           tbinfo->dobj.catId.oid);
6992                 }
6993                 else
6994                 {
6995                         appendPQExpBuffer(query,
6996                                                           "SELECT t.tableoid, t.oid, "
6997                                                           "t.relname AS indexname, "
6998                                                           "0 AS parentidx, "
6999                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
7000                                                           "t.relnatts AS indnkeyatts, "
7001                                                           "t.relnatts AS indnatts, "
7002                                                           "i.indkey, i.indisclustered, "
7003                                                           "false AS indisreplident, "
7004                                                           "c.contype, c.conname, "
7005                                                           "c.condeferrable, c.condeferred, "
7006                                                           "c.tableoid AS contableoid, "
7007                                                           "c.oid AS conoid, "
7008                                                           "null AS condef, "
7009                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
7010                                                           "null AS indreloptions, "
7011                                                           "'' AS indstatcols, "
7012                                                           "'' AS indstatvals "
7013                                                           "FROM pg_catalog.pg_index i "
7014                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
7015                                                           "LEFT JOIN pg_catalog.pg_depend d "
7016                                                           "ON (d.classid = t.tableoid "
7017                                                           "AND d.objid = t.oid "
7018                                                           "AND d.deptype = 'i') "
7019                                                           "LEFT JOIN pg_catalog.pg_constraint c "
7020                                                           "ON (d.refclassid = c.tableoid "
7021                                                           "AND d.refobjid = c.oid) "
7022                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
7023                                                           "ORDER BY indexname",
7024                                                           tbinfo->dobj.catId.oid);
7025                 }
7026
7027                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7028
7029                 ntups = PQntuples(res);
7030
7031                 i_tableoid = PQfnumber(res, "tableoid");
7032                 i_oid = PQfnumber(res, "oid");
7033                 i_indexname = PQfnumber(res, "indexname");
7034                 i_parentidx = PQfnumber(res, "parentidx");
7035                 i_indexdef = PQfnumber(res, "indexdef");
7036                 i_indnkeyatts = PQfnumber(res, "indnkeyatts");
7037                 i_indnatts = PQfnumber(res, "indnatts");
7038                 i_indkey = PQfnumber(res, "indkey");
7039                 i_indisclustered = PQfnumber(res, "indisclustered");
7040                 i_indisreplident = PQfnumber(res, "indisreplident");
7041                 i_contype = PQfnumber(res, "contype");
7042                 i_conname = PQfnumber(res, "conname");
7043                 i_condeferrable = PQfnumber(res, "condeferrable");
7044                 i_condeferred = PQfnumber(res, "condeferred");
7045                 i_contableoid = PQfnumber(res, "contableoid");
7046                 i_conoid = PQfnumber(res, "conoid");
7047                 i_condef = PQfnumber(res, "condef");
7048                 i_tablespace = PQfnumber(res, "tablespace");
7049                 i_indreloptions = PQfnumber(res, "indreloptions");
7050                 i_indstatcols = PQfnumber(res, "indstatcols");
7051                 i_indstatvals = PQfnumber(res, "indstatvals");
7052
7053                 tbinfo->indexes = indxinfo =
7054                         (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
7055                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7056                 tbinfo->numIndexes = ntups;
7057
7058                 for (j = 0; j < ntups; j++)
7059                 {
7060                         char            contype;
7061
7062                         indxinfo[j].dobj.objType = DO_INDEX;
7063                         indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
7064                         indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7065                         AssignDumpId(&indxinfo[j].dobj);
7066                         indxinfo[j].dobj.dump = tbinfo->dobj.dump;
7067                         indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
7068                         indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7069                         indxinfo[j].indextable = tbinfo;
7070                         indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
7071                         indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
7072                         indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
7073                         indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
7074                         indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
7075                         indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
7076                         indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
7077                         indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
7078                         parseOidArray(PQgetvalue(res, j, i_indkey),
7079                                                   indxinfo[j].indkeys, indxinfo[j].indnattrs);
7080                         indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
7081                         indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
7082                         indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
7083                         contype = *(PQgetvalue(res, j, i_contype));
7084
7085                         if (contype == 'p' || contype == 'u' || contype == 'x')
7086                         {
7087                                 /*
7088                                  * If we found a constraint matching the index, create an
7089                                  * entry for it.
7090                                  */
7091                                 constrinfo[j].dobj.objType = DO_CONSTRAINT;
7092                                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7093                                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7094                                 AssignDumpId(&constrinfo[j].dobj);
7095                                 constrinfo[j].dobj.dump = tbinfo->dobj.dump;
7096                                 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7097                                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7098                                 constrinfo[j].contable = tbinfo;
7099                                 constrinfo[j].condomain = NULL;
7100                                 constrinfo[j].contype = contype;
7101                                 if (contype == 'x')
7102                                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
7103                                 else
7104                                         constrinfo[j].condef = NULL;
7105                                 constrinfo[j].confrelid = InvalidOid;
7106                                 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
7107                                 constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
7108                                 constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
7109                                 constrinfo[j].conislocal = true;
7110                                 constrinfo[j].separate = true;
7111
7112                                 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
7113                         }
7114                         else
7115                         {
7116                                 /* Plain secondary index */
7117                                 indxinfo[j].indexconstraint = 0;
7118                         }
7119                 }
7120
7121                 PQclear(res);
7122         }
7123
7124         destroyPQExpBuffer(query);
7125 }
7126
7127 /*
7128  * getExtendedStatistics
7129  *        get information about extended-statistics objects.
7130  *
7131  * Note: extended statistics data is not returned directly to the caller, but
7132  * it does get entered into the DumpableObject tables.
7133  */
7134 void
7135 getExtendedStatistics(Archive *fout)
7136 {
7137         PQExpBuffer query;
7138         PGresult   *res;
7139         StatsExtInfo *statsextinfo;
7140         int                     ntups;
7141         int                     i_tableoid;
7142         int                     i_oid;
7143         int                     i_stxname;
7144         int                     i_stxnamespace;
7145         int                     i_rolname;
7146         int                     i;
7147
7148         /* Extended statistics were new in v10 */
7149         if (fout->remoteVersion < 100000)
7150                 return;
7151
7152         query = createPQExpBuffer();
7153
7154         appendPQExpBuffer(query, "SELECT tableoid, oid, stxname, "
7155                                           "stxnamespace, (%s stxowner) AS rolname "
7156                                           "FROM pg_catalog.pg_statistic_ext",
7157                                           username_subquery);
7158
7159         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7160
7161         ntups = PQntuples(res);
7162
7163         i_tableoid = PQfnumber(res, "tableoid");
7164         i_oid = PQfnumber(res, "oid");
7165         i_stxname = PQfnumber(res, "stxname");
7166         i_stxnamespace = PQfnumber(res, "stxnamespace");
7167         i_rolname = PQfnumber(res, "rolname");
7168
7169         statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
7170
7171         for (i = 0; i < ntups; i++)
7172         {
7173                 statsextinfo[i].dobj.objType = DO_STATSEXT;
7174                 statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7175                 statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7176                 AssignDumpId(&statsextinfo[i].dobj);
7177                 statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
7178                 statsextinfo[i].dobj.namespace =
7179                         findNamespace(fout,
7180                                                   atooid(PQgetvalue(res, i, i_stxnamespace)));
7181                 statsextinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7182
7183                 /* Decide whether we want to dump it */
7184                 selectDumpableObject(&(statsextinfo[i].dobj), fout);
7185
7186                 /* Stats objects do not currently have ACLs. */
7187                 statsextinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7188         }
7189
7190         PQclear(res);
7191         destroyPQExpBuffer(query);
7192 }
7193
7194 /*
7195  * getConstraints
7196  *
7197  * Get info about constraints on dumpable tables.
7198  *
7199  * Currently handles foreign keys only.
7200  * Unique and primary key constraints are handled with indexes,
7201  * while check constraints are processed in getTableAttrs().
7202  */
7203 void
7204 getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
7205 {
7206         int                     i,
7207                                 j;
7208         ConstraintInfo *constrinfo;
7209         PQExpBuffer query;
7210         PGresult   *res;
7211         int                     i_contableoid,
7212                                 i_conoid,
7213                                 i_conname,
7214                                 i_confrelid,
7215                                 i_condef;
7216         int                     ntups;
7217
7218         query = createPQExpBuffer();
7219
7220         for (i = 0; i < numTables; i++)
7221         {
7222                 TableInfo  *tbinfo = &tblinfo[i];
7223
7224                 /*
7225                  * For partitioned tables, foreign keys have no triggers so they must
7226                  * be included anyway in case some foreign keys are defined.
7227                  */
7228                 if ((!tbinfo->hastriggers &&
7229                          tbinfo->relkind != RELKIND_PARTITIONED_TABLE) ||
7230                         !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7231                         continue;
7232
7233                 pg_log_info("reading foreign key constraints for table \"%s.%s\"",
7234                                         tbinfo->dobj.namespace->dobj.name,
7235                                         tbinfo->dobj.name);
7236
7237                 resetPQExpBuffer(query);
7238                 if (fout->remoteVersion >= 110000)
7239                         appendPQExpBuffer(query,
7240                                                           "SELECT tableoid, oid, conname, confrelid, "
7241                                                           "pg_catalog.pg_get_constraintdef(oid) AS condef "
7242                                                           "FROM pg_catalog.pg_constraint "
7243                                                           "WHERE conrelid = '%u'::pg_catalog.oid "
7244                                                           "AND conparentid = 0 "
7245                                                           "AND contype = 'f'",
7246                                                           tbinfo->dobj.catId.oid);
7247                 else
7248                         appendPQExpBuffer(query,
7249                                                           "SELECT tableoid, oid, conname, confrelid, "
7250                                                           "pg_catalog.pg_get_constraintdef(oid) AS condef "
7251                                                           "FROM pg_catalog.pg_constraint "
7252                                                           "WHERE conrelid = '%u'::pg_catalog.oid "
7253                                                           "AND contype = 'f'",
7254                                                           tbinfo->dobj.catId.oid);
7255                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7256
7257                 ntups = PQntuples(res);
7258
7259                 i_contableoid = PQfnumber(res, "tableoid");
7260                 i_conoid = PQfnumber(res, "oid");
7261                 i_conname = PQfnumber(res, "conname");
7262                 i_confrelid = PQfnumber(res, "confrelid");
7263                 i_condef = PQfnumber(res, "condef");
7264
7265                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7266
7267                 for (j = 0; j < ntups; j++)
7268                 {
7269                         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
7270                         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7271                         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7272                         AssignDumpId(&constrinfo[j].dobj);
7273                         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7274                         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7275                         constrinfo[j].contable = tbinfo;
7276                         constrinfo[j].condomain = NULL;
7277                         constrinfo[j].contype = 'f';
7278                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
7279                         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
7280                         constrinfo[j].conindex = 0;
7281                         constrinfo[j].condeferrable = false;
7282                         constrinfo[j].condeferred = false;
7283                         constrinfo[j].conislocal = true;
7284                         constrinfo[j].separate = true;
7285                 }
7286
7287                 PQclear(res);
7288         }
7289
7290         destroyPQExpBuffer(query);
7291 }
7292
7293 /*
7294  * getDomainConstraints
7295  *
7296  * Get info about constraints on a domain.
7297  */
7298 static void
7299 getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
7300 {
7301         int                     i;
7302         ConstraintInfo *constrinfo;
7303         PQExpBuffer query;
7304         PGresult   *res;
7305         int                     i_tableoid,
7306                                 i_oid,
7307                                 i_conname,
7308                                 i_consrc;
7309         int                     ntups;
7310
7311         query = createPQExpBuffer();
7312
7313         if (fout->remoteVersion >= 90100)
7314                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
7315                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7316                                                   "convalidated "
7317                                                   "FROM pg_catalog.pg_constraint "
7318                                                   "WHERE contypid = '%u'::pg_catalog.oid "
7319                                                   "ORDER BY conname",
7320                                                   tyinfo->dobj.catId.oid);
7321
7322         else
7323                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
7324                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7325                                                   "true as convalidated "
7326                                                   "FROM pg_catalog.pg_constraint "
7327                                                   "WHERE contypid = '%u'::pg_catalog.oid "
7328                                                   "ORDER BY conname",
7329                                                   tyinfo->dobj.catId.oid);
7330
7331         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7332
7333         ntups = PQntuples(res);
7334
7335         i_tableoid = PQfnumber(res, "tableoid");
7336         i_oid = PQfnumber(res, "oid");
7337         i_conname = PQfnumber(res, "conname");
7338         i_consrc = PQfnumber(res, "consrc");
7339
7340         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7341
7342         tyinfo->nDomChecks = ntups;
7343         tyinfo->domChecks = constrinfo;
7344
7345         for (i = 0; i < ntups; i++)
7346         {
7347                 bool            validated = PQgetvalue(res, i, 4)[0] == 't';
7348
7349                 constrinfo[i].dobj.objType = DO_CONSTRAINT;
7350                 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7351                 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7352                 AssignDumpId(&constrinfo[i].dobj);
7353                 constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
7354                 constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
7355                 constrinfo[i].contable = NULL;
7356                 constrinfo[i].condomain = tyinfo;
7357                 constrinfo[i].contype = 'c';
7358                 constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
7359                 constrinfo[i].confrelid = InvalidOid;
7360                 constrinfo[i].conindex = 0;
7361                 constrinfo[i].condeferrable = false;
7362                 constrinfo[i].condeferred = false;
7363                 constrinfo[i].conislocal = true;
7364
7365                 constrinfo[i].separate = !validated;
7366
7367                 /*
7368                  * Make the domain depend on the constraint, ensuring it won't be
7369                  * output till any constraint dependencies are OK.  If the constraint
7370                  * has not been validated, it's going to be dumped after the domain
7371                  * anyway, so this doesn't matter.
7372                  */
7373                 if (validated)
7374                         addObjectDependency(&tyinfo->dobj,
7375                                                                 constrinfo[i].dobj.dumpId);
7376         }
7377
7378         PQclear(res);
7379
7380         destroyPQExpBuffer(query);
7381 }
7382
7383 /*
7384  * getRules
7385  *        get basic information about every rule in the system
7386  *
7387  * numRules is set to the number of rules read in
7388  */
7389 RuleInfo *
7390 getRules(Archive *fout, int *numRules)
7391 {
7392         PGresult   *res;
7393         int                     ntups;
7394         int                     i;
7395         PQExpBuffer query = createPQExpBuffer();
7396         RuleInfo   *ruleinfo;
7397         int                     i_tableoid;
7398         int                     i_oid;
7399         int                     i_rulename;
7400         int                     i_ruletable;
7401         int                     i_ev_type;
7402         int                     i_is_instead;
7403         int                     i_ev_enabled;
7404
7405         if (fout->remoteVersion >= 80300)
7406         {
7407                 appendPQExpBufferStr(query, "SELECT "
7408                                                          "tableoid, oid, rulename, "
7409                                                          "ev_class AS ruletable, ev_type, is_instead, "
7410                                                          "ev_enabled "
7411                                                          "FROM pg_rewrite "
7412                                                          "ORDER BY oid");
7413         }
7414         else
7415         {
7416                 appendPQExpBufferStr(query, "SELECT "
7417                                                          "tableoid, oid, rulename, "
7418                                                          "ev_class AS ruletable, ev_type, is_instead, "
7419                                                          "'O'::char AS ev_enabled "
7420                                                          "FROM pg_rewrite "
7421                                                          "ORDER BY oid");
7422         }
7423
7424         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7425
7426         ntups = PQntuples(res);
7427
7428         *numRules = ntups;
7429
7430         ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
7431
7432         i_tableoid = PQfnumber(res, "tableoid");
7433         i_oid = PQfnumber(res, "oid");
7434         i_rulename = PQfnumber(res, "rulename");
7435         i_ruletable = PQfnumber(res, "ruletable");
7436         i_ev_type = PQfnumber(res, "ev_type");
7437         i_is_instead = PQfnumber(res, "is_instead");
7438         i_ev_enabled = PQfnumber(res, "ev_enabled");
7439
7440         for (i = 0; i < ntups; i++)
7441         {
7442                 Oid                     ruletableoid;
7443
7444                 ruleinfo[i].dobj.objType = DO_RULE;
7445                 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7446                 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7447                 AssignDumpId(&ruleinfo[i].dobj);
7448                 ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
7449                 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
7450                 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
7451                 if (ruleinfo[i].ruletable == NULL)
7452                         fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
7453                                                   ruletableoid, ruleinfo[i].dobj.catId.oid);
7454                 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
7455                 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
7456                 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
7457                 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
7458                 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
7459                 if (ruleinfo[i].ruletable)
7460                 {
7461                         /*
7462                          * If the table is a view or materialized view, force its ON
7463                          * SELECT rule to be sorted before the view itself --- this
7464                          * ensures that any dependencies for the rule affect the table's
7465                          * positioning. Other rules are forced to appear after their
7466                          * table.
7467                          */
7468                         if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
7469                                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
7470                                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
7471                         {
7472                                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
7473                                                                         ruleinfo[i].dobj.dumpId);
7474                                 /* We'll merge the rule into CREATE VIEW, if possible */
7475                                 ruleinfo[i].separate = false;
7476                         }
7477                         else
7478                         {
7479                                 addObjectDependency(&ruleinfo[i].dobj,
7480                                                                         ruleinfo[i].ruletable->dobj.dumpId);
7481                                 ruleinfo[i].separate = true;
7482                         }
7483                 }
7484                 else
7485                         ruleinfo[i].separate = true;
7486         }
7487
7488         PQclear(res);
7489
7490         destroyPQExpBuffer(query);
7491
7492         return ruleinfo;
7493 }
7494
7495 /*
7496  * getTriggers
7497  *        get information about every trigger on a dumpable table
7498  *
7499  * Note: trigger data is not returned directly to the caller, but it
7500  * does get entered into the DumpableObject tables.
7501  */
7502 void
7503 getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
7504 {
7505         int                     i,
7506                                 j;
7507         PQExpBuffer query = createPQExpBuffer();
7508         PGresult   *res;
7509         TriggerInfo *tginfo;
7510         int                     i_tableoid,
7511                                 i_oid,
7512                                 i_tgname,
7513                                 i_tgfname,
7514                                 i_tgtype,
7515                                 i_tgnargs,
7516                                 i_tgargs,
7517                                 i_tgisconstraint,
7518                                 i_tgconstrname,
7519                                 i_tgconstrrelid,
7520                                 i_tgconstrrelname,
7521                                 i_tgenabled,
7522                                 i_tgdeferrable,
7523                                 i_tginitdeferred,
7524                                 i_tgdef;
7525         int                     ntups;
7526
7527         for (i = 0; i < numTables; i++)
7528         {
7529                 TableInfo  *tbinfo = &tblinfo[i];
7530
7531                 if (!tbinfo->hastriggers ||
7532                         !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7533                         continue;
7534
7535                 pg_log_info("reading triggers for table \"%s.%s\"",
7536                                         tbinfo->dobj.namespace->dobj.name,
7537                                         tbinfo->dobj.name);
7538
7539                 resetPQExpBuffer(query);
7540                 if (fout->remoteVersion >= 90000)
7541                 {
7542                         /*
7543                          * NB: think not to use pretty=true in pg_get_triggerdef.  It
7544                          * could result in non-forward-compatible dumps of WHEN clauses
7545                          * due to under-parenthesization.
7546                          */
7547                         appendPQExpBuffer(query,
7548                                                           "SELECT tgname, "
7549                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7550                                                           "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
7551                                                           "tgenabled, tableoid, oid "
7552                                                           "FROM pg_catalog.pg_trigger t "
7553                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7554                                                           "AND NOT tgisinternal",
7555                                                           tbinfo->dobj.catId.oid);
7556                 }
7557                 else if (fout->remoteVersion >= 80300)
7558                 {
7559                         /*
7560                          * We ignore triggers that are tied to a foreign-key constraint
7561                          */
7562                         appendPQExpBuffer(query,
7563                                                           "SELECT tgname, "
7564                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7565                                                           "tgtype, tgnargs, tgargs, tgenabled, "
7566                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
7567                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
7568                                                           "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
7569                                                           "FROM pg_catalog.pg_trigger t "
7570                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7571                                                           "AND tgconstraint = 0",
7572                                                           tbinfo->dobj.catId.oid);
7573                 }
7574                 else
7575                 {
7576                         /*
7577                          * We ignore triggers that are tied to a foreign-key constraint,
7578                          * but in these versions we have to grovel through pg_constraint
7579                          * to find out
7580                          */
7581                         appendPQExpBuffer(query,
7582                                                           "SELECT tgname, "
7583                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7584                                                           "tgtype, tgnargs, tgargs, tgenabled, "
7585                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
7586                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
7587                                                           "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
7588                                                           "FROM pg_catalog.pg_trigger t "
7589                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7590                                                           "AND (NOT tgisconstraint "
7591                                                           " OR NOT EXISTS"
7592                                                           "  (SELECT 1 FROM pg_catalog.pg_depend d "
7593                                                           "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
7594                                                           "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
7595                                                           tbinfo->dobj.catId.oid);
7596                 }
7597
7598                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7599
7600                 ntups = PQntuples(res);
7601
7602                 i_tableoid = PQfnumber(res, "tableoid");
7603                 i_oid = PQfnumber(res, "oid");
7604                 i_tgname = PQfnumber(res, "tgname");
7605                 i_tgfname = PQfnumber(res, "tgfname");
7606                 i_tgtype = PQfnumber(res, "tgtype");
7607                 i_tgnargs = PQfnumber(res, "tgnargs");
7608                 i_tgargs = PQfnumber(res, "tgargs");
7609                 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
7610                 i_tgconstrname = PQfnumber(res, "tgconstrname");
7611                 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
7612                 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
7613                 i_tgenabled = PQfnumber(res, "tgenabled");
7614                 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
7615                 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
7616                 i_tgdef = PQfnumber(res, "tgdef");
7617
7618                 tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
7619
7620                 tbinfo->numTriggers = ntups;
7621                 tbinfo->triggers = tginfo;
7622
7623                 for (j = 0; j < ntups; j++)
7624                 {
7625                         tginfo[j].dobj.objType = DO_TRIGGER;
7626                         tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
7627                         tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7628                         AssignDumpId(&tginfo[j].dobj);
7629                         tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
7630                         tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
7631                         tginfo[j].tgtable = tbinfo;
7632                         tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
7633                         if (i_tgdef >= 0)
7634                         {
7635                                 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
7636
7637                                 /* remaining fields are not valid if we have tgdef */
7638                                 tginfo[j].tgfname = NULL;
7639                                 tginfo[j].tgtype = 0;
7640                                 tginfo[j].tgnargs = 0;
7641                                 tginfo[j].tgargs = NULL;
7642                                 tginfo[j].tgisconstraint = false;
7643                                 tginfo[j].tgdeferrable = false;
7644                                 tginfo[j].tginitdeferred = false;
7645                                 tginfo[j].tgconstrname = NULL;
7646                                 tginfo[j].tgconstrrelid = InvalidOid;
7647                                 tginfo[j].tgconstrrelname = NULL;
7648                         }
7649                         else
7650                         {
7651                                 tginfo[j].tgdef = NULL;
7652
7653                                 tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
7654                                 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
7655                                 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
7656                                 tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
7657                                 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
7658                                 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
7659                                 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
7660
7661                                 if (tginfo[j].tgisconstraint)
7662                                 {
7663                                         tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
7664                                         tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
7665                                         if (OidIsValid(tginfo[j].tgconstrrelid))
7666                                         {
7667                                                 if (PQgetisnull(res, j, i_tgconstrrelname))
7668                                                         fatal("query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)",
7669                                                                                   tginfo[j].dobj.name,
7670                                                                                   tbinfo->dobj.name,
7671                                                                                   tginfo[j].tgconstrrelid);
7672                                                 tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
7673                                         }
7674                                         else
7675                                                 tginfo[j].tgconstrrelname = NULL;
7676                                 }
7677                                 else
7678                                 {
7679                                         tginfo[j].tgconstrname = NULL;
7680                                         tginfo[j].tgconstrrelid = InvalidOid;
7681                                         tginfo[j].tgconstrrelname = NULL;
7682                                 }
7683                         }
7684                 }
7685
7686                 PQclear(res);
7687         }
7688
7689         destroyPQExpBuffer(query);
7690 }
7691
7692 /*
7693  * getEventTriggers
7694  *        get information about event triggers
7695  */
7696 EventTriggerInfo *
7697 getEventTriggers(Archive *fout, int *numEventTriggers)
7698 {
7699         int                     i;
7700         PQExpBuffer query;
7701         PGresult   *res;
7702         EventTriggerInfo *evtinfo;
7703         int                     i_tableoid,
7704                                 i_oid,
7705                                 i_evtname,
7706                                 i_evtevent,
7707                                 i_evtowner,
7708                                 i_evttags,
7709                                 i_evtfname,
7710                                 i_evtenabled;
7711         int                     ntups;
7712
7713         /* Before 9.3, there are no event triggers */
7714         if (fout->remoteVersion < 90300)
7715         {
7716                 *numEventTriggers = 0;
7717                 return NULL;
7718         }
7719
7720         query = createPQExpBuffer();
7721
7722         appendPQExpBuffer(query,
7723                                           "SELECT e.tableoid, e.oid, evtname, evtenabled, "
7724                                           "evtevent, (%s evtowner) AS evtowner, "
7725                                           "array_to_string(array("
7726                                           "select quote_literal(x) "
7727                                           " from unnest(evttags) as t(x)), ', ') as evttags, "
7728                                           "e.evtfoid::regproc as evtfname "
7729                                           "FROM pg_event_trigger e "
7730                                           "ORDER BY e.oid",
7731                                           username_subquery);
7732
7733         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7734
7735         ntups = PQntuples(res);
7736
7737         *numEventTriggers = ntups;
7738
7739         evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
7740
7741         i_tableoid = PQfnumber(res, "tableoid");
7742         i_oid = PQfnumber(res, "oid");
7743         i_evtname = PQfnumber(res, "evtname");
7744         i_evtevent = PQfnumber(res, "evtevent");
7745         i_evtowner = PQfnumber(res, "evtowner");
7746         i_evttags = PQfnumber(res, "evttags");
7747         i_evtfname = PQfnumber(res, "evtfname");
7748         i_evtenabled = PQfnumber(res, "evtenabled");
7749
7750         for (i = 0; i < ntups; i++)
7751         {
7752                 evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
7753                 evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7754                 evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7755                 AssignDumpId(&evtinfo[i].dobj);
7756                 evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
7757                 evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
7758                 evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
7759                 evtinfo[i].evtowner = pg_strdup(PQgetvalue(res, i, i_evtowner));
7760                 evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
7761                 evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
7762                 evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
7763
7764                 /* Decide whether we want to dump it */
7765                 selectDumpableObject(&(evtinfo[i].dobj), fout);
7766
7767                 /* Event Triggers do not currently have ACLs. */
7768                 evtinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7769         }
7770
7771         PQclear(res);
7772
7773         destroyPQExpBuffer(query);
7774
7775         return evtinfo;
7776 }
7777
7778 /*
7779  * getProcLangs
7780  *        get basic information about every procedural language in the system
7781  *
7782  * numProcLangs is set to the number of langs read in
7783  *
7784  * NB: this must run after getFuncs() because we assume we can do
7785  * findFuncByOid().
7786  */
7787 ProcLangInfo *
7788 getProcLangs(Archive *fout, int *numProcLangs)
7789 {
7790         DumpOptions *dopt = fout->dopt;
7791         PGresult   *res;
7792         int                     ntups;
7793         int                     i;
7794         PQExpBuffer query = createPQExpBuffer();
7795         ProcLangInfo *planginfo;
7796         int                     i_tableoid;
7797         int                     i_oid;
7798         int                     i_lanname;
7799         int                     i_lanpltrusted;
7800         int                     i_lanplcallfoid;
7801         int                     i_laninline;
7802         int                     i_lanvalidator;
7803         int                     i_lanacl;
7804         int                     i_rlanacl;
7805         int                     i_initlanacl;
7806         int                     i_initrlanacl;
7807         int                     i_lanowner;
7808
7809         if (fout->remoteVersion >= 90600)
7810         {
7811                 PQExpBuffer acl_subquery = createPQExpBuffer();
7812                 PQExpBuffer racl_subquery = createPQExpBuffer();
7813                 PQExpBuffer initacl_subquery = createPQExpBuffer();
7814                 PQExpBuffer initracl_subquery = createPQExpBuffer();
7815
7816                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
7817                                                 initracl_subquery, "l.lanacl", "l.lanowner", "'l'",
7818                                                 dopt->binary_upgrade);
7819
7820                 /* pg_language has a laninline column */
7821                 appendPQExpBuffer(query, "SELECT l.tableoid, l.oid, "
7822                                                   "l.lanname, l.lanpltrusted, l.lanplcallfoid, "
7823                                                   "l.laninline, l.lanvalidator, "
7824                                                   "%s AS lanacl, "
7825                                                   "%s AS rlanacl, "
7826                                                   "%s AS initlanacl, "
7827                                                   "%s AS initrlanacl, "
7828                                                   "(%s l.lanowner) AS lanowner "
7829                                                   "FROM pg_language l "
7830                                                   "LEFT JOIN pg_init_privs pip ON "
7831                                                   "(l.oid = pip.objoid "
7832                                                   "AND pip.classoid = 'pg_language'::regclass "
7833                                                   "AND pip.objsubid = 0) "
7834                                                   "WHERE l.lanispl "
7835                                                   "ORDER BY l.oid",
7836                                                   acl_subquery->data,
7837                                                   racl_subquery->data,
7838                                                   initacl_subquery->data,
7839                                                   initracl_subquery->data,
7840                                                   username_subquery);
7841
7842                 destroyPQExpBuffer(acl_subquery);
7843                 destroyPQExpBuffer(racl_subquery);
7844                 destroyPQExpBuffer(initacl_subquery);
7845                 destroyPQExpBuffer(initracl_subquery);
7846         }
7847         else if (fout->remoteVersion >= 90000)
7848         {
7849                 /* pg_language has a laninline column */
7850                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7851                                                   "lanname, lanpltrusted, lanplcallfoid, "
7852                                                   "laninline, lanvalidator, lanacl, NULL AS rlanacl, "
7853                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7854                                                   "(%s lanowner) AS lanowner "
7855                                                   "FROM pg_language "
7856                                                   "WHERE lanispl "
7857                                                   "ORDER BY oid",
7858                                                   username_subquery);
7859         }
7860         else if (fout->remoteVersion >= 80300)
7861         {
7862                 /* pg_language has a lanowner column */
7863                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7864                                                   "lanname, lanpltrusted, lanplcallfoid, "
7865                                                   "0 AS laninline, lanvalidator, lanacl, "
7866                                                   "NULL AS rlanacl, "
7867                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7868                                                   "(%s lanowner) AS lanowner "
7869                                                   "FROM pg_language "
7870                                                   "WHERE lanispl "
7871                                                   "ORDER BY oid",
7872                                                   username_subquery);
7873         }
7874         else if (fout->remoteVersion >= 80100)
7875         {
7876                 /* Languages are owned by the bootstrap superuser, OID 10 */
7877                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7878                                                   "lanname, lanpltrusted, lanplcallfoid, "
7879                                                   "0 AS laninline, lanvalidator, lanacl, "
7880                                                   "NULL AS rlanacl, "
7881                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7882                                                   "(%s '10') AS lanowner "
7883                                                   "FROM pg_language "
7884                                                   "WHERE lanispl "
7885                                                   "ORDER BY oid",
7886                                                   username_subquery);
7887         }
7888         else
7889         {
7890                 /* Languages are owned by the bootstrap superuser, sysid 1 */
7891                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7892                                                   "lanname, lanpltrusted, lanplcallfoid, "
7893                                                   "0 AS laninline, lanvalidator, lanacl, "
7894                                                   "NULL AS rlanacl, "
7895                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7896                                                   "(%s '1') AS lanowner "
7897                                                   "FROM pg_language "
7898                                                   "WHERE lanispl "
7899                                                   "ORDER BY oid",
7900                                                   username_subquery);
7901         }
7902
7903         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7904
7905         ntups = PQntuples(res);
7906
7907         *numProcLangs = ntups;
7908
7909         planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
7910
7911         i_tableoid = PQfnumber(res, "tableoid");
7912         i_oid = PQfnumber(res, "oid");
7913         i_lanname = PQfnumber(res, "lanname");
7914         i_lanpltrusted = PQfnumber(res, "lanpltrusted");
7915         i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
7916         i_laninline = PQfnumber(res, "laninline");
7917         i_lanvalidator = PQfnumber(res, "lanvalidator");
7918         i_lanacl = PQfnumber(res, "lanacl");
7919         i_rlanacl = PQfnumber(res, "rlanacl");
7920         i_initlanacl = PQfnumber(res, "initlanacl");
7921         i_initrlanacl = PQfnumber(res, "initrlanacl");
7922         i_lanowner = PQfnumber(res, "lanowner");
7923
7924         for (i = 0; i < ntups; i++)
7925         {
7926                 planginfo[i].dobj.objType = DO_PROCLANG;
7927                 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7928                 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7929                 AssignDumpId(&planginfo[i].dobj);
7930
7931                 planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
7932                 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
7933                 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
7934                 planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
7935                 planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
7936                 planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
7937                 planginfo[i].rlanacl = pg_strdup(PQgetvalue(res, i, i_rlanacl));
7938                 planginfo[i].initlanacl = pg_strdup(PQgetvalue(res, i, i_initlanacl));
7939                 planginfo[i].initrlanacl = pg_strdup(PQgetvalue(res, i, i_initrlanacl));
7940                 planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
7941
7942                 /* Decide whether we want to dump it */
7943                 selectDumpableProcLang(&(planginfo[i]), fout);
7944
7945                 /* Do not try to dump ACL if no ACL exists. */
7946                 if (PQgetisnull(res, i, i_lanacl) && PQgetisnull(res, i, i_rlanacl) &&
7947                         PQgetisnull(res, i, i_initlanacl) &&
7948                         PQgetisnull(res, i, i_initrlanacl))
7949                         planginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7950         }
7951
7952         PQclear(res);
7953
7954         destroyPQExpBuffer(query);
7955
7956         return planginfo;
7957 }
7958
7959 /*
7960  * getCasts
7961  *        get basic information about every cast in the system
7962  *
7963  * numCasts is set to the number of casts read in
7964  */
7965 CastInfo *
7966 getCasts(Archive *fout, int *numCasts)
7967 {
7968         PGresult   *res;
7969         int                     ntups;
7970         int                     i;
7971         PQExpBuffer query = createPQExpBuffer();
7972         CastInfo   *castinfo;
7973         int                     i_tableoid;
7974         int                     i_oid;
7975         int                     i_castsource;
7976         int                     i_casttarget;
7977         int                     i_castfunc;
7978         int                     i_castcontext;
7979         int                     i_castmethod;
7980
7981         if (fout->remoteVersion >= 80400)
7982         {
7983                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
7984                                                          "castsource, casttarget, castfunc, castcontext, "
7985                                                          "castmethod "
7986                                                          "FROM pg_cast ORDER BY 3,4");
7987         }
7988         else
7989         {
7990                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
7991                                                          "castsource, casttarget, castfunc, castcontext, "
7992                                                          "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
7993                                                          "FROM pg_cast ORDER BY 3,4");
7994         }
7995
7996         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7997
7998         ntups = PQntuples(res);
7999
8000         *numCasts = ntups;
8001
8002         castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
8003
8004         i_tableoid = PQfnumber(res, "tableoid");
8005         i_oid = PQfnumber(res, "oid");
8006         i_castsource = PQfnumber(res, "castsource");
8007         i_casttarget = PQfnumber(res, "casttarget");
8008         i_castfunc = PQfnumber(res, "castfunc");
8009         i_castcontext = PQfnumber(res, "castcontext");
8010         i_castmethod = PQfnumber(res, "castmethod");
8011
8012         for (i = 0; i < ntups; i++)
8013         {
8014                 PQExpBufferData namebuf;
8015                 TypeInfo   *sTypeInfo;
8016                 TypeInfo   *tTypeInfo;
8017
8018                 castinfo[i].dobj.objType = DO_CAST;
8019                 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8020                 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8021                 AssignDumpId(&castinfo[i].dobj);
8022                 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
8023                 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
8024                 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
8025                 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
8026                 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
8027
8028                 /*
8029                  * Try to name cast as concatenation of typnames.  This is only used
8030                  * for purposes of sorting.  If we fail to find either type, the name
8031                  * will be an empty string.
8032                  */
8033                 initPQExpBuffer(&namebuf);
8034                 sTypeInfo = findTypeByOid(castinfo[i].castsource);
8035                 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
8036                 if (sTypeInfo && tTypeInfo)
8037                         appendPQExpBuffer(&namebuf, "%s %s",
8038                                                           sTypeInfo->dobj.name, tTypeInfo->dobj.name);
8039                 castinfo[i].dobj.name = namebuf.data;
8040
8041                 /* Decide whether we want to dump it */
8042                 selectDumpableCast(&(castinfo[i]), fout);
8043
8044                 /* Casts do not currently have ACLs. */
8045                 castinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8046         }
8047
8048         PQclear(res);
8049
8050         destroyPQExpBuffer(query);
8051
8052         return castinfo;
8053 }
8054
8055 static char *
8056 get_language_name(Archive *fout, Oid langid)
8057 {
8058         PQExpBuffer query;
8059         PGresult   *res;
8060         char       *lanname;
8061
8062         query = createPQExpBuffer();
8063         appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
8064         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8065         lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
8066         destroyPQExpBuffer(query);
8067         PQclear(res);
8068
8069         return lanname;
8070 }
8071
8072 /*
8073  * getTransforms
8074  *        get basic information about every transform in the system
8075  *
8076  * numTransforms is set to the number of transforms read in
8077  */
8078 TransformInfo *
8079 getTransforms(Archive *fout, int *numTransforms)
8080 {
8081         PGresult   *res;
8082         int                     ntups;
8083         int                     i;
8084         PQExpBuffer query;
8085         TransformInfo *transforminfo;
8086         int                     i_tableoid;
8087         int                     i_oid;
8088         int                     i_trftype;
8089         int                     i_trflang;
8090         int                     i_trffromsql;
8091         int                     i_trftosql;
8092
8093         /* Transforms didn't exist pre-9.5 */
8094         if (fout->remoteVersion < 90500)
8095         {
8096                 *numTransforms = 0;
8097                 return NULL;
8098         }
8099
8100         query = createPQExpBuffer();
8101
8102         appendPQExpBuffer(query, "SELECT tableoid, oid, "
8103                                           "trftype, trflang, trffromsql::oid, trftosql::oid "
8104                                           "FROM pg_transform "
8105                                           "ORDER BY 3,4");
8106
8107         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8108
8109         ntups = PQntuples(res);
8110
8111         *numTransforms = ntups;
8112
8113         transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
8114
8115         i_tableoid = PQfnumber(res, "tableoid");
8116         i_oid = PQfnumber(res, "oid");
8117         i_trftype = PQfnumber(res, "trftype");
8118         i_trflang = PQfnumber(res, "trflang");
8119         i_trffromsql = PQfnumber(res, "trffromsql");
8120         i_trftosql = PQfnumber(res, "trftosql");
8121
8122         for (i = 0; i < ntups; i++)
8123         {
8124                 PQExpBufferData namebuf;
8125                 TypeInfo   *typeInfo;
8126                 char       *lanname;
8127
8128                 transforminfo[i].dobj.objType = DO_TRANSFORM;
8129                 transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8130                 transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8131                 AssignDumpId(&transforminfo[i].dobj);
8132                 transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
8133                 transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
8134                 transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
8135                 transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
8136
8137                 /*
8138                  * Try to name transform as concatenation of type and language name.
8139                  * This is only used for purposes of sorting.  If we fail to find
8140                  * either, the name will be an empty string.
8141                  */
8142                 initPQExpBuffer(&namebuf);
8143                 typeInfo = findTypeByOid(transforminfo[i].trftype);
8144                 lanname = get_language_name(fout, transforminfo[i].trflang);
8145                 if (typeInfo && lanname)
8146                         appendPQExpBuffer(&namebuf, "%s %s",
8147                                                           typeInfo->dobj.name, lanname);
8148                 transforminfo[i].dobj.name = namebuf.data;
8149                 free(lanname);
8150
8151                 /* Decide whether we want to dump it */
8152                 selectDumpableObject(&(transforminfo[i].dobj), fout);
8153         }
8154
8155         PQclear(res);
8156
8157         destroyPQExpBuffer(query);
8158
8159         return transforminfo;
8160 }
8161
8162 /*
8163  * getTableAttrs -
8164  *        for each interesting table, read info about its attributes
8165  *        (names, types, default values, CHECK constraints, etc)
8166  *
8167  * This is implemented in a very inefficient way right now, looping
8168  * through the tblinfo and doing a join per table to find the attrs and their
8169  * types.  However, because we want type names and so forth to be named
8170  * relative to the schema of each table, we couldn't do it in just one
8171  * query.  (Maybe one query per schema?)
8172  *
8173  *      modifies tblinfo
8174  */
8175 void
8176 getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
8177 {
8178         DumpOptions *dopt = fout->dopt;
8179         int                     i,
8180                                 j;
8181         PQExpBuffer q = createPQExpBuffer();
8182         int                     i_attnum;
8183         int                     i_attname;
8184         int                     i_atttypname;
8185         int                     i_atttypmod;
8186         int                     i_attstattarget;
8187         int                     i_attstorage;
8188         int                     i_typstorage;
8189         int                     i_attnotnull;
8190         int                     i_atthasdef;
8191         int                     i_attidentity;
8192         int                     i_attgenerated;
8193         int                     i_attisdropped;
8194         int                     i_attlen;
8195         int                     i_attalign;
8196         int                     i_attislocal;
8197         int                     i_attoptions;
8198         int                     i_attcollation;
8199         int                     i_attfdwoptions;
8200         int                     i_attmissingval;
8201         PGresult   *res;
8202         int                     ntups;
8203         bool            hasdefaults;
8204
8205         for (i = 0; i < numTables; i++)
8206         {
8207                 TableInfo  *tbinfo = &tblinfo[i];
8208
8209                 /* Don't bother to collect info for sequences */
8210                 if (tbinfo->relkind == RELKIND_SEQUENCE)
8211                         continue;
8212
8213                 /* Don't bother with uninteresting tables, either */
8214                 if (!tbinfo->interesting)
8215                         continue;
8216
8217                 /* find all the user attributes and their types */
8218
8219                 /*
8220                  * we must read the attribute names in attribute number order! because
8221                  * we will use the attnum to index into the attnames array later.
8222                  */
8223                 pg_log_info("finding the columns and types of table \"%s.%s\"",
8224                                         tbinfo->dobj.namespace->dobj.name,
8225                                         tbinfo->dobj.name);
8226
8227                 resetPQExpBuffer(q);
8228
8229                 appendPQExpBuffer(q,
8230                                                   "SELECT\n"
8231                                                   "a.attnum,\n"
8232                                                   "a.attname,\n"
8233                                                   "a.atttypmod,\n"
8234                                                   "a.attstattarget,\n"
8235                                                   "a.attstorage,\n"
8236                                                   "t.typstorage,\n"
8237                                                   "a.attnotnull,\n"
8238                                                   "a.atthasdef,\n"
8239                                                   "a.attisdropped,\n"
8240                                                   "a.attlen,\n"
8241                                                   "a.attalign,\n"
8242                                                   "a.attislocal,\n"
8243                                                   "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n");
8244
8245                 if (fout->remoteVersion >= 120000)
8246                         appendPQExpBuffer(q,
8247                                                           "a.attgenerated,\n");
8248                 else
8249                         appendPQExpBuffer(q,
8250                                                           "'' AS attgenerated,\n");
8251
8252                 if (fout->remoteVersion >= 110000)
8253                         appendPQExpBuffer(q,
8254                                                           "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
8255                                                           "THEN a.attmissingval ELSE null END AS attmissingval,\n");
8256                 else
8257                         appendPQExpBuffer(q,
8258                                                           "NULL AS attmissingval,\n");
8259
8260                 if (fout->remoteVersion >= 100000)
8261                         appendPQExpBuffer(q,
8262                                                           "a.attidentity,\n");
8263                 else
8264                         appendPQExpBuffer(q,
8265                                                           "'' AS attidentity,\n");
8266
8267                 if (fout->remoteVersion >= 90200)
8268                         appendPQExpBuffer(q,
8269                                                           "pg_catalog.array_to_string(ARRAY("
8270                                                           "SELECT pg_catalog.quote_ident(option_name) || "
8271                                                           "' ' || pg_catalog.quote_literal(option_value) "
8272                                                           "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
8273                                                           "ORDER BY option_name"
8274                                                           "), E',\n    ') AS attfdwoptions,\n");
8275                 else
8276                         appendPQExpBuffer(q,
8277                                                           "'' AS attfdwoptions,\n");
8278
8279                 if (fout->remoteVersion >= 90100)
8280                 {
8281                         /*
8282                          * Since we only want to dump COLLATE clauses for attributes whose
8283                          * collation is different from their type's default, we use a CASE
8284                          * here to suppress uninteresting attcollations cheaply.
8285                          */
8286                         appendPQExpBuffer(q,
8287                                                           "CASE WHEN a.attcollation <> t.typcollation "
8288                                                           "THEN a.attcollation ELSE 0 END AS attcollation,\n");
8289                 }
8290                 else
8291                         appendPQExpBuffer(q,
8292                                                           "0 AS attcollation,\n");
8293
8294                 if (fout->remoteVersion >= 90000)
8295                         appendPQExpBuffer(q,
8296                                                           "array_to_string(a.attoptions, ', ') AS attoptions\n");
8297                 else
8298                         appendPQExpBuffer(q,
8299                                                           "'' AS attoptions\n");
8300
8301                 /* need left join here to not fail on dropped columns ... */
8302                 appendPQExpBuffer(q,
8303                                                   "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
8304                                                   "ON a.atttypid = t.oid\n"
8305                                                   "WHERE a.attrelid = '%u'::pg_catalog.oid "
8306                                                   "AND a.attnum > 0::pg_catalog.int2\n"
8307                                                   "ORDER BY a.attnum",
8308                                                   tbinfo->dobj.catId.oid);
8309
8310                 res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8311
8312                 ntups = PQntuples(res);
8313
8314                 i_attnum = PQfnumber(res, "attnum");
8315                 i_attname = PQfnumber(res, "attname");
8316                 i_atttypname = PQfnumber(res, "atttypname");
8317                 i_atttypmod = PQfnumber(res, "atttypmod");
8318                 i_attstattarget = PQfnumber(res, "attstattarget");
8319                 i_attstorage = PQfnumber(res, "attstorage");
8320                 i_typstorage = PQfnumber(res, "typstorage");
8321                 i_attnotnull = PQfnumber(res, "attnotnull");
8322                 i_atthasdef = PQfnumber(res, "atthasdef");
8323                 i_attidentity = PQfnumber(res, "attidentity");
8324                 i_attgenerated = PQfnumber(res, "attgenerated");
8325                 i_attisdropped = PQfnumber(res, "attisdropped");
8326                 i_attlen = PQfnumber(res, "attlen");
8327                 i_attalign = PQfnumber(res, "attalign");
8328                 i_attislocal = PQfnumber(res, "attislocal");
8329                 i_attoptions = PQfnumber(res, "attoptions");
8330                 i_attcollation = PQfnumber(res, "attcollation");
8331                 i_attfdwoptions = PQfnumber(res, "attfdwoptions");
8332                 i_attmissingval = PQfnumber(res, "attmissingval");
8333
8334                 tbinfo->numatts = ntups;
8335                 tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
8336                 tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
8337                 tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
8338                 tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
8339                 tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
8340                 tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
8341                 tbinfo->attidentity = (char *) pg_malloc(ntups * sizeof(char));
8342                 tbinfo->attgenerated = (char *) pg_malloc(ntups * sizeof(char));
8343                 tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
8344                 tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
8345                 tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
8346                 tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
8347                 tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
8348                 tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
8349                 tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
8350                 tbinfo->attmissingval = (char **) pg_malloc(ntups * sizeof(char *));
8351                 tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
8352                 tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
8353                 tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
8354                 hasdefaults = false;
8355
8356                 for (j = 0; j < ntups; j++)
8357                 {
8358                         if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
8359                                 fatal("invalid column numbering in table \"%s\"",
8360                                                           tbinfo->dobj.name);
8361                         tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
8362                         tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
8363                         tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
8364                         tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
8365                         tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
8366                         tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
8367                         tbinfo->attidentity[j] = *(PQgetvalue(res, j, i_attidentity));
8368                         tbinfo->attgenerated[j] = *(PQgetvalue(res, j, i_attgenerated));
8369                         tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
8370                         tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
8371                         tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
8372                         tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
8373                         tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
8374                         tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
8375                         tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
8376                         tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
8377                         tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
8378                         tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, j, i_attmissingval));
8379                         tbinfo->attrdefs[j] = NULL; /* fix below */
8380                         if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
8381                                 hasdefaults = true;
8382                         /* these flags will be set in flagInhAttrs() */
8383                         tbinfo->inhNotNull[j] = false;
8384                 }
8385
8386                 PQclear(res);
8387
8388                 /*
8389                  * Get info about column defaults
8390                  */
8391                 if (hasdefaults)
8392                 {
8393                         AttrDefInfo *attrdefs;
8394                         int                     numDefaults;
8395
8396                         pg_log_info("finding default expressions of table \"%s.%s\"",
8397                                                 tbinfo->dobj.namespace->dobj.name,
8398                                                 tbinfo->dobj.name);
8399
8400                         printfPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
8401                                                           "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
8402                                                           "FROM pg_catalog.pg_attrdef "
8403                                                           "WHERE adrelid = '%u'::pg_catalog.oid",
8404                                                           tbinfo->dobj.catId.oid);
8405
8406                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8407
8408                         numDefaults = PQntuples(res);
8409                         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
8410
8411                         for (j = 0; j < numDefaults; j++)
8412                         {
8413                                 int                     adnum;
8414
8415                                 adnum = atoi(PQgetvalue(res, j, 2));
8416
8417                                 if (adnum <= 0 || adnum > ntups)
8418                                         fatal("invalid adnum value %d for table \"%s\"",
8419                                                                   adnum, tbinfo->dobj.name);
8420
8421                                 /*
8422                                  * dropped columns shouldn't have defaults, but just in case,
8423                                  * ignore 'em
8424                                  */
8425                                 if (tbinfo->attisdropped[adnum - 1])
8426                                         continue;
8427
8428                                 attrdefs[j].dobj.objType = DO_ATTRDEF;
8429                                 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
8430                                 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
8431                                 AssignDumpId(&attrdefs[j].dobj);
8432                                 attrdefs[j].adtable = tbinfo;
8433                                 attrdefs[j].adnum = adnum;
8434                                 attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
8435
8436                                 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
8437                                 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
8438
8439                                 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
8440
8441                                 /*
8442                                  * Defaults on a VIEW must always be dumped as separate ALTER
8443                                  * TABLE commands.  Defaults on regular tables are dumped as
8444                                  * part of the CREATE TABLE if possible, which it won't be if
8445                                  * the column is not going to be emitted explicitly.
8446                                  */
8447                                 if (tbinfo->relkind == RELKIND_VIEW)
8448                                 {
8449                                         attrdefs[j].separate = true;
8450                                 }
8451                                 else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
8452                                 {
8453                                         /* column will be suppressed, print default separately */
8454                                         attrdefs[j].separate = true;
8455                                 }
8456                                 else
8457                                 {
8458                                         attrdefs[j].separate = false;
8459
8460                                         /*
8461                                          * Mark the default as needing to appear before the table,
8462                                          * so that any dependencies it has must be emitted before
8463                                          * the CREATE TABLE.  If this is not possible, we'll
8464                                          * change to "separate" mode while sorting dependencies.
8465                                          */
8466                                         addObjectDependency(&tbinfo->dobj,
8467                                                                                 attrdefs[j].dobj.dumpId);
8468                                 }
8469
8470                                 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
8471                         }
8472                         PQclear(res);
8473                 }
8474
8475                 /*
8476                  * Get info about table CHECK constraints
8477                  */
8478                 if (tbinfo->ncheck > 0)
8479                 {
8480                         ConstraintInfo *constrs;
8481                         int                     numConstrs;
8482
8483                         pg_log_info("finding check constraints for table \"%s.%s\"",
8484                                                 tbinfo->dobj.namespace->dobj.name,
8485                                                 tbinfo->dobj.name);
8486
8487                         resetPQExpBuffer(q);
8488                         if (fout->remoteVersion >= 90200)
8489                         {
8490                                 /*
8491                                  * convalidated is new in 9.2 (actually, it is there in 9.1,
8492                                  * but it wasn't ever false for check constraints until 9.2).
8493                                  */
8494                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8495                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8496                                                                   "conislocal, convalidated "
8497                                                                   "FROM pg_catalog.pg_constraint "
8498                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8499                                                                   "   AND contype = 'c' "
8500                                                                   "ORDER BY conname",
8501                                                                   tbinfo->dobj.catId.oid);
8502                         }
8503                         else if (fout->remoteVersion >= 80400)
8504                         {
8505                                 /* conislocal is new in 8.4 */
8506                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8507                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8508                                                                   "conislocal, true AS convalidated "
8509                                                                   "FROM pg_catalog.pg_constraint "
8510                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8511                                                                   "   AND contype = 'c' "
8512                                                                   "ORDER BY conname",
8513                                                                   tbinfo->dobj.catId.oid);
8514                         }
8515                         else
8516                         {
8517                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8518                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8519                                                                   "true AS conislocal, true AS convalidated "
8520                                                                   "FROM pg_catalog.pg_constraint "
8521                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8522                                                                   "   AND contype = 'c' "
8523                                                                   "ORDER BY conname",
8524                                                                   tbinfo->dobj.catId.oid);
8525                         }
8526
8527                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8528
8529                         numConstrs = PQntuples(res);
8530                         if (numConstrs != tbinfo->ncheck)
8531                         {
8532                                 pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
8533                                                                           "expected %d check constraints on table \"%s\" but found %d",
8534                                                                           tbinfo->ncheck),
8535                                                   tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
8536                                 pg_log_error("(The system catalogs might be corrupted.)");
8537                                 exit_nicely(1);
8538                         }
8539
8540                         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
8541                         tbinfo->checkexprs = constrs;
8542
8543                         for (j = 0; j < numConstrs; j++)
8544                         {
8545                                 bool            validated = PQgetvalue(res, j, 5)[0] == 't';
8546
8547                                 constrs[j].dobj.objType = DO_CONSTRAINT;
8548                                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
8549                                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
8550                                 AssignDumpId(&constrs[j].dobj);
8551                                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
8552                                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
8553                                 constrs[j].contable = tbinfo;
8554                                 constrs[j].condomain = NULL;
8555                                 constrs[j].contype = 'c';
8556                                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
8557                                 constrs[j].confrelid = InvalidOid;
8558                                 constrs[j].conindex = 0;
8559                                 constrs[j].condeferrable = false;
8560                                 constrs[j].condeferred = false;
8561                                 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
8562
8563                                 /*
8564                                  * An unvalidated constraint needs to be dumped separately, so
8565                                  * that potentially-violating existing data is loaded before
8566                                  * the constraint.
8567                                  */
8568                                 constrs[j].separate = !validated;
8569
8570                                 constrs[j].dobj.dump = tbinfo->dobj.dump;
8571
8572                                 /*
8573                                  * Mark the constraint as needing to appear before the table
8574                                  * --- this is so that any other dependencies of the
8575                                  * constraint will be emitted before we try to create the
8576                                  * table.  If the constraint is to be dumped separately, it
8577                                  * will be dumped after data is loaded anyway, so don't do it.
8578                                  * (There's an automatic dependency in the opposite direction
8579                                  * anyway, so don't need to add one manually here.)
8580                                  */
8581                                 if (!constrs[j].separate)
8582                                         addObjectDependency(&tbinfo->dobj,
8583                                                                                 constrs[j].dobj.dumpId);
8584
8585                                 /*
8586                                  * If the constraint is inherited, this will be detected later
8587                                  * (in pre-8.4 databases).  We also detect later if the
8588                                  * constraint must be split out from the table definition.
8589                                  */
8590                         }
8591                         PQclear(res);
8592                 }
8593         }
8594
8595         destroyPQExpBuffer(q);
8596 }
8597
8598 /*
8599  * Test whether a column should be printed as part of table's CREATE TABLE.
8600  * Column number is zero-based.
8601  *
8602  * Normally this is always true, but it's false for dropped columns, as well
8603  * as those that were inherited without any local definition.  (If we print
8604  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
8605  * For partitions, it's always true, because we want the partitions to be
8606  * created independently and ATTACH PARTITION used afterwards.
8607  *
8608  * In binary_upgrade mode, we must print all columns and fix the attislocal/
8609  * attisdropped state later, so as to keep control of the physical column
8610  * order.
8611  *
8612  * This function exists because there are scattered nonobvious places that
8613  * must be kept in sync with this decision.
8614  */
8615 bool
8616 shouldPrintColumn(DumpOptions *dopt, TableInfo *tbinfo, int colno)
8617 {
8618         if (dopt->binary_upgrade)
8619                 return true;
8620         if (tbinfo->attisdropped[colno])
8621                 return false;
8622         return (tbinfo->attislocal[colno] || tbinfo->ispartition);
8623 }
8624
8625
8626 /*
8627  * getTSParsers:
8628  *        read all text search parsers in the system catalogs and return them
8629  *        in the TSParserInfo* structure
8630  *
8631  *      numTSParsers is set to the number of parsers read in
8632  */
8633 TSParserInfo *
8634 getTSParsers(Archive *fout, int *numTSParsers)
8635 {
8636         PGresult   *res;
8637         int                     ntups;
8638         int                     i;
8639         PQExpBuffer query;
8640         TSParserInfo *prsinfo;
8641         int                     i_tableoid;
8642         int                     i_oid;
8643         int                     i_prsname;
8644         int                     i_prsnamespace;
8645         int                     i_prsstart;
8646         int                     i_prstoken;
8647         int                     i_prsend;
8648         int                     i_prsheadline;
8649         int                     i_prslextype;
8650
8651         /* Before 8.3, there is no built-in text search support */
8652         if (fout->remoteVersion < 80300)
8653         {
8654                 *numTSParsers = 0;
8655                 return NULL;
8656         }
8657
8658         query = createPQExpBuffer();
8659
8660         /*
8661          * find all text search objects, including builtin ones; we filter out
8662          * system-defined objects at dump-out time.
8663          */
8664
8665         appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
8666                                                  "prsstart::oid, prstoken::oid, "
8667                                                  "prsend::oid, prsheadline::oid, prslextype::oid "
8668                                                  "FROM pg_ts_parser");
8669
8670         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8671
8672         ntups = PQntuples(res);
8673         *numTSParsers = ntups;
8674
8675         prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
8676
8677         i_tableoid = PQfnumber(res, "tableoid");
8678         i_oid = PQfnumber(res, "oid");
8679         i_prsname = PQfnumber(res, "prsname");
8680         i_prsnamespace = PQfnumber(res, "prsnamespace");
8681         i_prsstart = PQfnumber(res, "prsstart");
8682         i_prstoken = PQfnumber(res, "prstoken");
8683         i_prsend = PQfnumber(res, "prsend");
8684         i_prsheadline = PQfnumber(res, "prsheadline");
8685         i_prslextype = PQfnumber(res, "prslextype");
8686
8687         for (i = 0; i < ntups; i++)
8688         {
8689                 prsinfo[i].dobj.objType = DO_TSPARSER;
8690                 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8691                 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8692                 AssignDumpId(&prsinfo[i].dobj);
8693                 prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
8694                 prsinfo[i].dobj.namespace =
8695                         findNamespace(fout,
8696                                                   atooid(PQgetvalue(res, i, i_prsnamespace)));
8697                 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
8698                 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
8699                 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
8700                 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
8701                 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
8702
8703                 /* Decide whether we want to dump it */
8704                 selectDumpableObject(&(prsinfo[i].dobj), fout);
8705
8706                 /* Text Search Parsers do not currently have ACLs. */
8707                 prsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8708         }
8709
8710         PQclear(res);
8711
8712         destroyPQExpBuffer(query);
8713
8714         return prsinfo;
8715 }
8716
8717 /*
8718  * getTSDictionaries:
8719  *        read all text search dictionaries in the system catalogs and return them
8720  *        in the TSDictInfo* structure
8721  *
8722  *      numTSDicts is set to the number of dictionaries read in
8723  */
8724 TSDictInfo *
8725 getTSDictionaries(Archive *fout, int *numTSDicts)
8726 {
8727         PGresult   *res;
8728         int                     ntups;
8729         int                     i;
8730         PQExpBuffer query;
8731         TSDictInfo *dictinfo;
8732         int                     i_tableoid;
8733         int                     i_oid;
8734         int                     i_dictname;
8735         int                     i_dictnamespace;
8736         int                     i_rolname;
8737         int                     i_dicttemplate;
8738         int                     i_dictinitoption;
8739
8740         /* Before 8.3, there is no built-in text search support */
8741         if (fout->remoteVersion < 80300)
8742         {
8743                 *numTSDicts = 0;
8744                 return NULL;
8745         }
8746
8747         query = createPQExpBuffer();
8748
8749         appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
8750                                           "dictnamespace, (%s dictowner) AS rolname, "
8751                                           "dicttemplate, dictinitoption "
8752                                           "FROM pg_ts_dict",
8753                                           username_subquery);
8754
8755         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8756
8757         ntups = PQntuples(res);
8758         *numTSDicts = ntups;
8759
8760         dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
8761
8762         i_tableoid = PQfnumber(res, "tableoid");
8763         i_oid = PQfnumber(res, "oid");
8764         i_dictname = PQfnumber(res, "dictname");
8765         i_dictnamespace = PQfnumber(res, "dictnamespace");
8766         i_rolname = PQfnumber(res, "rolname");
8767         i_dictinitoption = PQfnumber(res, "dictinitoption");
8768         i_dicttemplate = PQfnumber(res, "dicttemplate");
8769
8770         for (i = 0; i < ntups; i++)
8771         {
8772                 dictinfo[i].dobj.objType = DO_TSDICT;
8773                 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8774                 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8775                 AssignDumpId(&dictinfo[i].dobj);
8776                 dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
8777                 dictinfo[i].dobj.namespace =
8778                         findNamespace(fout,
8779                                                   atooid(PQgetvalue(res, i, i_dictnamespace)));
8780                 dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8781                 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
8782                 if (PQgetisnull(res, i, i_dictinitoption))
8783                         dictinfo[i].dictinitoption = NULL;
8784                 else
8785                         dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
8786
8787                 /* Decide whether we want to dump it */
8788                 selectDumpableObject(&(dictinfo[i].dobj), fout);
8789
8790                 /* Text Search Dictionaries do not currently have ACLs. */
8791                 dictinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8792         }
8793
8794         PQclear(res);
8795
8796         destroyPQExpBuffer(query);
8797
8798         return dictinfo;
8799 }
8800
8801 /*
8802  * getTSTemplates:
8803  *        read all text search templates in the system catalogs and return them
8804  *        in the TSTemplateInfo* structure
8805  *
8806  *      numTSTemplates is set to the number of templates read in
8807  */
8808 TSTemplateInfo *
8809 getTSTemplates(Archive *fout, int *numTSTemplates)
8810 {
8811         PGresult   *res;
8812         int                     ntups;
8813         int                     i;
8814         PQExpBuffer query;
8815         TSTemplateInfo *tmplinfo;
8816         int                     i_tableoid;
8817         int                     i_oid;
8818         int                     i_tmplname;
8819         int                     i_tmplnamespace;
8820         int                     i_tmplinit;
8821         int                     i_tmpllexize;
8822
8823         /* Before 8.3, there is no built-in text search support */
8824         if (fout->remoteVersion < 80300)
8825         {
8826                 *numTSTemplates = 0;
8827                 return NULL;
8828         }
8829
8830         query = createPQExpBuffer();
8831
8832         appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
8833                                                  "tmplnamespace, tmplinit::oid, tmpllexize::oid "
8834                                                  "FROM pg_ts_template");
8835
8836         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8837
8838         ntups = PQntuples(res);
8839         *numTSTemplates = ntups;
8840
8841         tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
8842
8843         i_tableoid = PQfnumber(res, "tableoid");
8844         i_oid = PQfnumber(res, "oid");
8845         i_tmplname = PQfnumber(res, "tmplname");
8846         i_tmplnamespace = PQfnumber(res, "tmplnamespace");
8847         i_tmplinit = PQfnumber(res, "tmplinit");
8848         i_tmpllexize = PQfnumber(res, "tmpllexize");
8849
8850         for (i = 0; i < ntups; i++)
8851         {
8852                 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
8853                 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8854                 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8855                 AssignDumpId(&tmplinfo[i].dobj);
8856                 tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
8857                 tmplinfo[i].dobj.namespace =
8858                         findNamespace(fout,
8859                                                   atooid(PQgetvalue(res, i, i_tmplnamespace)));
8860                 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
8861                 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
8862
8863                 /* Decide whether we want to dump it */
8864                 selectDumpableObject(&(tmplinfo[i].dobj), fout);
8865
8866                 /* Text Search Templates do not currently have ACLs. */
8867                 tmplinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8868         }
8869
8870         PQclear(res);
8871
8872         destroyPQExpBuffer(query);
8873
8874         return tmplinfo;
8875 }
8876
8877 /*
8878  * getTSConfigurations:
8879  *        read all text search configurations in the system catalogs and return
8880  *        them in the TSConfigInfo* structure
8881  *
8882  *      numTSConfigs is set to the number of configurations read in
8883  */
8884 TSConfigInfo *
8885 getTSConfigurations(Archive *fout, int *numTSConfigs)
8886 {
8887         PGresult   *res;
8888         int                     ntups;
8889         int                     i;
8890         PQExpBuffer query;
8891         TSConfigInfo *cfginfo;
8892         int                     i_tableoid;
8893         int                     i_oid;
8894         int                     i_cfgname;
8895         int                     i_cfgnamespace;
8896         int                     i_rolname;
8897         int                     i_cfgparser;
8898
8899         /* Before 8.3, there is no built-in text search support */
8900         if (fout->remoteVersion < 80300)
8901         {
8902                 *numTSConfigs = 0;
8903                 return NULL;
8904         }
8905
8906         query = createPQExpBuffer();
8907
8908         appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
8909                                           "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
8910                                           "FROM pg_ts_config",
8911                                           username_subquery);
8912
8913         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8914
8915         ntups = PQntuples(res);
8916         *numTSConfigs = ntups;
8917
8918         cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
8919
8920         i_tableoid = PQfnumber(res, "tableoid");
8921         i_oid = PQfnumber(res, "oid");
8922         i_cfgname = PQfnumber(res, "cfgname");
8923         i_cfgnamespace = PQfnumber(res, "cfgnamespace");
8924         i_rolname = PQfnumber(res, "rolname");
8925         i_cfgparser = PQfnumber(res, "cfgparser");
8926
8927         for (i = 0; i < ntups; i++)
8928         {
8929                 cfginfo[i].dobj.objType = DO_TSCONFIG;
8930                 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8931                 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8932                 AssignDumpId(&cfginfo[i].dobj);
8933                 cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
8934                 cfginfo[i].dobj.namespace =
8935                         findNamespace(fout,
8936                                                   atooid(PQgetvalue(res, i, i_cfgnamespace)));
8937                 cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8938                 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
8939
8940                 /* Decide whether we want to dump it */
8941                 selectDumpableObject(&(cfginfo[i].dobj), fout);
8942
8943                 /* Text Search Configurations do not currently have ACLs. */
8944                 cfginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8945         }
8946
8947         PQclear(res);
8948
8949         destroyPQExpBuffer(query);
8950
8951         return cfginfo;
8952 }
8953
8954 /*
8955  * getForeignDataWrappers:
8956  *        read all foreign-data wrappers in the system catalogs and return
8957  *        them in the FdwInfo* structure
8958  *
8959  *      numForeignDataWrappers is set to the number of fdws read in
8960  */
8961 FdwInfo *
8962 getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
8963 {
8964         DumpOptions *dopt = fout->dopt;
8965         PGresult   *res;
8966         int                     ntups;
8967         int                     i;
8968         PQExpBuffer query;
8969         FdwInfo    *fdwinfo;
8970         int                     i_tableoid;
8971         int                     i_oid;
8972         int                     i_fdwname;
8973         int                     i_rolname;
8974         int                     i_fdwhandler;
8975         int                     i_fdwvalidator;
8976         int                     i_fdwacl;
8977         int                     i_rfdwacl;
8978         int                     i_initfdwacl;
8979         int                     i_initrfdwacl;
8980         int                     i_fdwoptions;
8981
8982         /* Before 8.4, there are no foreign-data wrappers */
8983         if (fout->remoteVersion < 80400)
8984         {
8985                 *numForeignDataWrappers = 0;
8986                 return NULL;
8987         }
8988
8989         query = createPQExpBuffer();
8990
8991         if (fout->remoteVersion >= 90600)
8992         {
8993                 PQExpBuffer acl_subquery = createPQExpBuffer();
8994                 PQExpBuffer racl_subquery = createPQExpBuffer();
8995                 PQExpBuffer initacl_subquery = createPQExpBuffer();
8996                 PQExpBuffer initracl_subquery = createPQExpBuffer();
8997
8998                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
8999                                                 initracl_subquery, "f.fdwacl", "f.fdwowner", "'F'",
9000                                                 dopt->binary_upgrade);
9001
9002                 appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.fdwname, "
9003                                                   "(%s f.fdwowner) AS rolname, "
9004                                                   "f.fdwhandler::pg_catalog.regproc, "
9005                                                   "f.fdwvalidator::pg_catalog.regproc, "
9006                                                   "%s AS fdwacl, "
9007                                                   "%s AS rfdwacl, "
9008                                                   "%s AS initfdwacl, "
9009                                                   "%s AS initrfdwacl, "
9010                                                   "array_to_string(ARRAY("
9011                                                   "SELECT quote_ident(option_name) || ' ' || "
9012                                                   "quote_literal(option_value) "
9013                                                   "FROM pg_options_to_table(f.fdwoptions) "
9014                                                   "ORDER BY option_name"
9015                                                   "), E',\n    ') AS fdwoptions "
9016                                                   "FROM pg_foreign_data_wrapper f "
9017                                                   "LEFT JOIN pg_init_privs pip ON "
9018                                                   "(f.oid = pip.objoid "
9019                                                   "AND pip.classoid = 'pg_foreign_data_wrapper'::regclass "
9020                                                   "AND pip.objsubid = 0) ",
9021                                                   username_subquery,
9022                                                   acl_subquery->data,
9023                                                   racl_subquery->data,
9024                                                   initacl_subquery->data,
9025                                                   initracl_subquery->data);
9026
9027                 destroyPQExpBuffer(acl_subquery);
9028                 destroyPQExpBuffer(racl_subquery);
9029                 destroyPQExpBuffer(initacl_subquery);
9030                 destroyPQExpBuffer(initracl_subquery);
9031         }
9032         else if (fout->remoteVersion >= 90100)
9033         {
9034                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
9035                                                   "(%s fdwowner) AS rolname, "
9036                                                   "fdwhandler::pg_catalog.regproc, "
9037                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
9038                                                   "NULL as rfdwacl, "
9039                                                   "NULL as initfdwacl, NULL AS initrfdwacl, "
9040                                                   "array_to_string(ARRAY("
9041                                                   "SELECT quote_ident(option_name) || ' ' || "
9042                                                   "quote_literal(option_value) "
9043                                                   "FROM pg_options_to_table(fdwoptions) "
9044                                                   "ORDER BY option_name"
9045                                                   "), E',\n    ') AS fdwoptions "
9046                                                   "FROM pg_foreign_data_wrapper",
9047                                                   username_subquery);
9048         }
9049         else
9050         {
9051                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
9052                                                   "(%s fdwowner) AS rolname, "
9053                                                   "'-' AS fdwhandler, "
9054                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
9055                                                   "NULL as rfdwacl, "
9056                                                   "NULL as initfdwacl, NULL AS initrfdwacl, "
9057                                                   "array_to_string(ARRAY("
9058                                                   "SELECT quote_ident(option_name) || ' ' || "
9059                                                   "quote_literal(option_value) "
9060                                                   "FROM pg_options_to_table(fdwoptions) "
9061                                                   "ORDER BY option_name"
9062                                                   "), E',\n    ') AS fdwoptions "
9063                                                   "FROM pg_foreign_data_wrapper",
9064                                                   username_subquery);
9065         }
9066
9067         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9068
9069         ntups = PQntuples(res);
9070         *numForeignDataWrappers = ntups;
9071
9072         fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
9073
9074         i_tableoid = PQfnumber(res, "tableoid");
9075         i_oid = PQfnumber(res, "oid");
9076         i_fdwname = PQfnumber(res, "fdwname");
9077         i_rolname = PQfnumber(res, "rolname");
9078         i_fdwhandler = PQfnumber(res, "fdwhandler");
9079         i_fdwvalidator = PQfnumber(res, "fdwvalidator");
9080         i_fdwacl = PQfnumber(res, "fdwacl");
9081         i_rfdwacl = PQfnumber(res, "rfdwacl");
9082         i_initfdwacl = PQfnumber(res, "initfdwacl");
9083         i_initrfdwacl = PQfnumber(res, "initrfdwacl");
9084         i_fdwoptions = PQfnumber(res, "fdwoptions");
9085
9086         for (i = 0; i < ntups; i++)
9087         {
9088                 fdwinfo[i].dobj.objType = DO_FDW;
9089                 fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9090                 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9091                 AssignDumpId(&fdwinfo[i].dobj);
9092                 fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
9093                 fdwinfo[i].dobj.namespace = NULL;
9094                 fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
9095                 fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
9096                 fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
9097                 fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
9098                 fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
9099                 fdwinfo[i].rfdwacl = pg_strdup(PQgetvalue(res, i, i_rfdwacl));
9100                 fdwinfo[i].initfdwacl = pg_strdup(PQgetvalue(res, i, i_initfdwacl));
9101                 fdwinfo[i].initrfdwacl = pg_strdup(PQgetvalue(res, i, i_initrfdwacl));
9102
9103                 /* Decide whether we want to dump it */
9104                 selectDumpableObject(&(fdwinfo[i].dobj), fout);
9105
9106                 /* Do not try to dump ACL if no ACL exists. */
9107                 if (PQgetisnull(res, i, i_fdwacl) && PQgetisnull(res, i, i_rfdwacl) &&
9108                         PQgetisnull(res, i, i_initfdwacl) &&
9109                         PQgetisnull(res, i, i_initrfdwacl))
9110                         fdwinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
9111         }
9112
9113         PQclear(res);
9114
9115         destroyPQExpBuffer(query);
9116
9117         return fdwinfo;
9118 }
9119
9120 /*
9121  * getForeignServers:
9122  *        read all foreign servers in the system catalogs and return
9123  *        them in the ForeignServerInfo * structure
9124  *
9125  *      numForeignServers is set to the number of servers read in
9126  */
9127 ForeignServerInfo *
9128 getForeignServers(Archive *fout, int *numForeignServers)
9129 {
9130         DumpOptions *dopt = fout->dopt;
9131         PGresult   *res;
9132         int                     ntups;
9133         int                     i;
9134         PQExpBuffer query;
9135         ForeignServerInfo *srvinfo;
9136         int                     i_tableoid;
9137         int                     i_oid;
9138         int                     i_srvname;
9139         int                     i_rolname;
9140         int                     i_srvfdw;
9141         int                     i_srvtype;
9142         int                     i_srvversion;
9143         int                     i_srvacl;
9144         int                     i_rsrvacl;
9145         int                     i_initsrvacl;
9146         int                     i_initrsrvacl;
9147         int                     i_srvoptions;
9148
9149         /* Before 8.4, there are no foreign servers */
9150         if (fout->remoteVersion < 80400)
9151         {
9152                 *numForeignServers = 0;
9153                 return NULL;
9154         }
9155
9156         query = createPQExpBuffer();
9157
9158         if (fout->remoteVersion >= 90600)
9159         {
9160                 PQExpBuffer acl_subquery = createPQExpBuffer();
9161                 PQExpBuffer racl_subquery = createPQExpBuffer();
9162                 PQExpBuffer initacl_subquery = createPQExpBuffer();
9163                 PQExpBuffer initracl_subquery = createPQExpBuffer();
9164
9165                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9166                                                 initracl_subquery, "f.srvacl", "f.srvowner", "'S'",
9167                                                 dopt->binary_upgrade);
9168
9169                 appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.srvname, "
9170                                                   "(%s f.srvowner) AS rolname, "
9171                                                   "f.srvfdw, f.srvtype, f.srvversion, "
9172                                                   "%s AS srvacl, "
9173                                                   "%s AS rsrvacl, "
9174                                                   "%s AS initsrvacl, "
9175                                                   "%s AS initrsrvacl, "
9176                                                   "array_to_string(ARRAY("
9177                                                   "SELECT quote_ident(option_name) || ' ' || "
9178                                                   "quote_literal(option_value) "
9179                                                   "FROM pg_options_to_table(f.srvoptions) "
9180                                                   "ORDER BY option_name"
9181                                                   "), E',\n    ') AS srvoptions "
9182                                                   "FROM pg_foreign_server f "
9183                                                   "LEFT JOIN pg_init_privs pip "
9184                                                   "ON (f.oid = pip.objoid "
9185                                                   "AND pip.classoid = 'pg_foreign_server'::regclass "
9186                                                   "AND pip.objsubid = 0) ",
9187                                                   username_subquery,
9188                                                   acl_subquery->data,
9189                                                   racl_subquery->data,
9190                                                   initacl_subquery->data,
9191                                                   initracl_subquery->data);
9192
9193                 destroyPQExpBuffer(acl_subquery);
9194                 destroyPQExpBuffer(racl_subquery);
9195                 destroyPQExpBuffer(initacl_subquery);
9196                 destroyPQExpBuffer(initracl_subquery);
9197         }
9198         else
9199         {
9200                 appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
9201                                                   "(%s srvowner) AS rolname, "
9202                                                   "srvfdw, srvtype, srvversion, srvacl, "
9203                                                   "NULL AS rsrvacl, "
9204                                                   "NULL AS initsrvacl, NULL AS initrsrvacl, "
9205                                                   "array_to_string(ARRAY("
9206                                                   "SELECT quote_ident(option_name) || ' ' || "
9207                                                   "quote_literal(option_value) "
9208                                                   "FROM pg_options_to_table(srvoptions) "
9209                                                   "ORDER BY option_name"
9210                                                   "), E',\n    ') AS srvoptions "
9211                                                   "FROM pg_foreign_server",
9212                                                   username_subquery);
9213         }
9214
9215         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9216
9217         ntups = PQntuples(res);
9218         *numForeignServers = ntups;
9219
9220         srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
9221
9222         i_tableoid = PQfnumber(res, "tableoid");
9223         i_oid = PQfnumber(res, "oid");
9224         i_srvname = PQfnumber(res, "srvname");
9225         i_rolname = PQfnumber(res, "rolname");
9226         i_srvfdw = PQfnumber(res, "srvfdw");
9227         i_srvtype = PQfnumber(res, "srvtype");
9228         i_srvversion = PQfnumber(res, "srvversion");
9229         i_srvacl = PQfnumber(res, "srvacl");
9230         i_rsrvacl = PQfnumber(res, "rsrvacl");
9231         i_initsrvacl = PQfnumber(res, "initsrvacl");
9232         i_initrsrvacl = PQfnumber(res, "initrsrvacl");
9233         i_srvoptions = PQfnumber(res, "srvoptions");
9234
9235         for (i = 0; i < ntups; i++)
9236         {
9237                 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
9238                 srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9239                 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9240                 AssignDumpId(&srvinfo[i].dobj);
9241                 srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
9242                 srvinfo[i].dobj.namespace = NULL;
9243                 srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
9244                 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
9245                 srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
9246                 srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
9247                 srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
9248                 srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
9249                 srvinfo[i].rsrvacl = pg_strdup(PQgetvalue(res, i, i_rsrvacl));
9250                 srvinfo[i].initsrvacl = pg_strdup(PQgetvalue(res, i, i_initsrvacl));
9251                 srvinfo[i].initrsrvacl = pg_strdup(PQgetvalue(res, i, i_initrsrvacl));
9252
9253                 /* Decide whether we want to dump it */
9254                 selectDumpableObject(&(srvinfo[i].dobj), fout);
9255
9256                 /* Do not try to dump ACL if no ACL exists. */
9257                 if (PQgetisnull(res, i, i_srvacl) && PQgetisnull(res, i, i_rsrvacl) &&
9258                         PQgetisnull(res, i, i_initsrvacl) &&
9259                         PQgetisnull(res, i, i_initrsrvacl))
9260                         srvinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
9261         }
9262
9263         PQclear(res);
9264
9265         destroyPQExpBuffer(query);
9266
9267         return srvinfo;
9268 }
9269
9270 /*
9271  * getDefaultACLs:
9272  *        read all default ACL information in the system catalogs and return
9273  *        them in the DefaultACLInfo structure
9274  *
9275  *      numDefaultACLs is set to the number of ACLs read in
9276  */
9277 DefaultACLInfo *
9278 getDefaultACLs(Archive *fout, int *numDefaultACLs)
9279 {
9280         DumpOptions *dopt = fout->dopt;
9281         DefaultACLInfo *daclinfo;
9282         PQExpBuffer query;
9283         PGresult   *res;
9284         int                     i_oid;
9285         int                     i_tableoid;
9286         int                     i_defaclrole;
9287         int                     i_defaclnamespace;
9288         int                     i_defaclobjtype;
9289         int                     i_defaclacl;
9290         int                     i_rdefaclacl;
9291         int                     i_initdefaclacl;
9292         int                     i_initrdefaclacl;
9293         int                     i,
9294                                 ntups;
9295
9296         if (fout->remoteVersion < 90000)
9297         {
9298                 *numDefaultACLs = 0;
9299                 return NULL;
9300         }
9301
9302         query = createPQExpBuffer();
9303
9304         if (fout->remoteVersion >= 90600)
9305         {
9306                 PQExpBuffer acl_subquery = createPQExpBuffer();
9307                 PQExpBuffer racl_subquery = createPQExpBuffer();
9308                 PQExpBuffer initacl_subquery = createPQExpBuffer();
9309                 PQExpBuffer initracl_subquery = createPQExpBuffer();
9310
9311                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9312                                                 initracl_subquery, "defaclacl", "defaclrole",
9313                                                 "CASE WHEN defaclobjtype = 'S' THEN 's' ELSE defaclobjtype END::\"char\"",
9314                                                 dopt->binary_upgrade);
9315
9316                 appendPQExpBuffer(query, "SELECT d.oid, d.tableoid, "
9317                                                   "(%s d.defaclrole) AS defaclrole, "
9318                                                   "d.defaclnamespace, "
9319                                                   "d.defaclobjtype, "
9320                                                   "%s AS defaclacl, "
9321                                                   "%s AS rdefaclacl, "
9322                                                   "%s AS initdefaclacl, "
9323                                                   "%s AS initrdefaclacl "
9324                                                   "FROM pg_default_acl d "
9325                                                   "LEFT JOIN pg_init_privs pip ON "
9326                                                   "(d.oid = pip.objoid "
9327                                                   "AND pip.classoid = 'pg_default_acl'::regclass "
9328                                                   "AND pip.objsubid = 0) ",
9329                                                   username_subquery,
9330                                                   acl_subquery->data,
9331                                                   racl_subquery->data,
9332                                                   initacl_subquery->data,
9333                                                   initracl_subquery->data);
9334         }
9335         else
9336         {
9337                 appendPQExpBuffer(query, "SELECT oid, tableoid, "
9338                                                   "(%s defaclrole) AS defaclrole, "
9339                                                   "defaclnamespace, "
9340                                                   "defaclobjtype, "
9341                                                   "defaclacl, "
9342                                                   "NULL AS rdefaclacl, "
9343                                                   "NULL AS initdefaclacl, "
9344                                                   "NULL AS initrdefaclacl "
9345                                                   "FROM pg_default_acl",
9346                                                   username_subquery);
9347         }
9348
9349         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9350
9351         ntups = PQntuples(res);
9352         *numDefaultACLs = ntups;
9353
9354         daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
9355
9356         i_oid = PQfnumber(res, "oid");
9357         i_tableoid = PQfnumber(res, "tableoid");
9358         i_defaclrole = PQfnumber(res, "defaclrole");
9359         i_defaclnamespace = PQfnumber(res, "defaclnamespace");
9360         i_defaclobjtype = PQfnumber(res, "defaclobjtype");
9361         i_defaclacl = PQfnumber(res, "defaclacl");
9362         i_rdefaclacl = PQfnumber(res, "rdefaclacl");
9363         i_initdefaclacl = PQfnumber(res, "initdefaclacl");
9364         i_initrdefaclacl = PQfnumber(res, "initrdefaclacl");
9365
9366         for (i = 0; i < ntups; i++)
9367         {
9368                 Oid                     nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
9369
9370                 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
9371                 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9372                 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9373                 AssignDumpId(&daclinfo[i].dobj);
9374                 /* cheesy ... is it worth coming up with a better object name? */
9375                 daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
9376
9377                 if (nspid != InvalidOid)
9378                         daclinfo[i].dobj.namespace = findNamespace(fout, nspid);
9379                 else
9380                         daclinfo[i].dobj.namespace = NULL;
9381
9382                 daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
9383                 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
9384                 daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
9385                 daclinfo[i].rdefaclacl = pg_strdup(PQgetvalue(res, i, i_rdefaclacl));
9386                 daclinfo[i].initdefaclacl = pg_strdup(PQgetvalue(res, i, i_initdefaclacl));
9387                 daclinfo[i].initrdefaclacl = pg_strdup(PQgetvalue(res, i, i_initrdefaclacl));
9388
9389                 /* Decide whether we want to dump it */
9390                 selectDumpableDefaultACL(&(daclinfo[i]), dopt);
9391         }
9392
9393         PQclear(res);
9394
9395         destroyPQExpBuffer(query);
9396
9397         return daclinfo;
9398 }
9399
9400 /*
9401  * dumpComment --
9402  *
9403  * This routine is used to dump any comments associated with the
9404  * object handed to this routine. The routine takes the object type
9405  * and object name (ready to print, except for schema decoration), plus
9406  * the namespace and owner of the object (for labeling the ArchiveEntry),
9407  * plus catalog ID and subid which are the lookup key for pg_description,
9408  * plus the dump ID for the object (for setting a dependency).
9409  * If a matching pg_description entry is found, it is dumped.
9410  *
9411  * Note: in some cases, such as comments for triggers and rules, the "type"
9412  * string really looks like, e.g., "TRIGGER name ON".  This is a bit of a hack
9413  * but it doesn't seem worth complicating the API for all callers to make
9414  * it cleaner.
9415  *
9416  * Note: although this routine takes a dumpId for dependency purposes,
9417  * that purpose is just to mark the dependency in the emitted dump file
9418  * for possible future use by pg_restore.  We do NOT use it for determining
9419  * ordering of the comment in the dump file, because this routine is called
9420  * after dependency sorting occurs.  This routine should be called just after
9421  * calling ArchiveEntry() for the specified object.
9422  */
9423 static void
9424 dumpComment(Archive *fout, const char *type, const char *name,
9425                         const char *namespace, const char *owner,
9426                         CatalogId catalogId, int subid, DumpId dumpId)
9427 {
9428         DumpOptions *dopt = fout->dopt;
9429         CommentItem *comments;
9430         int                     ncomments;
9431
9432         /* do nothing, if --no-comments is supplied */
9433         if (dopt->no_comments)
9434                 return;
9435
9436         /* Comments are schema not data ... except blob comments are data */
9437         if (strcmp(type, "LARGE OBJECT") != 0)
9438         {
9439                 if (dopt->dataOnly)
9440                         return;
9441         }
9442         else
9443         {
9444                 /* We do dump blob comments in binary-upgrade mode */
9445                 if (dopt->schemaOnly && !dopt->binary_upgrade)
9446                         return;
9447         }
9448
9449         /* Search for comments associated with catalogId, using table */
9450         ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
9451                                                          &comments);
9452
9453         /* Is there one matching the subid? */
9454         while (ncomments > 0)
9455         {
9456                 if (comments->objsubid == subid)
9457                         break;
9458                 comments++;
9459                 ncomments--;
9460         }
9461
9462         /* If a comment exists, build COMMENT ON statement */
9463         if (ncomments > 0)
9464         {
9465                 PQExpBuffer query = createPQExpBuffer();
9466                 PQExpBuffer tag = createPQExpBuffer();
9467
9468                 appendPQExpBuffer(query, "COMMENT ON %s ", type);
9469                 if (namespace && *namespace)
9470                         appendPQExpBuffer(query, "%s.", fmtId(namespace));
9471                 appendPQExpBuffer(query, "%s IS ", name);
9472                 appendStringLiteralAH(query, comments->descr, fout);
9473                 appendPQExpBufferStr(query, ";\n");
9474
9475                 appendPQExpBuffer(tag, "%s %s", type, name);
9476
9477                 /*
9478                  * We mark comments as SECTION_NONE because they really belong in the
9479                  * same section as their parent, whether that is pre-data or
9480                  * post-data.
9481                  */
9482                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
9483                                          ARCHIVE_OPTS(.tag = tag->data,
9484                                                                   .namespace = namespace,
9485                                                                   .owner = owner,
9486                                                                   .description = "COMMENT",
9487                                                                   .section = SECTION_NONE,
9488                                                                   .createStmt = query->data,
9489                                                                   .deps = &dumpId,
9490                                                                   .nDeps = 1));
9491
9492                 destroyPQExpBuffer(query);
9493                 destroyPQExpBuffer(tag);
9494         }
9495 }
9496
9497 /*
9498  * dumpTableComment --
9499  *
9500  * As above, but dump comments for both the specified table (or view)
9501  * and its columns.
9502  */
9503 static void
9504 dumpTableComment(Archive *fout, TableInfo *tbinfo,
9505                                  const char *reltypename)
9506 {
9507         DumpOptions *dopt = fout->dopt;
9508         CommentItem *comments;
9509         int                     ncomments;
9510         PQExpBuffer query;
9511         PQExpBuffer tag;
9512
9513         /* do nothing, if --no-comments is supplied */
9514         if (dopt->no_comments)
9515                 return;
9516
9517         /* Comments are SCHEMA not data */
9518         if (dopt->dataOnly)
9519                 return;
9520
9521         /* Search for comments associated with relation, using table */
9522         ncomments = findComments(fout,
9523                                                          tbinfo->dobj.catId.tableoid,
9524                                                          tbinfo->dobj.catId.oid,
9525                                                          &comments);
9526
9527         /* If comments exist, build COMMENT ON statements */
9528         if (ncomments <= 0)
9529                 return;
9530
9531         query = createPQExpBuffer();
9532         tag = createPQExpBuffer();
9533
9534         while (ncomments > 0)
9535         {
9536                 const char *descr = comments->descr;
9537                 int                     objsubid = comments->objsubid;
9538
9539                 if (objsubid == 0)
9540                 {
9541                         resetPQExpBuffer(tag);
9542                         appendPQExpBuffer(tag, "%s %s", reltypename,
9543                                                           fmtId(tbinfo->dobj.name));
9544
9545                         resetPQExpBuffer(query);
9546                         appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
9547                                                           fmtQualifiedDumpable(tbinfo));
9548                         appendStringLiteralAH(query, descr, fout);
9549                         appendPQExpBufferStr(query, ";\n");
9550
9551                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
9552                                                  ARCHIVE_OPTS(.tag = tag->data,
9553                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
9554                                                                           .owner = tbinfo->rolname,
9555                                                                           .description = "COMMENT",
9556                                                                           .section = SECTION_NONE,
9557                                                                           .createStmt = query->data,
9558                                                                           .deps = &(tbinfo->dobj.dumpId),
9559                                                                           .nDeps = 1));
9560                 }
9561                 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
9562                 {
9563                         resetPQExpBuffer(tag);
9564                         appendPQExpBuffer(tag, "COLUMN %s.",
9565                                                           fmtId(tbinfo->dobj.name));
9566                         appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
9567
9568                         resetPQExpBuffer(query);
9569                         appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
9570                                                           fmtQualifiedDumpable(tbinfo));
9571                         appendPQExpBuffer(query, "%s IS ",
9572                                                           fmtId(tbinfo->attnames[objsubid - 1]));
9573                         appendStringLiteralAH(query, descr, fout);
9574                         appendPQExpBufferStr(query, ";\n");
9575
9576                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
9577                                                  ARCHIVE_OPTS(.tag = tag->data,
9578                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
9579                                                                           .owner = tbinfo->rolname,
9580                                                                           .description = "COMMENT",
9581                                                                           .section = SECTION_NONE,
9582                                                                           .createStmt = query->data,
9583                                                                           .deps = &(tbinfo->dobj.dumpId),
9584                                                                           .nDeps = 1));
9585                 }
9586
9587                 comments++;
9588                 ncomments--;
9589         }
9590
9591         destroyPQExpBuffer(query);
9592         destroyPQExpBuffer(tag);
9593 }
9594
9595 /*
9596  * findComments --
9597  *
9598  * Find the comment(s), if any, associated with the given object.  All the
9599  * objsubid values associated with the given classoid/objoid are found with
9600  * one search.
9601  */
9602 static int
9603 findComments(Archive *fout, Oid classoid, Oid objoid,
9604                          CommentItem **items)
9605 {
9606         /* static storage for table of comments */
9607         static CommentItem *comments = NULL;
9608         static int      ncomments = -1;
9609
9610         CommentItem *middle = NULL;
9611         CommentItem *low;
9612         CommentItem *high;
9613         int                     nmatch;
9614
9615         /* Get comments if we didn't already */
9616         if (ncomments < 0)
9617                 ncomments = collectComments(fout, &comments);
9618
9619         /*
9620          * Do binary search to find some item matching the object.
9621          */
9622         low = &comments[0];
9623         high = &comments[ncomments - 1];
9624         while (low <= high)
9625         {
9626                 middle = low + (high - low) / 2;
9627
9628                 if (classoid < middle->classoid)
9629                         high = middle - 1;
9630                 else if (classoid > middle->classoid)
9631                         low = middle + 1;
9632                 else if (objoid < middle->objoid)
9633                         high = middle - 1;
9634                 else if (objoid > middle->objoid)
9635                         low = middle + 1;
9636                 else
9637                         break;                          /* found a match */
9638         }
9639
9640         if (low > high)                         /* no matches */
9641         {
9642                 *items = NULL;
9643                 return 0;
9644         }
9645
9646         /*
9647          * Now determine how many items match the object.  The search loop
9648          * invariant still holds: only items between low and high inclusive could
9649          * match.
9650          */
9651         nmatch = 1;
9652         while (middle > low)
9653         {
9654                 if (classoid != middle[-1].classoid ||
9655                         objoid != middle[-1].objoid)
9656                         break;
9657                 middle--;
9658                 nmatch++;
9659         }
9660
9661         *items = middle;
9662
9663         middle += nmatch;
9664         while (middle <= high)
9665         {
9666                 if (classoid != middle->classoid ||
9667                         objoid != middle->objoid)
9668                         break;
9669                 middle++;
9670                 nmatch++;
9671         }
9672
9673         return nmatch;
9674 }
9675
9676 /*
9677  * collectComments --
9678  *
9679  * Construct a table of all comments available for database objects.
9680  * We used to do per-object queries for the comments, but it's much faster
9681  * to pull them all over at once, and on most databases the memory cost
9682  * isn't high.
9683  *
9684  * The table is sorted by classoid/objid/objsubid for speed in lookup.
9685  */
9686 static int
9687 collectComments(Archive *fout, CommentItem **items)
9688 {
9689         PGresult   *res;
9690         PQExpBuffer query;
9691         int                     i_description;
9692         int                     i_classoid;
9693         int                     i_objoid;
9694         int                     i_objsubid;
9695         int                     ntups;
9696         int                     i;
9697         CommentItem *comments;
9698
9699         query = createPQExpBuffer();
9700
9701         appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
9702                                                  "FROM pg_catalog.pg_description "
9703                                                  "ORDER BY classoid, objoid, objsubid");
9704
9705         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9706
9707         /* Construct lookup table containing OIDs in numeric form */
9708
9709         i_description = PQfnumber(res, "description");
9710         i_classoid = PQfnumber(res, "classoid");
9711         i_objoid = PQfnumber(res, "objoid");
9712         i_objsubid = PQfnumber(res, "objsubid");
9713
9714         ntups = PQntuples(res);
9715
9716         comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
9717
9718         for (i = 0; i < ntups; i++)
9719         {
9720                 comments[i].descr = PQgetvalue(res, i, i_description);
9721                 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
9722                 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
9723                 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
9724         }
9725
9726         /* Do NOT free the PGresult since we are keeping pointers into it */
9727         destroyPQExpBuffer(query);
9728
9729         *items = comments;
9730         return ntups;
9731 }
9732
9733 /*
9734  * dumpDumpableObject
9735  *
9736  * This routine and its subsidiaries are responsible for creating
9737  * ArchiveEntries (TOC objects) for each object to be dumped.
9738  */
9739 static void
9740 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
9741 {
9742         switch (dobj->objType)
9743         {
9744                 case DO_NAMESPACE:
9745                         dumpNamespace(fout, (NamespaceInfo *) dobj);
9746                         break;
9747                 case DO_EXTENSION:
9748                         dumpExtension(fout, (ExtensionInfo *) dobj);
9749                         break;
9750                 case DO_TYPE:
9751                         dumpType(fout, (TypeInfo *) dobj);
9752                         break;
9753                 case DO_SHELL_TYPE:
9754                         dumpShellType(fout, (ShellTypeInfo *) dobj);
9755                         break;
9756                 case DO_FUNC:
9757                         dumpFunc(fout, (FuncInfo *) dobj);
9758                         break;
9759                 case DO_AGG:
9760                         dumpAgg(fout, (AggInfo *) dobj);
9761                         break;
9762                 case DO_OPERATOR:
9763                         dumpOpr(fout, (OprInfo *) dobj);
9764                         break;
9765                 case DO_ACCESS_METHOD:
9766                         dumpAccessMethod(fout, (AccessMethodInfo *) dobj);
9767                         break;
9768                 case DO_OPCLASS:
9769                         dumpOpclass(fout, (OpclassInfo *) dobj);
9770                         break;
9771                 case DO_OPFAMILY:
9772                         dumpOpfamily(fout, (OpfamilyInfo *) dobj);
9773                         break;
9774                 case DO_COLLATION:
9775                         dumpCollation(fout, (CollInfo *) dobj);
9776                         break;
9777                 case DO_CONVERSION:
9778                         dumpConversion(fout, (ConvInfo *) dobj);
9779                         break;
9780                 case DO_TABLE:
9781                         dumpTable(fout, (TableInfo *) dobj);
9782                         break;
9783                 case DO_ATTRDEF:
9784                         dumpAttrDef(fout, (AttrDefInfo *) dobj);
9785                         break;
9786                 case DO_INDEX:
9787                         dumpIndex(fout, (IndxInfo *) dobj);
9788                         break;
9789                 case DO_INDEX_ATTACH:
9790                         dumpIndexAttach(fout, (IndexAttachInfo *) dobj);
9791                         break;
9792                 case DO_STATSEXT:
9793                         dumpStatisticsExt(fout, (StatsExtInfo *) dobj);
9794                         break;
9795                 case DO_REFRESH_MATVIEW:
9796                         refreshMatViewData(fout, (TableDataInfo *) dobj);
9797                         break;
9798                 case DO_RULE:
9799                         dumpRule(fout, (RuleInfo *) dobj);
9800                         break;
9801                 case DO_TRIGGER:
9802                         dumpTrigger(fout, (TriggerInfo *) dobj);
9803                         break;
9804                 case DO_EVENT_TRIGGER:
9805                         dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
9806                         break;
9807                 case DO_CONSTRAINT:
9808                         dumpConstraint(fout, (ConstraintInfo *) dobj);
9809                         break;
9810                 case DO_FK_CONSTRAINT:
9811                         dumpConstraint(fout, (ConstraintInfo *) dobj);
9812                         break;
9813                 case DO_PROCLANG:
9814                         dumpProcLang(fout, (ProcLangInfo *) dobj);
9815                         break;
9816                 case DO_CAST:
9817                         dumpCast(fout, (CastInfo *) dobj);
9818                         break;
9819                 case DO_TRANSFORM:
9820                         dumpTransform(fout, (TransformInfo *) dobj);
9821                         break;
9822                 case DO_SEQUENCE_SET:
9823                         dumpSequenceData(fout, (TableDataInfo *) dobj);
9824                         break;
9825                 case DO_TABLE_DATA:
9826                         dumpTableData(fout, (TableDataInfo *) dobj);
9827                         break;
9828                 case DO_DUMMY_TYPE:
9829                         /* table rowtypes and array types are never dumped separately */
9830                         break;
9831                 case DO_TSPARSER:
9832                         dumpTSParser(fout, (TSParserInfo *) dobj);
9833                         break;
9834                 case DO_TSDICT:
9835                         dumpTSDictionary(fout, (TSDictInfo *) dobj);
9836                         break;
9837                 case DO_TSTEMPLATE:
9838                         dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
9839                         break;
9840                 case DO_TSCONFIG:
9841                         dumpTSConfig(fout, (TSConfigInfo *) dobj);
9842                         break;
9843                 case DO_FDW:
9844                         dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
9845                         break;
9846                 case DO_FOREIGN_SERVER:
9847                         dumpForeignServer(fout, (ForeignServerInfo *) dobj);
9848                         break;
9849                 case DO_DEFAULT_ACL:
9850                         dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
9851                         break;
9852                 case DO_BLOB:
9853                         dumpBlob(fout, (BlobInfo *) dobj);
9854                         break;
9855                 case DO_BLOB_DATA:
9856                         if (dobj->dump & DUMP_COMPONENT_DATA)
9857                         {
9858                                 TocEntry   *te;
9859
9860                                 te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
9861                                                                   ARCHIVE_OPTS(.tag = dobj->name,
9862                                                                                            .description = "BLOBS",
9863                                                                                            .section = SECTION_DATA,
9864                                                                                            .dumpFn = dumpBlobs));
9865
9866                                 /*
9867                                  * Set the TocEntry's dataLength in case we are doing a
9868                                  * parallel dump and want to order dump jobs by table size.
9869                                  * (We need some size estimate for every TocEntry with a
9870                                  * DataDumper function.)  We don't currently have any cheap
9871                                  * way to estimate the size of blobs, but it doesn't matter;
9872                                  * let's just set the size to a large value so parallel dumps
9873                                  * will launch this job first.  If there's lots of blobs, we
9874                                  * win, and if there aren't, we don't lose much.  (If you want
9875                                  * to improve on this, really what you should be thinking
9876                                  * about is allowing blob dumping to be parallelized, not just
9877                                  * getting a smarter estimate for the single TOC entry.)
9878                                  */
9879                                 te->dataLength = MaxBlockNumber;
9880                         }
9881                         break;
9882                 case DO_POLICY:
9883                         dumpPolicy(fout, (PolicyInfo *) dobj);
9884                         break;
9885                 case DO_PUBLICATION:
9886                         dumpPublication(fout, (PublicationInfo *) dobj);
9887                         break;
9888                 case DO_PUBLICATION_REL:
9889                         dumpPublicationTable(fout, (PublicationRelInfo *) dobj);
9890                         break;
9891                 case DO_SUBSCRIPTION:
9892                         dumpSubscription(fout, (SubscriptionInfo *) dobj);
9893                         break;
9894                 case DO_PRE_DATA_BOUNDARY:
9895                 case DO_POST_DATA_BOUNDARY:
9896                         /* never dumped, nothing to do */
9897                         break;
9898         }
9899 }
9900
9901 /*
9902  * dumpNamespace
9903  *        writes out to fout the queries to recreate a user-defined namespace
9904  */
9905 static void
9906 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
9907 {
9908         DumpOptions *dopt = fout->dopt;
9909         PQExpBuffer q;
9910         PQExpBuffer delq;
9911         char       *qnspname;
9912
9913         /* Skip if not to be dumped */
9914         if (!nspinfo->dobj.dump || dopt->dataOnly)
9915                 return;
9916
9917         q = createPQExpBuffer();
9918         delq = createPQExpBuffer();
9919
9920         qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
9921
9922         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
9923
9924         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
9925
9926         if (dopt->binary_upgrade)
9927                 binary_upgrade_extension_member(q, &nspinfo->dobj,
9928                                                                                 "SCHEMA", qnspname, NULL);
9929
9930         if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
9931                 ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
9932                                          ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
9933                                                                   .owner = nspinfo->rolname,
9934                                                                   .description = "SCHEMA",
9935                                                                   .section = SECTION_PRE_DATA,
9936                                                                   .createStmt = q->data,
9937                                                                   .dropStmt = delq->data));
9938
9939         /* Dump Schema Comments and Security Labels */
9940         if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
9941                 dumpComment(fout, "SCHEMA", qnspname,
9942                                         NULL, nspinfo->rolname,
9943                                         nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
9944
9945         if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
9946                 dumpSecLabel(fout, "SCHEMA", qnspname,
9947                                          NULL, nspinfo->rolname,
9948                                          nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
9949
9950         if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
9951                 dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
9952                                 qnspname, NULL, NULL,
9953                                 nspinfo->rolname, nspinfo->nspacl, nspinfo->rnspacl,
9954                                 nspinfo->initnspacl, nspinfo->initrnspacl);
9955
9956         free(qnspname);
9957
9958         destroyPQExpBuffer(q);
9959         destroyPQExpBuffer(delq);
9960 }
9961
9962 /*
9963  * dumpExtension
9964  *        writes out to fout the queries to recreate an extension
9965  */
9966 static void
9967 dumpExtension(Archive *fout, ExtensionInfo *extinfo)
9968 {
9969         DumpOptions *dopt = fout->dopt;
9970         PQExpBuffer q;
9971         PQExpBuffer delq;
9972         char       *qextname;
9973
9974         /* Skip if not to be dumped */
9975         if (!extinfo->dobj.dump || dopt->dataOnly)
9976                 return;
9977
9978         q = createPQExpBuffer();
9979         delq = createPQExpBuffer();
9980
9981         qextname = pg_strdup(fmtId(extinfo->dobj.name));
9982
9983         appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
9984
9985         if (!dopt->binary_upgrade)
9986         {
9987                 /*
9988                  * In a regular dump, we simply create the extension, intentionally
9989                  * not specifying a version, so that the destination installation's
9990                  * default version is used.
9991                  *
9992                  * Use of IF NOT EXISTS here is unlike our behavior for other object
9993                  * types; but there are various scenarios in which it's convenient to
9994                  * manually create the desired extension before restoring, so we
9995                  * prefer to allow it to exist already.
9996                  */
9997                 appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
9998                                                   qextname, fmtId(extinfo->namespace));
9999         }
10000         else
10001         {
10002                 /*
10003                  * In binary-upgrade mode, it's critical to reproduce the state of the
10004                  * database exactly, so our procedure is to create an empty extension,
10005                  * restore all the contained objects normally, and add them to the
10006                  * extension one by one.  This function performs just the first of
10007                  * those steps.  binary_upgrade_extension_member() takes care of
10008                  * adding member objects as they're created.
10009                  */
10010                 int                     i;
10011                 int                     n;
10012
10013                 appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
10014
10015                 /*
10016                  * We unconditionally create the extension, so we must drop it if it
10017                  * exists.  This could happen if the user deleted 'plpgsql' and then
10018                  * readded it, causing its oid to be greater than g_last_builtin_oid.
10019                  */
10020                 appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
10021
10022                 appendPQExpBufferStr(q,
10023                                                          "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
10024                 appendStringLiteralAH(q, extinfo->dobj.name, fout);
10025                 appendPQExpBufferStr(q, ", ");
10026                 appendStringLiteralAH(q, extinfo->namespace, fout);
10027                 appendPQExpBufferStr(q, ", ");
10028                 appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
10029                 appendStringLiteralAH(q, extinfo->extversion, fout);
10030                 appendPQExpBufferStr(q, ", ");
10031
10032                 /*
10033                  * Note that we're pushing extconfig (an OID array) back into
10034                  * pg_extension exactly as-is.  This is OK because pg_class OIDs are
10035                  * preserved in binary upgrade.
10036                  */
10037                 if (strlen(extinfo->extconfig) > 2)
10038                         appendStringLiteralAH(q, extinfo->extconfig, fout);
10039                 else
10040                         appendPQExpBufferStr(q, "NULL");
10041                 appendPQExpBufferStr(q, ", ");
10042                 if (strlen(extinfo->extcondition) > 2)
10043                         appendStringLiteralAH(q, extinfo->extcondition, fout);
10044                 else
10045                         appendPQExpBufferStr(q, "NULL");
10046                 appendPQExpBufferStr(q, ", ");
10047                 appendPQExpBufferStr(q, "ARRAY[");
10048                 n = 0;
10049                 for (i = 0; i < extinfo->dobj.nDeps; i++)
10050                 {
10051                         DumpableObject *extobj;
10052
10053                         extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
10054                         if (extobj && extobj->objType == DO_EXTENSION)
10055                         {
10056                                 if (n++ > 0)
10057                                         appendPQExpBufferChar(q, ',');
10058                                 appendStringLiteralAH(q, extobj->name, fout);
10059                         }
10060                 }
10061                 appendPQExpBufferStr(q, "]::pg_catalog.text[]");
10062                 appendPQExpBufferStr(q, ");\n");
10063         }
10064
10065         if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10066                 ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
10067                                          ARCHIVE_OPTS(.tag = extinfo->dobj.name,
10068                                                                   .description = "EXTENSION",
10069                                                                   .section = SECTION_PRE_DATA,
10070                                                                   .createStmt = q->data,
10071                                                                   .dropStmt = delq->data));
10072
10073         /* Dump Extension Comments and Security Labels */
10074         if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10075                 dumpComment(fout, "EXTENSION", qextname,
10076                                         NULL, "",
10077                                         extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
10078
10079         if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10080                 dumpSecLabel(fout, "EXTENSION", qextname,
10081                                          NULL, "",
10082                                          extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
10083
10084         free(qextname);
10085
10086         destroyPQExpBuffer(q);
10087         destroyPQExpBuffer(delq);
10088 }
10089
10090 /*
10091  * dumpType
10092  *        writes out to fout the queries to recreate a user-defined type
10093  */
10094 static void
10095 dumpType(Archive *fout, TypeInfo *tyinfo)
10096 {
10097         DumpOptions *dopt = fout->dopt;
10098
10099         /* Skip if not to be dumped */
10100         if (!tyinfo->dobj.dump || dopt->dataOnly)
10101                 return;
10102
10103         /* Dump out in proper style */
10104         if (tyinfo->typtype == TYPTYPE_BASE)
10105                 dumpBaseType(fout, tyinfo);
10106         else if (tyinfo->typtype == TYPTYPE_DOMAIN)
10107                 dumpDomain(fout, tyinfo);
10108         else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
10109                 dumpCompositeType(fout, tyinfo);
10110         else if (tyinfo->typtype == TYPTYPE_ENUM)
10111                 dumpEnumType(fout, tyinfo);
10112         else if (tyinfo->typtype == TYPTYPE_RANGE)
10113                 dumpRangeType(fout, tyinfo);
10114         else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
10115                 dumpUndefinedType(fout, tyinfo);
10116         else
10117                 pg_log_warning("typtype of data type \"%s\" appears to be invalid",
10118                                   tyinfo->dobj.name);
10119 }
10120
10121 /*
10122  * dumpEnumType
10123  *        writes out to fout the queries to recreate a user-defined enum type
10124  */
10125 static void
10126 dumpEnumType(Archive *fout, TypeInfo *tyinfo)
10127 {
10128         DumpOptions *dopt = fout->dopt;
10129         PQExpBuffer q = createPQExpBuffer();
10130         PQExpBuffer delq = createPQExpBuffer();
10131         PQExpBuffer query = createPQExpBuffer();
10132         PGresult   *res;
10133         int                     num,
10134                                 i;
10135         Oid                     enum_oid;
10136         char       *qtypname;
10137         char       *qualtypname;
10138         char       *label;
10139
10140         if (fout->remoteVersion >= 90100)
10141                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
10142                                                   "FROM pg_catalog.pg_enum "
10143                                                   "WHERE enumtypid = '%u'"
10144                                                   "ORDER BY enumsortorder",
10145                                                   tyinfo->dobj.catId.oid);
10146         else
10147                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
10148                                                   "FROM pg_catalog.pg_enum "
10149                                                   "WHERE enumtypid = '%u'"
10150                                                   "ORDER BY oid",
10151                                                   tyinfo->dobj.catId.oid);
10152
10153         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10154
10155         num = PQntuples(res);
10156
10157         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10158         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10159
10160         /*
10161          * CASCADE shouldn't be required here as for normal types since the I/O
10162          * functions are generic and do not get dropped.
10163          */
10164         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10165
10166         if (dopt->binary_upgrade)
10167                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10168                                                                                                  tyinfo->dobj.catId.oid,
10169                                                                                                  false);
10170
10171         appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
10172                                           qualtypname);
10173
10174         if (!dopt->binary_upgrade)
10175         {
10176                 /* Labels with server-assigned oids */
10177                 for (i = 0; i < num; i++)
10178                 {
10179                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
10180                         if (i > 0)
10181                                 appendPQExpBufferChar(q, ',');
10182                         appendPQExpBufferStr(q, "\n    ");
10183                         appendStringLiteralAH(q, label, fout);
10184                 }
10185         }
10186
10187         appendPQExpBufferStr(q, "\n);\n");
10188
10189         if (dopt->binary_upgrade)
10190         {
10191                 /* Labels with dump-assigned (preserved) oids */
10192                 for (i = 0; i < num; i++)
10193                 {
10194                         enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
10195                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
10196
10197                         if (i == 0)
10198                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
10199                         appendPQExpBuffer(q,
10200                                                           "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
10201                                                           enum_oid);
10202                         appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
10203                         appendStringLiteralAH(q, label, fout);
10204                         appendPQExpBufferStr(q, ";\n\n");
10205                 }
10206         }
10207
10208         if (dopt->binary_upgrade)
10209                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10210                                                                                 "TYPE", qtypname,
10211                                                                                 tyinfo->dobj.namespace->dobj.name);
10212
10213         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10214                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10215                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10216                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10217                                                                   .owner = tyinfo->rolname,
10218                                                                   .description = "TYPE",
10219                                                                   .section = SECTION_PRE_DATA,
10220                                                                   .createStmt = q->data,
10221                                                                   .dropStmt = delq->data));
10222
10223         /* Dump Type Comments and Security Labels */
10224         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10225                 dumpComment(fout, "TYPE", qtypname,
10226                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10227                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10228
10229         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10230                 dumpSecLabel(fout, "TYPE", qtypname,
10231                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10232                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10233
10234         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10235                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10236                                 qtypname, NULL,
10237                                 tyinfo->dobj.namespace->dobj.name,
10238                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10239                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10240
10241         PQclear(res);
10242         destroyPQExpBuffer(q);
10243         destroyPQExpBuffer(delq);
10244         destroyPQExpBuffer(query);
10245         free(qtypname);
10246         free(qualtypname);
10247 }
10248
10249 /*
10250  * dumpRangeType
10251  *        writes out to fout the queries to recreate a user-defined range type
10252  */
10253 static void
10254 dumpRangeType(Archive *fout, TypeInfo *tyinfo)
10255 {
10256         DumpOptions *dopt = fout->dopt;
10257         PQExpBuffer q = createPQExpBuffer();
10258         PQExpBuffer delq = createPQExpBuffer();
10259         PQExpBuffer query = createPQExpBuffer();
10260         PGresult   *res;
10261         Oid                     collationOid;
10262         char       *qtypname;
10263         char       *qualtypname;
10264         char       *procname;
10265
10266         appendPQExpBuffer(query,
10267                                           "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
10268                                           "opc.opcname AS opcname, "
10269                                           "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
10270                                           "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
10271                                           "opc.opcdefault, "
10272                                           "CASE WHEN rngcollation = st.typcollation THEN 0 "
10273                                           "     ELSE rngcollation END AS collation, "
10274                                           "rngcanonical, rngsubdiff "
10275                                           "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
10276                                           "     pg_catalog.pg_opclass opc "
10277                                           "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
10278                                           "rngtypid = '%u'",
10279                                           tyinfo->dobj.catId.oid);
10280
10281         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10282
10283         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10284         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10285
10286         /*
10287          * CASCADE shouldn't be required here as for normal types since the I/O
10288          * functions are generic and do not get dropped.
10289          */
10290         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10291
10292         if (dopt->binary_upgrade)
10293                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10294                                                                                                  tyinfo->dobj.catId.oid,
10295                                                                                                  false);
10296
10297         appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
10298                                           qualtypname);
10299
10300         appendPQExpBuffer(q, "\n    subtype = %s",
10301                                           PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
10302
10303         /* print subtype_opclass only if not default for subtype */
10304         if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
10305         {
10306                 char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
10307                 char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
10308
10309                 appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
10310                                                   fmtId(nspname));
10311                 appendPQExpBufferStr(q, fmtId(opcname));
10312         }
10313
10314         collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
10315         if (OidIsValid(collationOid))
10316         {
10317                 CollInfo   *coll = findCollationByOid(collationOid);
10318
10319                 if (coll)
10320                         appendPQExpBuffer(q, ",\n    collation = %s",
10321                                                           fmtQualifiedDumpable(coll));
10322         }
10323
10324         procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
10325         if (strcmp(procname, "-") != 0)
10326                 appendPQExpBuffer(q, ",\n    canonical = %s", procname);
10327
10328         procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
10329         if (strcmp(procname, "-") != 0)
10330                 appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
10331
10332         appendPQExpBufferStr(q, "\n);\n");
10333
10334         if (dopt->binary_upgrade)
10335                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10336                                                                                 "TYPE", qtypname,
10337                                                                                 tyinfo->dobj.namespace->dobj.name);
10338
10339         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10340                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10341                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10342                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10343                                                                   .owner = tyinfo->rolname,
10344                                                                   .description = "TYPE",
10345                                                                   .section = SECTION_PRE_DATA,
10346                                                                   .createStmt = q->data,
10347                                                                   .dropStmt = delq->data));
10348
10349         /* Dump Type Comments and Security Labels */
10350         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10351                 dumpComment(fout, "TYPE", qtypname,
10352                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10353                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10354
10355         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10356                 dumpSecLabel(fout, "TYPE", qtypname,
10357                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10358                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10359
10360         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10361                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10362                                 qtypname, NULL,
10363                                 tyinfo->dobj.namespace->dobj.name,
10364                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10365                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10366
10367         PQclear(res);
10368         destroyPQExpBuffer(q);
10369         destroyPQExpBuffer(delq);
10370         destroyPQExpBuffer(query);
10371         free(qtypname);
10372         free(qualtypname);
10373 }
10374
10375 /*
10376  * dumpUndefinedType
10377  *        writes out to fout the queries to recreate a !typisdefined type
10378  *
10379  * This is a shell type, but we use different terminology to distinguish
10380  * this case from where we have to emit a shell type definition to break
10381  * circular dependencies.  An undefined type shouldn't ever have anything
10382  * depending on it.
10383  */
10384 static void
10385 dumpUndefinedType(Archive *fout, TypeInfo *tyinfo)
10386 {
10387         DumpOptions *dopt = fout->dopt;
10388         PQExpBuffer q = createPQExpBuffer();
10389         PQExpBuffer delq = createPQExpBuffer();
10390         char       *qtypname;
10391         char       *qualtypname;
10392
10393         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10394         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10395
10396         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10397
10398         if (dopt->binary_upgrade)
10399                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10400                                                                                                  tyinfo->dobj.catId.oid,
10401                                                                                                  false);
10402
10403         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
10404                                           qualtypname);
10405
10406         if (dopt->binary_upgrade)
10407                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10408                                                                                 "TYPE", qtypname,
10409                                                                                 tyinfo->dobj.namespace->dobj.name);
10410
10411         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10412                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10413                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10414                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10415                                                                   .owner = tyinfo->rolname,
10416                                                                   .description = "TYPE",
10417                                                                   .section = SECTION_PRE_DATA,
10418                                                                   .createStmt = q->data,
10419                                                                   .dropStmt = delq->data));
10420
10421         /* Dump Type Comments and Security Labels */
10422         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10423                 dumpComment(fout, "TYPE", qtypname,
10424                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10425                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10426
10427         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10428                 dumpSecLabel(fout, "TYPE", qtypname,
10429                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10430                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10431
10432         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10433                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10434                                 qtypname, NULL,
10435                                 tyinfo->dobj.namespace->dobj.name,
10436                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10437                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10438
10439         destroyPQExpBuffer(q);
10440         destroyPQExpBuffer(delq);
10441         free(qtypname);
10442         free(qualtypname);
10443 }
10444
10445 /*
10446  * dumpBaseType
10447  *        writes out to fout the queries to recreate a user-defined base type
10448  */
10449 static void
10450 dumpBaseType(Archive *fout, TypeInfo *tyinfo)
10451 {
10452         DumpOptions *dopt = fout->dopt;
10453         PQExpBuffer q = createPQExpBuffer();
10454         PQExpBuffer delq = createPQExpBuffer();
10455         PQExpBuffer query = createPQExpBuffer();
10456         PGresult   *res;
10457         char       *qtypname;
10458         char       *qualtypname;
10459         char       *typlen;
10460         char       *typinput;
10461         char       *typoutput;
10462         char       *typreceive;
10463         char       *typsend;
10464         char       *typmodin;
10465         char       *typmodout;
10466         char       *typanalyze;
10467         Oid                     typreceiveoid;
10468         Oid                     typsendoid;
10469         Oid                     typmodinoid;
10470         Oid                     typmodoutoid;
10471         Oid                     typanalyzeoid;
10472         char       *typcategory;
10473         char       *typispreferred;
10474         char       *typdelim;
10475         char       *typbyval;
10476         char       *typalign;
10477         char       *typstorage;
10478         char       *typcollatable;
10479         char       *typdefault;
10480         bool            typdefault_is_literal = false;
10481
10482         /* Fetch type-specific details */
10483         if (fout->remoteVersion >= 90100)
10484         {
10485                 appendPQExpBuffer(query, "SELECT typlen, "
10486                                                   "typinput, typoutput, typreceive, typsend, "
10487                                                   "typmodin, typmodout, typanalyze, "
10488                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10489                                                   "typsend::pg_catalog.oid AS typsendoid, "
10490                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10491                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10492                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10493                                                   "typcategory, typispreferred, "
10494                                                   "typdelim, typbyval, typalign, typstorage, "
10495                                                   "(typcollation <> 0) AS typcollatable, "
10496                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
10497                                                   "FROM pg_catalog.pg_type "
10498                                                   "WHERE oid = '%u'::pg_catalog.oid",
10499                                                   tyinfo->dobj.catId.oid);
10500         }
10501         else if (fout->remoteVersion >= 80400)
10502         {
10503                 appendPQExpBuffer(query, "SELECT typlen, "
10504                                                   "typinput, typoutput, typreceive, typsend, "
10505                                                   "typmodin, typmodout, typanalyze, "
10506                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10507                                                   "typsend::pg_catalog.oid AS typsendoid, "
10508                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10509                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10510                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10511                                                   "typcategory, typispreferred, "
10512                                                   "typdelim, typbyval, typalign, typstorage, "
10513                                                   "false AS typcollatable, "
10514                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
10515                                                   "FROM pg_catalog.pg_type "
10516                                                   "WHERE oid = '%u'::pg_catalog.oid",
10517                                                   tyinfo->dobj.catId.oid);
10518         }
10519         else if (fout->remoteVersion >= 80300)
10520         {
10521                 /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
10522                 appendPQExpBuffer(query, "SELECT typlen, "
10523                                                   "typinput, typoutput, typreceive, typsend, "
10524                                                   "typmodin, typmodout, typanalyze, "
10525                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10526                                                   "typsend::pg_catalog.oid AS typsendoid, "
10527                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10528                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10529                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10530                                                   "'U' AS typcategory, false AS typispreferred, "
10531                                                   "typdelim, typbyval, typalign, typstorage, "
10532                                                   "false AS typcollatable, "
10533                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10534                                                   "FROM pg_catalog.pg_type "
10535                                                   "WHERE oid = '%u'::pg_catalog.oid",
10536                                                   tyinfo->dobj.catId.oid);
10537         }
10538         else
10539         {
10540                 appendPQExpBuffer(query, "SELECT typlen, "
10541                                                   "typinput, typoutput, typreceive, typsend, "
10542                                                   "'-' AS typmodin, '-' AS typmodout, "
10543                                                   "typanalyze, "
10544                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10545                                                   "typsend::pg_catalog.oid AS typsendoid, "
10546                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
10547                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10548                                                   "'U' AS typcategory, false AS typispreferred, "
10549                                                   "typdelim, typbyval, typalign, typstorage, "
10550                                                   "false AS typcollatable, "
10551                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10552                                                   "FROM pg_catalog.pg_type "
10553                                                   "WHERE oid = '%u'::pg_catalog.oid",
10554                                                   tyinfo->dobj.catId.oid);
10555         }
10556
10557         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10558
10559         typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
10560         typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
10561         typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
10562         typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
10563         typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
10564         typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
10565         typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
10566         typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
10567         typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
10568         typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
10569         typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
10570         typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
10571         typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
10572         typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
10573         typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
10574         typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
10575         typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
10576         typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
10577         typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
10578         typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
10579         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
10580                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
10581         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
10582         {
10583                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
10584                 typdefault_is_literal = true;   /* it needs quotes */
10585         }
10586         else
10587                 typdefault = NULL;
10588
10589         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10590         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10591
10592         /*
10593          * The reason we include CASCADE is that the circular dependency between
10594          * the type and its I/O functions makes it impossible to drop the type any
10595          * other way.
10596          */
10597         appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
10598
10599         /*
10600          * We might already have a shell type, but setting pg_type_oid is
10601          * harmless, and in any case we'd better set the array type OID.
10602          */
10603         if (dopt->binary_upgrade)
10604                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10605                                                                                                  tyinfo->dobj.catId.oid,
10606                                                                                                  false);
10607
10608         appendPQExpBuffer(q,
10609                                           "CREATE TYPE %s (\n"
10610                                           "    INTERNALLENGTH = %s",
10611                                           qualtypname,
10612                                           (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
10613
10614         /* regproc result is sufficiently quoted already */
10615         appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
10616         appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
10617         if (OidIsValid(typreceiveoid))
10618                 appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
10619         if (OidIsValid(typsendoid))
10620                 appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
10621         if (OidIsValid(typmodinoid))
10622                 appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
10623         if (OidIsValid(typmodoutoid))
10624                 appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
10625         if (OidIsValid(typanalyzeoid))
10626                 appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
10627
10628         if (strcmp(typcollatable, "t") == 0)
10629                 appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
10630
10631         if (typdefault != NULL)
10632         {
10633                 appendPQExpBufferStr(q, ",\n    DEFAULT = ");
10634                 if (typdefault_is_literal)
10635                         appendStringLiteralAH(q, typdefault, fout);
10636                 else
10637                         appendPQExpBufferStr(q, typdefault);
10638         }
10639
10640         if (OidIsValid(tyinfo->typelem))
10641         {
10642                 char       *elemType;
10643
10644                 elemType = getFormattedTypeName(fout, tyinfo->typelem, zeroAsOpaque);
10645                 appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
10646                 free(elemType);
10647         }
10648
10649         if (strcmp(typcategory, "U") != 0)
10650         {
10651                 appendPQExpBufferStr(q, ",\n    CATEGORY = ");
10652                 appendStringLiteralAH(q, typcategory, fout);
10653         }
10654
10655         if (strcmp(typispreferred, "t") == 0)
10656                 appendPQExpBufferStr(q, ",\n    PREFERRED = true");
10657
10658         if (typdelim && strcmp(typdelim, ",") != 0)
10659         {
10660                 appendPQExpBufferStr(q, ",\n    DELIMITER = ");
10661                 appendStringLiteralAH(q, typdelim, fout);
10662         }
10663
10664         if (strcmp(typalign, "c") == 0)
10665                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
10666         else if (strcmp(typalign, "s") == 0)
10667                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
10668         else if (strcmp(typalign, "i") == 0)
10669                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
10670         else if (strcmp(typalign, "d") == 0)
10671                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
10672
10673         if (strcmp(typstorage, "p") == 0)
10674                 appendPQExpBufferStr(q, ",\n    STORAGE = plain");
10675         else if (strcmp(typstorage, "e") == 0)
10676                 appendPQExpBufferStr(q, ",\n    STORAGE = external");
10677         else if (strcmp(typstorage, "x") == 0)
10678                 appendPQExpBufferStr(q, ",\n    STORAGE = extended");
10679         else if (strcmp(typstorage, "m") == 0)
10680                 appendPQExpBufferStr(q, ",\n    STORAGE = main");
10681
10682         if (strcmp(typbyval, "t") == 0)
10683                 appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
10684
10685         appendPQExpBufferStr(q, "\n);\n");
10686
10687         if (dopt->binary_upgrade)
10688                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10689                                                                                 "TYPE", qtypname,
10690                                                                                 tyinfo->dobj.namespace->dobj.name);
10691
10692         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10693                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10694                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10695                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10696                                                                   .owner = tyinfo->rolname,
10697                                                                   .description = "TYPE",
10698                                                                   .section = SECTION_PRE_DATA,
10699                                                                   .createStmt = q->data,
10700                                                                   .dropStmt = delq->data));
10701
10702         /* Dump Type Comments and Security Labels */
10703         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10704                 dumpComment(fout, "TYPE", qtypname,
10705                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10706                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10707
10708         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10709                 dumpSecLabel(fout, "TYPE", qtypname,
10710                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10711                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10712
10713         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10714                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10715                                 qtypname, NULL,
10716                                 tyinfo->dobj.namespace->dobj.name,
10717                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10718                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10719
10720         PQclear(res);
10721         destroyPQExpBuffer(q);
10722         destroyPQExpBuffer(delq);
10723         destroyPQExpBuffer(query);
10724         free(qtypname);
10725         free(qualtypname);
10726 }
10727
10728 /*
10729  * dumpDomain
10730  *        writes out to fout the queries to recreate a user-defined domain
10731  */
10732 static void
10733 dumpDomain(Archive *fout, TypeInfo *tyinfo)
10734 {
10735         DumpOptions *dopt = fout->dopt;
10736         PQExpBuffer q = createPQExpBuffer();
10737         PQExpBuffer delq = createPQExpBuffer();
10738         PQExpBuffer query = createPQExpBuffer();
10739         PGresult   *res;
10740         int                     i;
10741         char       *qtypname;
10742         char       *qualtypname;
10743         char       *typnotnull;
10744         char       *typdefn;
10745         char       *typdefault;
10746         Oid                     typcollation;
10747         bool            typdefault_is_literal = false;
10748
10749         /* Fetch domain specific details */
10750         if (fout->remoteVersion >= 90100)
10751         {
10752                 /* typcollation is new in 9.1 */
10753                 appendPQExpBuffer(query, "SELECT t.typnotnull, "
10754                                                   "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
10755                                                   "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
10756                                                   "t.typdefault, "
10757                                                   "CASE WHEN t.typcollation <> u.typcollation "
10758                                                   "THEN t.typcollation ELSE 0 END AS typcollation "
10759                                                   "FROM pg_catalog.pg_type t "
10760                                                   "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
10761                                                   "WHERE t.oid = '%u'::pg_catalog.oid",
10762                                                   tyinfo->dobj.catId.oid);
10763         }
10764         else
10765         {
10766                 appendPQExpBuffer(query, "SELECT typnotnull, "
10767                                                   "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
10768                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
10769                                                   "typdefault, 0 AS typcollation "
10770                                                   "FROM pg_catalog.pg_type "
10771                                                   "WHERE oid = '%u'::pg_catalog.oid",
10772                                                   tyinfo->dobj.catId.oid);
10773         }
10774
10775         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10776
10777         typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
10778         typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
10779         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
10780                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
10781         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
10782         {
10783                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
10784                 typdefault_is_literal = true;   /* it needs quotes */
10785         }
10786         else
10787                 typdefault = NULL;
10788         typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
10789
10790         if (dopt->binary_upgrade)
10791                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10792                                                                                                  tyinfo->dobj.catId.oid,
10793                                                                                                  true); /* force array type */
10794
10795         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10796         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10797
10798         appendPQExpBuffer(q,
10799                                           "CREATE DOMAIN %s AS %s",
10800                                           qualtypname,
10801                                           typdefn);
10802
10803         /* Print collation only if different from base type's collation */
10804         if (OidIsValid(typcollation))
10805         {
10806                 CollInfo   *coll;
10807
10808                 coll = findCollationByOid(typcollation);
10809                 if (coll)
10810                         appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
10811         }
10812
10813         if (typnotnull[0] == 't')
10814                 appendPQExpBufferStr(q, " NOT NULL");
10815
10816         if (typdefault != NULL)
10817         {
10818                 appendPQExpBufferStr(q, " DEFAULT ");
10819                 if (typdefault_is_literal)
10820                         appendStringLiteralAH(q, typdefault, fout);
10821                 else
10822                         appendPQExpBufferStr(q, typdefault);
10823         }
10824
10825         PQclear(res);
10826
10827         /*
10828          * Add any CHECK constraints for the domain
10829          */
10830         for (i = 0; i < tyinfo->nDomChecks; i++)
10831         {
10832                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
10833
10834                 if (!domcheck->separate)
10835                         appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
10836                                                           fmtId(domcheck->dobj.name), domcheck->condef);
10837         }
10838
10839         appendPQExpBufferStr(q, ";\n");
10840
10841         appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
10842
10843         if (dopt->binary_upgrade)
10844                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10845                                                                                 "DOMAIN", qtypname,
10846                                                                                 tyinfo->dobj.namespace->dobj.name);
10847
10848         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10849                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10850                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10851                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10852                                                                   .owner = tyinfo->rolname,
10853                                                                   .description = "DOMAIN",
10854                                                                   .section = SECTION_PRE_DATA,
10855                                                                   .createStmt = q->data,
10856                                                                   .dropStmt = delq->data));
10857
10858         /* Dump Domain Comments and Security Labels */
10859         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10860                 dumpComment(fout, "DOMAIN", qtypname,
10861                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10862                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10863
10864         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10865                 dumpSecLabel(fout, "DOMAIN", qtypname,
10866                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10867                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10868
10869         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10870                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10871                                 qtypname, NULL,
10872                                 tyinfo->dobj.namespace->dobj.name,
10873                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10874                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10875
10876         /* Dump any per-constraint comments */
10877         for (i = 0; i < tyinfo->nDomChecks; i++)
10878         {
10879                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
10880                 PQExpBuffer conprefix = createPQExpBuffer();
10881
10882                 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
10883                                                   fmtId(domcheck->dobj.name));
10884
10885                 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10886                         dumpComment(fout, conprefix->data, qtypname,
10887                                                 tyinfo->dobj.namespace->dobj.name,
10888                                                 tyinfo->rolname,
10889                                                 domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
10890
10891                 destroyPQExpBuffer(conprefix);
10892         }
10893
10894         destroyPQExpBuffer(q);
10895         destroyPQExpBuffer(delq);
10896         destroyPQExpBuffer(query);
10897         free(qtypname);
10898         free(qualtypname);
10899 }
10900
10901 /*
10902  * dumpCompositeType
10903  *        writes out to fout the queries to recreate a user-defined stand-alone
10904  *        composite type
10905  */
10906 static void
10907 dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
10908 {
10909         DumpOptions *dopt = fout->dopt;
10910         PQExpBuffer q = createPQExpBuffer();
10911         PQExpBuffer dropped = createPQExpBuffer();
10912         PQExpBuffer delq = createPQExpBuffer();
10913         PQExpBuffer query = createPQExpBuffer();
10914         PGresult   *res;
10915         char       *qtypname;
10916         char       *qualtypname;
10917         int                     ntups;
10918         int                     i_attname;
10919         int                     i_atttypdefn;
10920         int                     i_attlen;
10921         int                     i_attalign;
10922         int                     i_attisdropped;
10923         int                     i_attcollation;
10924         int                     i;
10925         int                     actual_atts;
10926
10927         /* Fetch type specific details */
10928         if (fout->remoteVersion >= 90100)
10929         {
10930                 /*
10931                  * attcollation is new in 9.1.  Since we only want to dump COLLATE
10932                  * clauses for attributes whose collation is different from their
10933                  * type's default, we use a CASE here to suppress uninteresting
10934                  * attcollations cheaply.  atttypid will be 0 for dropped columns;
10935                  * collation does not matter for those.
10936                  */
10937                 appendPQExpBuffer(query, "SELECT a.attname, "
10938                                                   "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
10939                                                   "a.attlen, a.attalign, a.attisdropped, "
10940                                                   "CASE WHEN a.attcollation <> at.typcollation "
10941                                                   "THEN a.attcollation ELSE 0 END AS attcollation "
10942                                                   "FROM pg_catalog.pg_type ct "
10943                                                   "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
10944                                                   "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
10945                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
10946                                                   "ORDER BY a.attnum ",
10947                                                   tyinfo->dobj.catId.oid);
10948         }
10949         else
10950         {
10951                 /*
10952                  * Since ALTER TYPE could not drop columns until 9.1, attisdropped
10953                  * should always be false.
10954                  */
10955                 appendPQExpBuffer(query, "SELECT a.attname, "
10956                                                   "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
10957                                                   "a.attlen, a.attalign, a.attisdropped, "
10958                                                   "0 AS attcollation "
10959                                                   "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
10960                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
10961                                                   "AND a.attrelid = ct.typrelid "
10962                                                   "ORDER BY a.attnum ",
10963                                                   tyinfo->dobj.catId.oid);
10964         }
10965
10966         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10967
10968         ntups = PQntuples(res);
10969
10970         i_attname = PQfnumber(res, "attname");
10971         i_atttypdefn = PQfnumber(res, "atttypdefn");
10972         i_attlen = PQfnumber(res, "attlen");
10973         i_attalign = PQfnumber(res, "attalign");
10974         i_attisdropped = PQfnumber(res, "attisdropped");
10975         i_attcollation = PQfnumber(res, "attcollation");
10976
10977         if (dopt->binary_upgrade)
10978         {
10979                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10980                                                                                                  tyinfo->dobj.catId.oid,
10981                                                                                                  false);
10982                 binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid, false);
10983         }
10984
10985         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10986         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10987
10988         appendPQExpBuffer(q, "CREATE TYPE %s AS (",
10989                                           qualtypname);
10990
10991         actual_atts = 0;
10992         for (i = 0; i < ntups; i++)
10993         {
10994                 char       *attname;
10995                 char       *atttypdefn;
10996                 char       *attlen;
10997                 char       *attalign;
10998                 bool            attisdropped;
10999                 Oid                     attcollation;
11000
11001                 attname = PQgetvalue(res, i, i_attname);
11002                 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
11003                 attlen = PQgetvalue(res, i, i_attlen);
11004                 attalign = PQgetvalue(res, i, i_attalign);
11005                 attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
11006                 attcollation = atooid(PQgetvalue(res, i, i_attcollation));
11007
11008                 if (attisdropped && !dopt->binary_upgrade)
11009                         continue;
11010
11011                 /* Format properly if not first attr */
11012                 if (actual_atts++ > 0)
11013                         appendPQExpBufferChar(q, ',');
11014                 appendPQExpBufferStr(q, "\n\t");
11015
11016                 if (!attisdropped)
11017                 {
11018                         appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
11019
11020                         /* Add collation if not default for the column type */
11021                         if (OidIsValid(attcollation))
11022                         {
11023                                 CollInfo   *coll;
11024
11025                                 coll = findCollationByOid(attcollation);
11026                                 if (coll)
11027                                         appendPQExpBuffer(q, " COLLATE %s",
11028                                                                           fmtQualifiedDumpable(coll));
11029                         }
11030                 }
11031                 else
11032                 {
11033                         /*
11034                          * This is a dropped attribute and we're in binary_upgrade mode.
11035                          * Insert a placeholder for it in the CREATE TYPE command, and set
11036                          * length and alignment with direct UPDATE to the catalogs
11037                          * afterwards. See similar code in dumpTableSchema().
11038                          */
11039                         appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
11040
11041                         /* stash separately for insertion after the CREATE TYPE */
11042                         appendPQExpBufferStr(dropped,
11043                                                                  "\n-- For binary upgrade, recreate dropped column.\n");
11044                         appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
11045                                                           "SET attlen = %s, "
11046                                                           "attalign = '%s', attbyval = false\n"
11047                                                           "WHERE attname = ", attlen, attalign);
11048                         appendStringLiteralAH(dropped, attname, fout);
11049                         appendPQExpBufferStr(dropped, "\n  AND attrelid = ");
11050                         appendStringLiteralAH(dropped, qualtypname, fout);
11051                         appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
11052
11053                         appendPQExpBuffer(dropped, "ALTER TYPE %s ",
11054                                                           qualtypname);
11055                         appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
11056                                                           fmtId(attname));
11057                 }
11058         }
11059         appendPQExpBufferStr(q, "\n);\n");
11060         appendPQExpBufferStr(q, dropped->data);
11061
11062         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
11063
11064         if (dopt->binary_upgrade)
11065                 binary_upgrade_extension_member(q, &tyinfo->dobj,
11066                                                                                 "TYPE", qtypname,
11067                                                                                 tyinfo->dobj.namespace->dobj.name);
11068
11069         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11070                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
11071                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
11072                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
11073                                                                   .owner = tyinfo->rolname,
11074                                                                   .description = "TYPE",
11075                                                                   .section = SECTION_PRE_DATA,
11076                                                                   .createStmt = q->data,
11077                                                                   .dropStmt = delq->data));
11078
11079
11080         /* Dump Type Comments and Security Labels */
11081         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11082                 dumpComment(fout, "TYPE", qtypname,
11083                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11084                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11085
11086         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11087                 dumpSecLabel(fout, "TYPE", qtypname,
11088                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11089                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11090
11091         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
11092                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
11093                                 qtypname, NULL,
11094                                 tyinfo->dobj.namespace->dobj.name,
11095                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
11096                                 tyinfo->inittypacl, tyinfo->initrtypacl);
11097
11098         PQclear(res);
11099         destroyPQExpBuffer(q);
11100         destroyPQExpBuffer(dropped);
11101         destroyPQExpBuffer(delq);
11102         destroyPQExpBuffer(query);
11103         free(qtypname);
11104         free(qualtypname);
11105
11106         /* Dump any per-column comments */
11107         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11108                 dumpCompositeTypeColComments(fout, tyinfo);
11109 }
11110
11111 /*
11112  * dumpCompositeTypeColComments
11113  *        writes out to fout the queries to recreate comments on the columns of
11114  *        a user-defined stand-alone composite type
11115  */
11116 static void
11117 dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
11118 {
11119         CommentItem *comments;
11120         int                     ncomments;
11121         PGresult   *res;
11122         PQExpBuffer query;
11123         PQExpBuffer target;
11124         Oid                     pgClassOid;
11125         int                     i;
11126         int                     ntups;
11127         int                     i_attname;
11128         int                     i_attnum;
11129
11130         /* do nothing, if --no-comments is supplied */
11131         if (fout->dopt->no_comments)
11132                 return;
11133
11134         query = createPQExpBuffer();
11135
11136         appendPQExpBuffer(query,
11137                                           "SELECT c.tableoid, a.attname, a.attnum "
11138                                           "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
11139                                           "WHERE c.oid = '%u' AND c.oid = a.attrelid "
11140                                           "  AND NOT a.attisdropped "
11141                                           "ORDER BY a.attnum ",
11142                                           tyinfo->typrelid);
11143
11144         /* Fetch column attnames */
11145         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11146
11147         ntups = PQntuples(res);
11148         if (ntups < 1)
11149         {
11150                 PQclear(res);
11151                 destroyPQExpBuffer(query);
11152                 return;
11153         }
11154
11155         pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
11156
11157         /* Search for comments associated with type's pg_class OID */
11158         ncomments = findComments(fout,
11159                                                          pgClassOid,
11160                                                          tyinfo->typrelid,
11161                                                          &comments);
11162
11163         /* If no comments exist, we're done */
11164         if (ncomments <= 0)
11165         {
11166                 PQclear(res);
11167                 destroyPQExpBuffer(query);
11168                 return;
11169         }
11170
11171         /* Build COMMENT ON statements */
11172         target = createPQExpBuffer();
11173
11174         i_attnum = PQfnumber(res, "attnum");
11175         i_attname = PQfnumber(res, "attname");
11176         while (ncomments > 0)
11177         {
11178                 const char *attname;
11179
11180                 attname = NULL;
11181                 for (i = 0; i < ntups; i++)
11182                 {
11183                         if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
11184                         {
11185                                 attname = PQgetvalue(res, i, i_attname);
11186                                 break;
11187                         }
11188                 }
11189                 if (attname)                    /* just in case we don't find it */
11190                 {
11191                         const char *descr = comments->descr;
11192
11193                         resetPQExpBuffer(target);
11194                         appendPQExpBuffer(target, "COLUMN %s.",
11195                                                           fmtId(tyinfo->dobj.name));
11196                         appendPQExpBufferStr(target, fmtId(attname));
11197
11198                         resetPQExpBuffer(query);
11199                         appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
11200                                                           fmtQualifiedDumpable(tyinfo));
11201                         appendPQExpBuffer(query, "%s IS ", fmtId(attname));
11202                         appendStringLiteralAH(query, descr, fout);
11203                         appendPQExpBufferStr(query, ";\n");
11204
11205                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
11206                                                  ARCHIVE_OPTS(.tag = target->data,
11207                                                                           .namespace = tyinfo->dobj.namespace->dobj.name,
11208                                                                           .owner = tyinfo->rolname,
11209                                                                           .description = "COMMENT",
11210                                                                           .section = SECTION_NONE,
11211                                                                           .createStmt = query->data,
11212                                                                           .deps = &(tyinfo->dobj.dumpId),
11213                                                                           .nDeps = 1));
11214                 }
11215
11216                 comments++;
11217                 ncomments--;
11218         }
11219
11220         PQclear(res);
11221         destroyPQExpBuffer(query);
11222         destroyPQExpBuffer(target);
11223 }
11224
11225 /*
11226  * dumpShellType
11227  *        writes out to fout the queries to create a shell type
11228  *
11229  * We dump a shell definition in advance of the I/O functions for the type.
11230  */
11231 static void
11232 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
11233 {
11234         DumpOptions *dopt = fout->dopt;
11235         PQExpBuffer q;
11236
11237         /* Skip if not to be dumped */
11238         if (!stinfo->dobj.dump || dopt->dataOnly)
11239                 return;
11240
11241         q = createPQExpBuffer();
11242
11243         /*
11244          * Note the lack of a DROP command for the shell type; any required DROP
11245          * is driven off the base type entry, instead.  This interacts with
11246          * _printTocEntry()'s use of the presence of a DROP command to decide
11247          * whether an entry needs an ALTER OWNER command.  We don't want to alter
11248          * the shell type's owner immediately on creation; that should happen only
11249          * after it's filled in, otherwise the backend complains.
11250          */
11251
11252         if (dopt->binary_upgrade)
11253                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
11254                                                                                                  stinfo->baseType->dobj.catId.oid,
11255                                                                                                  false);
11256
11257         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
11258                                           fmtQualifiedDumpable(stinfo));
11259
11260         if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11261                 ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
11262                                          ARCHIVE_OPTS(.tag = stinfo->dobj.name,
11263                                                                   .namespace = stinfo->dobj.namespace->dobj.name,
11264                                                                   .owner = stinfo->baseType->rolname,
11265                                                                   .description = "SHELL TYPE",
11266                                                                   .section = SECTION_PRE_DATA,
11267                                                                   .createStmt = q->data));
11268
11269         destroyPQExpBuffer(q);
11270 }
11271
11272 /*
11273  * dumpProcLang
11274  *                writes out to fout the queries to recreate a user-defined
11275  *                procedural language
11276  */
11277 static void
11278 dumpProcLang(Archive *fout, ProcLangInfo *plang)
11279 {
11280         DumpOptions *dopt = fout->dopt;
11281         PQExpBuffer defqry;
11282         PQExpBuffer delqry;
11283         bool            useParams;
11284         char       *qlanname;
11285         FuncInfo   *funcInfo;
11286         FuncInfo   *inlineInfo = NULL;
11287         FuncInfo   *validatorInfo = NULL;
11288
11289         /* Skip if not to be dumped */
11290         if (!plang->dobj.dump || dopt->dataOnly)
11291                 return;
11292
11293         /*
11294          * Try to find the support function(s).  It is not an error if we don't
11295          * find them --- if the functions are in the pg_catalog schema, as is
11296          * standard in 8.1 and up, then we won't have loaded them. (In this case
11297          * we will emit a parameterless CREATE LANGUAGE command, which will
11298          * require PL template knowledge in the backend to reload.)
11299          */
11300
11301         funcInfo = findFuncByOid(plang->lanplcallfoid);
11302         if (funcInfo != NULL && !funcInfo->dobj.dump)
11303                 funcInfo = NULL;                /* treat not-dumped same as not-found */
11304
11305         if (OidIsValid(plang->laninline))
11306         {
11307                 inlineInfo = findFuncByOid(plang->laninline);
11308                 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
11309                         inlineInfo = NULL;
11310         }
11311
11312         if (OidIsValid(plang->lanvalidator))
11313         {
11314                 validatorInfo = findFuncByOid(plang->lanvalidator);
11315                 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
11316                         validatorInfo = NULL;
11317         }
11318
11319         /*
11320          * If the functions are dumpable then emit a traditional CREATE LANGUAGE
11321          * with parameters.  Otherwise, we'll write a parameterless command, which
11322          * will rely on data from pg_pltemplate.
11323          */
11324         useParams = (funcInfo != NULL &&
11325                                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
11326                                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
11327
11328         defqry = createPQExpBuffer();
11329         delqry = createPQExpBuffer();
11330
11331         qlanname = pg_strdup(fmtId(plang->dobj.name));
11332
11333         appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
11334                                           qlanname);
11335
11336         if (useParams)
11337         {
11338                 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
11339                                                   plang->lanpltrusted ? "TRUSTED " : "",
11340                                                   qlanname);
11341                 appendPQExpBuffer(defqry, " HANDLER %s",
11342                                                   fmtQualifiedDumpable(funcInfo));
11343                 if (OidIsValid(plang->laninline))
11344                         appendPQExpBuffer(defqry, " INLINE %s",
11345                                                           fmtQualifiedDumpable(inlineInfo));
11346                 if (OidIsValid(plang->lanvalidator))
11347                         appendPQExpBuffer(defqry, " VALIDATOR %s",
11348                                                           fmtQualifiedDumpable(validatorInfo));
11349         }
11350         else
11351         {
11352                 /*
11353                  * If not dumping parameters, then use CREATE OR REPLACE so that the
11354                  * command will not fail if the language is preinstalled in the target
11355                  * database.  We restrict the use of REPLACE to this case so as to
11356                  * eliminate the risk of replacing a language with incompatible
11357                  * parameter settings: this command will only succeed at all if there
11358                  * is a pg_pltemplate entry, and if there is one, the existing entry
11359                  * must match it too.
11360                  */
11361                 appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
11362                                                   qlanname);
11363         }
11364         appendPQExpBufferStr(defqry, ";\n");
11365
11366         if (dopt->binary_upgrade)
11367                 binary_upgrade_extension_member(defqry, &plang->dobj,
11368                                                                                 "LANGUAGE", qlanname, NULL);
11369
11370         if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
11371                 ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
11372                                          ARCHIVE_OPTS(.tag = plang->dobj.name,
11373                                                                   .owner = plang->lanowner,
11374                                                                   .description = "PROCEDURAL LANGUAGE",
11375                                                                   .section = SECTION_PRE_DATA,
11376                                                                   .createStmt = defqry->data,
11377                                                                   .dropStmt = delqry->data,
11378                                                                   ));
11379
11380         /* Dump Proc Lang Comments and Security Labels */
11381         if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
11382                 dumpComment(fout, "LANGUAGE", qlanname,
11383                                         NULL, plang->lanowner,
11384                                         plang->dobj.catId, 0, plang->dobj.dumpId);
11385
11386         if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
11387                 dumpSecLabel(fout, "LANGUAGE", qlanname,
11388                                          NULL, plang->lanowner,
11389                                          plang->dobj.catId, 0, plang->dobj.dumpId);
11390
11391         if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
11392                 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
11393                                 qlanname, NULL, NULL,
11394                                 plang->lanowner, plang->lanacl, plang->rlanacl,
11395                                 plang->initlanacl, plang->initrlanacl);
11396
11397         free(qlanname);
11398
11399         destroyPQExpBuffer(defqry);
11400         destroyPQExpBuffer(delqry);
11401 }
11402
11403 /*
11404  * format_function_arguments: generate function name and argument list
11405  *
11406  * This is used when we can rely on pg_get_function_arguments to format
11407  * the argument list.  Note, however, that pg_get_function_arguments
11408  * does not special-case zero-argument aggregates.
11409  */
11410 static char *
11411 format_function_arguments(FuncInfo *finfo, char *funcargs, bool is_agg)
11412 {
11413         PQExpBufferData fn;
11414
11415         initPQExpBuffer(&fn);
11416         appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
11417         if (is_agg && finfo->nargs == 0)
11418                 appendPQExpBufferStr(&fn, "(*)");
11419         else
11420                 appendPQExpBuffer(&fn, "(%s)", funcargs);
11421         return fn.data;
11422 }
11423
11424 /*
11425  * format_function_arguments_old: generate function name and argument list
11426  *
11427  * The argument type names are qualified if needed.  The function name
11428  * is never qualified.
11429  *
11430  * This is used only with pre-8.4 servers, so we aren't expecting to see
11431  * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
11432  *
11433  * Any or all of allargtypes, argmodes, argnames may be NULL.
11434  */
11435 static char *
11436 format_function_arguments_old(Archive *fout,
11437                                                           FuncInfo *finfo, int nallargs,
11438                                                           char **allargtypes,
11439                                                           char **argmodes,
11440                                                           char **argnames)
11441 {
11442         PQExpBufferData fn;
11443         int                     j;
11444
11445         initPQExpBuffer(&fn);
11446         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11447         for (j = 0; j < nallargs; j++)
11448         {
11449                 Oid                     typid;
11450                 char       *typname;
11451                 const char *argmode;
11452                 const char *argname;
11453
11454                 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
11455                 typname = getFormattedTypeName(fout, typid, zeroAsOpaque);
11456
11457                 if (argmodes)
11458                 {
11459                         switch (argmodes[j][0])
11460                         {
11461                                 case PROARGMODE_IN:
11462                                         argmode = "";
11463                                         break;
11464                                 case PROARGMODE_OUT:
11465                                         argmode = "OUT ";
11466                                         break;
11467                                 case PROARGMODE_INOUT:
11468                                         argmode = "INOUT ";
11469                                         break;
11470                                 default:
11471                                         pg_log_warning("bogus value in proargmodes array");
11472                                         argmode = "";
11473                                         break;
11474                         }
11475                 }
11476                 else
11477                         argmode = "";
11478
11479                 argname = argnames ? argnames[j] : (char *) NULL;
11480                 if (argname && argname[0] == '\0')
11481                         argname = NULL;
11482
11483                 appendPQExpBuffer(&fn, "%s%s%s%s%s",
11484                                                   (j > 0) ? ", " : "",
11485                                                   argmode,
11486                                                   argname ? fmtId(argname) : "",
11487                                                   argname ? " " : "",
11488                                                   typname);
11489                 free(typname);
11490         }
11491         appendPQExpBufferChar(&fn, ')');
11492         return fn.data;
11493 }
11494
11495 /*
11496  * format_function_signature: generate function name and argument list
11497  *
11498  * This is like format_function_arguments_old except that only a minimal
11499  * list of input argument types is generated; this is sufficient to
11500  * reference the function, but not to define it.
11501  *
11502  * If honor_quotes is false then the function name is never quoted.
11503  * This is appropriate for use in TOC tags, but not in SQL commands.
11504  */
11505 static char *
11506 format_function_signature(Archive *fout, FuncInfo *finfo, bool honor_quotes)
11507 {
11508         PQExpBufferData fn;
11509         int                     j;
11510
11511         initPQExpBuffer(&fn);
11512         if (honor_quotes)
11513                 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11514         else
11515                 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
11516         for (j = 0; j < finfo->nargs; j++)
11517         {
11518                 char       *typname;
11519
11520                 if (j > 0)
11521                         appendPQExpBufferStr(&fn, ", ");
11522
11523                 typname = getFormattedTypeName(fout, finfo->argtypes[j],
11524                                                                            zeroAsOpaque);
11525                 appendPQExpBufferStr(&fn, typname);
11526                 free(typname);
11527         }
11528         appendPQExpBufferChar(&fn, ')');
11529         return fn.data;
11530 }
11531
11532
11533 /*
11534  * dumpFunc:
11535  *        dump out one function
11536  */
11537 static void
11538 dumpFunc(Archive *fout, FuncInfo *finfo)
11539 {
11540         DumpOptions *dopt = fout->dopt;
11541         PQExpBuffer query;
11542         PQExpBuffer q;
11543         PQExpBuffer delqry;
11544         PQExpBuffer asPart;
11545         PGresult   *res;
11546         char       *funcsig;            /* identity signature */
11547         char       *funcfullsig = NULL; /* full signature */
11548         char       *funcsig_tag;
11549         char       *proretset;
11550         char       *prosrc;
11551         char       *probin;
11552         char       *funcargs;
11553         char       *funciargs;
11554         char       *funcresult;
11555         char       *proallargtypes;
11556         char       *proargmodes;
11557         char       *proargnames;
11558         char       *protrftypes;
11559         char       *prokind;
11560         char       *provolatile;
11561         char       *proisstrict;
11562         char       *prosecdef;
11563         char       *proleakproof;
11564         char       *proconfig;
11565         char       *procost;
11566         char       *prorows;
11567         char       *prosupport;
11568         char       *proparallel;
11569         char       *lanname;
11570         char       *rettypename;
11571         int                     nallargs;
11572         char      **allargtypes = NULL;
11573         char      **argmodes = NULL;
11574         char      **argnames = NULL;
11575         char      **configitems = NULL;
11576         int                     nconfigitems = 0;
11577         const char *keyword;
11578         int                     i;
11579
11580         /* Skip if not to be dumped */
11581         if (!finfo->dobj.dump || dopt->dataOnly)
11582                 return;
11583
11584         query = createPQExpBuffer();
11585         q = createPQExpBuffer();
11586         delqry = createPQExpBuffer();
11587         asPart = createPQExpBuffer();
11588
11589         /* Fetch function-specific details */
11590         if (fout->remoteVersion >= 120000)
11591         {
11592                 /*
11593                  * prosupport was added in 12
11594                  */
11595                 appendPQExpBuffer(query,
11596                                                   "SELECT proretset, prosrc, probin, "
11597                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11598                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11599                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11600                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11601                                                   "prokind, provolatile, proisstrict, prosecdef, "
11602                                                   "proleakproof, proconfig, procost, prorows, "
11603                                                   "prosupport, proparallel, "
11604                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11605                                                   "FROM pg_catalog.pg_proc "
11606                                                   "WHERE oid = '%u'::pg_catalog.oid",
11607                                                   finfo->dobj.catId.oid);
11608         }
11609         else if (fout->remoteVersion >= 110000)
11610         {
11611                 /*
11612                  * prokind was added in 11
11613                  */
11614                 appendPQExpBuffer(query,
11615                                                   "SELECT proretset, prosrc, probin, "
11616                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11617                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11618                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11619                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11620                                                   "prokind, provolatile, proisstrict, prosecdef, "
11621                                                   "proleakproof, proconfig, procost, prorows, "
11622                                                   "'-' AS prosupport, proparallel, "
11623                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11624                                                   "FROM pg_catalog.pg_proc "
11625                                                   "WHERE oid = '%u'::pg_catalog.oid",
11626                                                   finfo->dobj.catId.oid);
11627         }
11628         else if (fout->remoteVersion >= 90600)
11629         {
11630                 /*
11631                  * proparallel was added in 9.6
11632                  */
11633                 appendPQExpBuffer(query,
11634                                                   "SELECT proretset, prosrc, probin, "
11635                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11636                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11637                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11638                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11639                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11640                                                   "provolatile, proisstrict, prosecdef, "
11641                                                   "proleakproof, proconfig, procost, prorows, "
11642                                                   "'-' AS prosupport, proparallel, "
11643                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11644                                                   "FROM pg_catalog.pg_proc "
11645                                                   "WHERE oid = '%u'::pg_catalog.oid",
11646                                                   finfo->dobj.catId.oid);
11647         }
11648         else if (fout->remoteVersion >= 90500)
11649         {
11650                 /*
11651                  * protrftypes was added in 9.5
11652                  */
11653                 appendPQExpBuffer(query,
11654                                                   "SELECT proretset, prosrc, probin, "
11655                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11656                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11657                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11658                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11659                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11660                                                   "provolatile, proisstrict, prosecdef, "
11661                                                   "proleakproof, proconfig, procost, prorows, "
11662                                                   "'-' AS prosupport, "
11663                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11664                                                   "FROM pg_catalog.pg_proc "
11665                                                   "WHERE oid = '%u'::pg_catalog.oid",
11666                                                   finfo->dobj.catId.oid);
11667         }
11668         else if (fout->remoteVersion >= 90200)
11669         {
11670                 /*
11671                  * proleakproof was added in 9.2
11672                  */
11673                 appendPQExpBuffer(query,
11674                                                   "SELECT proretset, prosrc, probin, "
11675                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11676                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11677                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11678                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11679                                                   "provolatile, proisstrict, prosecdef, "
11680                                                   "proleakproof, proconfig, procost, prorows, "
11681                                                   "'-' AS prosupport, "
11682                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11683                                                   "FROM pg_catalog.pg_proc "
11684                                                   "WHERE oid = '%u'::pg_catalog.oid",
11685                                                   finfo->dobj.catId.oid);
11686         }
11687         else if (fout->remoteVersion >= 80400)
11688         {
11689                 /*
11690                  * In 8.4 and up we rely on pg_get_function_arguments and
11691                  * pg_get_function_result instead of examining proallargtypes etc.
11692                  */
11693                 appendPQExpBuffer(query,
11694                                                   "SELECT proretset, prosrc, probin, "
11695                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11696                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11697                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11698                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11699                                                   "provolatile, proisstrict, prosecdef, "
11700                                                   "false AS proleakproof, "
11701                                                   " proconfig, procost, prorows, "
11702                                                   "'-' AS prosupport, "
11703                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11704                                                   "FROM pg_catalog.pg_proc "
11705                                                   "WHERE oid = '%u'::pg_catalog.oid",
11706                                                   finfo->dobj.catId.oid);
11707         }
11708         else if (fout->remoteVersion >= 80300)
11709         {
11710                 appendPQExpBuffer(query,
11711                                                   "SELECT proretset, prosrc, probin, "
11712                                                   "proallargtypes, proargmodes, proargnames, "
11713                                                   "'f' AS prokind, "
11714                                                   "provolatile, proisstrict, prosecdef, "
11715                                                   "false AS proleakproof, "
11716                                                   "proconfig, procost, prorows, "
11717                                                   "'-' AS prosupport, "
11718                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11719                                                   "FROM pg_catalog.pg_proc "
11720                                                   "WHERE oid = '%u'::pg_catalog.oid",
11721                                                   finfo->dobj.catId.oid);
11722         }
11723         else if (fout->remoteVersion >= 80100)
11724         {
11725                 appendPQExpBuffer(query,
11726                                                   "SELECT proretset, prosrc, probin, "
11727                                                   "proallargtypes, proargmodes, proargnames, "
11728                                                   "'f' AS prokind, "
11729                                                   "provolatile, proisstrict, prosecdef, "
11730                                                   "false AS proleakproof, "
11731                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
11732                                                   "'-' AS prosupport, "
11733                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11734                                                   "FROM pg_catalog.pg_proc "
11735                                                   "WHERE oid = '%u'::pg_catalog.oid",
11736                                                   finfo->dobj.catId.oid);
11737         }
11738         else
11739         {
11740                 appendPQExpBuffer(query,
11741                                                   "SELECT proretset, prosrc, probin, "
11742                                                   "null AS proallargtypes, "
11743                                                   "null AS proargmodes, "
11744                                                   "proargnames, "
11745                                                   "'f' AS prokind, "
11746                                                   "provolatile, proisstrict, prosecdef, "
11747                                                   "false AS proleakproof, "
11748                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
11749                                                   "'-' AS prosupport, "
11750                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11751                                                   "FROM pg_catalog.pg_proc "
11752                                                   "WHERE oid = '%u'::pg_catalog.oid",
11753                                                   finfo->dobj.catId.oid);
11754         }
11755
11756         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11757
11758         proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
11759         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
11760         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
11761         if (fout->remoteVersion >= 80400)
11762         {
11763                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
11764                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
11765                 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
11766                 proallargtypes = proargmodes = proargnames = NULL;
11767         }
11768         else
11769         {
11770                 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
11771                 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
11772                 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
11773                 funcargs = funciargs = funcresult = NULL;
11774         }
11775         if (PQfnumber(res, "protrftypes") != -1)
11776                 protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
11777         else
11778                 protrftypes = NULL;
11779         prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
11780         provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
11781         proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
11782         prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
11783         proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
11784         proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
11785         procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
11786         prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
11787         prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
11788
11789         if (PQfnumber(res, "proparallel") != -1)
11790                 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
11791         else
11792                 proparallel = NULL;
11793
11794         lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
11795
11796         /*
11797          * See backend/commands/functioncmds.c for details of how the 'AS' clause
11798          * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
11799          * versions would set it to "-".  There are no known cases in which prosrc
11800          * is unused, so the tests below for "-" are probably useless.
11801          */
11802         if (probin[0] != '\0' && strcmp(probin, "-") != 0)
11803         {
11804                 appendPQExpBufferStr(asPart, "AS ");
11805                 appendStringLiteralAH(asPart, probin, fout);
11806                 if (strcmp(prosrc, "-") != 0)
11807                 {
11808                         appendPQExpBufferStr(asPart, ", ");
11809
11810                         /*
11811                          * where we have bin, use dollar quoting if allowed and src
11812                          * contains quote or backslash; else use regular quoting.
11813                          */
11814                         if (dopt->disable_dollar_quoting ||
11815                                 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
11816                                 appendStringLiteralAH(asPart, prosrc, fout);
11817                         else
11818                                 appendStringLiteralDQ(asPart, prosrc, NULL);
11819                 }
11820         }
11821         else
11822         {
11823                 if (strcmp(prosrc, "-") != 0)
11824                 {
11825                         appendPQExpBufferStr(asPart, "AS ");
11826                         /* with no bin, dollar quote src unconditionally if allowed */
11827                         if (dopt->disable_dollar_quoting)
11828                                 appendStringLiteralAH(asPart, prosrc, fout);
11829                         else
11830                                 appendStringLiteralDQ(asPart, prosrc, NULL);
11831                 }
11832         }
11833
11834         nallargs = finfo->nargs;        /* unless we learn different from allargs */
11835
11836         if (proallargtypes && *proallargtypes)
11837         {
11838                 int                     nitems = 0;
11839
11840                 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
11841                         nitems < finfo->nargs)
11842                 {
11843                         pg_log_warning("could not parse proallargtypes array");
11844                         if (allargtypes)
11845                                 free(allargtypes);
11846                         allargtypes = NULL;
11847                 }
11848                 else
11849                         nallargs = nitems;
11850         }
11851
11852         if (proargmodes && *proargmodes)
11853         {
11854                 int                     nitems = 0;
11855
11856                 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
11857                         nitems != nallargs)
11858                 {
11859                         pg_log_warning("could not parse proargmodes array");
11860                         if (argmodes)
11861                                 free(argmodes);
11862                         argmodes = NULL;
11863                 }
11864         }
11865
11866         if (proargnames && *proargnames)
11867         {
11868                 int                     nitems = 0;
11869
11870                 if (!parsePGArray(proargnames, &argnames, &nitems) ||
11871                         nitems != nallargs)
11872                 {
11873                         pg_log_warning("could not parse proargnames array");
11874                         if (argnames)
11875                                 free(argnames);
11876                         argnames = NULL;
11877                 }
11878         }
11879
11880         if (proconfig && *proconfig)
11881         {
11882                 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
11883                 {
11884                         pg_log_warning("could not parse proconfig array");
11885                         if (configitems)
11886                                 free(configitems);
11887                         configitems = NULL;
11888                         nconfigitems = 0;
11889                 }
11890         }
11891
11892         if (funcargs)
11893         {
11894                 /* 8.4 or later; we rely on server-side code for most of the work */
11895                 funcfullsig = format_function_arguments(finfo, funcargs, false);
11896                 funcsig = format_function_arguments(finfo, funciargs, false);
11897         }
11898         else
11899                 /* pre-8.4, do it ourselves */
11900                 funcsig = format_function_arguments_old(fout,
11901                                                                                                 finfo, nallargs, allargtypes,
11902                                                                                                 argmodes, argnames);
11903
11904         funcsig_tag = format_function_signature(fout, finfo, false);
11905
11906         if (prokind[0] == PROKIND_PROCEDURE)
11907                 keyword = "PROCEDURE";
11908         else
11909                 keyword = "FUNCTION";   /* works for window functions too */
11910
11911         appendPQExpBuffer(delqry, "DROP %s %s.%s;\n",
11912                                           keyword,
11913                                           fmtId(finfo->dobj.namespace->dobj.name),
11914                                           funcsig);
11915
11916         appendPQExpBuffer(q, "CREATE %s %s.%s",
11917                                           keyword,
11918                                           fmtId(finfo->dobj.namespace->dobj.name),
11919                                           funcfullsig ? funcfullsig :
11920                                           funcsig);
11921
11922         if (prokind[0] == PROKIND_PROCEDURE)
11923                  /* no result type to output */ ;
11924         else if (funcresult)
11925                 appendPQExpBuffer(q, " RETURNS %s", funcresult);
11926         else
11927         {
11928                 rettypename = getFormattedTypeName(fout, finfo->prorettype,
11929                                                                                    zeroAsOpaque);
11930                 appendPQExpBuffer(q, " RETURNS %s%s",
11931                                                   (proretset[0] == 't') ? "SETOF " : "",
11932                                                   rettypename);
11933                 free(rettypename);
11934         }
11935
11936         appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
11937
11938         if (protrftypes != NULL && strcmp(protrftypes, "") != 0)
11939         {
11940                 Oid                *typeids = palloc(FUNC_MAX_ARGS * sizeof(Oid));
11941                 int                     i;
11942
11943                 appendPQExpBufferStr(q, " TRANSFORM ");
11944                 parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
11945                 for (i = 0; typeids[i]; i++)
11946                 {
11947                         if (i != 0)
11948                                 appendPQExpBufferStr(q, ", ");
11949                         appendPQExpBuffer(q, "FOR TYPE %s",
11950                                                           getFormattedTypeName(fout, typeids[i], zeroAsNone));
11951                 }
11952         }
11953
11954         if (prokind[0] == PROKIND_WINDOW)
11955                 appendPQExpBufferStr(q, " WINDOW");
11956
11957         if (provolatile[0] != PROVOLATILE_VOLATILE)
11958         {
11959                 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
11960                         appendPQExpBufferStr(q, " IMMUTABLE");
11961                 else if (provolatile[0] == PROVOLATILE_STABLE)
11962                         appendPQExpBufferStr(q, " STABLE");
11963                 else if (provolatile[0] != PROVOLATILE_VOLATILE)
11964                         fatal("unrecognized provolatile value for function \"%s\"",
11965                                                   finfo->dobj.name);
11966         }
11967
11968         if (proisstrict[0] == 't')
11969                 appendPQExpBufferStr(q, " STRICT");
11970
11971         if (prosecdef[0] == 't')
11972                 appendPQExpBufferStr(q, " SECURITY DEFINER");
11973
11974         if (proleakproof[0] == 't')
11975                 appendPQExpBufferStr(q, " LEAKPROOF");
11976
11977         /*
11978          * COST and ROWS are emitted only if present and not default, so as not to
11979          * break backwards-compatibility of the dump without need.  Keep this code
11980          * in sync with the defaults in functioncmds.c.
11981          */
11982         if (strcmp(procost, "0") != 0)
11983         {
11984                 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
11985                 {
11986                         /* default cost is 1 */
11987                         if (strcmp(procost, "1") != 0)
11988                                 appendPQExpBuffer(q, " COST %s", procost);
11989                 }
11990                 else
11991                 {
11992                         /* default cost is 100 */
11993                         if (strcmp(procost, "100") != 0)
11994                                 appendPQExpBuffer(q, " COST %s", procost);
11995                 }
11996         }
11997         if (proretset[0] == 't' &&
11998                 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
11999                 appendPQExpBuffer(q, " ROWS %s", prorows);
12000
12001         if (strcmp(prosupport, "-") != 0)
12002         {
12003                 /* We rely on regprocout to provide quoting and qualification */
12004                 appendPQExpBuffer(q, " SUPPORT %s", prosupport);
12005         }
12006
12007         if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
12008         {
12009                 if (proparallel[0] == PROPARALLEL_SAFE)
12010                         appendPQExpBufferStr(q, " PARALLEL SAFE");
12011                 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
12012                         appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
12013                 else if (proparallel[0] != PROPARALLEL_UNSAFE)
12014                         fatal("unrecognized proparallel value for function \"%s\"",
12015                                                   finfo->dobj.name);
12016         }
12017
12018         for (i = 0; i < nconfigitems; i++)
12019         {
12020                 /* we feel free to scribble on configitems[] here */
12021                 char       *configitem = configitems[i];
12022                 char       *pos;
12023
12024                 pos = strchr(configitem, '=');
12025                 if (pos == NULL)
12026                         continue;
12027                 *pos++ = '\0';
12028                 appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
12029
12030                 /*
12031                  * Variables that are marked GUC_LIST_QUOTE were already fully quoted
12032                  * by flatten_set_variable_args() before they were put into the
12033                  * proconfig array.  However, because the quoting rules used there
12034                  * aren't exactly like SQL's, we have to break the list value apart
12035                  * and then quote the elements as string literals.  (The elements may
12036                  * be double-quoted as-is, but we can't just feed them to the SQL
12037                  * parser; it would do the wrong thing with elements that are
12038                  * zero-length or longer than NAMEDATALEN.)
12039                  *
12040                  * Variables that are not so marked should just be emitted as simple
12041                  * string literals.  If the variable is not known to
12042                  * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
12043                  * to use GUC_LIST_QUOTE for extension variables.
12044                  */
12045                 if (variable_is_guc_list_quote(configitem))
12046                 {
12047                         char      **namelist;
12048                         char      **nameptr;
12049
12050                         /* Parse string into list of identifiers */
12051                         /* this shouldn't fail really */
12052                         if (SplitGUCList(pos, ',', &namelist))
12053                         {
12054                                 for (nameptr = namelist; *nameptr; nameptr++)
12055                                 {
12056                                         if (nameptr != namelist)
12057                                                 appendPQExpBufferStr(q, ", ");
12058                                         appendStringLiteralAH(q, *nameptr, fout);
12059                                 }
12060                         }
12061                         pg_free(namelist);
12062                 }
12063                 else
12064                         appendStringLiteralAH(q, pos, fout);
12065         }
12066
12067         appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
12068
12069         if (dopt->binary_upgrade)
12070                 binary_upgrade_extension_member(q, &finfo->dobj,
12071                                                                                 keyword, funcsig,
12072                                                                                 finfo->dobj.namespace->dobj.name);
12073
12074         if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12075                 ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
12076                                          ARCHIVE_OPTS(.tag = funcsig_tag,
12077                                                                   .namespace = finfo->dobj.namespace->dobj.name,
12078                                                                   .owner = finfo->rolname,
12079                                                                   .description = keyword,
12080                                                                   .section = SECTION_PRE_DATA,
12081                                                                   .createStmt = q->data,
12082                                                                   .dropStmt = delqry->data));
12083
12084         /* Dump Function Comments and Security Labels */
12085         if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12086                 dumpComment(fout, keyword, funcsig,
12087                                         finfo->dobj.namespace->dobj.name, finfo->rolname,
12088                                         finfo->dobj.catId, 0, finfo->dobj.dumpId);
12089
12090         if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
12091                 dumpSecLabel(fout, keyword, funcsig,
12092                                          finfo->dobj.namespace->dobj.name, finfo->rolname,
12093                                          finfo->dobj.catId, 0, finfo->dobj.dumpId);
12094
12095         if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
12096                 dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, keyword,
12097                                 funcsig, NULL,
12098                                 finfo->dobj.namespace->dobj.name,
12099                                 finfo->rolname, finfo->proacl, finfo->rproacl,
12100                                 finfo->initproacl, finfo->initrproacl);
12101
12102         PQclear(res);
12103
12104         destroyPQExpBuffer(query);
12105         destroyPQExpBuffer(q);
12106         destroyPQExpBuffer(delqry);
12107         destroyPQExpBuffer(asPart);
12108         free(funcsig);
12109         if (funcfullsig)
12110                 free(funcfullsig);
12111         free(funcsig_tag);
12112         if (allargtypes)
12113                 free(allargtypes);
12114         if (argmodes)
12115                 free(argmodes);
12116         if (argnames)
12117                 free(argnames);
12118         if (configitems)
12119                 free(configitems);
12120 }
12121
12122
12123 /*
12124  * Dump a user-defined cast
12125  */
12126 static void
12127 dumpCast(Archive *fout, CastInfo *cast)
12128 {
12129         DumpOptions *dopt = fout->dopt;
12130         PQExpBuffer defqry;
12131         PQExpBuffer delqry;
12132         PQExpBuffer labelq;
12133         PQExpBuffer castargs;
12134         FuncInfo   *funcInfo = NULL;
12135         char       *sourceType;
12136         char       *targetType;
12137
12138         /* Skip if not to be dumped */
12139         if (!cast->dobj.dump || dopt->dataOnly)
12140                 return;
12141
12142         /* Cannot dump if we don't have the cast function's info */
12143         if (OidIsValid(cast->castfunc))
12144         {
12145                 funcInfo = findFuncByOid(cast->castfunc);
12146                 if (funcInfo == NULL)
12147                         fatal("could not find function definition for function with OID %u",
12148                                                   cast->castfunc);
12149         }
12150
12151         defqry = createPQExpBuffer();
12152         delqry = createPQExpBuffer();
12153         labelq = createPQExpBuffer();
12154         castargs = createPQExpBuffer();
12155
12156         sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
12157         targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
12158         appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
12159                                           sourceType, targetType);
12160
12161         appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
12162                                           sourceType, targetType);
12163
12164         switch (cast->castmethod)
12165         {
12166                 case COERCION_METHOD_BINARY:
12167                         appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
12168                         break;
12169                 case COERCION_METHOD_INOUT:
12170                         appendPQExpBufferStr(defqry, "WITH INOUT");
12171                         break;
12172                 case COERCION_METHOD_FUNCTION:
12173                         if (funcInfo)
12174                         {
12175                                 char       *fsig = format_function_signature(fout, funcInfo, true);
12176
12177                                 /*
12178                                  * Always qualify the function name (format_function_signature
12179                                  * won't qualify it).
12180                                  */
12181                                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
12182                                                                   fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
12183                                 free(fsig);
12184                         }
12185                         else
12186                                 pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
12187                         break;
12188                 default:
12189                         pg_log_warning("bogus value in pg_cast.castmethod field");
12190         }
12191
12192         if (cast->castcontext == 'a')
12193                 appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
12194         else if (cast->castcontext == 'i')
12195                 appendPQExpBufferStr(defqry, " AS IMPLICIT");
12196         appendPQExpBufferStr(defqry, ";\n");
12197
12198         appendPQExpBuffer(labelq, "CAST (%s AS %s)",
12199                                           sourceType, targetType);
12200
12201         appendPQExpBuffer(castargs, "(%s AS %s)",
12202                                           sourceType, targetType);
12203
12204         if (dopt->binary_upgrade)
12205                 binary_upgrade_extension_member(defqry, &cast->dobj,
12206                                                                                 "CAST", castargs->data, NULL);
12207
12208         if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
12209                 ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
12210                                          ARCHIVE_OPTS(.tag = labelq->data,
12211                                                                   .description = "CAST",
12212                                                                   .section = SECTION_PRE_DATA,
12213                                                                   .createStmt = defqry->data,
12214                                                                   .dropStmt = delqry->data));
12215
12216         /* Dump Cast Comments */
12217         if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
12218                 dumpComment(fout, "CAST", castargs->data,
12219                                         NULL, "",
12220                                         cast->dobj.catId, 0, cast->dobj.dumpId);
12221
12222         free(sourceType);
12223         free(targetType);
12224
12225         destroyPQExpBuffer(defqry);
12226         destroyPQExpBuffer(delqry);
12227         destroyPQExpBuffer(labelq);
12228         destroyPQExpBuffer(castargs);
12229 }
12230
12231 /*
12232  * Dump a transform
12233  */
12234 static void
12235 dumpTransform(Archive *fout, TransformInfo *transform)
12236 {
12237         DumpOptions *dopt = fout->dopt;
12238         PQExpBuffer defqry;
12239         PQExpBuffer delqry;
12240         PQExpBuffer labelq;
12241         PQExpBuffer transformargs;
12242         FuncInfo   *fromsqlFuncInfo = NULL;
12243         FuncInfo   *tosqlFuncInfo = NULL;
12244         char       *lanname;
12245         char       *transformType;
12246
12247         /* Skip if not to be dumped */
12248         if (!transform->dobj.dump || dopt->dataOnly)
12249                 return;
12250
12251         /* Cannot dump if we don't have the transform functions' info */
12252         if (OidIsValid(transform->trffromsql))
12253         {
12254                 fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
12255                 if (fromsqlFuncInfo == NULL)
12256                         fatal("could not find function definition for function with OID %u",
12257                                                   transform->trffromsql);
12258         }
12259         if (OidIsValid(transform->trftosql))
12260         {
12261                 tosqlFuncInfo = findFuncByOid(transform->trftosql);
12262                 if (tosqlFuncInfo == NULL)
12263                         fatal("could not find function definition for function with OID %u",
12264                                                   transform->trftosql);
12265         }
12266
12267         defqry = createPQExpBuffer();
12268         delqry = createPQExpBuffer();
12269         labelq = createPQExpBuffer();
12270         transformargs = createPQExpBuffer();
12271
12272         lanname = get_language_name(fout, transform->trflang);
12273         transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
12274
12275         appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
12276                                           transformType, lanname);
12277
12278         appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
12279                                           transformType, lanname);
12280
12281         if (!transform->trffromsql && !transform->trftosql)
12282                 pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
12283
12284         if (transform->trffromsql)
12285         {
12286                 if (fromsqlFuncInfo)
12287                 {
12288                         char       *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
12289
12290                         /*
12291                          * Always qualify the function name (format_function_signature
12292                          * won't qualify it).
12293                          */
12294                         appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
12295                                                           fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
12296                         free(fsig);
12297                 }
12298                 else
12299                         pg_log_warning("bogus value in pg_transform.trffromsql field");
12300         }
12301
12302         if (transform->trftosql)
12303         {
12304                 if (transform->trffromsql)
12305                         appendPQExpBuffer(defqry, ", ");
12306
12307                 if (tosqlFuncInfo)
12308                 {
12309                         char       *fsig = format_function_signature(fout, tosqlFuncInfo, true);
12310
12311                         /*
12312                          * Always qualify the function name (format_function_signature
12313                          * won't qualify it).
12314                          */
12315                         appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
12316                                                           fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
12317                         free(fsig);
12318                 }
12319                 else
12320                         pg_log_warning("bogus value in pg_transform.trftosql field");
12321         }
12322
12323         appendPQExpBuffer(defqry, ");\n");
12324
12325         appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
12326                                           transformType, lanname);
12327
12328         appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
12329                                           transformType, lanname);
12330
12331         if (dopt->binary_upgrade)
12332                 binary_upgrade_extension_member(defqry, &transform->dobj,
12333                                                                                 "TRANSFORM", transformargs->data, NULL);
12334
12335         if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
12336                 ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
12337                                          ARCHIVE_OPTS(.tag = labelq->data,
12338                                                                   .description = "TRANSFORM",
12339                                                                   .section = SECTION_PRE_DATA,
12340                                                                   .createStmt = defqry->data,
12341                                                                   .dropStmt = delqry->data,
12342                                                                   .deps = transform->dobj.dependencies,
12343                                                                   .nDeps = transform->dobj.nDeps));
12344
12345         /* Dump Transform Comments */
12346         if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
12347                 dumpComment(fout, "TRANSFORM", transformargs->data,
12348                                         NULL, "",
12349                                         transform->dobj.catId, 0, transform->dobj.dumpId);
12350
12351         free(lanname);
12352         free(transformType);
12353         destroyPQExpBuffer(defqry);
12354         destroyPQExpBuffer(delqry);
12355         destroyPQExpBuffer(labelq);
12356         destroyPQExpBuffer(transformargs);
12357 }
12358
12359
12360 /*
12361  * dumpOpr
12362  *        write out a single operator definition
12363  */
12364 static void
12365 dumpOpr(Archive *fout, OprInfo *oprinfo)
12366 {
12367         DumpOptions *dopt = fout->dopt;
12368         PQExpBuffer query;
12369         PQExpBuffer q;
12370         PQExpBuffer delq;
12371         PQExpBuffer oprid;
12372         PQExpBuffer details;
12373         PGresult   *res;
12374         int                     i_oprkind;
12375         int                     i_oprcode;
12376         int                     i_oprleft;
12377         int                     i_oprright;
12378         int                     i_oprcom;
12379         int                     i_oprnegate;
12380         int                     i_oprrest;
12381         int                     i_oprjoin;
12382         int                     i_oprcanmerge;
12383         int                     i_oprcanhash;
12384         char       *oprkind;
12385         char       *oprcode;
12386         char       *oprleft;
12387         char       *oprright;
12388         char       *oprcom;
12389         char       *oprnegate;
12390         char       *oprrest;
12391         char       *oprjoin;
12392         char       *oprcanmerge;
12393         char       *oprcanhash;
12394         char       *oprregproc;
12395         char       *oprref;
12396
12397         /* Skip if not to be dumped */
12398         if (!oprinfo->dobj.dump || dopt->dataOnly)
12399                 return;
12400
12401         /*
12402          * some operators are invalid because they were the result of user
12403          * defining operators before commutators exist
12404          */
12405         if (!OidIsValid(oprinfo->oprcode))
12406                 return;
12407
12408         query = createPQExpBuffer();
12409         q = createPQExpBuffer();
12410         delq = createPQExpBuffer();
12411         oprid = createPQExpBuffer();
12412         details = createPQExpBuffer();
12413
12414         if (fout->remoteVersion >= 80300)
12415         {
12416                 appendPQExpBuffer(query, "SELECT oprkind, "
12417                                                   "oprcode::pg_catalog.regprocedure, "
12418                                                   "oprleft::pg_catalog.regtype, "
12419                                                   "oprright::pg_catalog.regtype, "
12420                                                   "oprcom, "
12421                                                   "oprnegate, "
12422                                                   "oprrest::pg_catalog.regprocedure, "
12423                                                   "oprjoin::pg_catalog.regprocedure, "
12424                                                   "oprcanmerge, oprcanhash "
12425                                                   "FROM pg_catalog.pg_operator "
12426                                                   "WHERE oid = '%u'::pg_catalog.oid",
12427                                                   oprinfo->dobj.catId.oid);
12428         }
12429         else
12430         {
12431                 appendPQExpBuffer(query, "SELECT oprkind, "
12432                                                   "oprcode::pg_catalog.regprocedure, "
12433                                                   "oprleft::pg_catalog.regtype, "
12434                                                   "oprright::pg_catalog.regtype, "
12435                                                   "oprcom, "
12436                                                   "oprnegate, "
12437                                                   "oprrest::pg_catalog.regprocedure, "
12438                                                   "oprjoin::pg_catalog.regprocedure, "
12439                                                   "(oprlsortop != 0) AS oprcanmerge, "
12440                                                   "oprcanhash "
12441                                                   "FROM pg_catalog.pg_operator "
12442                                                   "WHERE oid = '%u'::pg_catalog.oid",
12443                                                   oprinfo->dobj.catId.oid);
12444         }
12445
12446         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12447
12448         i_oprkind = PQfnumber(res, "oprkind");
12449         i_oprcode = PQfnumber(res, "oprcode");
12450         i_oprleft = PQfnumber(res, "oprleft");
12451         i_oprright = PQfnumber(res, "oprright");
12452         i_oprcom = PQfnumber(res, "oprcom");
12453         i_oprnegate = PQfnumber(res, "oprnegate");
12454         i_oprrest = PQfnumber(res, "oprrest");
12455         i_oprjoin = PQfnumber(res, "oprjoin");
12456         i_oprcanmerge = PQfnumber(res, "oprcanmerge");
12457         i_oprcanhash = PQfnumber(res, "oprcanhash");
12458
12459         oprkind = PQgetvalue(res, 0, i_oprkind);
12460         oprcode = PQgetvalue(res, 0, i_oprcode);
12461         oprleft = PQgetvalue(res, 0, i_oprleft);
12462         oprright = PQgetvalue(res, 0, i_oprright);
12463         oprcom = PQgetvalue(res, 0, i_oprcom);
12464         oprnegate = PQgetvalue(res, 0, i_oprnegate);
12465         oprrest = PQgetvalue(res, 0, i_oprrest);
12466         oprjoin = PQgetvalue(res, 0, i_oprjoin);
12467         oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
12468         oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
12469
12470         oprregproc = convertRegProcReference(fout, oprcode);
12471         if (oprregproc)
12472         {
12473                 appendPQExpBuffer(details, "    FUNCTION = %s", oprregproc);
12474                 free(oprregproc);
12475         }
12476
12477         appendPQExpBuffer(oprid, "%s (",
12478                                           oprinfo->dobj.name);
12479
12480         /*
12481          * right unary means there's a left arg and left unary means there's a
12482          * right arg
12483          */
12484         if (strcmp(oprkind, "r") == 0 ||
12485                 strcmp(oprkind, "b") == 0)
12486         {
12487                 appendPQExpBuffer(details, ",\n    LEFTARG = %s", oprleft);
12488                 appendPQExpBufferStr(oprid, oprleft);
12489         }
12490         else
12491                 appendPQExpBufferStr(oprid, "NONE");
12492
12493         if (strcmp(oprkind, "l") == 0 ||
12494                 strcmp(oprkind, "b") == 0)
12495         {
12496                 appendPQExpBuffer(details, ",\n    RIGHTARG = %s", oprright);
12497                 appendPQExpBuffer(oprid, ", %s)", oprright);
12498         }
12499         else
12500                 appendPQExpBufferStr(oprid, ", NONE)");
12501
12502         oprref = getFormattedOperatorName(fout, oprcom);
12503         if (oprref)
12504         {
12505                 appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", oprref);
12506                 free(oprref);
12507         }
12508
12509         oprref = getFormattedOperatorName(fout, oprnegate);
12510         if (oprref)
12511         {
12512                 appendPQExpBuffer(details, ",\n    NEGATOR = %s", oprref);
12513                 free(oprref);
12514         }
12515
12516         if (strcmp(oprcanmerge, "t") == 0)
12517                 appendPQExpBufferStr(details, ",\n    MERGES");
12518
12519         if (strcmp(oprcanhash, "t") == 0)
12520                 appendPQExpBufferStr(details, ",\n    HASHES");
12521
12522         oprregproc = convertRegProcReference(fout, oprrest);
12523         if (oprregproc)
12524         {
12525                 appendPQExpBuffer(details, ",\n    RESTRICT = %s", oprregproc);
12526                 free(oprregproc);
12527         }
12528
12529         oprregproc = convertRegProcReference(fout, oprjoin);
12530         if (oprregproc)
12531         {
12532                 appendPQExpBuffer(details, ",\n    JOIN = %s", oprregproc);
12533                 free(oprregproc);
12534         }
12535
12536         appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
12537                                           fmtId(oprinfo->dobj.namespace->dobj.name),
12538                                           oprid->data);
12539
12540         appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
12541                                           fmtId(oprinfo->dobj.namespace->dobj.name),
12542                                           oprinfo->dobj.name, details->data);
12543
12544         if (dopt->binary_upgrade)
12545                 binary_upgrade_extension_member(q, &oprinfo->dobj,
12546                                                                                 "OPERATOR", oprid->data,
12547                                                                                 oprinfo->dobj.namespace->dobj.name);
12548
12549         if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12550                 ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
12551                                          ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
12552                                                                   .namespace = oprinfo->dobj.namespace->dobj.name,
12553                                                                   .owner = oprinfo->rolname,
12554                                                                   .description = "OPERATOR",
12555                                                                   .section = SECTION_PRE_DATA,
12556                                                                   .createStmt = q->data,
12557                                                                   .dropStmt = delq->data));
12558
12559         /* Dump Operator Comments */
12560         if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12561                 dumpComment(fout, "OPERATOR", oprid->data,
12562                                         oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
12563                                         oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
12564
12565         PQclear(res);
12566
12567         destroyPQExpBuffer(query);
12568         destroyPQExpBuffer(q);
12569         destroyPQExpBuffer(delq);
12570         destroyPQExpBuffer(oprid);
12571         destroyPQExpBuffer(details);
12572 }
12573
12574 /*
12575  * Convert a function reference obtained from pg_operator
12576  *
12577  * Returns allocated string of what to print, or NULL if function references
12578  * is InvalidOid. Returned string is expected to be free'd by the caller.
12579  *
12580  * The input is a REGPROCEDURE display; we have to strip the argument-types
12581  * part.
12582  */
12583 static char *
12584 convertRegProcReference(Archive *fout, const char *proc)
12585 {
12586         char       *name;
12587         char       *paren;
12588         bool            inquote;
12589
12590         /* In all cases "-" means a null reference */
12591         if (strcmp(proc, "-") == 0)
12592                 return NULL;
12593
12594         name = pg_strdup(proc);
12595         /* find non-double-quoted left paren */
12596         inquote = false;
12597         for (paren = name; *paren; paren++)
12598         {
12599                 if (*paren == '(' && !inquote)
12600                 {
12601                         *paren = '\0';
12602                         break;
12603                 }
12604                 if (*paren == '"')
12605                         inquote = !inquote;
12606         }
12607         return name;
12608 }
12609
12610 /*
12611  * getFormattedOperatorName - retrieve the operator name for the
12612  * given operator OID (presented in string form).
12613  *
12614  * Returns an allocated string, or NULL if the given OID is invalid.
12615  * Caller is responsible for free'ing result string.
12616  *
12617  * What we produce has the format "OPERATOR(schema.oprname)".  This is only
12618  * useful in commands where the operator's argument types can be inferred from
12619  * context.  We always schema-qualify the name, though.  The predecessor to
12620  * this code tried to skip the schema qualification if possible, but that led
12621  * to wrong results in corner cases, such as if an operator and its negator
12622  * are in different schemas.
12623  */
12624 static char *
12625 getFormattedOperatorName(Archive *fout, const char *oproid)
12626 {
12627         OprInfo    *oprInfo;
12628
12629         /* In all cases "0" means a null reference */
12630         if (strcmp(oproid, "0") == 0)
12631                 return NULL;
12632
12633         oprInfo = findOprByOid(atooid(oproid));
12634         if (oprInfo == NULL)
12635         {
12636                 pg_log_warning("could not find operator with OID %s",
12637                                   oproid);
12638                 return NULL;
12639         }
12640
12641         return psprintf("OPERATOR(%s.%s)",
12642                                         fmtId(oprInfo->dobj.namespace->dobj.name),
12643                                         oprInfo->dobj.name);
12644 }
12645
12646 /*
12647  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
12648  *
12649  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
12650  * argument lists of these functions are predetermined.  Note that the
12651  * caller should ensure we are in the proper schema, because the results
12652  * are search path dependent!
12653  */
12654 static char *
12655 convertTSFunction(Archive *fout, Oid funcOid)
12656 {
12657         char       *result;
12658         char            query[128];
12659         PGresult   *res;
12660
12661         snprintf(query, sizeof(query),
12662                          "SELECT '%u'::pg_catalog.regproc", funcOid);
12663         res = ExecuteSqlQueryForSingleRow(fout, query);
12664
12665         result = pg_strdup(PQgetvalue(res, 0, 0));
12666
12667         PQclear(res);
12668
12669         return result;
12670 }
12671
12672 /*
12673  * dumpAccessMethod
12674  *        write out a single access method definition
12675  */
12676 static void
12677 dumpAccessMethod(Archive *fout, AccessMethodInfo *aminfo)
12678 {
12679         DumpOptions *dopt = fout->dopt;
12680         PQExpBuffer q;
12681         PQExpBuffer delq;
12682         char       *qamname;
12683
12684         /* Skip if not to be dumped */
12685         if (!aminfo->dobj.dump || dopt->dataOnly)
12686                 return;
12687
12688         q = createPQExpBuffer();
12689         delq = createPQExpBuffer();
12690
12691         qamname = pg_strdup(fmtId(aminfo->dobj.name));
12692
12693         appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
12694
12695         switch (aminfo->amtype)
12696         {
12697                 case AMTYPE_INDEX:
12698                         appendPQExpBuffer(q, "TYPE INDEX ");
12699                         break;
12700                 case AMTYPE_TABLE:
12701                         appendPQExpBuffer(q, "TYPE TABLE ");
12702                         break;
12703                 default:
12704                         pg_log_warning("invalid type \"%c\" of access method \"%s\"",
12705                                           aminfo->amtype, qamname);
12706                         destroyPQExpBuffer(q);
12707                         destroyPQExpBuffer(delq);
12708                         free(qamname);
12709                         return;
12710         }
12711
12712         appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
12713
12714         appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
12715                                           qamname);
12716
12717         if (dopt->binary_upgrade)
12718                 binary_upgrade_extension_member(q, &aminfo->dobj,
12719                                                                                 "ACCESS METHOD", qamname, NULL);
12720
12721         if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12722                 ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
12723                                          ARCHIVE_OPTS(.tag = aminfo->dobj.name,
12724                                                                   .description = "ACCESS METHOD",
12725                                                                   .section = SECTION_PRE_DATA,
12726                                                                   .createStmt = q->data,
12727                                                                   .dropStmt = delq->data));
12728
12729         /* Dump Access Method Comments */
12730         if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12731                 dumpComment(fout, "ACCESS METHOD", qamname,
12732                                         NULL, "",
12733                                         aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
12734
12735         destroyPQExpBuffer(q);
12736         destroyPQExpBuffer(delq);
12737         free(qamname);
12738 }
12739
12740 /*
12741  * dumpOpclass
12742  *        write out a single operator class definition
12743  */
12744 static void
12745 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
12746 {
12747         DumpOptions *dopt = fout->dopt;
12748         PQExpBuffer query;
12749         PQExpBuffer q;
12750         PQExpBuffer delq;
12751         PQExpBuffer nameusing;
12752         PGresult   *res;
12753         int                     ntups;
12754         int                     i_opcintype;
12755         int                     i_opckeytype;
12756         int                     i_opcdefault;
12757         int                     i_opcfamily;
12758         int                     i_opcfamilyname;
12759         int                     i_opcfamilynsp;
12760         int                     i_amname;
12761         int                     i_amopstrategy;
12762         int                     i_amopreqcheck;
12763         int                     i_amopopr;
12764         int                     i_sortfamily;
12765         int                     i_sortfamilynsp;
12766         int                     i_amprocnum;
12767         int                     i_amproc;
12768         int                     i_amproclefttype;
12769         int                     i_amprocrighttype;
12770         char       *opcintype;
12771         char       *opckeytype;
12772         char       *opcdefault;
12773         char       *opcfamily;
12774         char       *opcfamilyname;
12775         char       *opcfamilynsp;
12776         char       *amname;
12777         char       *amopstrategy;
12778         char       *amopreqcheck;
12779         char       *amopopr;
12780         char       *sortfamily;
12781         char       *sortfamilynsp;
12782         char       *amprocnum;
12783         char       *amproc;
12784         char       *amproclefttype;
12785         char       *amprocrighttype;
12786         bool            needComma;
12787         int                     i;
12788
12789         /* Skip if not to be dumped */
12790         if (!opcinfo->dobj.dump || dopt->dataOnly)
12791                 return;
12792
12793         query = createPQExpBuffer();
12794         q = createPQExpBuffer();
12795         delq = createPQExpBuffer();
12796         nameusing = createPQExpBuffer();
12797
12798         /* Get additional fields from the pg_opclass row */
12799         if (fout->remoteVersion >= 80300)
12800         {
12801                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
12802                                                   "opckeytype::pg_catalog.regtype, "
12803                                                   "opcdefault, opcfamily, "
12804                                                   "opfname AS opcfamilyname, "
12805                                                   "nspname AS opcfamilynsp, "
12806                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
12807                                                   "FROM pg_catalog.pg_opclass c "
12808                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
12809                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12810                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
12811                                                   opcinfo->dobj.catId.oid);
12812         }
12813         else
12814         {
12815                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
12816                                                   "opckeytype::pg_catalog.regtype, "
12817                                                   "opcdefault, NULL AS opcfamily, "
12818                                                   "NULL AS opcfamilyname, "
12819                                                   "NULL AS opcfamilynsp, "
12820                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
12821                                                   "FROM pg_catalog.pg_opclass "
12822                                                   "WHERE oid = '%u'::pg_catalog.oid",
12823                                                   opcinfo->dobj.catId.oid);
12824         }
12825
12826         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12827
12828         i_opcintype = PQfnumber(res, "opcintype");
12829         i_opckeytype = PQfnumber(res, "opckeytype");
12830         i_opcdefault = PQfnumber(res, "opcdefault");
12831         i_opcfamily = PQfnumber(res, "opcfamily");
12832         i_opcfamilyname = PQfnumber(res, "opcfamilyname");
12833         i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
12834         i_amname = PQfnumber(res, "amname");
12835
12836         /* opcintype may still be needed after we PQclear res */
12837         opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
12838         opckeytype = PQgetvalue(res, 0, i_opckeytype);
12839         opcdefault = PQgetvalue(res, 0, i_opcdefault);
12840         /* opcfamily will still be needed after we PQclear res */
12841         opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
12842         opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
12843         opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
12844         /* amname will still be needed after we PQclear res */
12845         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
12846
12847         appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
12848                                           fmtQualifiedDumpable(opcinfo));
12849         appendPQExpBuffer(delq, " USING %s;\n",
12850                                           fmtId(amname));
12851
12852         /* Build the fixed portion of the CREATE command */
12853         appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
12854                                           fmtQualifiedDumpable(opcinfo));
12855         if (strcmp(opcdefault, "t") == 0)
12856                 appendPQExpBufferStr(q, "DEFAULT ");
12857         appendPQExpBuffer(q, "FOR TYPE %s USING %s",
12858                                           opcintype,
12859                                           fmtId(amname));
12860         if (strlen(opcfamilyname) > 0)
12861         {
12862                 appendPQExpBufferStr(q, " FAMILY ");
12863                 appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
12864                 appendPQExpBufferStr(q, fmtId(opcfamilyname));
12865         }
12866         appendPQExpBufferStr(q, " AS\n    ");
12867
12868         needComma = false;
12869
12870         if (strcmp(opckeytype, "-") != 0)
12871         {
12872                 appendPQExpBuffer(q, "STORAGE %s",
12873                                                   opckeytype);
12874                 needComma = true;
12875         }
12876
12877         PQclear(res);
12878
12879         /*
12880          * Now fetch and print the OPERATOR entries (pg_amop rows).
12881          *
12882          * Print only those opfamily members that are tied to the opclass by
12883          * pg_depend entries.
12884          *
12885          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
12886          * older server's opclass in which it is used.  This is to avoid
12887          * hard-to-detect breakage if a newer pg_dump is used to dump from an
12888          * older server and then reload into that old version.  This can go away
12889          * once 8.3 is so old as to not be of interest to anyone.
12890          */
12891         resetPQExpBuffer(query);
12892
12893         if (fout->remoteVersion >= 90100)
12894         {
12895                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12896                                                   "amopopr::pg_catalog.regoperator, "
12897                                                   "opfname AS sortfamily, "
12898                                                   "nspname AS sortfamilynsp "
12899                                                   "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
12900                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
12901                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
12902                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12903                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12904                                                   "AND refobjid = '%u'::pg_catalog.oid "
12905                                                   "AND amopfamily = '%s'::pg_catalog.oid "
12906                                                   "ORDER BY amopstrategy",
12907                                                   opcinfo->dobj.catId.oid,
12908                                                   opcfamily);
12909         }
12910         else if (fout->remoteVersion >= 80400)
12911         {
12912                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12913                                                   "amopopr::pg_catalog.regoperator, "
12914                                                   "NULL AS sortfamily, "
12915                                                   "NULL AS sortfamilynsp "
12916                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12917                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12918                                                   "AND refobjid = '%u'::pg_catalog.oid "
12919                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12920                                                   "AND objid = ao.oid "
12921                                                   "ORDER BY amopstrategy",
12922                                                   opcinfo->dobj.catId.oid);
12923         }
12924         else if (fout->remoteVersion >= 80300)
12925         {
12926                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
12927                                                   "amopopr::pg_catalog.regoperator, "
12928                                                   "NULL AS sortfamily, "
12929                                                   "NULL AS sortfamilynsp "
12930                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12931                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12932                                                   "AND refobjid = '%u'::pg_catalog.oid "
12933                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12934                                                   "AND objid = ao.oid "
12935                                                   "ORDER BY amopstrategy",
12936                                                   opcinfo->dobj.catId.oid);
12937         }
12938         else
12939         {
12940                 /*
12941                  * Here, we print all entries since there are no opfamilies and hence
12942                  * no loose operators to worry about.
12943                  */
12944                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
12945                                                   "amopopr::pg_catalog.regoperator, "
12946                                                   "NULL AS sortfamily, "
12947                                                   "NULL AS sortfamilynsp "
12948                                                   "FROM pg_catalog.pg_amop "
12949                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
12950                                                   "ORDER BY amopstrategy",
12951                                                   opcinfo->dobj.catId.oid);
12952         }
12953
12954         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12955
12956         ntups = PQntuples(res);
12957
12958         i_amopstrategy = PQfnumber(res, "amopstrategy");
12959         i_amopreqcheck = PQfnumber(res, "amopreqcheck");
12960         i_amopopr = PQfnumber(res, "amopopr");
12961         i_sortfamily = PQfnumber(res, "sortfamily");
12962         i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
12963
12964         for (i = 0; i < ntups; i++)
12965         {
12966                 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
12967                 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
12968                 amopopr = PQgetvalue(res, i, i_amopopr);
12969                 sortfamily = PQgetvalue(res, i, i_sortfamily);
12970                 sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
12971
12972                 if (needComma)
12973                         appendPQExpBufferStr(q, " ,\n    ");
12974
12975                 appendPQExpBuffer(q, "OPERATOR %s %s",
12976                                                   amopstrategy, amopopr);
12977
12978                 if (strlen(sortfamily) > 0)
12979                 {
12980                         appendPQExpBufferStr(q, " FOR ORDER BY ");
12981                         appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
12982                         appendPQExpBufferStr(q, fmtId(sortfamily));
12983                 }
12984
12985                 if (strcmp(amopreqcheck, "t") == 0)
12986                         appendPQExpBufferStr(q, " RECHECK");
12987
12988                 needComma = true;
12989         }
12990
12991         PQclear(res);
12992
12993         /*
12994          * Now fetch and print the FUNCTION entries (pg_amproc rows).
12995          *
12996          * Print only those opfamily members that are tied to the opclass by
12997          * pg_depend entries.
12998          *
12999          * We print the amproclefttype/amprocrighttype even though in most cases
13000          * the backend could deduce the right values, because of the corner case
13001          * of a btree sort support function for a cross-type comparison.  That's
13002          * only allowed in 9.2 and later, but for simplicity print them in all
13003          * versions that have the columns.
13004          */
13005         resetPQExpBuffer(query);
13006
13007         if (fout->remoteVersion >= 80300)
13008         {
13009                 appendPQExpBuffer(query, "SELECT amprocnum, "
13010                                                   "amproc::pg_catalog.regprocedure, "
13011                                                   "amproclefttype::pg_catalog.regtype, "
13012                                                   "amprocrighttype::pg_catalog.regtype "
13013                                                   "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
13014                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
13015                                                   "AND refobjid = '%u'::pg_catalog.oid "
13016                                                   "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
13017                                                   "AND objid = ap.oid "
13018                                                   "ORDER BY amprocnum",
13019                                                   opcinfo->dobj.catId.oid);
13020         }
13021         else
13022         {
13023                 appendPQExpBuffer(query, "SELECT amprocnum, "
13024                                                   "amproc::pg_catalog.regprocedure, "
13025                                                   "'' AS amproclefttype, "
13026                                                   "'' AS amprocrighttype "
13027                                                   "FROM pg_catalog.pg_amproc "
13028                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
13029                                                   "ORDER BY amprocnum",
13030                                                   opcinfo->dobj.catId.oid);
13031         }
13032
13033         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13034
13035         ntups = PQntuples(res);
13036
13037         i_amprocnum = PQfnumber(res, "amprocnum");
13038         i_amproc = PQfnumber(res, "amproc");
13039         i_amproclefttype = PQfnumber(res, "amproclefttype");
13040         i_amprocrighttype = PQfnumber(res, "amprocrighttype");
13041
13042         for (i = 0; i < ntups; i++)
13043         {
13044                 amprocnum = PQgetvalue(res, i, i_amprocnum);
13045                 amproc = PQgetvalue(res, i, i_amproc);
13046                 amproclefttype = PQgetvalue(res, i, i_amproclefttype);
13047                 amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
13048
13049                 if (needComma)
13050                         appendPQExpBufferStr(q, " ,\n    ");
13051
13052                 appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
13053
13054                 if (*amproclefttype && *amprocrighttype)
13055                         appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
13056
13057                 appendPQExpBuffer(q, " %s", amproc);
13058
13059                 needComma = true;
13060         }
13061
13062         PQclear(res);
13063
13064         /*
13065          * If needComma is still false it means we haven't added anything after
13066          * the AS keyword.  To avoid printing broken SQL, append a dummy STORAGE
13067          * clause with the same datatype.  This isn't sanctioned by the
13068          * documentation, but actually DefineOpClass will treat it as a no-op.
13069          */
13070         if (!needComma)
13071                 appendPQExpBuffer(q, "STORAGE %s", opcintype);
13072
13073         appendPQExpBufferStr(q, ";\n");
13074
13075         appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
13076         appendPQExpBuffer(nameusing, " USING %s",
13077                                           fmtId(amname));
13078
13079         if (dopt->binary_upgrade)
13080                 binary_upgrade_extension_member(q, &opcinfo->dobj,
13081                                                                                 "OPERATOR CLASS", nameusing->data,
13082                                                                                 opcinfo->dobj.namespace->dobj.name);
13083
13084         if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13085                 ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
13086                                          ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
13087                                                                   .namespace = opcinfo->dobj.namespace->dobj.name,
13088                                                                   .owner = opcinfo->rolname,
13089                                                                   .description = "OPERATOR CLASS",
13090                                                                   .section = SECTION_PRE_DATA,
13091                                                                   .createStmt = q->data,
13092                                                                   .dropStmt = delq->data));
13093
13094         /* Dump Operator Class Comments */
13095         if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13096                 dumpComment(fout, "OPERATOR CLASS", nameusing->data,
13097                                         opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
13098                                         opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
13099
13100         free(opcintype);
13101         free(opcfamily);
13102         free(amname);
13103         destroyPQExpBuffer(query);
13104         destroyPQExpBuffer(q);
13105         destroyPQExpBuffer(delq);
13106         destroyPQExpBuffer(nameusing);
13107 }
13108
13109 /*
13110  * dumpOpfamily
13111  *        write out a single operator family definition
13112  *
13113  * Note: this also dumps any "loose" operator members that aren't bound to a
13114  * specific opclass within the opfamily.
13115  */
13116 static void
13117 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
13118 {
13119         DumpOptions *dopt = fout->dopt;
13120         PQExpBuffer query;
13121         PQExpBuffer q;
13122         PQExpBuffer delq;
13123         PQExpBuffer nameusing;
13124         PGresult   *res;
13125         PGresult   *res_ops;
13126         PGresult   *res_procs;
13127         int                     ntups;
13128         int                     i_amname;
13129         int                     i_amopstrategy;
13130         int                     i_amopreqcheck;
13131         int                     i_amopopr;
13132         int                     i_sortfamily;
13133         int                     i_sortfamilynsp;
13134         int                     i_amprocnum;
13135         int                     i_amproc;
13136         int                     i_amproclefttype;
13137         int                     i_amprocrighttype;
13138         char       *amname;
13139         char       *amopstrategy;
13140         char       *amopreqcheck;
13141         char       *amopopr;
13142         char       *sortfamily;
13143         char       *sortfamilynsp;
13144         char       *amprocnum;
13145         char       *amproc;
13146         char       *amproclefttype;
13147         char       *amprocrighttype;
13148         bool            needComma;
13149         int                     i;
13150
13151         /* Skip if not to be dumped */
13152         if (!opfinfo->dobj.dump || dopt->dataOnly)
13153                 return;
13154
13155         query = createPQExpBuffer();
13156         q = createPQExpBuffer();
13157         delq = createPQExpBuffer();
13158         nameusing = createPQExpBuffer();
13159
13160         /*
13161          * Fetch only those opfamily members that are tied directly to the
13162          * opfamily by pg_depend entries.
13163          *
13164          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
13165          * older server's opclass in which it is used.  This is to avoid
13166          * hard-to-detect breakage if a newer pg_dump is used to dump from an
13167          * older server and then reload into that old version.  This can go away
13168          * once 8.3 is so old as to not be of interest to anyone.
13169          */
13170         if (fout->remoteVersion >= 90100)
13171         {
13172                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
13173                                                   "amopopr::pg_catalog.regoperator, "
13174                                                   "opfname AS sortfamily, "
13175                                                   "nspname AS sortfamilynsp "
13176                                                   "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
13177                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
13178                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
13179                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
13180                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13181                                                   "AND refobjid = '%u'::pg_catalog.oid "
13182                                                   "AND amopfamily = '%u'::pg_catalog.oid "
13183                                                   "ORDER BY amopstrategy",
13184                                                   opfinfo->dobj.catId.oid,
13185                                                   opfinfo->dobj.catId.oid);
13186         }
13187         else if (fout->remoteVersion >= 80400)
13188         {
13189                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
13190                                                   "amopopr::pg_catalog.regoperator, "
13191                                                   "NULL AS sortfamily, "
13192                                                   "NULL AS sortfamilynsp "
13193                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
13194                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13195                                                   "AND refobjid = '%u'::pg_catalog.oid "
13196                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
13197                                                   "AND objid = ao.oid "
13198                                                   "ORDER BY amopstrategy",
13199                                                   opfinfo->dobj.catId.oid);
13200         }
13201         else
13202         {
13203                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
13204                                                   "amopopr::pg_catalog.regoperator, "
13205                                                   "NULL AS sortfamily, "
13206                                                   "NULL AS sortfamilynsp "
13207                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
13208                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13209                                                   "AND refobjid = '%u'::pg_catalog.oid "
13210                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
13211                                                   "AND objid = ao.oid "
13212                                                   "ORDER BY amopstrategy",
13213                                                   opfinfo->dobj.catId.oid);
13214         }
13215
13216         res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13217
13218         resetPQExpBuffer(query);
13219
13220         appendPQExpBuffer(query, "SELECT amprocnum, "
13221                                           "amproc::pg_catalog.regprocedure, "
13222                                           "amproclefttype::pg_catalog.regtype, "
13223                                           "amprocrighttype::pg_catalog.regtype "
13224                                           "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
13225                                           "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13226                                           "AND refobjid = '%u'::pg_catalog.oid "
13227                                           "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
13228                                           "AND objid = ap.oid "
13229                                           "ORDER BY amprocnum",
13230                                           opfinfo->dobj.catId.oid);
13231
13232         res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13233
13234         /* Get additional fields from the pg_opfamily row */
13235         resetPQExpBuffer(query);
13236
13237         appendPQExpBuffer(query, "SELECT "
13238                                           "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
13239                                           "FROM pg_catalog.pg_opfamily "
13240                                           "WHERE oid = '%u'::pg_catalog.oid",
13241                                           opfinfo->dobj.catId.oid);
13242
13243         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13244
13245         i_amname = PQfnumber(res, "amname");
13246
13247         /* amname will still be needed after we PQclear res */
13248         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
13249
13250         appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
13251                                           fmtQualifiedDumpable(opfinfo));
13252         appendPQExpBuffer(delq, " USING %s;\n",
13253                                           fmtId(amname));
13254
13255         /* Build the fixed portion of the CREATE command */
13256         appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
13257                                           fmtQualifiedDumpable(opfinfo));
13258         appendPQExpBuffer(q, " USING %s;\n",
13259                                           fmtId(amname));
13260
13261         PQclear(res);
13262
13263         /* Do we need an ALTER to add loose members? */
13264         if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
13265         {
13266                 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
13267                                                   fmtQualifiedDumpable(opfinfo));
13268                 appendPQExpBuffer(q, " USING %s ADD\n    ",
13269                                                   fmtId(amname));
13270
13271                 needComma = false;
13272
13273                 /*
13274                  * Now fetch and print the OPERATOR entries (pg_amop rows).
13275                  */
13276                 ntups = PQntuples(res_ops);
13277
13278                 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
13279                 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
13280                 i_amopopr = PQfnumber(res_ops, "amopopr");
13281                 i_sortfamily = PQfnumber(res_ops, "sortfamily");
13282                 i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
13283
13284                 for (i = 0; i < ntups; i++)
13285                 {
13286                         amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
13287                         amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
13288                         amopopr = PQgetvalue(res_ops, i, i_amopopr);
13289                         sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
13290                         sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
13291
13292                         if (needComma)
13293                                 appendPQExpBufferStr(q, " ,\n    ");
13294
13295                         appendPQExpBuffer(q, "OPERATOR %s %s",
13296                                                           amopstrategy, amopopr);
13297
13298                         if (strlen(sortfamily) > 0)
13299                         {
13300                                 appendPQExpBufferStr(q, " FOR ORDER BY ");
13301                                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
13302                                 appendPQExpBufferStr(q, fmtId(sortfamily));
13303                         }
13304
13305                         if (strcmp(amopreqcheck, "t") == 0)
13306                                 appendPQExpBufferStr(q, " RECHECK");
13307
13308                         needComma = true;
13309                 }
13310
13311                 /*
13312                  * Now fetch and print the FUNCTION entries (pg_amproc rows).
13313                  */
13314                 ntups = PQntuples(res_procs);
13315
13316                 i_amprocnum = PQfnumber(res_procs, "amprocnum");
13317                 i_amproc = PQfnumber(res_procs, "amproc");
13318                 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
13319                 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
13320
13321                 for (i = 0; i < ntups; i++)
13322                 {
13323                         amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
13324                         amproc = PQgetvalue(res_procs, i, i_amproc);
13325                         amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
13326                         amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
13327
13328                         if (needComma)
13329                                 appendPQExpBufferStr(q, " ,\n    ");
13330
13331                         appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
13332                                                           amprocnum, amproclefttype, amprocrighttype,
13333                                                           amproc);
13334
13335                         needComma = true;
13336                 }
13337
13338                 appendPQExpBufferStr(q, ";\n");
13339         }
13340
13341         appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
13342         appendPQExpBuffer(nameusing, " USING %s",
13343                                           fmtId(amname));
13344
13345         if (dopt->binary_upgrade)
13346                 binary_upgrade_extension_member(q, &opfinfo->dobj,
13347                                                                                 "OPERATOR FAMILY", nameusing->data,
13348                                                                                 opfinfo->dobj.namespace->dobj.name);
13349
13350         if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13351                 ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
13352                                          ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
13353                                                                   .namespace = opfinfo->dobj.namespace->dobj.name,
13354                                                                   .owner = opfinfo->rolname,
13355                                                                   .description = "OPERATOR FAMILY",
13356                                                                   .section = SECTION_PRE_DATA,
13357                                                                   .createStmt = q->data,
13358                                                                   .dropStmt = delq->data));
13359
13360         /* Dump Operator Family Comments */
13361         if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13362                 dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
13363                                         opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
13364                                         opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
13365
13366         free(amname);
13367         PQclear(res_ops);
13368         PQclear(res_procs);
13369         destroyPQExpBuffer(query);
13370         destroyPQExpBuffer(q);
13371         destroyPQExpBuffer(delq);
13372         destroyPQExpBuffer(nameusing);
13373 }
13374
13375 /*
13376  * dumpCollation
13377  *        write out a single collation definition
13378  */
13379 static void
13380 dumpCollation(Archive *fout, CollInfo *collinfo)
13381 {
13382         DumpOptions *dopt = fout->dopt;
13383         PQExpBuffer query;
13384         PQExpBuffer q;
13385         PQExpBuffer delq;
13386         char       *qcollname;
13387         PGresult   *res;
13388         int                     i_collprovider;
13389         int                     i_collisdeterministic;
13390         int                     i_collcollate;
13391         int                     i_collctype;
13392         const char *collprovider;
13393         const char *collcollate;
13394         const char *collctype;
13395
13396         /* Skip if not to be dumped */
13397         if (!collinfo->dobj.dump || dopt->dataOnly)
13398                 return;
13399
13400         query = createPQExpBuffer();
13401         q = createPQExpBuffer();
13402         delq = createPQExpBuffer();
13403
13404         qcollname = pg_strdup(fmtId(collinfo->dobj.name));
13405
13406         /* Get collation-specific details */
13407         appendPQExpBuffer(query, "SELECT ");
13408
13409         if (fout->remoteVersion >= 100000)
13410                 appendPQExpBuffer(query,
13411                                                   "collprovider, "
13412                                                   "collversion, ");
13413         else
13414                 appendPQExpBuffer(query,
13415                                                   "'c' AS collprovider, "
13416                                                   "NULL AS collversion, ");
13417
13418         if (fout->remoteVersion >= 120000)
13419                 appendPQExpBuffer(query,
13420                                                   "collisdeterministic, ");
13421         else
13422                 appendPQExpBuffer(query,
13423                                                   "true AS collisdeterministic, ");
13424
13425         appendPQExpBuffer(query,
13426                                           "collcollate, "
13427                                           "collctype "
13428                                           "FROM pg_catalog.pg_collation c "
13429                                           "WHERE c.oid = '%u'::pg_catalog.oid",
13430                                           collinfo->dobj.catId.oid);
13431
13432         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13433
13434         i_collprovider = PQfnumber(res, "collprovider");
13435         i_collisdeterministic = PQfnumber(res, "collisdeterministic");
13436         i_collcollate = PQfnumber(res, "collcollate");
13437         i_collctype = PQfnumber(res, "collctype");
13438
13439         collprovider = PQgetvalue(res, 0, i_collprovider);
13440         collcollate = PQgetvalue(res, 0, i_collcollate);
13441         collctype = PQgetvalue(res, 0, i_collctype);
13442
13443         appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
13444                                           fmtQualifiedDumpable(collinfo));
13445
13446         appendPQExpBuffer(q, "CREATE COLLATION %s (",
13447                                           fmtQualifiedDumpable(collinfo));
13448
13449         appendPQExpBufferStr(q, "provider = ");
13450         if (collprovider[0] == 'c')
13451                 appendPQExpBufferStr(q, "libc");
13452         else if (collprovider[0] == 'i')
13453                 appendPQExpBufferStr(q, "icu");
13454         else if (collprovider[0] == 'd')
13455                 /* to allow dumping pg_catalog; not accepted on input */
13456                 appendPQExpBufferStr(q, "default");
13457         else
13458                 fatal("unrecognized collation provider: %s\n",
13459                                           collprovider);
13460
13461         if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
13462                 appendPQExpBufferStr(q, ", deterministic = false");
13463
13464         if (strcmp(collcollate, collctype) == 0)
13465         {
13466                 appendPQExpBufferStr(q, ", locale = ");
13467                 appendStringLiteralAH(q, collcollate, fout);
13468         }
13469         else
13470         {
13471                 appendPQExpBufferStr(q, ", lc_collate = ");
13472                 appendStringLiteralAH(q, collcollate, fout);
13473                 appendPQExpBufferStr(q, ", lc_ctype = ");
13474                 appendStringLiteralAH(q, collctype, fout);
13475         }
13476
13477         /*
13478          * For binary upgrade, carry over the collation version.  For normal
13479          * dump/restore, omit the version, so that it is computed upon restore.
13480          */
13481         if (dopt->binary_upgrade)
13482         {
13483                 int                     i_collversion;
13484
13485                 i_collversion = PQfnumber(res, "collversion");
13486                 if (!PQgetisnull(res, 0, i_collversion))
13487                 {
13488                         appendPQExpBufferStr(q, ", version = ");
13489                         appendStringLiteralAH(q,
13490                                                                   PQgetvalue(res, 0, i_collversion),
13491                                                                   fout);
13492                 }
13493         }
13494
13495         appendPQExpBufferStr(q, ");\n");
13496
13497         if (dopt->binary_upgrade)
13498                 binary_upgrade_extension_member(q, &collinfo->dobj,
13499                                                                                 "COLLATION", qcollname,
13500                                                                                 collinfo->dobj.namespace->dobj.name);
13501
13502         if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13503                 ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
13504                                          ARCHIVE_OPTS(.tag = collinfo->dobj.name,
13505                                                                   .namespace = collinfo->dobj.namespace->dobj.name,
13506                                                                   .owner = collinfo->rolname,
13507                                                                   .description = "COLLATION",
13508                                                                   .section = SECTION_PRE_DATA,
13509                                                                   .createStmt = q->data,
13510                                                                   .dropStmt = delq->data));
13511
13512         /* Dump Collation Comments */
13513         if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13514                 dumpComment(fout, "COLLATION", qcollname,
13515                                         collinfo->dobj.namespace->dobj.name, collinfo->rolname,
13516                                         collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
13517
13518         PQclear(res);
13519
13520         destroyPQExpBuffer(query);
13521         destroyPQExpBuffer(q);
13522         destroyPQExpBuffer(delq);
13523         free(qcollname);
13524 }
13525
13526 /*
13527  * dumpConversion
13528  *        write out a single conversion definition
13529  */
13530 static void
13531 dumpConversion(Archive *fout, ConvInfo *convinfo)
13532 {
13533         DumpOptions *dopt = fout->dopt;
13534         PQExpBuffer query;
13535         PQExpBuffer q;
13536         PQExpBuffer delq;
13537         char       *qconvname;
13538         PGresult   *res;
13539         int                     i_conforencoding;
13540         int                     i_contoencoding;
13541         int                     i_conproc;
13542         int                     i_condefault;
13543         const char *conforencoding;
13544         const char *contoencoding;
13545         const char *conproc;
13546         bool            condefault;
13547
13548         /* Skip if not to be dumped */
13549         if (!convinfo->dobj.dump || dopt->dataOnly)
13550                 return;
13551
13552         query = createPQExpBuffer();
13553         q = createPQExpBuffer();
13554         delq = createPQExpBuffer();
13555
13556         qconvname = pg_strdup(fmtId(convinfo->dobj.name));
13557
13558         /* Get conversion-specific details */
13559         appendPQExpBuffer(query, "SELECT "
13560                                           "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
13561                                           "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
13562                                           "conproc, condefault "
13563                                           "FROM pg_catalog.pg_conversion c "
13564                                           "WHERE c.oid = '%u'::pg_catalog.oid",
13565                                           convinfo->dobj.catId.oid);
13566
13567         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13568
13569         i_conforencoding = PQfnumber(res, "conforencoding");
13570         i_contoencoding = PQfnumber(res, "contoencoding");
13571         i_conproc = PQfnumber(res, "conproc");
13572         i_condefault = PQfnumber(res, "condefault");
13573
13574         conforencoding = PQgetvalue(res, 0, i_conforencoding);
13575         contoencoding = PQgetvalue(res, 0, i_contoencoding);
13576         conproc = PQgetvalue(res, 0, i_conproc);
13577         condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
13578
13579         appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
13580                                           fmtQualifiedDumpable(convinfo));
13581
13582         appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
13583                                           (condefault) ? "DEFAULT " : "",
13584                                           fmtQualifiedDumpable(convinfo));
13585         appendStringLiteralAH(q, conforencoding, fout);
13586         appendPQExpBufferStr(q, " TO ");
13587         appendStringLiteralAH(q, contoencoding, fout);
13588         /* regproc output is already sufficiently quoted */
13589         appendPQExpBuffer(q, " FROM %s;\n", conproc);
13590
13591         if (dopt->binary_upgrade)
13592                 binary_upgrade_extension_member(q, &convinfo->dobj,
13593                                                                                 "CONVERSION", qconvname,
13594                                                                                 convinfo->dobj.namespace->dobj.name);
13595
13596         if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13597                 ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
13598                                          ARCHIVE_OPTS(.tag = convinfo->dobj.name,
13599                                                                   .namespace = convinfo->dobj.namespace->dobj.name,
13600                                                                   .owner = convinfo->rolname,
13601                                                                   .description = "CONVERSION",
13602                                                                   .section = SECTION_PRE_DATA,
13603                                                                   .createStmt = q->data,
13604                                                                   .dropStmt = delq->data));
13605
13606         /* Dump Conversion Comments */
13607         if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13608                 dumpComment(fout, "CONVERSION", qconvname,
13609                                         convinfo->dobj.namespace->dobj.name, convinfo->rolname,
13610                                         convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
13611
13612         PQclear(res);
13613
13614         destroyPQExpBuffer(query);
13615         destroyPQExpBuffer(q);
13616         destroyPQExpBuffer(delq);
13617         free(qconvname);
13618 }
13619
13620 /*
13621  * format_aggregate_signature: generate aggregate name and argument list
13622  *
13623  * The argument type names are qualified if needed.  The aggregate name
13624  * is never qualified.
13625  */
13626 static char *
13627 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
13628 {
13629         PQExpBufferData buf;
13630         int                     j;
13631
13632         initPQExpBuffer(&buf);
13633         if (honor_quotes)
13634                 appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
13635         else
13636                 appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
13637
13638         if (agginfo->aggfn.nargs == 0)
13639                 appendPQExpBuffer(&buf, "(*)");
13640         else
13641         {
13642                 appendPQExpBufferChar(&buf, '(');
13643                 for (j = 0; j < agginfo->aggfn.nargs; j++)
13644                 {
13645                         char       *typname;
13646
13647                         typname = getFormattedTypeName(fout, agginfo->aggfn.argtypes[j],
13648                                                                                    zeroAsOpaque);
13649
13650                         appendPQExpBuffer(&buf, "%s%s",
13651                                                           (j > 0) ? ", " : "",
13652                                                           typname);
13653                         free(typname);
13654                 }
13655                 appendPQExpBufferChar(&buf, ')');
13656         }
13657         return buf.data;
13658 }
13659
13660 /*
13661  * dumpAgg
13662  *        write out a single aggregate definition
13663  */
13664 static void
13665 dumpAgg(Archive *fout, AggInfo *agginfo)
13666 {
13667         DumpOptions *dopt = fout->dopt;
13668         PQExpBuffer query;
13669         PQExpBuffer q;
13670         PQExpBuffer delq;
13671         PQExpBuffer details;
13672         char       *aggsig;                     /* identity signature */
13673         char       *aggfullsig = NULL;  /* full signature */
13674         char       *aggsig_tag;
13675         PGresult   *res;
13676         int                     i_aggtransfn;
13677         int                     i_aggfinalfn;
13678         int                     i_aggcombinefn;
13679         int                     i_aggserialfn;
13680         int                     i_aggdeserialfn;
13681         int                     i_aggmtransfn;
13682         int                     i_aggminvtransfn;
13683         int                     i_aggmfinalfn;
13684         int                     i_aggfinalextra;
13685         int                     i_aggmfinalextra;
13686         int                     i_aggfinalmodify;
13687         int                     i_aggmfinalmodify;
13688         int                     i_aggsortop;
13689         int                     i_aggkind;
13690         int                     i_aggtranstype;
13691         int                     i_aggtransspace;
13692         int                     i_aggmtranstype;
13693         int                     i_aggmtransspace;
13694         int                     i_agginitval;
13695         int                     i_aggminitval;
13696         int                     i_convertok;
13697         int                     i_proparallel;
13698         const char *aggtransfn;
13699         const char *aggfinalfn;
13700         const char *aggcombinefn;
13701         const char *aggserialfn;
13702         const char *aggdeserialfn;
13703         const char *aggmtransfn;
13704         const char *aggminvtransfn;
13705         const char *aggmfinalfn;
13706         bool            aggfinalextra;
13707         bool            aggmfinalextra;
13708         char            aggfinalmodify;
13709         char            aggmfinalmodify;
13710         const char *aggsortop;
13711         char       *aggsortconvop;
13712         char            aggkind;
13713         const char *aggtranstype;
13714         const char *aggtransspace;
13715         const char *aggmtranstype;
13716         const char *aggmtransspace;
13717         const char *agginitval;
13718         const char *aggminitval;
13719         bool            convertok;
13720         const char *proparallel;
13721         char            defaultfinalmodify;
13722
13723         /* Skip if not to be dumped */
13724         if (!agginfo->aggfn.dobj.dump || dopt->dataOnly)
13725                 return;
13726
13727         query = createPQExpBuffer();
13728         q = createPQExpBuffer();
13729         delq = createPQExpBuffer();
13730         details = createPQExpBuffer();
13731
13732         /* Get aggregate-specific details */
13733         if (fout->remoteVersion >= 110000)
13734         {
13735                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13736                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13737                                                   "aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
13738                                                   "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13739                                                   "aggfinalextra, aggmfinalextra, "
13740                                                   "aggfinalmodify, aggmfinalmodify, "
13741                                                   "aggsortop, "
13742                                                   "aggkind, "
13743                                                   "aggtransspace, agginitval, "
13744                                                   "aggmtransspace, aggminitval, "
13745                                                   "true AS convertok, "
13746                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13747                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs, "
13748                                                   "p.proparallel "
13749                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13750                                                   "WHERE a.aggfnoid = p.oid "
13751                                                   "AND p.oid = '%u'::pg_catalog.oid",
13752                                                   agginfo->aggfn.dobj.catId.oid);
13753         }
13754         else if (fout->remoteVersion >= 90600)
13755         {
13756                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13757                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13758                                                   "aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
13759                                                   "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13760                                                   "aggfinalextra, aggmfinalextra, "
13761                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13762                                                   "aggsortop, "
13763                                                   "aggkind, "
13764                                                   "aggtransspace, agginitval, "
13765                                                   "aggmtransspace, aggminitval, "
13766                                                   "true AS convertok, "
13767                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13768                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs, "
13769                                                   "p.proparallel "
13770                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13771                                                   "WHERE a.aggfnoid = p.oid "
13772                                                   "AND p.oid = '%u'::pg_catalog.oid",
13773                                                   agginfo->aggfn.dobj.catId.oid);
13774         }
13775         else if (fout->remoteVersion >= 90400)
13776         {
13777                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13778                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13779                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13780                                                   "'-' AS aggdeserialfn, aggmtransfn, aggminvtransfn, "
13781                                                   "aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13782                                                   "aggfinalextra, aggmfinalextra, "
13783                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13784                                                   "aggsortop, "
13785                                                   "aggkind, "
13786                                                   "aggtransspace, agginitval, "
13787                                                   "aggmtransspace, aggminitval, "
13788                                                   "true AS convertok, "
13789                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13790                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
13791                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13792                                                   "WHERE a.aggfnoid = p.oid "
13793                                                   "AND p.oid = '%u'::pg_catalog.oid",
13794                                                   agginfo->aggfn.dobj.catId.oid);
13795         }
13796         else if (fout->remoteVersion >= 80400)
13797         {
13798                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13799                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13800                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13801                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13802                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13803                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13804                                                   "false AS aggmfinalextra, "
13805                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13806                                                   "aggsortop, "
13807                                                   "'n' AS aggkind, "
13808                                                   "0 AS aggtransspace, agginitval, "
13809                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13810                                                   "true AS convertok, "
13811                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13812                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
13813                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13814                                                   "WHERE a.aggfnoid = p.oid "
13815                                                   "AND p.oid = '%u'::pg_catalog.oid",
13816                                                   agginfo->aggfn.dobj.catId.oid);
13817         }
13818         else if (fout->remoteVersion >= 80100)
13819         {
13820                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13821                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13822                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13823                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13824                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13825                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13826                                                   "false AS aggmfinalextra, "
13827                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13828                                                   "aggsortop, "
13829                                                   "'n' AS aggkind, "
13830                                                   "0 AS aggtransspace, agginitval, "
13831                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13832                                                   "true AS convertok "
13833                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13834                                                   "WHERE a.aggfnoid = p.oid "
13835                                                   "AND p.oid = '%u'::pg_catalog.oid",
13836                                                   agginfo->aggfn.dobj.catId.oid);
13837         }
13838         else
13839         {
13840                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13841                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13842                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13843                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13844                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13845                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13846                                                   "false AS aggmfinalextra, "
13847                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13848                                                   "0 AS aggsortop, "
13849                                                   "'n' AS aggkind, "
13850                                                   "0 AS aggtransspace, agginitval, "
13851                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13852                                                   "true AS convertok "
13853                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13854                                                   "WHERE a.aggfnoid = p.oid "
13855                                                   "AND p.oid = '%u'::pg_catalog.oid",
13856                                                   agginfo->aggfn.dobj.catId.oid);
13857         }
13858
13859         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13860
13861         i_aggtransfn = PQfnumber(res, "aggtransfn");
13862         i_aggfinalfn = PQfnumber(res, "aggfinalfn");
13863         i_aggcombinefn = PQfnumber(res, "aggcombinefn");
13864         i_aggserialfn = PQfnumber(res, "aggserialfn");
13865         i_aggdeserialfn = PQfnumber(res, "aggdeserialfn");
13866         i_aggmtransfn = PQfnumber(res, "aggmtransfn");
13867         i_aggminvtransfn = PQfnumber(res, "aggminvtransfn");
13868         i_aggmfinalfn = PQfnumber(res, "aggmfinalfn");
13869         i_aggfinalextra = PQfnumber(res, "aggfinalextra");
13870         i_aggmfinalextra = PQfnumber(res, "aggmfinalextra");
13871         i_aggfinalmodify = PQfnumber(res, "aggfinalmodify");
13872         i_aggmfinalmodify = PQfnumber(res, "aggmfinalmodify");
13873         i_aggsortop = PQfnumber(res, "aggsortop");
13874         i_aggkind = PQfnumber(res, "aggkind");
13875         i_aggtranstype = PQfnumber(res, "aggtranstype");
13876         i_aggtransspace = PQfnumber(res, "aggtransspace");
13877         i_aggmtranstype = PQfnumber(res, "aggmtranstype");
13878         i_aggmtransspace = PQfnumber(res, "aggmtransspace");
13879         i_agginitval = PQfnumber(res, "agginitval");
13880         i_aggminitval = PQfnumber(res, "aggminitval");
13881         i_convertok = PQfnumber(res, "convertok");
13882         i_proparallel = PQfnumber(res, "proparallel");
13883
13884         aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
13885         aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
13886         aggcombinefn = PQgetvalue(res, 0, i_aggcombinefn);
13887         aggserialfn = PQgetvalue(res, 0, i_aggserialfn);
13888         aggdeserialfn = PQgetvalue(res, 0, i_aggdeserialfn);
13889         aggmtransfn = PQgetvalue(res, 0, i_aggmtransfn);
13890         aggminvtransfn = PQgetvalue(res, 0, i_aggminvtransfn);
13891         aggmfinalfn = PQgetvalue(res, 0, i_aggmfinalfn);
13892         aggfinalextra = (PQgetvalue(res, 0, i_aggfinalextra)[0] == 't');
13893         aggmfinalextra = (PQgetvalue(res, 0, i_aggmfinalextra)[0] == 't');
13894         aggfinalmodify = PQgetvalue(res, 0, i_aggfinalmodify)[0];
13895         aggmfinalmodify = PQgetvalue(res, 0, i_aggmfinalmodify)[0];
13896         aggsortop = PQgetvalue(res, 0, i_aggsortop);
13897         aggkind = PQgetvalue(res, 0, i_aggkind)[0];
13898         aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
13899         aggtransspace = PQgetvalue(res, 0, i_aggtransspace);
13900         aggmtranstype = PQgetvalue(res, 0, i_aggmtranstype);
13901         aggmtransspace = PQgetvalue(res, 0, i_aggmtransspace);
13902         agginitval = PQgetvalue(res, 0, i_agginitval);
13903         aggminitval = PQgetvalue(res, 0, i_aggminitval);
13904         convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
13905
13906         if (fout->remoteVersion >= 80400)
13907         {
13908                 /* 8.4 or later; we rely on server-side code for most of the work */
13909                 char       *funcargs;
13910                 char       *funciargs;
13911
13912                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
13913                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
13914                 aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
13915                 aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
13916         }
13917         else
13918                 /* pre-8.4, do it ourselves */
13919                 aggsig = format_aggregate_signature(agginfo, fout, true);
13920
13921         aggsig_tag = format_aggregate_signature(agginfo, fout, false);
13922
13923         if (i_proparallel != -1)
13924                 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
13925         else
13926                 proparallel = NULL;
13927
13928         if (!convertok)
13929         {
13930                 pg_log_warning("aggregate function %s could not be dumped correctly for this database version; ignored",
13931                                   aggsig);
13932
13933                 if (aggfullsig)
13934                         free(aggfullsig);
13935
13936                 free(aggsig);
13937
13938                 return;
13939         }
13940
13941         /* identify default modify flag for aggkind (must match DefineAggregate) */
13942         defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
13943         /* replace omitted flags for old versions */
13944         if (aggfinalmodify == '0')
13945                 aggfinalmodify = defaultfinalmodify;
13946         if (aggmfinalmodify == '0')
13947                 aggmfinalmodify = defaultfinalmodify;
13948
13949         /* regproc and regtype output is already sufficiently quoted */
13950         appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
13951                                           aggtransfn, aggtranstype);
13952
13953         if (strcmp(aggtransspace, "0") != 0)
13954         {
13955                 appendPQExpBuffer(details, ",\n    SSPACE = %s",
13956                                                   aggtransspace);
13957         }
13958
13959         if (!PQgetisnull(res, 0, i_agginitval))
13960         {
13961                 appendPQExpBufferStr(details, ",\n    INITCOND = ");
13962                 appendStringLiteralAH(details, agginitval, fout);
13963         }
13964
13965         if (strcmp(aggfinalfn, "-") != 0)
13966         {
13967                 appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
13968                                                   aggfinalfn);
13969                 if (aggfinalextra)
13970                         appendPQExpBufferStr(details, ",\n    FINALFUNC_EXTRA");
13971                 if (aggfinalmodify != defaultfinalmodify)
13972                 {
13973                         switch (aggfinalmodify)
13974                         {
13975                                 case AGGMODIFY_READ_ONLY:
13976                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_ONLY");
13977                                         break;
13978                                 case AGGMODIFY_SHAREABLE:
13979                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = SHAREABLE");
13980                                         break;
13981                                 case AGGMODIFY_READ_WRITE:
13982                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_WRITE");
13983                                         break;
13984                                 default:
13985                                         fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
13986                                                                   agginfo->aggfn.dobj.name);
13987                                         break;
13988                         }
13989                 }
13990         }
13991
13992         if (strcmp(aggcombinefn, "-") != 0)
13993                 appendPQExpBuffer(details, ",\n    COMBINEFUNC = %s", aggcombinefn);
13994
13995         if (strcmp(aggserialfn, "-") != 0)
13996                 appendPQExpBuffer(details, ",\n    SERIALFUNC = %s", aggserialfn);
13997
13998         if (strcmp(aggdeserialfn, "-") != 0)
13999                 appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s", aggdeserialfn);
14000
14001         if (strcmp(aggmtransfn, "-") != 0)
14002         {
14003                 appendPQExpBuffer(details, ",\n    MSFUNC = %s,\n    MINVFUNC = %s,\n    MSTYPE = %s",
14004                                                   aggmtransfn,
14005                                                   aggminvtransfn,
14006                                                   aggmtranstype);
14007         }
14008
14009         if (strcmp(aggmtransspace, "0") != 0)
14010         {
14011                 appendPQExpBuffer(details, ",\n    MSSPACE = %s",
14012                                                   aggmtransspace);
14013         }
14014
14015         if (!PQgetisnull(res, 0, i_aggminitval))
14016         {
14017                 appendPQExpBufferStr(details, ",\n    MINITCOND = ");
14018                 appendStringLiteralAH(details, aggminitval, fout);
14019         }
14020
14021         if (strcmp(aggmfinalfn, "-") != 0)
14022         {
14023                 appendPQExpBuffer(details, ",\n    MFINALFUNC = %s",
14024                                                   aggmfinalfn);
14025                 if (aggmfinalextra)
14026                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_EXTRA");
14027                 if (aggmfinalmodify != defaultfinalmodify)
14028                 {
14029                         switch (aggmfinalmodify)
14030                         {
14031                                 case AGGMODIFY_READ_ONLY:
14032                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_ONLY");
14033                                         break;
14034                                 case AGGMODIFY_SHAREABLE:
14035                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = SHAREABLE");
14036                                         break;
14037                                 case AGGMODIFY_READ_WRITE:
14038                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_WRITE");
14039                                         break;
14040                                 default:
14041                                         fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
14042                                                                   agginfo->aggfn.dobj.name);
14043                                         break;
14044                         }
14045                 }
14046         }
14047
14048         aggsortconvop = getFormattedOperatorName(fout, aggsortop);
14049         if (aggsortconvop)
14050         {
14051                 appendPQExpBuffer(details, ",\n    SORTOP = %s",
14052                                                   aggsortconvop);
14053                 free(aggsortconvop);
14054         }
14055
14056         if (aggkind == AGGKIND_HYPOTHETICAL)
14057                 appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
14058
14059         if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
14060         {
14061                 if (proparallel[0] == PROPARALLEL_SAFE)
14062                         appendPQExpBufferStr(details, ",\n    PARALLEL = safe");
14063                 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
14064                         appendPQExpBufferStr(details, ",\n    PARALLEL = restricted");
14065                 else if (proparallel[0] != PROPARALLEL_UNSAFE)
14066                         fatal("unrecognized proparallel value for function \"%s\"",
14067                                                   agginfo->aggfn.dobj.name);
14068         }
14069
14070         appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
14071                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
14072                                           aggsig);
14073
14074         appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
14075                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
14076                                           aggfullsig ? aggfullsig : aggsig, details->data);
14077
14078         if (dopt->binary_upgrade)
14079                 binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
14080                                                                                 "AGGREGATE", aggsig,
14081                                                                                 agginfo->aggfn.dobj.namespace->dobj.name);
14082
14083         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
14084                 ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
14085                                          agginfo->aggfn.dobj.dumpId,
14086                                          ARCHIVE_OPTS(.tag = aggsig_tag,
14087                                                                   .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
14088                                                                   .owner = agginfo->aggfn.rolname,
14089                                                                   .description = "AGGREGATE",
14090                                                                   .section = SECTION_PRE_DATA,
14091                                                                   .createStmt = q->data,
14092                                                                   .dropStmt = delq->data));
14093
14094         /* Dump Aggregate Comments */
14095         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
14096                 dumpComment(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         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
14102                 dumpSecLabel(fout, "AGGREGATE", aggsig,
14103                                          agginfo->aggfn.dobj.namespace->dobj.name,
14104                                          agginfo->aggfn.rolname,
14105                                          agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
14106
14107         /*
14108          * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
14109          * command look like a function's GRANT; in particular this affects the
14110          * syntax for zero-argument aggregates and ordered-set aggregates.
14111          */
14112         free(aggsig);
14113
14114         aggsig = format_function_signature(fout, &agginfo->aggfn, true);
14115
14116         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
14117                 dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
14118                                 "FUNCTION", aggsig, NULL,
14119                                 agginfo->aggfn.dobj.namespace->dobj.name,
14120                                 agginfo->aggfn.rolname, agginfo->aggfn.proacl,
14121                                 agginfo->aggfn.rproacl,
14122                                 agginfo->aggfn.initproacl, agginfo->aggfn.initrproacl);
14123
14124         free(aggsig);
14125         if (aggfullsig)
14126                 free(aggfullsig);
14127         free(aggsig_tag);
14128
14129         PQclear(res);
14130
14131         destroyPQExpBuffer(query);
14132         destroyPQExpBuffer(q);
14133         destroyPQExpBuffer(delq);
14134         destroyPQExpBuffer(details);
14135 }
14136
14137 /*
14138  * dumpTSParser
14139  *        write out a single text search parser
14140  */
14141 static void
14142 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
14143 {
14144         DumpOptions *dopt = fout->dopt;
14145         PQExpBuffer q;
14146         PQExpBuffer delq;
14147         char       *qprsname;
14148
14149         /* Skip if not to be dumped */
14150         if (!prsinfo->dobj.dump || dopt->dataOnly)
14151                 return;
14152
14153         q = createPQExpBuffer();
14154         delq = createPQExpBuffer();
14155
14156         qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
14157
14158         appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
14159                                           fmtQualifiedDumpable(prsinfo));
14160
14161         appendPQExpBuffer(q, "    START = %s,\n",
14162                                           convertTSFunction(fout, prsinfo->prsstart));
14163         appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
14164                                           convertTSFunction(fout, prsinfo->prstoken));
14165         appendPQExpBuffer(q, "    END = %s,\n",
14166                                           convertTSFunction(fout, prsinfo->prsend));
14167         if (prsinfo->prsheadline != InvalidOid)
14168                 appendPQExpBuffer(q, "    HEADLINE = %s,\n",
14169                                                   convertTSFunction(fout, prsinfo->prsheadline));
14170         appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
14171                                           convertTSFunction(fout, prsinfo->prslextype));
14172
14173         appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
14174                                           fmtQualifiedDumpable(prsinfo));
14175
14176         if (dopt->binary_upgrade)
14177                 binary_upgrade_extension_member(q, &prsinfo->dobj,
14178                                                                                 "TEXT SEARCH PARSER", qprsname,
14179                                                                                 prsinfo->dobj.namespace->dobj.name);
14180
14181         if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14182                 ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
14183                                          ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
14184                                                                   .namespace = prsinfo->dobj.namespace->dobj.name,
14185                                                                   .description = "TEXT SEARCH PARSER",
14186                                                                   .section = SECTION_PRE_DATA,
14187                                                                   .createStmt = q->data,
14188                                                                   .dropStmt = delq->data));
14189
14190         /* Dump Parser Comments */
14191         if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14192                 dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
14193                                         prsinfo->dobj.namespace->dobj.name, "",
14194                                         prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
14195
14196         destroyPQExpBuffer(q);
14197         destroyPQExpBuffer(delq);
14198         free(qprsname);
14199 }
14200
14201 /*
14202  * dumpTSDictionary
14203  *        write out a single text search dictionary
14204  */
14205 static void
14206 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
14207 {
14208         DumpOptions *dopt = fout->dopt;
14209         PQExpBuffer q;
14210         PQExpBuffer delq;
14211         PQExpBuffer query;
14212         char       *qdictname;
14213         PGresult   *res;
14214         char       *nspname;
14215         char       *tmplname;
14216
14217         /* Skip if not to be dumped */
14218         if (!dictinfo->dobj.dump || dopt->dataOnly)
14219                 return;
14220
14221         q = createPQExpBuffer();
14222         delq = createPQExpBuffer();
14223         query = createPQExpBuffer();
14224
14225         qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
14226
14227         /* Fetch name and namespace of the dictionary's template */
14228         appendPQExpBuffer(query, "SELECT nspname, tmplname "
14229                                           "FROM pg_ts_template p, pg_namespace n "
14230                                           "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
14231                                           dictinfo->dicttemplate);
14232         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14233         nspname = PQgetvalue(res, 0, 0);
14234         tmplname = PQgetvalue(res, 0, 1);
14235
14236         appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
14237                                           fmtQualifiedDumpable(dictinfo));
14238
14239         appendPQExpBufferStr(q, "    TEMPLATE = ");
14240         appendPQExpBuffer(q, "%s.", fmtId(nspname));
14241         appendPQExpBufferStr(q, fmtId(tmplname));
14242
14243         PQclear(res);
14244
14245         /* the dictinitoption can be dumped straight into the command */
14246         if (dictinfo->dictinitoption)
14247                 appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
14248
14249         appendPQExpBufferStr(q, " );\n");
14250
14251         appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
14252                                           fmtQualifiedDumpable(dictinfo));
14253
14254         if (dopt->binary_upgrade)
14255                 binary_upgrade_extension_member(q, &dictinfo->dobj,
14256                                                                                 "TEXT SEARCH DICTIONARY", qdictname,
14257                                                                                 dictinfo->dobj.namespace->dobj.name);
14258
14259         if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14260                 ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
14261                                          ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
14262                                                                   .namespace = dictinfo->dobj.namespace->dobj.name,
14263                                                                   .owner = dictinfo->rolname,
14264                                                                   .description = "TEXT SEARCH DICTIONARY",
14265                                                                   .section = SECTION_PRE_DATA,
14266                                                                   .createStmt = q->data,
14267                                                                   .dropStmt = delq->data));
14268
14269         /* Dump Dictionary Comments */
14270         if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14271                 dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
14272                                         dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
14273                                         dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
14274
14275         destroyPQExpBuffer(q);
14276         destroyPQExpBuffer(delq);
14277         destroyPQExpBuffer(query);
14278         free(qdictname);
14279 }
14280
14281 /*
14282  * dumpTSTemplate
14283  *        write out a single text search template
14284  */
14285 static void
14286 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
14287 {
14288         DumpOptions *dopt = fout->dopt;
14289         PQExpBuffer q;
14290         PQExpBuffer delq;
14291         char       *qtmplname;
14292
14293         /* Skip if not to be dumped */
14294         if (!tmplinfo->dobj.dump || dopt->dataOnly)
14295                 return;
14296
14297         q = createPQExpBuffer();
14298         delq = createPQExpBuffer();
14299
14300         qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
14301
14302         appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
14303                                           fmtQualifiedDumpable(tmplinfo));
14304
14305         if (tmplinfo->tmplinit != InvalidOid)
14306                 appendPQExpBuffer(q, "    INIT = %s,\n",
14307                                                   convertTSFunction(fout, tmplinfo->tmplinit));
14308         appendPQExpBuffer(q, "    LEXIZE = %s );\n",
14309                                           convertTSFunction(fout, tmplinfo->tmpllexize));
14310
14311         appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
14312                                           fmtQualifiedDumpable(tmplinfo));
14313
14314         if (dopt->binary_upgrade)
14315                 binary_upgrade_extension_member(q, &tmplinfo->dobj,
14316                                                                                 "TEXT SEARCH TEMPLATE", qtmplname,
14317                                                                                 tmplinfo->dobj.namespace->dobj.name);
14318
14319         if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14320                 ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
14321                                          ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
14322                                                                   .namespace = tmplinfo->dobj.namespace->dobj.name,
14323                                                                   .description = "TEXT SEARCH TEMPLATE",
14324                                                                   .section = SECTION_PRE_DATA,
14325                                                                   .createStmt = q->data,
14326                                                                   .dropStmt = delq->data));
14327
14328         /* Dump Template Comments */
14329         if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14330                 dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
14331                                         tmplinfo->dobj.namespace->dobj.name, "",
14332                                         tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
14333
14334         destroyPQExpBuffer(q);
14335         destroyPQExpBuffer(delq);
14336         free(qtmplname);
14337 }
14338
14339 /*
14340  * dumpTSConfig
14341  *        write out a single text search configuration
14342  */
14343 static void
14344 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
14345 {
14346         DumpOptions *dopt = fout->dopt;
14347         PQExpBuffer q;
14348         PQExpBuffer delq;
14349         PQExpBuffer query;
14350         char       *qcfgname;
14351         PGresult   *res;
14352         char       *nspname;
14353         char       *prsname;
14354         int                     ntups,
14355                                 i;
14356         int                     i_tokenname;
14357         int                     i_dictname;
14358
14359         /* Skip if not to be dumped */
14360         if (!cfginfo->dobj.dump || dopt->dataOnly)
14361                 return;
14362
14363         q = createPQExpBuffer();
14364         delq = createPQExpBuffer();
14365         query = createPQExpBuffer();
14366
14367         qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
14368
14369         /* Fetch name and namespace of the config's parser */
14370         appendPQExpBuffer(query, "SELECT nspname, prsname "
14371                                           "FROM pg_ts_parser p, pg_namespace n "
14372                                           "WHERE p.oid = '%u' AND n.oid = prsnamespace",
14373                                           cfginfo->cfgparser);
14374         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14375         nspname = PQgetvalue(res, 0, 0);
14376         prsname = PQgetvalue(res, 0, 1);
14377
14378         appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
14379                                           fmtQualifiedDumpable(cfginfo));
14380
14381         appendPQExpBuffer(q, "    PARSER = %s.", fmtId(nspname));
14382         appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
14383
14384         PQclear(res);
14385
14386         resetPQExpBuffer(query);
14387         appendPQExpBuffer(query,
14388                                           "SELECT\n"
14389                                           "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
14390                                           "    WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
14391                                           "  m.mapdict::pg_catalog.regdictionary AS dictname\n"
14392                                           "FROM pg_catalog.pg_ts_config_map AS m\n"
14393                                           "WHERE m.mapcfg = '%u'\n"
14394                                           "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
14395                                           cfginfo->cfgparser, cfginfo->dobj.catId.oid);
14396
14397         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14398         ntups = PQntuples(res);
14399
14400         i_tokenname = PQfnumber(res, "tokenname");
14401         i_dictname = PQfnumber(res, "dictname");
14402
14403         for (i = 0; i < ntups; i++)
14404         {
14405                 char       *tokenname = PQgetvalue(res, i, i_tokenname);
14406                 char       *dictname = PQgetvalue(res, i, i_dictname);
14407
14408                 if (i == 0 ||
14409                         strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
14410                 {
14411                         /* starting a new token type, so start a new command */
14412                         if (i > 0)
14413                                 appendPQExpBufferStr(q, ";\n");
14414                         appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
14415                                                           fmtQualifiedDumpable(cfginfo));
14416                         /* tokenname needs quoting, dictname does NOT */
14417                         appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
14418                                                           fmtId(tokenname), dictname);
14419                 }
14420                 else
14421                         appendPQExpBuffer(q, ", %s", dictname);
14422         }
14423
14424         if (ntups > 0)
14425                 appendPQExpBufferStr(q, ";\n");
14426
14427         PQclear(res);
14428
14429         appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
14430                                           fmtQualifiedDumpable(cfginfo));
14431
14432         if (dopt->binary_upgrade)
14433                 binary_upgrade_extension_member(q, &cfginfo->dobj,
14434                                                                                 "TEXT SEARCH CONFIGURATION", qcfgname,
14435                                                                                 cfginfo->dobj.namespace->dobj.name);
14436
14437         if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14438                 ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
14439                                          ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
14440                                                                   .namespace = cfginfo->dobj.namespace->dobj.name,
14441                                                                   .owner = cfginfo->rolname,
14442                                                                   .description = "TEXT SEARCH CONFIGURATION",
14443                                                                   .section = SECTION_PRE_DATA,
14444                                                                   .createStmt = q->data,
14445                                                                   .dropStmt = delq->data));
14446
14447         /* Dump Configuration Comments */
14448         if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14449                 dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
14450                                         cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
14451                                         cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
14452
14453         destroyPQExpBuffer(q);
14454         destroyPQExpBuffer(delq);
14455         destroyPQExpBuffer(query);
14456         free(qcfgname);
14457 }
14458
14459 /*
14460  * dumpForeignDataWrapper
14461  *        write out a single foreign-data wrapper definition
14462  */
14463 static void
14464 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
14465 {
14466         DumpOptions *dopt = fout->dopt;
14467         PQExpBuffer q;
14468         PQExpBuffer delq;
14469         char       *qfdwname;
14470
14471         /* Skip if not to be dumped */
14472         if (!fdwinfo->dobj.dump || dopt->dataOnly)
14473                 return;
14474
14475         q = createPQExpBuffer();
14476         delq = createPQExpBuffer();
14477
14478         qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
14479
14480         appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
14481                                           qfdwname);
14482
14483         if (strcmp(fdwinfo->fdwhandler, "-") != 0)
14484                 appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
14485
14486         if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
14487                 appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
14488
14489         if (strlen(fdwinfo->fdwoptions) > 0)
14490                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
14491
14492         appendPQExpBufferStr(q, ";\n");
14493
14494         appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
14495                                           qfdwname);
14496
14497         if (dopt->binary_upgrade)
14498                 binary_upgrade_extension_member(q, &fdwinfo->dobj,
14499                                                                                 "FOREIGN DATA WRAPPER", qfdwname,
14500                                                                                 NULL);
14501
14502         if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14503                 ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14504                                          ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
14505                                                                   .owner = fdwinfo->rolname,
14506                                                                   .description = "FOREIGN DATA WRAPPER",
14507                                                                   .section = SECTION_PRE_DATA,
14508                                                                   .createStmt = q->data,
14509                                                                   .dropStmt = delq->data));
14510
14511         /* Dump Foreign Data Wrapper Comments */
14512         if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14513                 dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
14514                                         NULL, fdwinfo->rolname,
14515                                         fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
14516
14517         /* Handle the ACL */
14518         if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
14519                 dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14520                                 "FOREIGN DATA WRAPPER", qfdwname, NULL,
14521                                 NULL, fdwinfo->rolname,
14522                                 fdwinfo->fdwacl, fdwinfo->rfdwacl,
14523                                 fdwinfo->initfdwacl, fdwinfo->initrfdwacl);
14524
14525         free(qfdwname);
14526
14527         destroyPQExpBuffer(q);
14528         destroyPQExpBuffer(delq);
14529 }
14530
14531 /*
14532  * dumpForeignServer
14533  *        write out a foreign server definition
14534  */
14535 static void
14536 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
14537 {
14538         DumpOptions *dopt = fout->dopt;
14539         PQExpBuffer q;
14540         PQExpBuffer delq;
14541         PQExpBuffer query;
14542         PGresult   *res;
14543         char       *qsrvname;
14544         char       *fdwname;
14545
14546         /* Skip if not to be dumped */
14547         if (!srvinfo->dobj.dump || dopt->dataOnly)
14548                 return;
14549
14550         q = createPQExpBuffer();
14551         delq = createPQExpBuffer();
14552         query = createPQExpBuffer();
14553
14554         qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
14555
14556         /* look up the foreign-data wrapper */
14557         appendPQExpBuffer(query, "SELECT fdwname "
14558                                           "FROM pg_foreign_data_wrapper w "
14559                                           "WHERE w.oid = '%u'",
14560                                           srvinfo->srvfdw);
14561         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14562         fdwname = PQgetvalue(res, 0, 0);
14563
14564         appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
14565         if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
14566         {
14567                 appendPQExpBufferStr(q, " TYPE ");
14568                 appendStringLiteralAH(q, srvinfo->srvtype, fout);
14569         }
14570         if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
14571         {
14572                 appendPQExpBufferStr(q, " VERSION ");
14573                 appendStringLiteralAH(q, srvinfo->srvversion, fout);
14574         }
14575
14576         appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
14577         appendPQExpBufferStr(q, fmtId(fdwname));
14578
14579         if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
14580                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
14581
14582         appendPQExpBufferStr(q, ";\n");
14583
14584         appendPQExpBuffer(delq, "DROP SERVER %s;\n",
14585                                           qsrvname);
14586
14587         if (dopt->binary_upgrade)
14588                 binary_upgrade_extension_member(q, &srvinfo->dobj,
14589                                                                                 "SERVER", qsrvname, NULL);
14590
14591         if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14592                 ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14593                                          ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
14594                                                                   .owner = srvinfo->rolname,
14595                                                                   .description = "SERVER",
14596                                                                   .section = SECTION_PRE_DATA,
14597                                                                   .createStmt = q->data,
14598                                                                   .dropStmt = delq->data));
14599
14600         /* Dump Foreign Server Comments */
14601         if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14602                 dumpComment(fout, "SERVER", qsrvname,
14603                                         NULL, srvinfo->rolname,
14604                                         srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
14605
14606         /* Handle the ACL */
14607         if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
14608                 dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14609                                 "FOREIGN SERVER", qsrvname, NULL,
14610                                 NULL, srvinfo->rolname,
14611                                 srvinfo->srvacl, srvinfo->rsrvacl,
14612                                 srvinfo->initsrvacl, srvinfo->initrsrvacl);
14613
14614         /* Dump user mappings */
14615         if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
14616                 dumpUserMappings(fout,
14617                                                  srvinfo->dobj.name, NULL,
14618                                                  srvinfo->rolname,
14619                                                  srvinfo->dobj.catId, srvinfo->dobj.dumpId);
14620
14621         free(qsrvname);
14622
14623         destroyPQExpBuffer(q);
14624         destroyPQExpBuffer(delq);
14625         destroyPQExpBuffer(query);
14626 }
14627
14628 /*
14629  * dumpUserMappings
14630  *
14631  * This routine is used to dump any user mappings associated with the
14632  * server handed to this routine. Should be called after ArchiveEntry()
14633  * for the server.
14634  */
14635 static void
14636 dumpUserMappings(Archive *fout,
14637                                  const char *servername, const char *namespace,
14638                                  const char *owner,
14639                                  CatalogId catalogId, DumpId dumpId)
14640 {
14641         PQExpBuffer q;
14642         PQExpBuffer delq;
14643         PQExpBuffer query;
14644         PQExpBuffer tag;
14645         PGresult   *res;
14646         int                     ntups;
14647         int                     i_usename;
14648         int                     i_umoptions;
14649         int                     i;
14650
14651         q = createPQExpBuffer();
14652         tag = createPQExpBuffer();
14653         delq = createPQExpBuffer();
14654         query = createPQExpBuffer();
14655
14656         /*
14657          * We read from the publicly accessible view pg_user_mappings, so as not
14658          * to fail if run by a non-superuser.  Note that the view will show
14659          * umoptions as null if the user hasn't got privileges for the associated
14660          * server; this means that pg_dump will dump such a mapping, but with no
14661          * OPTIONS clause.  A possible alternative is to skip such mappings
14662          * altogether, but it's not clear that that's an improvement.
14663          */
14664         appendPQExpBuffer(query,
14665                                           "SELECT usename, "
14666                                           "array_to_string(ARRAY("
14667                                           "SELECT quote_ident(option_name) || ' ' || "
14668                                           "quote_literal(option_value) "
14669                                           "FROM pg_options_to_table(umoptions) "
14670                                           "ORDER BY option_name"
14671                                           "), E',\n    ') AS umoptions "
14672                                           "FROM pg_user_mappings "
14673                                           "WHERE srvid = '%u' "
14674                                           "ORDER BY usename",
14675                                           catalogId.oid);
14676
14677         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14678
14679         ntups = PQntuples(res);
14680         i_usename = PQfnumber(res, "usename");
14681         i_umoptions = PQfnumber(res, "umoptions");
14682
14683         for (i = 0; i < ntups; i++)
14684         {
14685                 char       *usename;
14686                 char       *umoptions;
14687
14688                 usename = PQgetvalue(res, i, i_usename);
14689                 umoptions = PQgetvalue(res, i, i_umoptions);
14690
14691                 resetPQExpBuffer(q);
14692                 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
14693                 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
14694
14695                 if (umoptions && strlen(umoptions) > 0)
14696                         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
14697
14698                 appendPQExpBufferStr(q, ";\n");
14699
14700                 resetPQExpBuffer(delq);
14701                 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
14702                 appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
14703
14704                 resetPQExpBuffer(tag);
14705                 appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
14706                                                   usename, servername);
14707
14708                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14709                                          ARCHIVE_OPTS(.tag = tag->data,
14710                                                                   .namespace = namespace,
14711                                                                   .owner = owner,
14712                                                                   .description = "USER MAPPING",
14713                                                                   .section = SECTION_PRE_DATA,
14714                                                                   .createStmt = q->data,
14715                                                                   .dropStmt = delq->data));
14716         }
14717
14718         PQclear(res);
14719
14720         destroyPQExpBuffer(query);
14721         destroyPQExpBuffer(delq);
14722         destroyPQExpBuffer(tag);
14723         destroyPQExpBuffer(q);
14724 }
14725
14726 /*
14727  * Write out default privileges information
14728  */
14729 static void
14730 dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
14731 {
14732         DumpOptions *dopt = fout->dopt;
14733         PQExpBuffer q;
14734         PQExpBuffer tag;
14735         const char *type;
14736
14737         /* Skip if not to be dumped */
14738         if (!daclinfo->dobj.dump || dopt->dataOnly || dopt->aclsSkip)
14739                 return;
14740
14741         q = createPQExpBuffer();
14742         tag = createPQExpBuffer();
14743
14744         switch (daclinfo->defaclobjtype)
14745         {
14746                 case DEFACLOBJ_RELATION:
14747                         type = "TABLES";
14748                         break;
14749                 case DEFACLOBJ_SEQUENCE:
14750                         type = "SEQUENCES";
14751                         break;
14752                 case DEFACLOBJ_FUNCTION:
14753                         type = "FUNCTIONS";
14754                         break;
14755                 case DEFACLOBJ_TYPE:
14756                         type = "TYPES";
14757                         break;
14758                 case DEFACLOBJ_NAMESPACE:
14759                         type = "SCHEMAS";
14760                         break;
14761                 default:
14762                         /* shouldn't get here */
14763                         fatal("unrecognized object type in default privileges: %d",
14764                                                   (int) daclinfo->defaclobjtype);
14765                         type = "";                      /* keep compiler quiet */
14766         }
14767
14768         appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
14769
14770         /* build the actual command(s) for this tuple */
14771         if (!buildDefaultACLCommands(type,
14772                                                                  daclinfo->dobj.namespace != NULL ?
14773                                                                  daclinfo->dobj.namespace->dobj.name : NULL,
14774                                                                  daclinfo->defaclacl,
14775                                                                  daclinfo->rdefaclacl,
14776                                                                  daclinfo->initdefaclacl,
14777                                                                  daclinfo->initrdefaclacl,
14778                                                                  daclinfo->defaclrole,
14779                                                                  fout->remoteVersion,
14780                                                                  q))
14781                 fatal("could not parse default ACL list (%s)",
14782                                           daclinfo->defaclacl);
14783
14784         if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
14785                 ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
14786                                          ARCHIVE_OPTS(.tag = tag->data,
14787                                                                   .namespace = daclinfo->dobj.namespace ?
14788                                                                   daclinfo->dobj.namespace->dobj.name : NULL,
14789                                                                   .owner = daclinfo->defaclrole,
14790                                                                   .description = "DEFAULT ACL",
14791                                                                   .section = SECTION_POST_DATA,
14792                                                                   .createStmt = q->data));
14793
14794         destroyPQExpBuffer(tag);
14795         destroyPQExpBuffer(q);
14796 }
14797
14798 /*----------
14799  * Write out grant/revoke information
14800  *
14801  * 'objCatId' is the catalog ID of the underlying object.
14802  * 'objDumpId' is the dump ID of the underlying object.
14803  * 'type' must be one of
14804  *              TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
14805  *              FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
14806  * 'name' is the formatted name of the object.  Must be quoted etc. already.
14807  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
14808  *              (Currently we assume that subname is only provided for table columns.)
14809  * 'nspname' is the namespace the object is in (NULL if none).
14810  * 'owner' is the owner, NULL if there is no owner (for languages).
14811  * 'acls' contains the ACL string of the object from the appropriate system
14812  *              catalog field; it will be passed to buildACLCommands for building the
14813  *              appropriate GRANT commands.
14814  * 'racls' contains the ACL string of any initial-but-now-revoked ACLs of the
14815  *              object; it will be passed to buildACLCommands for building the
14816  *              appropriate REVOKE commands.
14817  * 'initacls' In binary-upgrade mode, ACL string of the object's initial
14818  *              privileges, to be recorded into pg_init_privs
14819  * 'initracls' In binary-upgrade mode, ACL string of the object's
14820  *              revoked-from-default privileges, to be recorded into pg_init_privs
14821  *
14822  * NB: initacls/initracls are needed because extensions can set privileges on
14823  * an object during the extension's script file and we record those into
14824  * pg_init_privs as that object's initial privileges.
14825  *----------
14826  */
14827 static void
14828 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
14829                 const char *type, const char *name, const char *subname,
14830                 const char *nspname, const char *owner,
14831                 const char *acls, const char *racls,
14832                 const char *initacls, const char *initracls)
14833 {
14834         DumpOptions *dopt = fout->dopt;
14835         PQExpBuffer sql;
14836
14837         /* Do nothing if ACL dump is not enabled */
14838         if (dopt->aclsSkip)
14839                 return;
14840
14841         /* --data-only skips ACLs *except* BLOB ACLs */
14842         if (dopt->dataOnly && strcmp(type, "LARGE OBJECT") != 0)
14843                 return;
14844
14845         sql = createPQExpBuffer();
14846
14847         /*
14848          * Check to see if this object has had any initial ACLs included for it.
14849          * If so, we are in binary upgrade mode and these are the ACLs to turn
14850          * into GRANT and REVOKE statements to set and record the initial
14851          * privileges for an extension object.  Let the backend know that these
14852          * are to be recorded by calling binary_upgrade_set_record_init_privs()
14853          * before and after.
14854          */
14855         if (strlen(initacls) != 0 || strlen(initracls) != 0)
14856         {
14857                 appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
14858                 if (!buildACLCommands(name, subname, nspname, type,
14859                                                           initacls, initracls, owner,
14860                                                           "", fout->remoteVersion, sql))
14861                         fatal("could not parse initial GRANT ACL list (%s) or initial REVOKE ACL list (%s) for object \"%s\" (%s)",
14862                                                   initacls, initracls, name, type);
14863                 appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
14864         }
14865
14866         if (!buildACLCommands(name, subname, nspname, type,
14867                                                   acls, racls, owner,
14868                                                   "", fout->remoteVersion, sql))
14869                 fatal("could not parse GRANT ACL list (%s) or REVOKE ACL list (%s) for object \"%s\" (%s)",
14870                                           acls, racls, name, type);
14871
14872         if (sql->len > 0)
14873         {
14874                 PQExpBuffer tag = createPQExpBuffer();
14875
14876                 if (subname)
14877                         appendPQExpBuffer(tag, "COLUMN %s.%s", name, subname);
14878                 else
14879                         appendPQExpBuffer(tag, "%s %s", type, name);
14880
14881                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14882                                          ARCHIVE_OPTS(.tag = tag->data,
14883                                                                   .namespace = nspname,
14884                                                                   .owner = owner,
14885                                                                   .description = "ACL",
14886                                                                   .section = SECTION_NONE,
14887                                                                   .createStmt = sql->data,
14888                                                                   .deps = &objDumpId,
14889                                                                   .nDeps = 1));
14890                 destroyPQExpBuffer(tag);
14891         }
14892
14893         destroyPQExpBuffer(sql);
14894 }
14895
14896 /*
14897  * dumpSecLabel
14898  *
14899  * This routine is used to dump any security labels associated with the
14900  * object handed to this routine. The routine takes the object type
14901  * and object name (ready to print, except for schema decoration), plus
14902  * the namespace and owner of the object (for labeling the ArchiveEntry),
14903  * plus catalog ID and subid which are the lookup key for pg_seclabel,
14904  * plus the dump ID for the object (for setting a dependency).
14905  * If a matching pg_seclabel entry is found, it is dumped.
14906  *
14907  * Note: although this routine takes a dumpId for dependency purposes,
14908  * that purpose is just to mark the dependency in the emitted dump file
14909  * for possible future use by pg_restore.  We do NOT use it for determining
14910  * ordering of the label in the dump file, because this routine is called
14911  * after dependency sorting occurs.  This routine should be called just after
14912  * calling ArchiveEntry() for the specified object.
14913  */
14914 static void
14915 dumpSecLabel(Archive *fout, const char *type, const char *name,
14916                          const char *namespace, const char *owner,
14917                          CatalogId catalogId, int subid, DumpId dumpId)
14918 {
14919         DumpOptions *dopt = fout->dopt;
14920         SecLabelItem *labels;
14921         int                     nlabels;
14922         int                     i;
14923         PQExpBuffer query;
14924
14925         /* do nothing, if --no-security-labels is supplied */
14926         if (dopt->no_security_labels)
14927                 return;
14928
14929         /* Security labels are schema not data ... except blob labels are data */
14930         if (strcmp(type, "LARGE OBJECT") != 0)
14931         {
14932                 if (dopt->dataOnly)
14933                         return;
14934         }
14935         else
14936         {
14937                 /* We do dump blob security labels in binary-upgrade mode */
14938                 if (dopt->schemaOnly && !dopt->binary_upgrade)
14939                         return;
14940         }
14941
14942         /* Search for security labels associated with catalogId, using table */
14943         nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
14944
14945         query = createPQExpBuffer();
14946
14947         for (i = 0; i < nlabels; i++)
14948         {
14949                 /*
14950                  * Ignore label entries for which the subid doesn't match.
14951                  */
14952                 if (labels[i].objsubid != subid)
14953                         continue;
14954
14955                 appendPQExpBuffer(query,
14956                                                   "SECURITY LABEL FOR %s ON %s ",
14957                                                   fmtId(labels[i].provider), type);
14958                 if (namespace && *namespace)
14959                         appendPQExpBuffer(query, "%s.", fmtId(namespace));
14960                 appendPQExpBuffer(query, "%s IS ", name);
14961                 appendStringLiteralAH(query, labels[i].label, fout);
14962                 appendPQExpBufferStr(query, ";\n");
14963         }
14964
14965         if (query->len > 0)
14966         {
14967                 PQExpBuffer tag = createPQExpBuffer();
14968
14969                 appendPQExpBuffer(tag, "%s %s", type, name);
14970                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14971                                          ARCHIVE_OPTS(.tag = tag->data,
14972                                                                   .namespace = namespace,
14973                                                                   .owner = owner,
14974                                                                   .description = "SECURITY LABEL",
14975                                                                   .section = SECTION_NONE,
14976                                                                   .createStmt = query->data,
14977                                                                   .deps = &dumpId,
14978                                                                   .nDeps = 1));
14979                 destroyPQExpBuffer(tag);
14980         }
14981
14982         destroyPQExpBuffer(query);
14983 }
14984
14985 /*
14986  * dumpTableSecLabel
14987  *
14988  * As above, but dump security label for both the specified table (or view)
14989  * and its columns.
14990  */
14991 static void
14992 dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
14993 {
14994         DumpOptions *dopt = fout->dopt;
14995         SecLabelItem *labels;
14996         int                     nlabels;
14997         int                     i;
14998         PQExpBuffer query;
14999         PQExpBuffer target;
15000
15001         /* do nothing, if --no-security-labels is supplied */
15002         if (dopt->no_security_labels)
15003                 return;
15004
15005         /* SecLabel are SCHEMA not data */
15006         if (dopt->dataOnly)
15007                 return;
15008
15009         /* Search for comments associated with relation, using table */
15010         nlabels = findSecLabels(fout,
15011                                                         tbinfo->dobj.catId.tableoid,
15012                                                         tbinfo->dobj.catId.oid,
15013                                                         &labels);
15014
15015         /* If security labels exist, build SECURITY LABEL statements */
15016         if (nlabels <= 0)
15017                 return;
15018
15019         query = createPQExpBuffer();
15020         target = createPQExpBuffer();
15021
15022         for (i = 0; i < nlabels; i++)
15023         {
15024                 const char *colname;
15025                 const char *provider = labels[i].provider;
15026                 const char *label = labels[i].label;
15027                 int                     objsubid = labels[i].objsubid;
15028
15029                 resetPQExpBuffer(target);
15030                 if (objsubid == 0)
15031                 {
15032                         appendPQExpBuffer(target, "%s %s", reltypename,
15033                                                           fmtQualifiedDumpable(tbinfo));
15034                 }
15035                 else
15036                 {
15037                         colname = getAttrName(objsubid, tbinfo);
15038                         /* first fmtXXX result must be consumed before calling again */
15039                         appendPQExpBuffer(target, "COLUMN %s",
15040                                                           fmtQualifiedDumpable(tbinfo));
15041                         appendPQExpBuffer(target, ".%s", fmtId(colname));
15042                 }
15043                 appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
15044                                                   fmtId(provider), target->data);
15045                 appendStringLiteralAH(query, label, fout);
15046                 appendPQExpBufferStr(query, ";\n");
15047         }
15048         if (query->len > 0)
15049         {
15050                 resetPQExpBuffer(target);
15051                 appendPQExpBuffer(target, "%s %s", reltypename,
15052                                                   fmtId(tbinfo->dobj.name));
15053                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
15054                                          ARCHIVE_OPTS(.tag = target->data,
15055                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
15056                                                                   .owner = tbinfo->rolname,
15057                                                                   .description = "SECURITY LABEL",
15058                                                                   .section = SECTION_NONE,
15059                                                                   .createStmt = query->data,
15060                                                                   .deps = &(tbinfo->dobj.dumpId),
15061                                                                   .nDeps = 1));
15062         }
15063         destroyPQExpBuffer(query);
15064         destroyPQExpBuffer(target);
15065 }
15066
15067 /*
15068  * findSecLabels
15069  *
15070  * Find the security label(s), if any, associated with the given object.
15071  * All the objsubid values associated with the given classoid/objoid are
15072  * found with one search.
15073  */
15074 static int
15075 findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
15076 {
15077         /* static storage for table of security labels */
15078         static SecLabelItem *labels = NULL;
15079         static int      nlabels = -1;
15080
15081         SecLabelItem *middle = NULL;
15082         SecLabelItem *low;
15083         SecLabelItem *high;
15084         int                     nmatch;
15085
15086         /* Get security labels if we didn't already */
15087         if (nlabels < 0)
15088                 nlabels = collectSecLabels(fout, &labels);
15089
15090         if (nlabels <= 0)                       /* no labels, so no match is possible */
15091         {
15092                 *items = NULL;
15093                 return 0;
15094         }
15095
15096         /*
15097          * Do binary search to find some item matching the object.
15098          */
15099         low = &labels[0];
15100         high = &labels[nlabels - 1];
15101         while (low <= high)
15102         {
15103                 middle = low + (high - low) / 2;
15104
15105                 if (classoid < middle->classoid)
15106                         high = middle - 1;
15107                 else if (classoid > middle->classoid)
15108                         low = middle + 1;
15109                 else if (objoid < middle->objoid)
15110                         high = middle - 1;
15111                 else if (objoid > middle->objoid)
15112                         low = middle + 1;
15113                 else
15114                         break;                          /* found a match */
15115         }
15116
15117         if (low > high)                         /* no matches */
15118         {
15119                 *items = NULL;
15120                 return 0;
15121         }
15122
15123         /*
15124          * Now determine how many items match the object.  The search loop
15125          * invariant still holds: only items between low and high inclusive could
15126          * match.
15127          */
15128         nmatch = 1;
15129         while (middle > low)
15130         {
15131                 if (classoid != middle[-1].classoid ||
15132                         objoid != middle[-1].objoid)
15133                         break;
15134                 middle--;
15135                 nmatch++;
15136         }
15137
15138         *items = middle;
15139
15140         middle += nmatch;
15141         while (middle <= high)
15142         {
15143                 if (classoid != middle->classoid ||
15144                         objoid != middle->objoid)
15145                         break;
15146                 middle++;
15147                 nmatch++;
15148         }
15149
15150         return nmatch;
15151 }
15152
15153 /*
15154  * collectSecLabels
15155  *
15156  * Construct a table of all security labels available for database objects.
15157  * It's much faster to pull them all at once.
15158  *
15159  * The table is sorted by classoid/objid/objsubid for speed in lookup.
15160  */
15161 static int
15162 collectSecLabels(Archive *fout, SecLabelItem **items)
15163 {
15164         PGresult   *res;
15165         PQExpBuffer query;
15166         int                     i_label;
15167         int                     i_provider;
15168         int                     i_classoid;
15169         int                     i_objoid;
15170         int                     i_objsubid;
15171         int                     ntups;
15172         int                     i;
15173         SecLabelItem *labels;
15174
15175         query = createPQExpBuffer();
15176
15177         appendPQExpBufferStr(query,
15178                                                  "SELECT label, provider, classoid, objoid, objsubid "
15179                                                  "FROM pg_catalog.pg_seclabel "
15180                                                  "ORDER BY classoid, objoid, objsubid");
15181
15182         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15183
15184         /* Construct lookup table containing OIDs in numeric form */
15185         i_label = PQfnumber(res, "label");
15186         i_provider = PQfnumber(res, "provider");
15187         i_classoid = PQfnumber(res, "classoid");
15188         i_objoid = PQfnumber(res, "objoid");
15189         i_objsubid = PQfnumber(res, "objsubid");
15190
15191         ntups = PQntuples(res);
15192
15193         labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
15194
15195         for (i = 0; i < ntups; i++)
15196         {
15197                 labels[i].label = PQgetvalue(res, i, i_label);
15198                 labels[i].provider = PQgetvalue(res, i, i_provider);
15199                 labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
15200                 labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
15201                 labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
15202         }
15203
15204         /* Do NOT free the PGresult since we are keeping pointers into it */
15205         destroyPQExpBuffer(query);
15206
15207         *items = labels;
15208         return ntups;
15209 }
15210
15211 /*
15212  * dumpTable
15213  *        write out to fout the declarations (not data) of a user-defined table
15214  */
15215 static void
15216 dumpTable(Archive *fout, TableInfo *tbinfo)
15217 {
15218         DumpOptions *dopt = fout->dopt;
15219         char       *namecopy;
15220
15221         /*
15222          * noop if we are not dumping anything about this table, or if we are
15223          * doing a data-only dump
15224          */
15225         if (!tbinfo->dobj.dump || dopt->dataOnly)
15226                 return;
15227
15228         if (tbinfo->relkind == RELKIND_SEQUENCE)
15229                 dumpSequence(fout, tbinfo);
15230         else
15231                 dumpTableSchema(fout, tbinfo);
15232
15233         /* Handle the ACL here */
15234         namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
15235         if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15236         {
15237                 const char *objtype =
15238                 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
15239
15240                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
15241                                 objtype, namecopy, NULL,
15242                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15243                                 tbinfo->relacl, tbinfo->rrelacl,
15244                                 tbinfo->initrelacl, tbinfo->initrrelacl);
15245         }
15246
15247         /*
15248          * Handle column ACLs, if any.  Note: we pull these with a separate query
15249          * rather than trying to fetch them during getTableAttrs, so that we won't
15250          * miss ACLs on system columns.
15251          */
15252         if (fout->remoteVersion >= 80400 && tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15253         {
15254                 PQExpBuffer query = createPQExpBuffer();
15255                 PGresult   *res;
15256                 int                     i;
15257
15258                 if (fout->remoteVersion >= 90600)
15259                 {
15260                         PQExpBuffer acl_subquery = createPQExpBuffer();
15261                         PQExpBuffer racl_subquery = createPQExpBuffer();
15262                         PQExpBuffer initacl_subquery = createPQExpBuffer();
15263                         PQExpBuffer initracl_subquery = createPQExpBuffer();
15264
15265                         buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
15266                                                         initracl_subquery, "at.attacl", "c.relowner", "'c'",
15267                                                         dopt->binary_upgrade);
15268
15269                         appendPQExpBuffer(query,
15270                                                           "SELECT at.attname, "
15271                                                           "%s AS attacl, "
15272                                                           "%s AS rattacl, "
15273                                                           "%s AS initattacl, "
15274                                                           "%s AS initrattacl "
15275                                                           "FROM pg_catalog.pg_attribute at "
15276                                                           "JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
15277                                                           "LEFT JOIN pg_catalog.pg_init_privs pip ON "
15278                                                           "(at.attrelid = pip.objoid "
15279                                                           "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
15280                                                           "AND at.attnum = pip.objsubid) "
15281                                                           "WHERE at.attrelid = '%u'::pg_catalog.oid AND "
15282                                                           "NOT at.attisdropped "
15283                                                           "AND ("
15284                                                           "%s IS NOT NULL OR "
15285                                                           "%s IS NOT NULL OR "
15286                                                           "%s IS NOT NULL OR "
15287                                                           "%s IS NOT NULL)"
15288                                                           "ORDER BY at.attnum",
15289                                                           acl_subquery->data,
15290                                                           racl_subquery->data,
15291                                                           initacl_subquery->data,
15292                                                           initracl_subquery->data,
15293                                                           tbinfo->dobj.catId.oid,
15294                                                           acl_subquery->data,
15295                                                           racl_subquery->data,
15296                                                           initacl_subquery->data,
15297                                                           initracl_subquery->data);
15298
15299                         destroyPQExpBuffer(acl_subquery);
15300                         destroyPQExpBuffer(racl_subquery);
15301                         destroyPQExpBuffer(initacl_subquery);
15302                         destroyPQExpBuffer(initracl_subquery);
15303                 }
15304                 else
15305                 {
15306                         appendPQExpBuffer(query,
15307                                                           "SELECT attname, attacl, NULL as rattacl, "
15308                                                           "NULL AS initattacl, NULL AS initrattacl "
15309                                                           "FROM pg_catalog.pg_attribute "
15310                                                           "WHERE attrelid = '%u'::pg_catalog.oid AND NOT attisdropped "
15311                                                           "AND attacl IS NOT NULL "
15312                                                           "ORDER BY attnum",
15313                                                           tbinfo->dobj.catId.oid);
15314                 }
15315
15316                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15317
15318                 for (i = 0; i < PQntuples(res); i++)
15319                 {
15320                         char       *attname = PQgetvalue(res, i, 0);
15321                         char       *attacl = PQgetvalue(res, i, 1);
15322                         char       *rattacl = PQgetvalue(res, i, 2);
15323                         char       *initattacl = PQgetvalue(res, i, 3);
15324                         char       *initrattacl = PQgetvalue(res, i, 4);
15325                         char       *attnamecopy;
15326
15327                         attnamecopy = pg_strdup(fmtId(attname));
15328                         /* Column's GRANT type is always TABLE */
15329                         dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
15330                                         "TABLE", namecopy, attnamecopy,
15331                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15332                                         attacl, rattacl, initattacl, initrattacl);
15333                         free(attnamecopy);
15334                 }
15335                 PQclear(res);
15336                 destroyPQExpBuffer(query);
15337         }
15338
15339         free(namecopy);
15340
15341         return;
15342 }
15343
15344 /*
15345  * Create the AS clause for a view or materialized view. The semicolon is
15346  * stripped because a materialized view must add a WITH NO DATA clause.
15347  *
15348  * This returns a new buffer which must be freed by the caller.
15349  */
15350 static PQExpBuffer
15351 createViewAsClause(Archive *fout, TableInfo *tbinfo)
15352 {
15353         PQExpBuffer query = createPQExpBuffer();
15354         PQExpBuffer result = createPQExpBuffer();
15355         PGresult   *res;
15356         int                     len;
15357
15358         /* Fetch the view definition */
15359         appendPQExpBuffer(query,
15360                                           "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
15361                                           tbinfo->dobj.catId.oid);
15362
15363         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15364
15365         if (PQntuples(res) != 1)
15366         {
15367                 if (PQntuples(res) < 1)
15368                         fatal("query to obtain definition of view \"%s\" returned no data",
15369                                                   tbinfo->dobj.name);
15370                 else
15371                         fatal("query to obtain definition of view \"%s\" returned more than one definition",
15372                                                   tbinfo->dobj.name);
15373         }
15374
15375         len = PQgetlength(res, 0, 0);
15376
15377         if (len == 0)
15378                 fatal("definition of view \"%s\" appears to be empty (length zero)",
15379                                           tbinfo->dobj.name);
15380
15381         /* Strip off the trailing semicolon so that other things may follow. */
15382         Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
15383         appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
15384
15385         PQclear(res);
15386         destroyPQExpBuffer(query);
15387
15388         return result;
15389 }
15390
15391 /*
15392  * Create a dummy AS clause for a view.  This is used when the real view
15393  * definition has to be postponed because of circular dependencies.
15394  * We must duplicate the view's external properties -- column names and types
15395  * (including collation) -- so that it works for subsequent references.
15396  *
15397  * This returns a new buffer which must be freed by the caller.
15398  */
15399 static PQExpBuffer
15400 createDummyViewAsClause(Archive *fout, TableInfo *tbinfo)
15401 {
15402         PQExpBuffer result = createPQExpBuffer();
15403         int                     j;
15404
15405         appendPQExpBufferStr(result, "SELECT");
15406
15407         for (j = 0; j < tbinfo->numatts; j++)
15408         {
15409                 if (j > 0)
15410                         appendPQExpBufferChar(result, ',');
15411                 appendPQExpBufferStr(result, "\n    ");
15412
15413                 appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
15414
15415                 /*
15416                  * Must add collation if not default for the type, because CREATE OR
15417                  * REPLACE VIEW won't change it
15418                  */
15419                 if (OidIsValid(tbinfo->attcollation[j]))
15420                 {
15421                         CollInfo   *coll;
15422
15423                         coll = findCollationByOid(tbinfo->attcollation[j]);
15424                         if (coll)
15425                                 appendPQExpBuffer(result, " COLLATE %s",
15426                                                                   fmtQualifiedDumpable(coll));
15427                 }
15428
15429                 appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
15430         }
15431
15432         return result;
15433 }
15434
15435 /*
15436  * dumpTableSchema
15437  *        write the declaration (not data) of one user-defined table or view
15438  */
15439 static void
15440 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
15441 {
15442         DumpOptions *dopt = fout->dopt;
15443         PQExpBuffer q = createPQExpBuffer();
15444         PQExpBuffer delq = createPQExpBuffer();
15445         char       *qrelname;
15446         char       *qualrelname;
15447         int                     numParents;
15448         TableInfo **parents;
15449         int                     actual_atts;    /* number of attrs in this CREATE statement */
15450         const char *reltypename;
15451         char       *storage;
15452         int                     j,
15453                                 k;
15454
15455         qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
15456         qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
15457
15458
15459         if (tbinfo->hasoids)
15460                 pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
15461                                   qrelname);
15462
15463         if (dopt->binary_upgrade)
15464                 binary_upgrade_set_type_oids_by_rel_oid(fout, q,
15465                                                                                                 tbinfo->dobj.catId.oid);
15466
15467         /* Is it a table or a view? */
15468         if (tbinfo->relkind == RELKIND_VIEW)
15469         {
15470                 PQExpBuffer result;
15471
15472                 /*
15473                  * Note: keep this code in sync with the is_view case in dumpRule()
15474                  */
15475
15476                 reltypename = "VIEW";
15477
15478                 appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
15479
15480                 if (dopt->binary_upgrade)
15481                         binary_upgrade_set_pg_class_oids(fout, q,
15482                                                                                          tbinfo->dobj.catId.oid, false);
15483
15484                 appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
15485
15486                 if (tbinfo->dummy_view)
15487                         result = createDummyViewAsClause(fout, tbinfo);
15488                 else
15489                 {
15490                         if (nonemptyReloptions(tbinfo->reloptions))
15491                         {
15492                                 appendPQExpBufferStr(q, " WITH (");
15493                                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15494                                 appendPQExpBufferChar(q, ')');
15495                         }
15496                         result = createViewAsClause(fout, tbinfo);
15497                 }
15498                 appendPQExpBuffer(q, " AS\n%s", result->data);
15499                 destroyPQExpBuffer(result);
15500
15501                 if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
15502                         appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
15503                 appendPQExpBufferStr(q, ";\n");
15504         }
15505         else
15506         {
15507                 char       *ftoptions = NULL;
15508                 char       *srvname = NULL;
15509
15510                 switch (tbinfo->relkind)
15511                 {
15512                         case RELKIND_FOREIGN_TABLE:
15513                                 {
15514                                         PQExpBuffer query = createPQExpBuffer();
15515                                         PGresult   *res;
15516                                         int                     i_srvname;
15517                                         int                     i_ftoptions;
15518
15519                                         reltypename = "FOREIGN TABLE";
15520
15521                                         /* retrieve name of foreign server and generic options */
15522                                         appendPQExpBuffer(query,
15523                                                                           "SELECT fs.srvname, "
15524                                                                           "pg_catalog.array_to_string(ARRAY("
15525                                                                           "SELECT pg_catalog.quote_ident(option_name) || "
15526                                                                           "' ' || pg_catalog.quote_literal(option_value) "
15527                                                                           "FROM pg_catalog.pg_options_to_table(ftoptions) "
15528                                                                           "ORDER BY option_name"
15529                                                                           "), E',\n    ') AS ftoptions "
15530                                                                           "FROM pg_catalog.pg_foreign_table ft "
15531                                                                           "JOIN pg_catalog.pg_foreign_server fs "
15532                                                                           "ON (fs.oid = ft.ftserver) "
15533                                                                           "WHERE ft.ftrelid = '%u'",
15534                                                                           tbinfo->dobj.catId.oid);
15535                                         res = ExecuteSqlQueryForSingleRow(fout, query->data);
15536                                         i_srvname = PQfnumber(res, "srvname");
15537                                         i_ftoptions = PQfnumber(res, "ftoptions");
15538                                         srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
15539                                         ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
15540                                         PQclear(res);
15541                                         destroyPQExpBuffer(query);
15542                                         break;
15543                                 }
15544                         case RELKIND_MATVIEW:
15545                                 reltypename = "MATERIALIZED VIEW";
15546                                 break;
15547                         default:
15548                                 reltypename = "TABLE";
15549                 }
15550
15551                 numParents = tbinfo->numParents;
15552                 parents = tbinfo->parents;
15553
15554                 appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
15555
15556                 if (dopt->binary_upgrade)
15557                         binary_upgrade_set_pg_class_oids(fout, q,
15558                                                                                          tbinfo->dobj.catId.oid, false);
15559
15560                 appendPQExpBuffer(q, "CREATE %s%s %s",
15561                                                   tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
15562                                                   "UNLOGGED " : "",
15563                                                   reltypename,
15564                                                   qualrelname);
15565
15566                 /*
15567                  * Attach to type, if reloftype; except in case of a binary upgrade,
15568                  * we dump the table normally and attach it to the type afterward.
15569                  */
15570                 if (tbinfo->reloftype && !dopt->binary_upgrade)
15571                         appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
15572
15573                 if (tbinfo->relkind != RELKIND_MATVIEW)
15574                 {
15575                         /* Dump the attributes */
15576                         actual_atts = 0;
15577                         for (j = 0; j < tbinfo->numatts; j++)
15578                         {
15579                                 /*
15580                                  * Normally, dump if it's locally defined in this table, and
15581                                  * not dropped.  But for binary upgrade, we'll dump all the
15582                                  * columns, and then fix up the dropped and nonlocal cases
15583                                  * below.
15584                                  */
15585                                 if (shouldPrintColumn(dopt, tbinfo, j))
15586                                 {
15587                                         /*
15588                                          * Default value --- suppress if to be printed separately.
15589                                          */
15590                                         bool            has_default = (tbinfo->attrdefs[j] != NULL &&
15591                                                                                            !tbinfo->attrdefs[j]->separate);
15592
15593                                         /*
15594                                          * Not Null constraint --- suppress if inherited, except
15595                                          * in binary-upgrade case where that won't work.
15596                                          */
15597                                         bool            has_notnull = (tbinfo->notnull[j] &&
15598                                                                                            (!tbinfo->inhNotNull[j] ||
15599                                                                                                 dopt->binary_upgrade));
15600
15601                                         /* Skip column if fully defined by reloftype */
15602                                         if (tbinfo->reloftype && !has_default && !has_notnull &&
15603                                                 !dopt->binary_upgrade)
15604                                                 continue;
15605
15606                                         /* Format properly if not first attr */
15607                                         if (actual_atts == 0)
15608                                                 appendPQExpBufferStr(q, " (");
15609                                         else
15610                                                 appendPQExpBufferChar(q, ',');
15611                                         appendPQExpBufferStr(q, "\n    ");
15612                                         actual_atts++;
15613
15614                                         /* Attribute name */
15615                                         appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
15616
15617                                         if (tbinfo->attisdropped[j])
15618                                         {
15619                                                 /*
15620                                                  * ALTER TABLE DROP COLUMN clears
15621                                                  * pg_attribute.atttypid, so we will not have gotten a
15622                                                  * valid type name; insert INTEGER as a stopgap. We'll
15623                                                  * clean things up later.
15624                                                  */
15625                                                 appendPQExpBufferStr(q, " INTEGER /* dummy */");
15626                                                 /* and skip to the next column */
15627                                                 continue;
15628                                         }
15629
15630                                         /*
15631                                          * Attribute type; print it except when creating a typed
15632                                          * table ('OF type_name'), but in binary-upgrade mode,
15633                                          * print it in that case too.
15634                                          */
15635                                         if (dopt->binary_upgrade || !tbinfo->reloftype)
15636                                         {
15637                                                 appendPQExpBuffer(q, " %s",
15638                                                                                   tbinfo->atttypnames[j]);
15639                                         }
15640
15641                                         if (has_default)
15642                                         {
15643                                                 if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
15644                                                         appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
15645                                                                                           tbinfo->attrdefs[j]->adef_expr);
15646                                                 else
15647                                                         appendPQExpBuffer(q, " DEFAULT %s",
15648                                                                                           tbinfo->attrdefs[j]->adef_expr);
15649                                         }
15650
15651
15652                                         if (has_notnull)
15653                                                 appendPQExpBufferStr(q, " NOT NULL");
15654
15655                                         /* Add collation if not default for the type */
15656                                         if (OidIsValid(tbinfo->attcollation[j]))
15657                                         {
15658                                                 CollInfo   *coll;
15659
15660                                                 coll = findCollationByOid(tbinfo->attcollation[j]);
15661                                                 if (coll)
15662                                                         appendPQExpBuffer(q, " COLLATE %s",
15663                                                                                           fmtQualifiedDumpable(coll));
15664                                         }
15665                                 }
15666                         }
15667
15668                         /*
15669                          * Add non-inherited CHECK constraints, if any.
15670                          */
15671                         for (j = 0; j < tbinfo->ncheck; j++)
15672                         {
15673                                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
15674
15675                                 if (constr->separate || !constr->conislocal)
15676                                         continue;
15677
15678                                 if (actual_atts == 0)
15679                                         appendPQExpBufferStr(q, " (\n    ");
15680                                 else
15681                                         appendPQExpBufferStr(q, ",\n    ");
15682
15683                                 appendPQExpBuffer(q, "CONSTRAINT %s ",
15684                                                                   fmtId(constr->dobj.name));
15685                                 appendPQExpBufferStr(q, constr->condef);
15686
15687                                 actual_atts++;
15688                         }
15689
15690                         if (actual_atts)
15691                                 appendPQExpBufferStr(q, "\n)");
15692                         else if (!(tbinfo->reloftype && !dopt->binary_upgrade))
15693                         {
15694                                 /*
15695                                  * No attributes? we must have a parenthesized attribute list,
15696                                  * even though empty, when not using the OF TYPE syntax.
15697                                  */
15698                                 appendPQExpBufferStr(q, " (\n)");
15699                         }
15700
15701                         /*
15702                          * Emit the INHERITS clause (not for partitions), except in
15703                          * binary-upgrade mode.
15704                          */
15705                         if (numParents > 0 && !tbinfo->ispartition &&
15706                                 !dopt->binary_upgrade)
15707                         {
15708                                 appendPQExpBufferStr(q, "\nINHERITS (");
15709                                 for (k = 0; k < numParents; k++)
15710                                 {
15711                                         TableInfo  *parentRel = parents[k];
15712
15713                                         if (k > 0)
15714                                                 appendPQExpBufferStr(q, ", ");
15715                                         appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
15716                                 }
15717                                 appendPQExpBufferChar(q, ')');
15718                         }
15719
15720                         if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15721                                 appendPQExpBuffer(q, "\nPARTITION BY %s", tbinfo->partkeydef);
15722
15723                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
15724                                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
15725                 }
15726
15727                 if (nonemptyReloptions(tbinfo->reloptions) ||
15728                         nonemptyReloptions(tbinfo->toast_reloptions))
15729                 {
15730                         bool            addcomma = false;
15731
15732                         appendPQExpBufferStr(q, "\nWITH (");
15733                         if (nonemptyReloptions(tbinfo->reloptions))
15734                         {
15735                                 addcomma = true;
15736                                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15737                         }
15738                         if (nonemptyReloptions(tbinfo->toast_reloptions))
15739                         {
15740                                 if (addcomma)
15741                                         appendPQExpBufferStr(q, ", ");
15742                                 appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
15743                                                                                 fout);
15744                         }
15745                         appendPQExpBufferChar(q, ')');
15746                 }
15747
15748                 /* Dump generic options if any */
15749                 if (ftoptions && ftoptions[0])
15750                         appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
15751
15752                 /*
15753                  * For materialized views, create the AS clause just like a view. At
15754                  * this point, we always mark the view as not populated.
15755                  */
15756                 if (tbinfo->relkind == RELKIND_MATVIEW)
15757                 {
15758                         PQExpBuffer result;
15759
15760                         result = createViewAsClause(fout, tbinfo);
15761                         appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
15762                                                           result->data);
15763                         destroyPQExpBuffer(result);
15764                 }
15765                 else
15766                         appendPQExpBufferStr(q, ";\n");
15767
15768                 /*
15769                  * in binary upgrade mode, update the catalog with any missing values
15770                  * that might be present.
15771                  */
15772                 if (dopt->binary_upgrade)
15773                 {
15774                         for (j = 0; j < tbinfo->numatts; j++)
15775                         {
15776                                 if (tbinfo->attmissingval[j][0] != '\0')
15777                                 {
15778                                         appendPQExpBufferStr(q, "\n-- set missing value.\n");
15779                                         appendPQExpBufferStr(q,
15780                                                                                  "SELECT pg_catalog.binary_upgrade_set_missing_value(");
15781                                         appendStringLiteralAH(q, qualrelname, fout);
15782                                         appendPQExpBufferStr(q, "::pg_catalog.regclass,");
15783                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15784                                         appendPQExpBufferStr(q, ",");
15785                                         appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
15786                                         appendPQExpBufferStr(q, ");\n\n");
15787                                 }
15788                         }
15789                 }
15790
15791                 /*
15792                  * To create binary-compatible heap files, we have to ensure the same
15793                  * physical column order, including dropped columns, as in the
15794                  * original.  Therefore, we create dropped columns above and drop them
15795                  * here, also updating their attlen/attalign values so that the
15796                  * dropped column can be skipped properly.  (We do not bother with
15797                  * restoring the original attbyval setting.)  Also, inheritance
15798                  * relationships are set up by doing ALTER TABLE INHERIT rather than
15799                  * using an INHERITS clause --- the latter would possibly mess up the
15800                  * column order.  That also means we have to take care about setting
15801                  * attislocal correctly, plus fix up any inherited CHECK constraints.
15802                  * Analogously, we set up typed tables using ALTER TABLE / OF here.
15803                  *
15804                  * We process foreign and partitioned tables here, even though they
15805                  * lack heap storage, because they can participate in inheritance
15806                  * relationships and we want this stuff to be consistent across the
15807                  * inheritance tree.  We can exclude indexes, toast tables, sequences
15808                  * and matviews, even though they have storage, because we don't
15809                  * support altering or dropping columns in them, nor can they be part
15810                  * of inheritance trees.
15811                  */
15812                 if (dopt->binary_upgrade &&
15813                         (tbinfo->relkind == RELKIND_RELATION ||
15814                          tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
15815                          tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
15816                 {
15817                         for (j = 0; j < tbinfo->numatts; j++)
15818                         {
15819                                 if (tbinfo->attisdropped[j])
15820                                 {
15821                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
15822                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
15823                                                                           "SET attlen = %d, "
15824                                                                           "attalign = '%c', attbyval = false\n"
15825                                                                           "WHERE attname = ",
15826                                                                           tbinfo->attlen[j],
15827                                                                           tbinfo->attalign[j]);
15828                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15829                                         appendPQExpBufferStr(q, "\n  AND attrelid = ");
15830                                         appendStringLiteralAH(q, qualrelname, fout);
15831                                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15832
15833                                         if (tbinfo->relkind == RELKIND_RELATION ||
15834                                                 tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15835                                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15836                                                                                   qualrelname);
15837                                         else
15838                                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE ONLY %s ",
15839                                                                                   qualrelname);
15840                                         appendPQExpBuffer(q, "DROP COLUMN %s;\n",
15841                                                                           fmtId(tbinfo->attnames[j]));
15842                                 }
15843                                 else if (!tbinfo->attislocal[j])
15844                                 {
15845                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
15846                                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
15847                                                                                  "SET attislocal = false\n"
15848                                                                                  "WHERE attname = ");
15849                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15850                                         appendPQExpBufferStr(q, "\n  AND attrelid = ");
15851                                         appendStringLiteralAH(q, qualrelname, fout);
15852                                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15853                                 }
15854                         }
15855
15856                         for (k = 0; k < tbinfo->ncheck; k++)
15857                         {
15858                                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
15859
15860                                 if (constr->separate || constr->conislocal)
15861                                         continue;
15862
15863                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
15864                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15865                                                                   qualrelname);
15866                                 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
15867                                                                   fmtId(constr->dobj.name));
15868                                 appendPQExpBuffer(q, "%s;\n", constr->condef);
15869                                 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
15870                                                                          "SET conislocal = false\n"
15871                                                                          "WHERE contype = 'c' AND conname = ");
15872                                 appendStringLiteralAH(q, constr->dobj.name, fout);
15873                                 appendPQExpBufferStr(q, "\n  AND conrelid = ");
15874                                 appendStringLiteralAH(q, qualrelname, fout);
15875                                 appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15876                         }
15877
15878                         if (numParents > 0 && !tbinfo->ispartition)
15879                         {
15880                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
15881                                 for (k = 0; k < numParents; k++)
15882                                 {
15883                                         TableInfo  *parentRel = parents[k];
15884
15885                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT %s;\n",
15886                                                                           qualrelname,
15887                                                                           fmtQualifiedDumpable(parentRel));
15888                                 }
15889                         }
15890
15891                         if (tbinfo->reloftype)
15892                         {
15893                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
15894                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
15895                                                                   qualrelname,
15896                                                                   tbinfo->reloftype);
15897                         }
15898                 }
15899
15900                 /*
15901                  * For partitioned tables, emit the ATTACH PARTITION clause.  Note
15902                  * that we always want to create partitions this way instead of using
15903                  * CREATE TABLE .. PARTITION OF, mainly to preserve a possible column
15904                  * layout discrepancy with the parent, but also to ensure it gets the
15905                  * correct tablespace setting if it differs from the parent's.
15906                  */
15907                 if (tbinfo->ispartition)
15908                 {
15909                         /* With partitions there can only be one parent */
15910                         if (tbinfo->numParents != 1)
15911                                 fatal("invalid number of parents %d for table \"%s\"",
15912                                           tbinfo->numParents, tbinfo->dobj.name);
15913
15914                         /* Perform ALTER TABLE on the parent */
15915                         appendPQExpBuffer(q,
15916                                                           "ALTER TABLE ONLY %s ATTACH PARTITION %s %s;\n",
15917                                                           fmtQualifiedDumpable(parents[0]),
15918                                                           qualrelname, tbinfo->partbound);
15919                 }
15920
15921                 /*
15922                  * In binary_upgrade mode, arrange to restore the old relfrozenxid and
15923                  * relminmxid of all vacuumable relations.  (While vacuum.c processes
15924                  * TOAST tables semi-independently, here we see them only as children
15925                  * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
15926                  * child toast table is handled below.)
15927                  */
15928                 if (dopt->binary_upgrade &&
15929                         (tbinfo->relkind == RELKIND_RELATION ||
15930                          tbinfo->relkind == RELKIND_MATVIEW))
15931                 {
15932                         appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
15933                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
15934                                                           "SET relfrozenxid = '%u', relminmxid = '%u'\n"
15935                                                           "WHERE oid = ",
15936                                                           tbinfo->frozenxid, tbinfo->minmxid);
15937                         appendStringLiteralAH(q, qualrelname, fout);
15938                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15939
15940                         if (tbinfo->toast_oid)
15941                         {
15942                                 /*
15943                                  * The toast table will have the same OID at restore, so we
15944                                  * can safely target it by OID.
15945                                  */
15946                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
15947                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
15948                                                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
15949                                                                   "WHERE oid = '%u';\n",
15950                                                                   tbinfo->toast_frozenxid,
15951                                                                   tbinfo->toast_minmxid, tbinfo->toast_oid);
15952                         }
15953                 }
15954
15955                 /*
15956                  * In binary_upgrade mode, restore matviews' populated status by
15957                  * poking pg_class directly.  This is pretty ugly, but we can't use
15958                  * REFRESH MATERIALIZED VIEW since it's possible that some underlying
15959                  * matview is not populated even though this matview is; in any case,
15960                  * we want to transfer the matview's heap storage, not run REFRESH.
15961                  */
15962                 if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
15963                         tbinfo->relispopulated)
15964                 {
15965                         appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
15966                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
15967                                                                  "SET relispopulated = 't'\n"
15968                                                                  "WHERE oid = ");
15969                         appendStringLiteralAH(q, qualrelname, fout);
15970                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15971                 }
15972
15973                 /*
15974                  * Dump additional per-column properties that we can't handle in the
15975                  * main CREATE TABLE command.
15976                  */
15977                 for (j = 0; j < tbinfo->numatts; j++)
15978                 {
15979                         /* None of this applies to dropped columns */
15980                         if (tbinfo->attisdropped[j])
15981                                 continue;
15982
15983                         /*
15984                          * If we didn't dump the column definition explicitly above, and
15985                          * it is NOT NULL and did not inherit that property from a parent,
15986                          * we have to mark it separately.
15987                          */
15988                         if (!shouldPrintColumn(dopt, tbinfo, j) &&
15989                                 tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
15990                         {
15991                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15992                                                                   qualrelname);
15993                                 appendPQExpBuffer(q, "ALTER COLUMN %s SET NOT NULL;\n",
15994                                                                   fmtId(tbinfo->attnames[j]));
15995                         }
15996
15997                         /*
15998                          * Dump per-column statistics information. We only issue an ALTER
15999                          * TABLE statement if the attstattarget entry for this column is
16000                          * non-negative (i.e. it's not the default value)
16001                          */
16002                         if (tbinfo->attstattarget[j] >= 0)
16003                         {
16004                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16005                                                                   qualrelname);
16006                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
16007                                                                   fmtId(tbinfo->attnames[j]));
16008                                 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
16009                                                                   tbinfo->attstattarget[j]);
16010                         }
16011
16012                         /*
16013                          * Dump per-column storage information.  The statement is only
16014                          * dumped if the storage has been changed from the type's default.
16015                          */
16016                         if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
16017                         {
16018                                 switch (tbinfo->attstorage[j])
16019                                 {
16020                                         case 'p':
16021                                                 storage = "PLAIN";
16022                                                 break;
16023                                         case 'e':
16024                                                 storage = "EXTERNAL";
16025                                                 break;
16026                                         case 'm':
16027                                                 storage = "MAIN";
16028                                                 break;
16029                                         case 'x':
16030                                                 storage = "EXTENDED";
16031                                                 break;
16032                                         default:
16033                                                 storage = NULL;
16034                                 }
16035
16036                                 /*
16037                                  * Only dump the statement if it's a storage type we recognize
16038                                  */
16039                                 if (storage != NULL)
16040                                 {
16041                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16042                                                                           qualrelname);
16043                                         appendPQExpBuffer(q, "ALTER COLUMN %s ",
16044                                                                           fmtId(tbinfo->attnames[j]));
16045                                         appendPQExpBuffer(q, "SET STORAGE %s;\n",
16046                                                                           storage);
16047                                 }
16048                         }
16049
16050                         /*
16051                          * Dump per-column attributes.
16052                          */
16053                         if (tbinfo->attoptions[j][0] != '\0')
16054                         {
16055                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16056                                                                   qualrelname);
16057                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
16058                                                                   fmtId(tbinfo->attnames[j]));
16059                                 appendPQExpBuffer(q, "SET (%s);\n",
16060                                                                   tbinfo->attoptions[j]);
16061                         }
16062
16063                         /*
16064                          * Dump per-column fdw options.
16065                          */
16066                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
16067                                 tbinfo->attfdwoptions[j][0] != '\0')
16068                         {
16069                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
16070                                                                   qualrelname);
16071                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
16072                                                                   fmtId(tbinfo->attnames[j]));
16073                                 appendPQExpBuffer(q, "OPTIONS (\n    %s\n);\n",
16074                                                                   tbinfo->attfdwoptions[j]);
16075                         }
16076                 }
16077
16078                 if (ftoptions)
16079                         free(ftoptions);
16080                 if (srvname)
16081                         free(srvname);
16082         }
16083
16084         /*
16085          * dump properties we only have ALTER TABLE syntax for
16086          */
16087         if ((tbinfo->relkind == RELKIND_RELATION ||
16088                  tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
16089                  tbinfo->relkind == RELKIND_MATVIEW) &&
16090                 tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
16091         {
16092                 if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
16093                 {
16094                         /* nothing to do, will be set when the index is dumped */
16095                 }
16096                 else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
16097                 {
16098                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
16099                                                           qualrelname);
16100                 }
16101                 else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
16102                 {
16103                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
16104                                                           qualrelname);
16105                 }
16106         }
16107
16108         if (tbinfo->forcerowsec)
16109                 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
16110                                                   qualrelname);
16111
16112         if (dopt->binary_upgrade)
16113                 binary_upgrade_extension_member(q, &tbinfo->dobj,
16114                                                                                 reltypename, qrelname,
16115                                                                                 tbinfo->dobj.namespace->dobj.name);
16116
16117         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16118         {
16119                 char *tableam = NULL;
16120
16121                 if (tbinfo->relkind == RELKIND_RELATION ||
16122                         tbinfo->relkind == RELKIND_MATVIEW)
16123                         tableam = tbinfo->amname;
16124
16125                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
16126                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
16127                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
16128                                                                   .tablespace = (tbinfo->relkind == RELKIND_VIEW) ?
16129                                                                   NULL : tbinfo->reltablespace,
16130                                                                   .tableam = tableam,
16131                                                                   .owner = tbinfo->rolname,
16132                                                                   .description = reltypename,
16133                                                                   .section = tbinfo->postponed_def ?
16134                                                                   SECTION_POST_DATA : SECTION_PRE_DATA,
16135                                                                   .createStmt = q->data,
16136                                                                   .dropStmt = delq->data));
16137         }
16138
16139         /* Dump Table Comments */
16140         if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16141                 dumpTableComment(fout, tbinfo, reltypename);
16142
16143         /* Dump Table Security Labels */
16144         if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
16145                 dumpTableSecLabel(fout, tbinfo, reltypename);
16146
16147         /* Dump comments on inlined table constraints */
16148         for (j = 0; j < tbinfo->ncheck; j++)
16149         {
16150                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
16151
16152                 if (constr->separate || !constr->conislocal)
16153                         continue;
16154
16155                 if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16156                         dumpTableConstraintComment(fout, constr);
16157         }
16158
16159         destroyPQExpBuffer(q);
16160         destroyPQExpBuffer(delq);
16161         free(qrelname);
16162         free(qualrelname);
16163 }
16164
16165 /*
16166  * dumpAttrDef --- dump an attribute's default-value declaration
16167  */
16168 static void
16169 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
16170 {
16171         DumpOptions *dopt = fout->dopt;
16172         TableInfo  *tbinfo = adinfo->adtable;
16173         int                     adnum = adinfo->adnum;
16174         PQExpBuffer q;
16175         PQExpBuffer delq;
16176         char       *qualrelname;
16177         char       *tag;
16178
16179         /* Skip if table definition not to be dumped */
16180         if (!tbinfo->dobj.dump || dopt->dataOnly)
16181                 return;
16182
16183         /* Skip if not "separate"; it was dumped in the table's definition */
16184         if (!adinfo->separate)
16185                 return;
16186
16187         q = createPQExpBuffer();
16188         delq = createPQExpBuffer();
16189
16190         qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
16191
16192         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16193                                           qualrelname);
16194         appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
16195                                           fmtId(tbinfo->attnames[adnum - 1]),
16196                                           adinfo->adef_expr);
16197
16198         appendPQExpBuffer(delq, "ALTER TABLE %s ",
16199                                           qualrelname);
16200         appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
16201                                           fmtId(tbinfo->attnames[adnum - 1]));
16202
16203         tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
16204
16205         if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16206                 ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
16207                                          ARCHIVE_OPTS(.tag = tag,
16208                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
16209                                                                   .owner = tbinfo->rolname,
16210                                                                   .description = "DEFAULT",
16211                                                                   .section = SECTION_PRE_DATA,
16212                                                                   .createStmt = q->data,
16213                                                                   .dropStmt = delq->data));
16214
16215         free(tag);
16216         destroyPQExpBuffer(q);
16217         destroyPQExpBuffer(delq);
16218         free(qualrelname);
16219 }
16220
16221 /*
16222  * getAttrName: extract the correct name for an attribute
16223  *
16224  * The array tblInfo->attnames[] only provides names of user attributes;
16225  * if a system attribute number is supplied, we have to fake it.
16226  * We also do a little bit of bounds checking for safety's sake.
16227  */
16228 static const char *
16229 getAttrName(int attrnum, TableInfo *tblInfo)
16230 {
16231         if (attrnum > 0 && attrnum <= tblInfo->numatts)
16232                 return tblInfo->attnames[attrnum - 1];
16233         switch (attrnum)
16234         {
16235                 case SelfItemPointerAttributeNumber:
16236                         return "ctid";
16237                 case MinTransactionIdAttributeNumber:
16238                         return "xmin";
16239                 case MinCommandIdAttributeNumber:
16240                         return "cmin";
16241                 case MaxTransactionIdAttributeNumber:
16242                         return "xmax";
16243                 case MaxCommandIdAttributeNumber:
16244                         return "cmax";
16245                 case TableOidAttributeNumber:
16246                         return "tableoid";
16247         }
16248         fatal("invalid column number %d for table \"%s\"",
16249                                   attrnum, tblInfo->dobj.name);
16250         return NULL;                            /* keep compiler quiet */
16251 }
16252
16253 /*
16254  * dumpIndex
16255  *        write out to fout a user-defined index
16256  */
16257 static void
16258 dumpIndex(Archive *fout, IndxInfo *indxinfo)
16259 {
16260         DumpOptions *dopt = fout->dopt;
16261         TableInfo  *tbinfo = indxinfo->indextable;
16262         bool            is_constraint = (indxinfo->indexconstraint != 0);
16263         PQExpBuffer q;
16264         PQExpBuffer delq;
16265         char       *qindxname;
16266
16267         if (dopt->dataOnly)
16268                 return;
16269
16270         q = createPQExpBuffer();
16271         delq = createPQExpBuffer();
16272
16273         qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
16274
16275         /*
16276          * If there's an associated constraint, don't dump the index per se, but
16277          * do dump any comment for it.  (This is safe because dependency ordering
16278          * will have ensured the constraint is emitted first.)  Note that the
16279          * emitted comment has to be shown as depending on the constraint, not the
16280          * index, in such cases.
16281          */
16282         if (!is_constraint)
16283         {
16284                 char       *indstatcols = indxinfo->indstatcols;
16285                 char       *indstatvals = indxinfo->indstatvals;
16286                 char      **indstatcolsarray = NULL;
16287                 char      **indstatvalsarray = NULL;
16288                 int                     nstatcols;
16289                 int                     nstatvals;
16290
16291                 if (dopt->binary_upgrade)
16292                         binary_upgrade_set_pg_class_oids(fout, q,
16293                                                                                          indxinfo->dobj.catId.oid, true);
16294
16295                 /* Plain secondary index */
16296                 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
16297
16298                 /*
16299                  * Append ALTER TABLE commands as needed to set properties that we
16300                  * only have ALTER TABLE syntax for.  Keep this in sync with the
16301                  * similar code in dumpConstraint!
16302                  */
16303
16304                 /* If the index is clustered, we need to record that. */
16305                 if (indxinfo->indisclustered)
16306                 {
16307                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16308                                                           fmtQualifiedDumpable(tbinfo));
16309                         /* index name is not qualified in this syntax */
16310                         appendPQExpBuffer(q, " ON %s;\n",
16311                                                           qindxname);
16312                 }
16313
16314                 /*
16315                  * If the index has any statistics on some of its columns, generate
16316                  * the associated ALTER INDEX queries.
16317                  */
16318                 if (parsePGArray(indstatcols, &indstatcolsarray, &nstatcols) &&
16319                         parsePGArray(indstatvals, &indstatvalsarray, &nstatvals) &&
16320                         nstatcols == nstatvals)
16321                 {
16322                         int                     j;
16323
16324                         for (j = 0; j < nstatcols; j++)
16325                         {
16326                                 appendPQExpBuffer(q, "ALTER INDEX %s ",
16327                                                                   fmtQualifiedDumpable(indxinfo));
16328
16329                                 /*
16330                                  * Note that this is a column number, so no quotes should be
16331                                  * used.
16332                                  */
16333                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
16334                                                                   indstatcolsarray[j]);
16335                                 appendPQExpBuffer(q, "SET STATISTICS %s;\n",
16336                                                                   indstatvalsarray[j]);
16337                         }
16338                 }
16339
16340                 /* If the index defines identity, we need to record that. */
16341                 if (indxinfo->indisreplident)
16342                 {
16343                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
16344                                                           fmtQualifiedDumpable(tbinfo));
16345                         /* index name is not qualified in this syntax */
16346                         appendPQExpBuffer(q, " INDEX %s;\n",
16347                                                           qindxname);
16348                 }
16349
16350                 appendPQExpBuffer(delq, "DROP INDEX %s;\n",
16351                                                   fmtQualifiedDumpable(indxinfo));
16352
16353                 if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16354                         ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
16355                                                  ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
16356                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
16357                                                                           .tablespace = indxinfo->tablespace,
16358                                                                           .owner = tbinfo->rolname,
16359                                                                           .description = "INDEX",
16360                                                                           .section = SECTION_POST_DATA,
16361                                                                           .createStmt = q->data,
16362                                                                           .dropStmt = delq->data));
16363
16364                 if (indstatcolsarray)
16365                         free(indstatcolsarray);
16366                 if (indstatvalsarray)
16367                         free(indstatvalsarray);
16368         }
16369
16370         /* Dump Index Comments */
16371         if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16372                 dumpComment(fout, "INDEX", qindxname,
16373                                         tbinfo->dobj.namespace->dobj.name,
16374                                         tbinfo->rolname,
16375                                         indxinfo->dobj.catId, 0,
16376                                         is_constraint ? indxinfo->indexconstraint :
16377                                         indxinfo->dobj.dumpId);
16378
16379         destroyPQExpBuffer(q);
16380         destroyPQExpBuffer(delq);
16381         free(qindxname);
16382 }
16383
16384 /*
16385  * dumpIndexAttach
16386  *        write out to fout a partitioned-index attachment clause
16387  */
16388 static void
16389 dumpIndexAttach(Archive *fout, IndexAttachInfo *attachinfo)
16390 {
16391         if (fout->dopt->dataOnly)
16392                 return;
16393
16394         if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
16395         {
16396                 PQExpBuffer q = createPQExpBuffer();
16397
16398                 appendPQExpBuffer(q, "ALTER INDEX %s ",
16399                                                   fmtQualifiedDumpable(attachinfo->parentIdx));
16400                 appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
16401                                                   fmtQualifiedDumpable(attachinfo->partitionIdx));
16402
16403                 ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
16404                                          ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
16405                                                                   .namespace = attachinfo->dobj.namespace->dobj.name,
16406                                                                   .description = "INDEX ATTACH",
16407                                                                   .section = SECTION_POST_DATA,
16408                                                                   .createStmt = q->data));
16409
16410                 destroyPQExpBuffer(q);
16411         }
16412 }
16413
16414 /*
16415  * dumpStatisticsExt
16416  *        write out to fout an extended statistics object
16417  */
16418 static void
16419 dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo)
16420 {
16421         DumpOptions *dopt = fout->dopt;
16422         PQExpBuffer q;
16423         PQExpBuffer delq;
16424         PQExpBuffer query;
16425         char       *qstatsextname;
16426         PGresult   *res;
16427         char       *stxdef;
16428
16429         /* Skip if not to be dumped */
16430         if (!statsextinfo->dobj.dump || dopt->dataOnly)
16431                 return;
16432
16433         q = createPQExpBuffer();
16434         delq = createPQExpBuffer();
16435         query = createPQExpBuffer();
16436
16437         qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
16438
16439         appendPQExpBuffer(query, "SELECT "
16440                                           "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
16441                                           statsextinfo->dobj.catId.oid);
16442
16443         res = ExecuteSqlQueryForSingleRow(fout, query->data);
16444
16445         stxdef = PQgetvalue(res, 0, 0);
16446
16447         /* Result of pg_get_statisticsobjdef is complete except for semicolon */
16448         appendPQExpBuffer(q, "%s;\n", stxdef);
16449
16450         appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
16451                                           fmtQualifiedDumpable(statsextinfo));
16452
16453         if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16454                 ArchiveEntry(fout, statsextinfo->dobj.catId,
16455                                          statsextinfo->dobj.dumpId,
16456                                          ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
16457                                                                   .namespace = statsextinfo->dobj.namespace->dobj.name,
16458                                                                   .owner = statsextinfo->rolname,
16459                                                                   .description = "STATISTICS",
16460                                                                   .section = SECTION_POST_DATA,
16461                                                                   .createStmt = q->data,
16462                                                                   .dropStmt = delq->data));
16463
16464         /* Dump Statistics Comments */
16465         if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16466                 dumpComment(fout, "STATISTICS", qstatsextname,
16467                                         statsextinfo->dobj.namespace->dobj.name,
16468                                         statsextinfo->rolname,
16469                                         statsextinfo->dobj.catId, 0,
16470                                         statsextinfo->dobj.dumpId);
16471
16472         PQclear(res);
16473         destroyPQExpBuffer(q);
16474         destroyPQExpBuffer(delq);
16475         destroyPQExpBuffer(query);
16476         free(qstatsextname);
16477 }
16478
16479 /*
16480  * dumpConstraint
16481  *        write out to fout a user-defined constraint
16482  */
16483 static void
16484 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
16485 {
16486         DumpOptions *dopt = fout->dopt;
16487         TableInfo  *tbinfo = coninfo->contable;
16488         PQExpBuffer q;
16489         PQExpBuffer delq;
16490         char       *tag = NULL;
16491
16492         /* Skip if not to be dumped */
16493         if (!coninfo->dobj.dump || dopt->dataOnly)
16494                 return;
16495
16496         q = createPQExpBuffer();
16497         delq = createPQExpBuffer();
16498
16499         if (coninfo->contype == 'p' ||
16500                 coninfo->contype == 'u' ||
16501                 coninfo->contype == 'x')
16502         {
16503                 /* Index-related constraint */
16504                 IndxInfo   *indxinfo;
16505                 int                     k;
16506
16507                 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
16508
16509                 if (indxinfo == NULL)
16510                         fatal("missing index for constraint \"%s\"",
16511                                                   coninfo->dobj.name);
16512
16513                 if (dopt->binary_upgrade)
16514                         binary_upgrade_set_pg_class_oids(fout, q,
16515                                                                                          indxinfo->dobj.catId.oid, true);
16516
16517                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
16518                                                   fmtQualifiedDumpable(tbinfo));
16519                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
16520                                                   fmtId(coninfo->dobj.name));
16521
16522                 if (coninfo->condef)
16523                 {
16524                         /* pg_get_constraintdef should have provided everything */
16525                         appendPQExpBuffer(q, "%s;\n", coninfo->condef);
16526                 }
16527                 else
16528                 {
16529                         appendPQExpBuffer(q, "%s (",
16530                                                           coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
16531                         for (k = 0; k < indxinfo->indnkeyattrs; k++)
16532                         {
16533                                 int                     indkey = (int) indxinfo->indkeys[k];
16534                                 const char *attname;
16535
16536                                 if (indkey == InvalidAttrNumber)
16537                                         break;
16538                                 attname = getAttrName(indkey, tbinfo);
16539
16540                                 appendPQExpBuffer(q, "%s%s",
16541                                                                   (k == 0) ? "" : ", ",
16542                                                                   fmtId(attname));
16543                         }
16544
16545                         if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
16546                                 appendPQExpBuffer(q, ") INCLUDE (");
16547
16548                         for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
16549                         {
16550                                 int                     indkey = (int) indxinfo->indkeys[k];
16551                                 const char *attname;
16552
16553                                 if (indkey == InvalidAttrNumber)
16554                                         break;
16555                                 attname = getAttrName(indkey, tbinfo);
16556
16557                                 appendPQExpBuffer(q, "%s%s",
16558                                                                   (k == indxinfo->indnkeyattrs) ? "" : ", ",
16559                                                                   fmtId(attname));
16560                         }
16561
16562                         appendPQExpBufferChar(q, ')');
16563
16564                         if (nonemptyReloptions(indxinfo->indreloptions))
16565                         {
16566                                 appendPQExpBufferStr(q, " WITH (");
16567                                 appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
16568                                 appendPQExpBufferChar(q, ')');
16569                         }
16570
16571                         if (coninfo->condeferrable)
16572                         {
16573                                 appendPQExpBufferStr(q, " DEFERRABLE");
16574                                 if (coninfo->condeferred)
16575                                         appendPQExpBufferStr(q, " INITIALLY DEFERRED");
16576                         }
16577
16578                         appendPQExpBufferStr(q, ";\n");
16579                 }
16580
16581                 /*
16582                  * Append ALTER TABLE commands as needed to set properties that we
16583                  * only have ALTER TABLE syntax for.  Keep this in sync with the
16584                  * similar code in dumpIndex!
16585                  */
16586
16587                 /* If the index is clustered, we need to record that. */
16588                 if (indxinfo->indisclustered)
16589                 {
16590                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16591                                                           fmtQualifiedDumpable(tbinfo));
16592                         /* index name is not qualified in this syntax */
16593                         appendPQExpBuffer(q, " ON %s;\n",
16594                                                           fmtId(indxinfo->dobj.name));
16595                 }
16596
16597                 /* If the index defines identity, we need to record that. */
16598                 if (indxinfo->indisreplident)
16599                 {
16600                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
16601                                                           fmtQualifiedDumpable(tbinfo));
16602                         /* index name is not qualified in this syntax */
16603                         appendPQExpBuffer(q, " INDEX %s;\n",
16604                                                           fmtId(indxinfo->dobj.name));
16605                 }
16606
16607                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s ",
16608                                                   fmtQualifiedDumpable(tbinfo));
16609                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16610                                                   fmtId(coninfo->dobj.name));
16611
16612                 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16613
16614                 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16615                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16616                                                  ARCHIVE_OPTS(.tag = tag,
16617                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
16618                                                                           .tablespace = indxinfo->tablespace,
16619                                                                           .owner = tbinfo->rolname,
16620                                                                           .description = "CONSTRAINT",
16621                                                                           .section = SECTION_POST_DATA,
16622                                                                           .createStmt = q->data,
16623                                                                           .dropStmt = delq->data));
16624         }
16625         else if (coninfo->contype == 'f')
16626         {
16627                 char       *only;
16628
16629                 /*
16630                  * Foreign keys on partitioned tables are always declared as
16631                  * inheriting to partitions; for all other cases, emit them as
16632                  * applying ONLY directly to the named table, because that's how they
16633                  * work for regular inherited tables.
16634                  */
16635                 only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
16636
16637                 /*
16638                  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
16639                  * current table data is not processed
16640                  */
16641                 appendPQExpBuffer(q, "ALTER TABLE %s%s\n",
16642                                                   only, fmtQualifiedDumpable(tbinfo));
16643                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16644                                                   fmtId(coninfo->dobj.name),
16645                                                   coninfo->condef);
16646
16647                 appendPQExpBuffer(delq, "ALTER TABLE %s%s ",
16648                                                   only, fmtQualifiedDumpable(tbinfo));
16649                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16650                                                   fmtId(coninfo->dobj.name));
16651
16652                 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16653
16654                 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16655                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16656                                                  ARCHIVE_OPTS(.tag = tag,
16657                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
16658                                                                           .owner = tbinfo->rolname,
16659                                                                           .description = "FK CONSTRAINT",
16660                                                                           .section = SECTION_POST_DATA,
16661                                                                           .createStmt = q->data,
16662                                                                           .dropStmt = delq->data));
16663         }
16664         else if (coninfo->contype == 'c' && tbinfo)
16665         {
16666                 /* CHECK constraint on a table */
16667
16668                 /* Ignore if not to be dumped separately, or if it was inherited */
16669                 if (coninfo->separate && coninfo->conislocal)
16670                 {
16671                         /* not ONLY since we want it to propagate to children */
16672                         appendPQExpBuffer(q, "ALTER TABLE %s\n",
16673                                                           fmtQualifiedDumpable(tbinfo));
16674                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16675                                                           fmtId(coninfo->dobj.name),
16676                                                           coninfo->condef);
16677
16678                         appendPQExpBuffer(delq, "ALTER TABLE %s ",
16679                                                           fmtQualifiedDumpable(tbinfo));
16680                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16681                                                           fmtId(coninfo->dobj.name));
16682
16683                         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16684
16685                         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16686                                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16687                                                          ARCHIVE_OPTS(.tag = tag,
16688                                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
16689                                                                                   .owner = tbinfo->rolname,
16690                                                                                   .description = "CHECK CONSTRAINT",
16691                                                                                   .section = SECTION_POST_DATA,
16692                                                                                   .createStmt = q->data,
16693                                                                                   .dropStmt = delq->data));
16694                 }
16695         }
16696         else if (coninfo->contype == 'c' && tbinfo == NULL)
16697         {
16698                 /* CHECK constraint on a domain */
16699                 TypeInfo   *tyinfo = coninfo->condomain;
16700
16701                 /* Ignore if not to be dumped separately */
16702                 if (coninfo->separate)
16703                 {
16704                         appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
16705                                                           fmtQualifiedDumpable(tyinfo));
16706                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16707                                                           fmtId(coninfo->dobj.name),
16708                                                           coninfo->condef);
16709
16710                         appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
16711                                                           fmtQualifiedDumpable(tyinfo));
16712                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16713                                                           fmtId(coninfo->dobj.name));
16714
16715                         tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
16716
16717                         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16718                                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16719                                                          ARCHIVE_OPTS(.tag = tag,
16720                                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
16721                                                                                   .owner = tyinfo->rolname,
16722                                                                                   .description = "CHECK CONSTRAINT",
16723                                                                                   .section = SECTION_POST_DATA,
16724                                                                                   .createStmt = q->data,
16725                                                                                   .dropStmt = delq->data));
16726                 }
16727         }
16728         else
16729         {
16730                 fatal("unrecognized constraint type: %c",
16731                                           coninfo->contype);
16732         }
16733
16734         /* Dump Constraint Comments --- only works for table constraints */
16735         if (tbinfo && coninfo->separate &&
16736                 coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16737                 dumpTableConstraintComment(fout, coninfo);
16738
16739         free(tag);
16740         destroyPQExpBuffer(q);
16741         destroyPQExpBuffer(delq);
16742 }
16743
16744 /*
16745  * dumpTableConstraintComment --- dump a constraint's comment if any
16746  *
16747  * This is split out because we need the function in two different places
16748  * depending on whether the constraint is dumped as part of CREATE TABLE
16749  * or as a separate ALTER command.
16750  */
16751 static void
16752 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
16753 {
16754         TableInfo  *tbinfo = coninfo->contable;
16755         PQExpBuffer conprefix = createPQExpBuffer();
16756         char       *qtabname;
16757
16758         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
16759
16760         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
16761                                           fmtId(coninfo->dobj.name));
16762
16763         if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16764                 dumpComment(fout, conprefix->data, qtabname,
16765                                         tbinfo->dobj.namespace->dobj.name,
16766                                         tbinfo->rolname,
16767                                         coninfo->dobj.catId, 0,
16768                                         coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
16769
16770         destroyPQExpBuffer(conprefix);
16771         free(qtabname);
16772 }
16773
16774 /*
16775  * findLastBuiltinOid_V71 -
16776  *
16777  * find the last built in oid
16778  *
16779  * For 7.1 through 8.0, we do this by retrieving datlastsysoid from the
16780  * pg_database entry for the current database.  (Note: current_database()
16781  * requires 7.3; pg_dump requires 8.0 now.)
16782  */
16783 static Oid
16784 findLastBuiltinOid_V71(Archive *fout)
16785 {
16786         PGresult   *res;
16787         Oid                     last_oid;
16788
16789         res = ExecuteSqlQueryForSingleRow(fout,
16790                                                                           "SELECT datlastsysoid FROM pg_database WHERE datname = current_database()");
16791         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
16792         PQclear(res);
16793
16794         return last_oid;
16795 }
16796
16797 /*
16798  * dumpSequence
16799  *        write the declaration (not data) of one user-defined sequence
16800  */
16801 static void
16802 dumpSequence(Archive *fout, TableInfo *tbinfo)
16803 {
16804         DumpOptions *dopt = fout->dopt;
16805         PGresult   *res;
16806         char       *startv,
16807                            *incby,
16808                            *maxv,
16809                            *minv,
16810                            *cache,
16811                            *seqtype;
16812         bool            cycled;
16813         bool            is_ascending;
16814         int64           default_minv,
16815                                 default_maxv;
16816         char            bufm[32],
16817                                 bufx[32];
16818         PQExpBuffer query = createPQExpBuffer();
16819         PQExpBuffer delqry = createPQExpBuffer();
16820         char       *qseqname;
16821
16822         qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
16823
16824         if (fout->remoteVersion >= 100000)
16825         {
16826                 appendPQExpBuffer(query,
16827                                                   "SELECT format_type(seqtypid, NULL), "
16828                                                   "seqstart, seqincrement, "
16829                                                   "seqmax, seqmin, "
16830                                                   "seqcache, seqcycle "
16831                                                   "FROM pg_catalog.pg_sequence "
16832                                                   "WHERE seqrelid = '%u'::oid",
16833                                                   tbinfo->dobj.catId.oid);
16834         }
16835         else if (fout->remoteVersion >= 80400)
16836         {
16837                 /*
16838                  * Before PostgreSQL 10, sequence metadata is in the sequence itself.
16839                  *
16840                  * Note: it might seem that 'bigint' potentially needs to be
16841                  * schema-qualified, but actually that's a keyword.
16842                  */
16843                 appendPQExpBuffer(query,
16844                                                   "SELECT 'bigint' AS sequence_type, "
16845                                                   "start_value, increment_by, max_value, min_value, "
16846                                                   "cache_value, is_cycled FROM %s",
16847                                                   fmtQualifiedDumpable(tbinfo));
16848         }
16849         else
16850         {
16851                 appendPQExpBuffer(query,
16852                                                   "SELECT 'bigint' AS sequence_type, "
16853                                                   "0 AS start_value, increment_by, max_value, min_value, "
16854                                                   "cache_value, is_cycled FROM %s",
16855                                                   fmtQualifiedDumpable(tbinfo));
16856         }
16857
16858         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16859
16860         if (PQntuples(res) != 1)
16861         {
16862                 pg_log_error(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
16863                                                           "query to get data of sequence \"%s\" returned %d rows (expected 1)",
16864                                                                  PQntuples(res)),
16865                                   tbinfo->dobj.name, PQntuples(res));
16866                 exit_nicely(1);
16867         }
16868
16869         seqtype = PQgetvalue(res, 0, 0);
16870         startv = PQgetvalue(res, 0, 1);
16871         incby = PQgetvalue(res, 0, 2);
16872         maxv = PQgetvalue(res, 0, 3);
16873         minv = PQgetvalue(res, 0, 4);
16874         cache = PQgetvalue(res, 0, 5);
16875         cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
16876
16877         /* Calculate default limits for a sequence of this type */
16878         is_ascending = (incby[0] != '-');
16879         if (strcmp(seqtype, "smallint") == 0)
16880         {
16881                 default_minv = is_ascending ? 1 : PG_INT16_MIN;
16882                 default_maxv = is_ascending ? PG_INT16_MAX : -1;
16883         }
16884         else if (strcmp(seqtype, "integer") == 0)
16885         {
16886                 default_minv = is_ascending ? 1 : PG_INT32_MIN;
16887                 default_maxv = is_ascending ? PG_INT32_MAX : -1;
16888         }
16889         else if (strcmp(seqtype, "bigint") == 0)
16890         {
16891                 default_minv = is_ascending ? 1 : PG_INT64_MIN;
16892                 default_maxv = is_ascending ? PG_INT64_MAX : -1;
16893         }
16894         else
16895         {
16896                 fatal("unrecognized sequence type: %s", seqtype);
16897                 default_minv = default_maxv = 0;        /* keep compiler quiet */
16898         }
16899
16900         /*
16901          * 64-bit strtol() isn't very portable, so convert the limits to strings
16902          * and compare that way.
16903          */
16904         snprintf(bufm, sizeof(bufm), INT64_FORMAT, default_minv);
16905         snprintf(bufx, sizeof(bufx), INT64_FORMAT, default_maxv);
16906
16907         /* Don't print minv/maxv if they match the respective default limit */
16908         if (strcmp(minv, bufm) == 0)
16909                 minv = NULL;
16910         if (strcmp(maxv, bufx) == 0)
16911                 maxv = NULL;
16912
16913         /*
16914          * Identity sequences are not to be dropped separately.
16915          */
16916         if (!tbinfo->is_identity_sequence)
16917         {
16918                 appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
16919                                                   fmtQualifiedDumpable(tbinfo));
16920         }
16921
16922         resetPQExpBuffer(query);
16923
16924         if (dopt->binary_upgrade)
16925         {
16926                 binary_upgrade_set_pg_class_oids(fout, query,
16927                                                                                  tbinfo->dobj.catId.oid, false);
16928                 binary_upgrade_set_type_oids_by_rel_oid(fout, query,
16929                                                                                                 tbinfo->dobj.catId.oid);
16930         }
16931
16932         if (tbinfo->is_identity_sequence)
16933         {
16934                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
16935
16936                 appendPQExpBuffer(query,
16937                                                   "ALTER TABLE %s ",
16938                                                   fmtQualifiedDumpable(owning_tab));
16939                 appendPQExpBuffer(query,
16940                                                   "ALTER COLUMN %s ADD GENERATED ",
16941                                                   fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
16942                 if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
16943                         appendPQExpBuffer(query, "ALWAYS");
16944                 else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
16945                         appendPQExpBuffer(query, "BY DEFAULT");
16946                 appendPQExpBuffer(query, " AS IDENTITY (\n    SEQUENCE NAME %s\n",
16947                                                   fmtQualifiedDumpable(tbinfo));
16948         }
16949         else
16950         {
16951                 appendPQExpBuffer(query,
16952                                                   "CREATE SEQUENCE %s\n",
16953                                                   fmtQualifiedDumpable(tbinfo));
16954
16955                 if (strcmp(seqtype, "bigint") != 0)
16956                         appendPQExpBuffer(query, "    AS %s\n", seqtype);
16957         }
16958
16959         if (fout->remoteVersion >= 80400)
16960                 appendPQExpBuffer(query, "    START WITH %s\n", startv);
16961
16962         appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
16963
16964         if (minv)
16965                 appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
16966         else
16967                 appendPQExpBufferStr(query, "    NO MINVALUE\n");
16968
16969         if (maxv)
16970                 appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
16971         else
16972                 appendPQExpBufferStr(query, "    NO MAXVALUE\n");
16973
16974         appendPQExpBuffer(query,
16975                                           "    CACHE %s%s",
16976                                           cache, (cycled ? "\n    CYCLE" : ""));
16977
16978         if (tbinfo->is_identity_sequence)
16979                 appendPQExpBufferStr(query, "\n);\n");
16980         else
16981                 appendPQExpBufferStr(query, ";\n");
16982
16983         /* binary_upgrade:      no need to clear TOAST table oid */
16984
16985         if (dopt->binary_upgrade)
16986                 binary_upgrade_extension_member(query, &tbinfo->dobj,
16987                                                                                 "SEQUENCE", qseqname,
16988                                                                                 tbinfo->dobj.namespace->dobj.name);
16989
16990         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16991                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
16992                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
16993                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
16994                                                                   .owner = tbinfo->rolname,
16995                                                                   .description = "SEQUENCE",
16996                                                                   .section = SECTION_PRE_DATA,
16997                                                                   .createStmt = query->data,
16998                                                                   .dropStmt = delqry->data));
16999
17000         /*
17001          * If the sequence is owned by a table column, emit the ALTER for it as a
17002          * separate TOC entry immediately following the sequence's own entry. It's
17003          * OK to do this rather than using full sorting logic, because the
17004          * dependency that tells us it's owned will have forced the table to be
17005          * created first.  We can't just include the ALTER in the TOC entry
17006          * because it will fail if we haven't reassigned the sequence owner to
17007          * match the table's owner.
17008          *
17009          * We need not schema-qualify the table reference because both sequence
17010          * and table must be in the same schema.
17011          */
17012         if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
17013         {
17014                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
17015
17016                 if (owning_tab == NULL)
17017                         fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
17018                                                   tbinfo->owning_tab, tbinfo->dobj.catId.oid);
17019
17020                 if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
17021                 {
17022                         resetPQExpBuffer(query);
17023                         appendPQExpBuffer(query, "ALTER SEQUENCE %s",
17024                                                           fmtQualifiedDumpable(tbinfo));
17025                         appendPQExpBuffer(query, " OWNED BY %s",
17026                                                           fmtQualifiedDumpable(owning_tab));
17027                         appendPQExpBuffer(query, ".%s;\n",
17028                                                           fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
17029
17030                         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17031                                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
17032                                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17033                                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17034                                                                                   .owner = tbinfo->rolname,
17035                                                                                   .description = "SEQUENCE OWNED BY",
17036                                                                                   .section = SECTION_PRE_DATA,
17037                                                                                   .createStmt = query->data,
17038                                                                                   .deps = &(tbinfo->dobj.dumpId),
17039                                                                                   .nDeps = 1));
17040                 }
17041         }
17042
17043         /* Dump Sequence Comments and Security Labels */
17044         if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17045                 dumpComment(fout, "SEQUENCE", qseqname,
17046                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17047                                         tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
17048
17049         if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
17050                 dumpSecLabel(fout, "SEQUENCE", qseqname,
17051                                          tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17052                                          tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
17053
17054         PQclear(res);
17055
17056         destroyPQExpBuffer(query);
17057         destroyPQExpBuffer(delqry);
17058         free(qseqname);
17059 }
17060
17061 /*
17062  * dumpSequenceData
17063  *        write the data of one user-defined sequence
17064  */
17065 static void
17066 dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
17067 {
17068         TableInfo  *tbinfo = tdinfo->tdtable;
17069         PGresult   *res;
17070         char       *last;
17071         bool            called;
17072         PQExpBuffer query = createPQExpBuffer();
17073
17074         appendPQExpBuffer(query,
17075                                           "SELECT last_value, is_called FROM %s",
17076                                           fmtQualifiedDumpable(tbinfo));
17077
17078         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17079
17080         if (PQntuples(res) != 1)
17081         {
17082                 pg_log_error(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
17083                                                           "query to get data of sequence \"%s\" returned %d rows (expected 1)",
17084                                                                  PQntuples(res)),
17085                                   tbinfo->dobj.name, PQntuples(res));
17086                 exit_nicely(1);
17087         }
17088
17089         last = PQgetvalue(res, 0, 0);
17090         called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
17091
17092         resetPQExpBuffer(query);
17093         appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
17094         appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
17095         appendPQExpBuffer(query, ", %s, %s);\n",
17096                                           last, (called ? "true" : "false"));
17097
17098         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
17099                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
17100                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17101                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17102                                                                   .owner = tbinfo->rolname,
17103                                                                   .description = "SEQUENCE SET",
17104                                                                   .section = SECTION_DATA,
17105                                                                   .createStmt = query->data,
17106                                                                   .deps = &(tbinfo->dobj.dumpId),
17107                                                                   .nDeps = 1));
17108
17109         PQclear(res);
17110
17111         destroyPQExpBuffer(query);
17112 }
17113
17114 /*
17115  * dumpTrigger
17116  *        write the declaration of one user-defined table trigger
17117  */
17118 static void
17119 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
17120 {
17121         DumpOptions *dopt = fout->dopt;
17122         TableInfo  *tbinfo = tginfo->tgtable;
17123         PQExpBuffer query;
17124         PQExpBuffer delqry;
17125         PQExpBuffer trigprefix;
17126         char       *qtabname;
17127         char       *tgargs;
17128         size_t          lentgargs;
17129         const char *p;
17130         int                     findx;
17131         char       *tag;
17132
17133         /*
17134          * we needn't check dobj.dump because TriggerInfo wouldn't have been
17135          * created in the first place for non-dumpable triggers
17136          */
17137         if (dopt->dataOnly)
17138                 return;
17139
17140         query = createPQExpBuffer();
17141         delqry = createPQExpBuffer();
17142         trigprefix = createPQExpBuffer();
17143
17144         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17145
17146         appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
17147                                           fmtId(tginfo->dobj.name));
17148         appendPQExpBuffer(delqry, "ON %s;\n",
17149                                           fmtQualifiedDumpable(tbinfo));
17150
17151         if (tginfo->tgdef)
17152         {
17153                 appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
17154         }
17155         else
17156         {
17157                 if (tginfo->tgisconstraint)
17158                 {
17159                         appendPQExpBufferStr(query, "CREATE CONSTRAINT TRIGGER ");
17160                         appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
17161                 }
17162                 else
17163                 {
17164                         appendPQExpBufferStr(query, "CREATE TRIGGER ");
17165                         appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
17166                 }
17167                 appendPQExpBufferStr(query, "\n    ");
17168
17169                 /* Trigger type */
17170                 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
17171                         appendPQExpBufferStr(query, "BEFORE");
17172                 else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
17173                         appendPQExpBufferStr(query, "AFTER");
17174                 else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
17175                         appendPQExpBufferStr(query, "INSTEAD OF");
17176                 else
17177                 {
17178                         pg_log_error("unexpected tgtype value: %d", tginfo->tgtype);
17179                         exit_nicely(1);
17180                 }
17181
17182                 findx = 0;
17183                 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
17184                 {
17185                         appendPQExpBufferStr(query, " INSERT");
17186                         findx++;
17187                 }
17188                 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
17189                 {
17190                         if (findx > 0)
17191                                 appendPQExpBufferStr(query, " OR DELETE");
17192                         else
17193                                 appendPQExpBufferStr(query, " DELETE");
17194                         findx++;
17195                 }
17196                 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
17197                 {
17198                         if (findx > 0)
17199                                 appendPQExpBufferStr(query, " OR UPDATE");
17200                         else
17201                                 appendPQExpBufferStr(query, " UPDATE");
17202                         findx++;
17203                 }
17204                 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
17205                 {
17206                         if (findx > 0)
17207                                 appendPQExpBufferStr(query, " OR TRUNCATE");
17208                         else
17209                                 appendPQExpBufferStr(query, " TRUNCATE");
17210                         findx++;
17211                 }
17212                 appendPQExpBuffer(query, " ON %s\n",
17213                                                   fmtQualifiedDumpable(tbinfo));
17214
17215                 if (tginfo->tgisconstraint)
17216                 {
17217                         if (OidIsValid(tginfo->tgconstrrelid))
17218                         {
17219                                 /* regclass output is already quoted */
17220                                 appendPQExpBuffer(query, "    FROM %s\n    ",
17221                                                                   tginfo->tgconstrrelname);
17222                         }
17223                         if (!tginfo->tgdeferrable)
17224                                 appendPQExpBufferStr(query, "NOT ");
17225                         appendPQExpBufferStr(query, "DEFERRABLE INITIALLY ");
17226                         if (tginfo->tginitdeferred)
17227                                 appendPQExpBufferStr(query, "DEFERRED\n");
17228                         else
17229                                 appendPQExpBufferStr(query, "IMMEDIATE\n");
17230                 }
17231
17232                 if (TRIGGER_FOR_ROW(tginfo->tgtype))
17233                         appendPQExpBufferStr(query, "    FOR EACH ROW\n    ");
17234                 else
17235                         appendPQExpBufferStr(query, "    FOR EACH STATEMENT\n    ");
17236
17237                 /* regproc output is already sufficiently quoted */
17238                 appendPQExpBuffer(query, "EXECUTE FUNCTION %s(",
17239                                                   tginfo->tgfname);
17240
17241                 tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
17242                                                                                   &lentgargs);
17243                 p = tgargs;
17244                 for (findx = 0; findx < tginfo->tgnargs; findx++)
17245                 {
17246                         /* find the embedded null that terminates this trigger argument */
17247                         size_t          tlen = strlen(p);
17248
17249                         if (p + tlen >= tgargs + lentgargs)
17250                         {
17251                                 /* hm, not found before end of bytea value... */
17252                                 pg_log_error("invalid argument string (%s) for trigger \"%s\" on table \"%s\"",
17253                                                   tginfo->tgargs,
17254                                                   tginfo->dobj.name,
17255                                                   tbinfo->dobj.name);
17256                                 exit_nicely(1);
17257                         }
17258
17259                         if (findx > 0)
17260                                 appendPQExpBufferStr(query, ", ");
17261                         appendStringLiteralAH(query, p, fout);
17262                         p += tlen + 1;
17263                 }
17264                 free(tgargs);
17265                 appendPQExpBufferStr(query, ");\n");
17266         }
17267
17268         if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
17269         {
17270                 appendPQExpBuffer(query, "\nALTER TABLE %s ",
17271                                                   fmtQualifiedDumpable(tbinfo));
17272                 switch (tginfo->tgenabled)
17273                 {
17274                         case 'D':
17275                         case 'f':
17276                                 appendPQExpBufferStr(query, "DISABLE");
17277                                 break;
17278                         case 'A':
17279                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
17280                                 break;
17281                         case 'R':
17282                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
17283                                 break;
17284                         default:
17285                                 appendPQExpBufferStr(query, "ENABLE");
17286                                 break;
17287                 }
17288                 appendPQExpBuffer(query, " TRIGGER %s;\n",
17289                                                   fmtId(tginfo->dobj.name));
17290         }
17291
17292         appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
17293                                           fmtId(tginfo->dobj.name));
17294
17295         tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
17296
17297         if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17298                 ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
17299                                          ARCHIVE_OPTS(.tag = tag,
17300                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17301                                                                   .owner = tbinfo->rolname,
17302                                                                   .description = "TRIGGER",
17303                                                                   .section = SECTION_POST_DATA,
17304                                                                   .createStmt = query->data,
17305                                                                   .dropStmt = delqry->data));
17306
17307         if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17308                 dumpComment(fout, trigprefix->data, qtabname,
17309                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17310                                         tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
17311
17312         free(tag);
17313         destroyPQExpBuffer(query);
17314         destroyPQExpBuffer(delqry);
17315         destroyPQExpBuffer(trigprefix);
17316         free(qtabname);
17317 }
17318
17319 /*
17320  * dumpEventTrigger
17321  *        write the declaration of one user-defined event trigger
17322  */
17323 static void
17324 dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
17325 {
17326         DumpOptions *dopt = fout->dopt;
17327         PQExpBuffer query;
17328         PQExpBuffer delqry;
17329         char       *qevtname;
17330
17331         /* Skip if not to be dumped */
17332         if (!evtinfo->dobj.dump || dopt->dataOnly)
17333                 return;
17334
17335         query = createPQExpBuffer();
17336         delqry = createPQExpBuffer();
17337
17338         qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
17339
17340         appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
17341         appendPQExpBufferStr(query, qevtname);
17342         appendPQExpBufferStr(query, " ON ");
17343         appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
17344
17345         if (strcmp("", evtinfo->evttags) != 0)
17346         {
17347                 appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
17348                 appendPQExpBufferStr(query, evtinfo->evttags);
17349                 appendPQExpBufferChar(query, ')');
17350         }
17351
17352         appendPQExpBufferStr(query, "\n   EXECUTE FUNCTION ");
17353         appendPQExpBufferStr(query, evtinfo->evtfname);
17354         appendPQExpBufferStr(query, "();\n");
17355
17356         if (evtinfo->evtenabled != 'O')
17357         {
17358                 appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
17359                                                   qevtname);
17360                 switch (evtinfo->evtenabled)
17361                 {
17362                         case 'D':
17363                                 appendPQExpBufferStr(query, "DISABLE");
17364                                 break;
17365                         case 'A':
17366                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
17367                                 break;
17368                         case 'R':
17369                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
17370                                 break;
17371                         default:
17372                                 appendPQExpBufferStr(query, "ENABLE");
17373                                 break;
17374                 }
17375                 appendPQExpBufferStr(query, ";\n");
17376         }
17377
17378         appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
17379                                           qevtname);
17380
17381         if (dopt->binary_upgrade)
17382                 binary_upgrade_extension_member(query, &evtinfo->dobj,
17383                                                                                 "EVENT TRIGGER", qevtname, NULL);
17384
17385         if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17386                 ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
17387                                          ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
17388                                                                   .owner = evtinfo->evtowner,
17389                                                                   .description = "EVENT TRIGGER",
17390                                                                   .section = SECTION_POST_DATA,
17391                                                                   .createStmt = query->data,
17392                                                                   .dropStmt = delqry->data));
17393
17394         if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17395                 dumpComment(fout, "EVENT TRIGGER", qevtname,
17396                                         NULL, evtinfo->evtowner,
17397                                         evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
17398
17399         destroyPQExpBuffer(query);
17400         destroyPQExpBuffer(delqry);
17401         free(qevtname);
17402 }
17403
17404 /*
17405  * dumpRule
17406  *              Dump a rule
17407  */
17408 static void
17409 dumpRule(Archive *fout, RuleInfo *rinfo)
17410 {
17411         DumpOptions *dopt = fout->dopt;
17412         TableInfo  *tbinfo = rinfo->ruletable;
17413         bool            is_view;
17414         PQExpBuffer query;
17415         PQExpBuffer cmd;
17416         PQExpBuffer delcmd;
17417         PQExpBuffer ruleprefix;
17418         char       *qtabname;
17419         PGresult   *res;
17420         char       *tag;
17421
17422         /* Skip if not to be dumped */
17423         if (!rinfo->dobj.dump || dopt->dataOnly)
17424                 return;
17425
17426         /*
17427          * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
17428          * we do not want to dump it as a separate object.
17429          */
17430         if (!rinfo->separate)
17431                 return;
17432
17433         /*
17434          * If it's an ON SELECT rule, we want to print it as a view definition,
17435          * instead of a rule.
17436          */
17437         is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
17438
17439         query = createPQExpBuffer();
17440         cmd = createPQExpBuffer();
17441         delcmd = createPQExpBuffer();
17442         ruleprefix = createPQExpBuffer();
17443
17444         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17445
17446         if (is_view)
17447         {
17448                 PQExpBuffer result;
17449
17450                 /*
17451                  * We need OR REPLACE here because we'll be replacing a dummy view.
17452                  * Otherwise this should look largely like the regular view dump code.
17453                  */
17454                 appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
17455                                                   fmtQualifiedDumpable(tbinfo));
17456                 if (nonemptyReloptions(tbinfo->reloptions))
17457                 {
17458                         appendPQExpBufferStr(cmd, " WITH (");
17459                         appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
17460                         appendPQExpBufferChar(cmd, ')');
17461                 }
17462                 result = createViewAsClause(fout, tbinfo);
17463                 appendPQExpBuffer(cmd, " AS\n%s", result->data);
17464                 destroyPQExpBuffer(result);
17465                 if (tbinfo->checkoption != NULL)
17466                         appendPQExpBuffer(cmd, "\n  WITH %s CHECK OPTION",
17467                                                           tbinfo->checkoption);
17468                 appendPQExpBufferStr(cmd, ";\n");
17469         }
17470         else
17471         {
17472                 /* In the rule case, just print pg_get_ruledef's result verbatim */
17473                 appendPQExpBuffer(query,
17474                                                   "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
17475                                                   rinfo->dobj.catId.oid);
17476
17477                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17478
17479                 if (PQntuples(res) != 1)
17480                 {
17481                         pg_log_error("query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
17482                                           rinfo->dobj.name, tbinfo->dobj.name);
17483                         exit_nicely(1);
17484                 }
17485
17486                 printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
17487
17488                 PQclear(res);
17489         }
17490
17491         /*
17492          * Add the command to alter the rules replication firing semantics if it
17493          * differs from the default.
17494          */
17495         if (rinfo->ev_enabled != 'O')
17496         {
17497                 appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
17498                 switch (rinfo->ev_enabled)
17499                 {
17500                         case 'A':
17501                                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
17502                                                                   fmtId(rinfo->dobj.name));
17503                                 break;
17504                         case 'R':
17505                                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
17506                                                                   fmtId(rinfo->dobj.name));
17507                                 break;
17508                         case 'D':
17509                                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
17510                                                                   fmtId(rinfo->dobj.name));
17511                                 break;
17512                 }
17513         }
17514
17515         if (is_view)
17516         {
17517                 /*
17518                  * We can't DROP a view's ON SELECT rule.  Instead, use CREATE OR
17519                  * REPLACE VIEW to replace the rule with something with minimal
17520                  * dependencies.
17521                  */
17522                 PQExpBuffer result;
17523
17524                 appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
17525                                                   fmtQualifiedDumpable(tbinfo));
17526                 result = createDummyViewAsClause(fout, tbinfo);
17527                 appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
17528                 destroyPQExpBuffer(result);
17529         }
17530         else
17531         {
17532                 appendPQExpBuffer(delcmd, "DROP RULE %s ",
17533                                                   fmtId(rinfo->dobj.name));
17534                 appendPQExpBuffer(delcmd, "ON %s;\n",
17535                                                   fmtQualifiedDumpable(tbinfo));
17536         }
17537
17538         appendPQExpBuffer(ruleprefix, "RULE %s ON",
17539                                           fmtId(rinfo->dobj.name));
17540
17541         tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
17542
17543         if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17544                 ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
17545                                          ARCHIVE_OPTS(.tag = tag,
17546                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17547                                                                   .owner = tbinfo->rolname,
17548                                                                   .description = "RULE",
17549                                                                   .section = SECTION_POST_DATA,
17550                                                                   .createStmt = cmd->data,
17551                                                                   .dropStmt = delcmd->data));
17552
17553         /* Dump rule comments */
17554         if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17555                 dumpComment(fout, ruleprefix->data, qtabname,
17556                                         tbinfo->dobj.namespace->dobj.name,
17557                                         tbinfo->rolname,
17558                                         rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
17559
17560         free(tag);
17561         destroyPQExpBuffer(query);
17562         destroyPQExpBuffer(cmd);
17563         destroyPQExpBuffer(delcmd);
17564         destroyPQExpBuffer(ruleprefix);
17565         free(qtabname);
17566 }
17567
17568 /*
17569  * getExtensionMembership --- obtain extension membership data
17570  *
17571  * We need to identify objects that are extension members as soon as they're
17572  * loaded, so that we can correctly determine whether they need to be dumped.
17573  * Generally speaking, extension member objects will get marked as *not* to
17574  * be dumped, as they will be recreated by the single CREATE EXTENSION
17575  * command.  However, in binary upgrade mode we still need to dump the members
17576  * individually.
17577  */
17578 void
17579 getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
17580                                            int numExtensions)
17581 {
17582         PQExpBuffer query;
17583         PGresult   *res;
17584         int                     ntups,
17585                                 nextmembers,
17586                                 i;
17587         int                     i_classid,
17588                                 i_objid,
17589                                 i_refobjid;
17590         ExtensionMemberId *extmembers;
17591         ExtensionInfo *ext;
17592
17593         /* Nothing to do if no extensions */
17594         if (numExtensions == 0)
17595                 return;
17596
17597         query = createPQExpBuffer();
17598
17599         /* refclassid constraint is redundant but may speed the search */
17600         appendPQExpBufferStr(query, "SELECT "
17601                                                  "classid, objid, refobjid "
17602                                                  "FROM pg_depend "
17603                                                  "WHERE refclassid = 'pg_extension'::regclass "
17604                                                  "AND deptype = 'e' "
17605                                                  "ORDER BY 3");
17606
17607         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17608
17609         ntups = PQntuples(res);
17610
17611         i_classid = PQfnumber(res, "classid");
17612         i_objid = PQfnumber(res, "objid");
17613         i_refobjid = PQfnumber(res, "refobjid");
17614
17615         extmembers = (ExtensionMemberId *) pg_malloc(ntups * sizeof(ExtensionMemberId));
17616         nextmembers = 0;
17617
17618         /*
17619          * Accumulate data into extmembers[].
17620          *
17621          * Since we ordered the SELECT by referenced ID, we can expect that
17622          * multiple entries for the same extension will appear together; this
17623          * saves on searches.
17624          */
17625         ext = NULL;
17626
17627         for (i = 0; i < ntups; i++)
17628         {
17629                 CatalogId       objId;
17630                 Oid                     extId;
17631
17632                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17633                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
17634                 extId = atooid(PQgetvalue(res, i, i_refobjid));
17635
17636                 if (ext == NULL ||
17637                         ext->dobj.catId.oid != extId)
17638                         ext = findExtensionByOid(extId);
17639
17640                 if (ext == NULL)
17641                 {
17642                         /* shouldn't happen */
17643                         pg_log_warning("could not find referenced extension %u", extId);
17644                         continue;
17645                 }
17646
17647                 extmembers[nextmembers].catId = objId;
17648                 extmembers[nextmembers].ext = ext;
17649                 nextmembers++;
17650         }
17651
17652         PQclear(res);
17653
17654         /* Remember the data for use later */
17655         setExtensionMembership(extmembers, nextmembers);
17656
17657         destroyPQExpBuffer(query);
17658 }
17659
17660 /*
17661  * processExtensionTables --- deal with extension configuration tables
17662  *
17663  * There are two parts to this process:
17664  *
17665  * 1. Identify and create dump records for extension configuration tables.
17666  *
17667  *        Extensions can mark tables as "configuration", which means that the user
17668  *        is able and expected to modify those tables after the extension has been
17669  *        loaded.  For these tables, we dump out only the data- the structure is
17670  *        expected to be handled at CREATE EXTENSION time, including any indexes or
17671  *        foreign keys, which brings us to-
17672  *
17673  * 2. Record FK dependencies between configuration tables.
17674  *
17675  *        Due to the FKs being created at CREATE EXTENSION time and therefore before
17676  *        the data is loaded, we have to work out what the best order for reloading
17677  *        the data is, to avoid FK violations when the tables are restored.  This is
17678  *        not perfect- we can't handle circular dependencies and if any exist they
17679  *        will cause an invalid dump to be produced (though at least all of the data
17680  *        is included for a user to manually restore).  This is currently documented
17681  *        but perhaps we can provide a better solution in the future.
17682  */
17683 void
17684 processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
17685                                            int numExtensions)
17686 {
17687         DumpOptions *dopt = fout->dopt;
17688         PQExpBuffer query;
17689         PGresult   *res;
17690         int                     ntups,
17691                                 i;
17692         int                     i_conrelid,
17693                                 i_confrelid;
17694
17695         /* Nothing to do if no extensions */
17696         if (numExtensions == 0)
17697                 return;
17698
17699         /*
17700          * Identify extension configuration tables and create TableDataInfo
17701          * objects for them, ensuring their data will be dumped even though the
17702          * tables themselves won't be.
17703          *
17704          * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
17705          * user data in a configuration table is treated like schema data. This
17706          * seems appropriate since system data in a config table would get
17707          * reloaded by CREATE EXTENSION.
17708          */
17709         for (i = 0; i < numExtensions; i++)
17710         {
17711                 ExtensionInfo *curext = &(extinfo[i]);
17712                 char       *extconfig = curext->extconfig;
17713                 char       *extcondition = curext->extcondition;
17714                 char      **extconfigarray = NULL;
17715                 char      **extconditionarray = NULL;
17716                 int                     nconfigitems;
17717                 int                     nconditionitems;
17718
17719                 if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
17720                         parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
17721                         nconfigitems == nconditionitems)
17722                 {
17723                         int                     j;
17724
17725                         for (j = 0; j < nconfigitems; j++)
17726                         {
17727                                 TableInfo  *configtbl;
17728                                 Oid                     configtbloid = atooid(extconfigarray[j]);
17729                                 bool            dumpobj =
17730                                 curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
17731
17732                                 configtbl = findTableByOid(configtbloid);
17733                                 if (configtbl == NULL)
17734                                         continue;
17735
17736                                 /*
17737                                  * Tables of not-to-be-dumped extensions shouldn't be dumped
17738                                  * unless the table or its schema is explicitly included
17739                                  */
17740                                 if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
17741                                 {
17742                                         /* check table explicitly requested */
17743                                         if (table_include_oids.head != NULL &&
17744                                                 simple_oid_list_member(&table_include_oids,
17745                                                                                            configtbloid))
17746                                                 dumpobj = true;
17747
17748                                         /* check table's schema explicitly requested */
17749                                         if (configtbl->dobj.namespace->dobj.dump &
17750                                                 DUMP_COMPONENT_DATA)
17751                                                 dumpobj = true;
17752                                 }
17753
17754                                 /* check table excluded by an exclusion switch */
17755                                 if (table_exclude_oids.head != NULL &&
17756                                         simple_oid_list_member(&table_exclude_oids,
17757                                                                                    configtbloid))
17758                                         dumpobj = false;
17759
17760                                 /* check schema excluded by an exclusion switch */
17761                                 if (simple_oid_list_member(&schema_exclude_oids,
17762                                                                                    configtbl->dobj.namespace->dobj.catId.oid))
17763                                         dumpobj = false;
17764
17765                                 if (dumpobj)
17766                                 {
17767                                         makeTableDataInfo(dopt, configtbl);
17768                                         if (configtbl->dataObj != NULL)
17769                                         {
17770                                                 if (strlen(extconditionarray[j]) > 0)
17771                                                         configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
17772                                         }
17773                                 }
17774                         }
17775                 }
17776                 if (extconfigarray)
17777                         free(extconfigarray);
17778                 if (extconditionarray)
17779                         free(extconditionarray);
17780         }
17781
17782         /*
17783          * Now that all the TableInfoData objects have been created for all the
17784          * extensions, check their FK dependencies and register them to try and
17785          * dump the data out in an order that they can be restored in.
17786          *
17787          * Note that this is not a problem for user tables as their FKs are
17788          * recreated after the data has been loaded.
17789          */
17790
17791         query = createPQExpBuffer();
17792
17793         printfPQExpBuffer(query,
17794                                           "SELECT conrelid, confrelid "
17795                                           "FROM pg_constraint "
17796                                           "JOIN pg_depend ON (objid = confrelid) "
17797                                           "WHERE contype = 'f' "
17798                                           "AND refclassid = 'pg_extension'::regclass "
17799                                           "AND classid = 'pg_class'::regclass;");
17800
17801         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17802         ntups = PQntuples(res);
17803
17804         i_conrelid = PQfnumber(res, "conrelid");
17805         i_confrelid = PQfnumber(res, "confrelid");
17806
17807         /* Now get the dependencies and register them */
17808         for (i = 0; i < ntups; i++)
17809         {
17810                 Oid                     conrelid,
17811                                         confrelid;
17812                 TableInfo  *reftable,
17813                                    *contable;
17814
17815                 conrelid = atooid(PQgetvalue(res, i, i_conrelid));
17816                 confrelid = atooid(PQgetvalue(res, i, i_confrelid));
17817                 contable = findTableByOid(conrelid);
17818                 reftable = findTableByOid(confrelid);
17819
17820                 if (reftable == NULL ||
17821                         reftable->dataObj == NULL ||
17822                         contable == NULL ||
17823                         contable->dataObj == NULL)
17824                         continue;
17825
17826                 /*
17827                  * Make referencing TABLE_DATA object depend on the referenced table's
17828                  * TABLE_DATA object.
17829                  */
17830                 addObjectDependency(&contable->dataObj->dobj,
17831                                                         reftable->dataObj->dobj.dumpId);
17832         }
17833         PQclear(res);
17834         destroyPQExpBuffer(query);
17835 }
17836
17837 /*
17838  * getDependencies --- obtain available dependency data
17839  */
17840 static void
17841 getDependencies(Archive *fout)
17842 {
17843         PQExpBuffer query;
17844         PGresult   *res;
17845         int                     ntups,
17846                                 i;
17847         int                     i_classid,
17848                                 i_objid,
17849                                 i_refclassid,
17850                                 i_refobjid,
17851                                 i_deptype;
17852         DumpableObject *dobj,
17853                            *refdobj;
17854
17855         pg_log_info("reading dependency data");
17856
17857         query = createPQExpBuffer();
17858
17859         /*
17860          * PIN dependencies aren't interesting, and EXTENSION dependencies were
17861          * already processed by getExtensionMembership.
17862          */
17863         appendPQExpBufferStr(query, "SELECT "
17864                                                  "classid, objid, refclassid, refobjid, deptype "
17865                                                  "FROM pg_depend "
17866                                                  "WHERE deptype != 'p' AND deptype != 'e' "
17867                                                  "ORDER BY 1,2");
17868
17869         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17870
17871         ntups = PQntuples(res);
17872
17873         i_classid = PQfnumber(res, "classid");
17874         i_objid = PQfnumber(res, "objid");
17875         i_refclassid = PQfnumber(res, "refclassid");
17876         i_refobjid = PQfnumber(res, "refobjid");
17877         i_deptype = PQfnumber(res, "deptype");
17878
17879         /*
17880          * Since we ordered the SELECT by referencing ID, we can expect that
17881          * multiple entries for the same object will appear together; this saves
17882          * on searches.
17883          */
17884         dobj = NULL;
17885
17886         for (i = 0; i < ntups; i++)
17887         {
17888                 CatalogId       objId;
17889                 CatalogId       refobjId;
17890                 char            deptype;
17891
17892                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17893                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
17894                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
17895                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
17896                 deptype = *(PQgetvalue(res, i, i_deptype));
17897
17898                 if (dobj == NULL ||
17899                         dobj->catId.tableoid != objId.tableoid ||
17900                         dobj->catId.oid != objId.oid)
17901                         dobj = findObjectByCatalogId(objId);
17902
17903                 /*
17904                  * Failure to find objects mentioned in pg_depend is not unexpected,
17905                  * since for example we don't collect info about TOAST tables.
17906                  */
17907                 if (dobj == NULL)
17908                 {
17909 #ifdef NOT_USED
17910                         pg_log_warning("no referencing object %u %u",
17911                                         objId.tableoid, objId.oid);
17912 #endif
17913                         continue;
17914                 }
17915
17916                 refdobj = findObjectByCatalogId(refobjId);
17917
17918                 if (refdobj == NULL)
17919                 {
17920 #ifdef NOT_USED
17921                         pg_log_warning("no referenced object %u %u",
17922                                         refobjId.tableoid, refobjId.oid);
17923 #endif
17924                         continue;
17925                 }
17926
17927                 /*
17928                  * Ordinarily, table rowtypes have implicit dependencies on their
17929                  * tables.  However, for a composite type the implicit dependency goes
17930                  * the other way in pg_depend; which is the right thing for DROP but
17931                  * it doesn't produce the dependency ordering we need. So in that one
17932                  * case, we reverse the direction of the dependency.
17933                  */
17934                 if (deptype == 'i' &&
17935                         dobj->objType == DO_TABLE &&
17936                         refdobj->objType == DO_TYPE)
17937                         addObjectDependency(refdobj, dobj->dumpId);
17938                 else
17939                         /* normal case */
17940                         addObjectDependency(dobj, refdobj->dumpId);
17941         }
17942
17943         PQclear(res);
17944
17945         destroyPQExpBuffer(query);
17946 }
17947
17948
17949 /*
17950  * createBoundaryObjects - create dummy DumpableObjects to represent
17951  * dump section boundaries.
17952  */
17953 static DumpableObject *
17954 createBoundaryObjects(void)
17955 {
17956         DumpableObject *dobjs;
17957
17958         dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
17959
17960         dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
17961         dobjs[0].catId = nilCatalogId;
17962         AssignDumpId(dobjs + 0);
17963         dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
17964
17965         dobjs[1].objType = DO_POST_DATA_BOUNDARY;
17966         dobjs[1].catId = nilCatalogId;
17967         AssignDumpId(dobjs + 1);
17968         dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
17969
17970         return dobjs;
17971 }
17972
17973 /*
17974  * addBoundaryDependencies - add dependencies as needed to enforce the dump
17975  * section boundaries.
17976  */
17977 static void
17978 addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
17979                                                 DumpableObject *boundaryObjs)
17980 {
17981         DumpableObject *preDataBound = boundaryObjs + 0;
17982         DumpableObject *postDataBound = boundaryObjs + 1;
17983         int                     i;
17984
17985         for (i = 0; i < numObjs; i++)
17986         {
17987                 DumpableObject *dobj = dobjs[i];
17988
17989                 /*
17990                  * The classification of object types here must match the SECTION_xxx
17991                  * values assigned during subsequent ArchiveEntry calls!
17992                  */
17993                 switch (dobj->objType)
17994                 {
17995                         case DO_NAMESPACE:
17996                         case DO_EXTENSION:
17997                         case DO_TYPE:
17998                         case DO_SHELL_TYPE:
17999                         case DO_FUNC:
18000                         case DO_AGG:
18001                         case DO_OPERATOR:
18002                         case DO_ACCESS_METHOD:
18003                         case DO_OPCLASS:
18004                         case DO_OPFAMILY:
18005                         case DO_COLLATION:
18006                         case DO_CONVERSION:
18007                         case DO_TABLE:
18008                         case DO_ATTRDEF:
18009                         case DO_PROCLANG:
18010                         case DO_CAST:
18011                         case DO_DUMMY_TYPE:
18012                         case DO_TSPARSER:
18013                         case DO_TSDICT:
18014                         case DO_TSTEMPLATE:
18015                         case DO_TSCONFIG:
18016                         case DO_FDW:
18017                         case DO_FOREIGN_SERVER:
18018                         case DO_TRANSFORM:
18019                         case DO_BLOB:
18020                                 /* Pre-data objects: must come before the pre-data boundary */
18021                                 addObjectDependency(preDataBound, dobj->dumpId);
18022                                 break;
18023                         case DO_TABLE_DATA:
18024                         case DO_SEQUENCE_SET:
18025                         case DO_BLOB_DATA:
18026                                 /* Data objects: must come between the boundaries */
18027                                 addObjectDependency(dobj, preDataBound->dumpId);
18028                                 addObjectDependency(postDataBound, dobj->dumpId);
18029                                 break;
18030                         case DO_INDEX:
18031                         case DO_INDEX_ATTACH:
18032                         case DO_STATSEXT:
18033                         case DO_REFRESH_MATVIEW:
18034                         case DO_TRIGGER:
18035                         case DO_EVENT_TRIGGER:
18036                         case DO_DEFAULT_ACL:
18037                         case DO_POLICY:
18038                         case DO_PUBLICATION:
18039                         case DO_PUBLICATION_REL:
18040                         case DO_SUBSCRIPTION:
18041                                 /* Post-data objects: must come after the post-data boundary */
18042                                 addObjectDependency(dobj, postDataBound->dumpId);
18043                                 break;
18044                         case DO_RULE:
18045                                 /* Rules are post-data, but only if dumped separately */
18046                                 if (((RuleInfo *) dobj)->separate)
18047                                         addObjectDependency(dobj, postDataBound->dumpId);
18048                                 break;
18049                         case DO_CONSTRAINT:
18050                         case DO_FK_CONSTRAINT:
18051                                 /* Constraints are post-data, but only if dumped separately */
18052                                 if (((ConstraintInfo *) dobj)->separate)
18053                                         addObjectDependency(dobj, postDataBound->dumpId);
18054                                 break;
18055                         case DO_PRE_DATA_BOUNDARY:
18056                                 /* nothing to do */
18057                                 break;
18058                         case DO_POST_DATA_BOUNDARY:
18059                                 /* must come after the pre-data boundary */
18060                                 addObjectDependency(dobj, preDataBound->dumpId);
18061                                 break;
18062                 }
18063         }
18064 }
18065
18066
18067 /*
18068  * BuildArchiveDependencies - create dependency data for archive TOC entries
18069  *
18070  * The raw dependency data obtained by getDependencies() is not terribly
18071  * useful in an archive dump, because in many cases there are dependency
18072  * chains linking through objects that don't appear explicitly in the dump.
18073  * For example, a view will depend on its _RETURN rule while the _RETURN rule
18074  * will depend on other objects --- but the rule will not appear as a separate
18075  * object in the dump.  We need to adjust the view's dependencies to include
18076  * whatever the rule depends on that is included in the dump.
18077  *
18078  * Just to make things more complicated, there are also "special" dependencies
18079  * such as the dependency of a TABLE DATA item on its TABLE, which we must
18080  * not rearrange because pg_restore knows that TABLE DATA only depends on
18081  * its table.  In these cases we must leave the dependencies strictly as-is
18082  * even if they refer to not-to-be-dumped objects.
18083  *
18084  * To handle this, the convention is that "special" dependencies are created
18085  * during ArchiveEntry calls, and an archive TOC item that has any such
18086  * entries will not be touched here.  Otherwise, we recursively search the
18087  * DumpableObject data structures to build the correct dependencies for each
18088  * archive TOC item.
18089  */
18090 static void
18091 BuildArchiveDependencies(Archive *fout)
18092 {
18093         ArchiveHandle *AH = (ArchiveHandle *) fout;
18094         TocEntry   *te;
18095
18096         /* Scan all TOC entries in the archive */
18097         for (te = AH->toc->next; te != AH->toc; te = te->next)
18098         {
18099                 DumpableObject *dobj;
18100                 DumpId     *dependencies;
18101                 int                     nDeps;
18102                 int                     allocDeps;
18103
18104                 /* No need to process entries that will not be dumped */
18105                 if (te->reqs == 0)
18106                         continue;
18107                 /* Ignore entries that already have "special" dependencies */
18108                 if (te->nDeps > 0)
18109                         continue;
18110                 /* Otherwise, look up the item's original DumpableObject, if any */
18111                 dobj = findObjectByDumpId(te->dumpId);
18112                 if (dobj == NULL)
18113                         continue;
18114                 /* No work if it has no dependencies */
18115                 if (dobj->nDeps <= 0)
18116                         continue;
18117                 /* Set up work array */
18118                 allocDeps = 64;
18119                 dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
18120                 nDeps = 0;
18121                 /* Recursively find all dumpable dependencies */
18122                 findDumpableDependencies(AH, dobj,
18123                                                                  &dependencies, &nDeps, &allocDeps);
18124                 /* And save 'em ... */
18125                 if (nDeps > 0)
18126                 {
18127                         dependencies = (DumpId *) pg_realloc(dependencies,
18128                                                                                                  nDeps * sizeof(DumpId));
18129                         te->dependencies = dependencies;
18130                         te->nDeps = nDeps;
18131                 }
18132                 else
18133                         free(dependencies);
18134         }
18135 }
18136
18137 /* Recursive search subroutine for BuildArchiveDependencies */
18138 static void
18139 findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
18140                                                  DumpId **dependencies, int *nDeps, int *allocDeps)
18141 {
18142         int                     i;
18143
18144         /*
18145          * Ignore section boundary objects: if we search through them, we'll
18146          * report lots of bogus dependencies.
18147          */
18148         if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
18149                 dobj->objType == DO_POST_DATA_BOUNDARY)
18150                 return;
18151
18152         for (i = 0; i < dobj->nDeps; i++)
18153         {
18154                 DumpId          depid = dobj->dependencies[i];
18155
18156                 if (TocIDRequired(AH, depid) != 0)
18157                 {
18158                         /* Object will be dumped, so just reference it as a dependency */
18159                         if (*nDeps >= *allocDeps)
18160                         {
18161                                 *allocDeps *= 2;
18162                                 *dependencies = (DumpId *) pg_realloc(*dependencies,
18163                                                                                                           *allocDeps * sizeof(DumpId));
18164                         }
18165                         (*dependencies)[*nDeps] = depid;
18166                         (*nDeps)++;
18167                 }
18168                 else
18169                 {
18170                         /*
18171                          * Object will not be dumped, so recursively consider its deps. We
18172                          * rely on the assumption that sortDumpableObjects already broke
18173                          * any dependency loops, else we might recurse infinitely.
18174                          */
18175                         DumpableObject *otherdobj = findObjectByDumpId(depid);
18176
18177                         if (otherdobj)
18178                                 findDumpableDependencies(AH, otherdobj,
18179                                                                                  dependencies, nDeps, allocDeps);
18180                 }
18181         }
18182 }
18183
18184
18185 /*
18186  * getFormattedTypeName - retrieve a nicely-formatted type name for the
18187  * given type OID.
18188  *
18189  * This does not guarantee to schema-qualify the output, so it should not
18190  * be used to create the target object name for CREATE or ALTER commands.
18191  *
18192  * TODO: there might be some value in caching the results.
18193  */
18194 static char *
18195 getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
18196 {
18197         char       *result;
18198         PQExpBuffer query;
18199         PGresult   *res;
18200
18201         if (oid == 0)
18202         {
18203                 if ((opts & zeroAsOpaque) != 0)
18204                         return pg_strdup(g_opaque_type);
18205                 else if ((opts & zeroAsAny) != 0)
18206                         return pg_strdup("'any'");
18207                 else if ((opts & zeroAsStar) != 0)
18208                         return pg_strdup("*");
18209                 else if ((opts & zeroAsNone) != 0)
18210                         return pg_strdup("NONE");
18211         }
18212
18213         query = createPQExpBuffer();
18214         appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
18215                                           oid);
18216
18217         res = ExecuteSqlQueryForSingleRow(fout, query->data);
18218
18219         /* result of format_type is already quoted */
18220         result = pg_strdup(PQgetvalue(res, 0, 0));
18221
18222         PQclear(res);
18223         destroyPQExpBuffer(query);
18224
18225         return result;
18226 }
18227
18228 /*
18229  * Return a column list clause for the given relation.
18230  *
18231  * Special case: if there are no undropped columns in the relation, return
18232  * "", not an invalid "()" column list.
18233  */
18234 static const char *
18235 fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
18236 {
18237         int                     numatts = ti->numatts;
18238         char      **attnames = ti->attnames;
18239         bool       *attisdropped = ti->attisdropped;
18240         char       *attgenerated = ti->attgenerated;
18241         bool            needComma;
18242         int                     i;
18243
18244         appendPQExpBufferChar(buffer, '(');
18245         needComma = false;
18246         for (i = 0; i < numatts; i++)
18247         {
18248                 if (attisdropped[i])
18249                         continue;
18250                 if (attgenerated[i])
18251                         continue;
18252                 if (needComma)
18253                         appendPQExpBufferStr(buffer, ", ");
18254                 appendPQExpBufferStr(buffer, fmtId(attnames[i]));
18255                 needComma = true;
18256         }
18257
18258         if (!needComma)
18259                 return "";                              /* no undropped columns */
18260
18261         appendPQExpBufferChar(buffer, ')');
18262         return buffer->data;
18263 }
18264
18265 /*
18266  * Check if a reloptions array is nonempty.
18267  */
18268 static bool
18269 nonemptyReloptions(const char *reloptions)
18270 {
18271         /* Don't want to print it if it's just "{}" */
18272         return (reloptions != NULL && strlen(reloptions) > 2);
18273 }
18274
18275 /*
18276  * Format a reloptions array and append it to the given buffer.
18277  *
18278  * "prefix" is prepended to the option names; typically it's "" or "toast.".
18279  */
18280 static void
18281 appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
18282                                                 const char *prefix, Archive *fout)
18283 {
18284         bool            res;
18285
18286         res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
18287                                                                 fout->std_strings);
18288         if (!res)
18289                 pg_log_warning("could not parse reloptions array");
18290 }