]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_dump.c
Un-break pg_dump for pre-8.3 source servers.
[postgresql] / src / bin / pg_dump / pg_dump.c
1 /*-------------------------------------------------------------------------
2  *
3  * pg_dump.c
4  *        pg_dump is a utility for dumping out a postgres database
5  *        into a script file.
6  *
7  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *      pg_dump will read the system catalogs in a database and dump out a
11  *      script that reproduces the schema in terms of SQL that is understood
12  *      by PostgreSQL
13  *
14  *      Note that pg_dump runs in a transaction-snapshot mode transaction,
15  *      so it sees a consistent snapshot of the database including system
16  *      catalogs. However, it relies in part on various specialized backend
17  *      functions like pg_get_indexdef(), and those things tend to look at
18  *      the currently committed state.  So it is possible to get 'cache
19  *      lookup failed' error if someone performs DDL changes while a dump is
20  *      happening. The window for this sort of thing is from the acquisition
21  *      of the transaction snapshot to getSchemaData() (when pg_dump acquires
22  *      AccessShareLock on every table it intends to dump). It isn't very large,
23  *      but it can happen.
24  *
25  *      http://archives.postgresql.org/pgsql-bugs/2010-02/msg00187.php
26  *
27  * IDENTIFICATION
28  *        src/bin/pg_dump/pg_dump.c
29  *
30  *-------------------------------------------------------------------------
31  */
32 #include "postgres_fe.h"
33
34 #include <unistd.h>
35 #include <ctype.h>
36 #include <limits.h>
37 #ifdef HAVE_TERMIOS_H
38 #include <termios.h>
39 #endif
40
41 #include "getopt_long.h"
42
43 #include "access/attnum.h"
44 #include "access/sysattr.h"
45 #include "access/transam.h"
46 #include "catalog/pg_aggregate_d.h"
47 #include "catalog/pg_am_d.h"
48 #include "catalog/pg_attribute_d.h"
49 #include "catalog/pg_cast_d.h"
50 #include "catalog/pg_class_d.h"
51 #include "catalog/pg_default_acl_d.h"
52 #include "catalog/pg_largeobject_d.h"
53 #include "catalog/pg_largeobject_metadata_d.h"
54 #include "catalog/pg_proc_d.h"
55 #include "catalog/pg_trigger_d.h"
56 #include "catalog/pg_type_d.h"
57 #include "libpq/libpq-fs.h"
58 #include "storage/block.h"
59
60 #include "dumputils.h"
61 #include "parallel.h"
62 #include "pg_backup_db.h"
63 #include "pg_backup_utils.h"
64 #include "pg_dump.h"
65 #include "fe_utils/connect.h"
66 #include "fe_utils/string_utils.h"
67
68
69 typedef struct
70 {
71         const char *descr;                      /* comment for an object */
72         Oid                     classoid;               /* object class (catalog OID) */
73         Oid                     objoid;                 /* object OID */
74         int                     objsubid;               /* subobject (table column #) */
75 } CommentItem;
76
77 typedef struct
78 {
79         const char *provider;           /* label provider of this security label */
80         const char *label;                      /* security label for an object */
81         Oid                     classoid;               /* object class (catalog OID) */
82         Oid                     objoid;                 /* object OID */
83         int                     objsubid;               /* subobject (table column #) */
84 } SecLabelItem;
85
86 typedef enum OidOptions
87 {
88         zeroAsOpaque = 1,
89         zeroAsAny = 2,
90         zeroAsStar = 4,
91         zeroAsNone = 8
92 } OidOptions;
93
94 /* global decls */
95 static bool dosync = true;              /* Issue fsync() to make dump durable on disk. */
96
97 /* subquery used to convert user ID (eg, datdba) to user name */
98 static const char *username_subquery;
99
100 /*
101  * For 8.0 and earlier servers, pulled from pg_database, for 8.1+ we use
102  * FirstNormalObjectId - 1.
103  */
104 static Oid      g_last_builtin_oid; /* value of the last builtin oid */
105
106 /* The specified names/patterns should to match at least one entity */
107 static int      strict_names = 0;
108
109 /*
110  * Object inclusion/exclusion lists
111  *
112  * The string lists record the patterns given by command-line switches,
113  * which we then convert to lists of OIDs of matching objects.
114  */
115 static SimpleStringList schema_include_patterns = {NULL, NULL};
116 static SimpleOidList schema_include_oids = {NULL, NULL};
117 static SimpleStringList schema_exclude_patterns = {NULL, NULL};
118 static SimpleOidList schema_exclude_oids = {NULL, NULL};
119
120 static SimpleStringList table_include_patterns = {NULL, NULL};
121 static SimpleOidList table_include_oids = {NULL, NULL};
122 static SimpleStringList table_exclude_patterns = {NULL, NULL};
123 static SimpleOidList table_exclude_oids = {NULL, NULL};
124 static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
125 static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
126
127
128 char            g_opaque_type[10];      /* name for the opaque type */
129
130 /* placeholders for the delimiters for comments */
131 char            g_comment_start[10];
132 char            g_comment_end[10];
133
134 static const CatalogId nilCatalogId = {0, 0};
135
136 /* override for standard extra_float_digits setting */
137 static bool have_extra_float_digits = false;
138 static int      extra_float_digits;
139
140 /*
141  * The default number of rows per INSERT when
142  * --inserts is specified without --rows-per-insert
143  */
144 #define DUMP_DEFAULT_ROWS_PER_INSERT 1
145
146 /*
147  * Macro for producing quoted, schema-qualified name of a dumpable object.
148  */
149 #define fmtQualifiedDumpable(obj) \
150         fmtQualifiedId((obj)->dobj.namespace->dobj.name, \
151                                    (obj)->dobj.name)
152
153 static void help(const char *progname);
154 static void setup_connection(Archive *AH,
155                                                          const char *dumpencoding, const char *dumpsnapshot,
156                                                          char *use_role);
157 static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
158 static void expand_schema_name_patterns(Archive *fout,
159                                                                                 SimpleStringList *patterns,
160                                                                                 SimpleOidList *oids,
161                                                                                 bool strict_names);
162 static void expand_table_name_patterns(Archive *fout,
163                                                                            SimpleStringList *patterns,
164                                                                            SimpleOidList *oids,
165                                                                            bool strict_names);
166 static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid);
167 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
168 static void refreshMatViewData(Archive *fout, TableDataInfo *tdinfo);
169 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
170 static void dumpComment(Archive *fout, const char *type, const char *name,
171                                                 const char *namespace, const char *owner,
172                                                 CatalogId catalogId, int subid, DumpId dumpId);
173 static int      findComments(Archive *fout, Oid classoid, Oid objoid,
174                                                  CommentItem **items);
175 static int      collectComments(Archive *fout, CommentItem **items);
176 static void dumpSecLabel(Archive *fout, const char *type, const char *name,
177                                                  const char *namespace, const char *owner,
178                                                  CatalogId catalogId, int subid, DumpId dumpId);
179 static int      findSecLabels(Archive *fout, Oid classoid, Oid objoid,
180                                                   SecLabelItem **items);
181 static int      collectSecLabels(Archive *fout, SecLabelItem **items);
182 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
183 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
184 static void dumpExtension(Archive *fout, ExtensionInfo *extinfo);
185 static void dumpType(Archive *fout, TypeInfo *tyinfo);
186 static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
187 static void dumpEnumType(Archive *fout, TypeInfo *tyinfo);
188 static void dumpRangeType(Archive *fout, TypeInfo *tyinfo);
189 static void dumpUndefinedType(Archive *fout, TypeInfo *tyinfo);
190 static void dumpDomain(Archive *fout, TypeInfo *tyinfo);
191 static void dumpCompositeType(Archive *fout, TypeInfo *tyinfo);
192 static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
193 static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
194 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
195 static void dumpFunc(Archive *fout, FuncInfo *finfo);
196 static void dumpCast(Archive *fout, CastInfo *cast);
197 static void dumpTransform(Archive *fout, TransformInfo *transform);
198 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
199 static void dumpAccessMethod(Archive *fout, AccessMethodInfo *oprinfo);
200 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
201 static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
202 static void dumpCollation(Archive *fout, CollInfo *collinfo);
203 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
204 static void dumpRule(Archive *fout, RuleInfo *rinfo);
205 static void dumpAgg(Archive *fout, AggInfo *agginfo);
206 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
207 static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
208 static void dumpTable(Archive *fout, TableInfo *tbinfo);
209 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
210 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
211 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
212 static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo);
213 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
214 static void dumpIndexAttach(Archive *fout, IndexAttachInfo *attachinfo);
215 static void dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo);
216 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
217 static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
218 static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
219 static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
220 static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
221 static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
222 static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
223 static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
224 static void dumpUserMappings(Archive *fout,
225                                                          const char *servername, const char *namespace,
226                                                          const char *owner, CatalogId catalogId, DumpId dumpId);
227 static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
228
229 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
230                                         const char *type, const char *name, const char *subname,
231                                         const char *nspname, const char *owner,
232                                         const char *acls, const char *racls,
233                                         const char *initacls, const char *initracls);
234
235 static void getDependencies(Archive *fout);
236 static void BuildArchiveDependencies(Archive *fout);
237 static void findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
238                                                                          DumpId **dependencies, int *nDeps, int *allocDeps);
239
240 static DumpableObject *createBoundaryObjects(void);
241 static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
242                                                                         DumpableObject *boundaryObjs);
243
244 static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
245 static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind);
246 static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo);
247 static void buildMatViewRefreshDependencies(Archive *fout);
248 static void getTableDataFKConstraints(void);
249 static char *format_function_arguments(FuncInfo *finfo, char *funcargs,
250                                                                            bool is_agg);
251 static char *format_function_arguments_old(Archive *fout,
252                                                                                    FuncInfo *finfo, int nallargs,
253                                                                                    char **allargtypes,
254                                                                                    char **argmodes,
255                                                                                    char **argnames);
256 static char *format_function_signature(Archive *fout,
257                                                                            FuncInfo *finfo, bool honor_quotes);
258 static char *convertRegProcReference(Archive *fout,
259                                                                          const char *proc);
260 static char *getFormattedOperatorName(Archive *fout, const char *oproid);
261 static char *convertTSFunction(Archive *fout, Oid funcOid);
262 static Oid      findLastBuiltinOid_V71(Archive *fout);
263 static char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
264 static void getBlobs(Archive *fout);
265 static void dumpBlob(Archive *fout, BlobInfo *binfo);
266 static int      dumpBlobs(Archive *fout, void *arg);
267 static void dumpPolicy(Archive *fout, PolicyInfo *polinfo);
268 static void dumpPublication(Archive *fout, PublicationInfo *pubinfo);
269 static void dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo);
270 static void dumpSubscription(Archive *fout, SubscriptionInfo *subinfo);
271 static void dumpDatabase(Archive *AH);
272 static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
273                                                            const char *dbname, Oid dboid);
274 static void dumpEncoding(Archive *AH);
275 static void dumpStdStrings(Archive *AH);
276 static void dumpSearchPath(Archive *AH);
277 static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
278                                                                                                          PQExpBuffer upgrade_buffer,
279                                                                                                          Oid pg_type_oid,
280                                                                                                          bool force_array_type);
281 static bool binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
282                                                                                                         PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
283 static void binary_upgrade_set_pg_class_oids(Archive *fout,
284                                                                                          PQExpBuffer upgrade_buffer,
285                                                                                          Oid pg_class_oid, bool is_index);
286 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
287                                                                                         DumpableObject *dobj,
288                                                                                         const char *objtype,
289                                                                                         const char *objname,
290                                                                                         const char *objnamespace);
291 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
292 static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
293 static bool nonemptyReloptions(const char *reloptions);
294 static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
295                                                                         const char *prefix, Archive *fout);
296 static char *get_synchronized_snapshot(Archive *fout);
297 static void setupDumpWorker(Archive *AHX);
298 static TableInfo *getRootTableInfo(TableInfo *tbinfo);
299
300
301 int
302 main(int argc, char **argv)
303 {
304         int                     c;
305         const char *filename = NULL;
306         const char *format = "p";
307         TableInfo  *tblinfo;
308         int                     numTables;
309         DumpableObject **dobjs;
310         int                     numObjs;
311         DumpableObject *boundaryObjs;
312         int                     i;
313         int                     optindex;
314         char       *endptr;
315         RestoreOptions *ropt;
316         Archive    *fout;                       /* the script file */
317         bool            g_verbose = false;
318         const char *dumpencoding = NULL;
319         const char *dumpsnapshot = NULL;
320         char       *use_role = NULL;
321         long            rowsPerInsert;
322         int                     numWorkers = 1;
323         trivalue        prompt_password = TRI_DEFAULT;
324         int                     compressLevel = -1;
325         int                     plainText = 0;
326         ArchiveFormat archiveFormat = archUnknown;
327         ArchiveMode archiveMode;
328
329         static DumpOptions dopt;
330
331         static struct option long_options[] = {
332                 {"data-only", no_argument, NULL, 'a'},
333                 {"blobs", no_argument, NULL, 'b'},
334                 {"no-blobs", no_argument, NULL, 'B'},
335                 {"clean", no_argument, NULL, 'c'},
336                 {"create", no_argument, NULL, 'C'},
337                 {"dbname", required_argument, NULL, 'd'},
338                 {"file", required_argument, NULL, 'f'},
339                 {"format", required_argument, NULL, 'F'},
340                 {"host", required_argument, NULL, 'h'},
341                 {"jobs", 1, NULL, 'j'},
342                 {"no-reconnect", no_argument, NULL, 'R'},
343                 {"no-owner", no_argument, NULL, 'O'},
344                 {"port", required_argument, NULL, 'p'},
345                 {"schema", required_argument, NULL, 'n'},
346                 {"exclude-schema", required_argument, NULL, 'N'},
347                 {"schema-only", no_argument, NULL, 's'},
348                 {"superuser", required_argument, NULL, 'S'},
349                 {"table", required_argument, NULL, 't'},
350                 {"exclude-table", required_argument, NULL, 'T'},
351                 {"no-password", no_argument, NULL, 'w'},
352                 {"password", no_argument, NULL, 'W'},
353                 {"username", required_argument, NULL, 'U'},
354                 {"verbose", no_argument, NULL, 'v'},
355                 {"no-privileges", no_argument, NULL, 'x'},
356                 {"no-acl", no_argument, NULL, 'x'},
357                 {"compress", required_argument, NULL, 'Z'},
358                 {"encoding", required_argument, NULL, 'E'},
359                 {"help", no_argument, NULL, '?'},
360                 {"version", no_argument, NULL, 'V'},
361
362                 /*
363                  * the following options don't have an equivalent short option letter
364                  */
365                 {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
366                 {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
367                 {"column-inserts", no_argument, &dopt.column_inserts, 1},
368                 {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
369                 {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
370                 {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
371                 {"exclude-table-data", required_argument, NULL, 4},
372                 {"extra-float-digits", required_argument, NULL, 8},
373                 {"if-exists", no_argument, &dopt.if_exists, 1},
374                 {"inserts", no_argument, NULL, 9},
375                 {"lock-wait-timeout", required_argument, NULL, 2},
376                 {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
377                 {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
378                 {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
379                 {"role", required_argument, NULL, 3},
380                 {"section", required_argument, NULL, 5},
381                 {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
382                 {"snapshot", required_argument, NULL, 6},
383                 {"strict-names", no_argument, &strict_names, 1},
384                 {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
385                 {"no-comments", no_argument, &dopt.no_comments, 1},
386                 {"no-publications", no_argument, &dopt.no_publications, 1},
387                 {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
388                 {"no-synchronized-snapshots", no_argument, &dopt.no_synchronized_snapshots, 1},
389                 {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
390                 {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
391                 {"no-sync", no_argument, NULL, 7},
392                 {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
393                 {"rows-per-insert", required_argument, NULL, 10},
394
395                 {NULL, 0, NULL, 0}
396         };
397
398         pg_logging_init(argv[0]);
399         pg_logging_set_level(PG_LOG_WARNING);
400         set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
401
402         /*
403          * Initialize what we need for parallel execution, especially for thread
404          * support on Windows.
405          */
406         init_parallel_dump_utils();
407
408         strcpy(g_comment_start, "-- ");
409         g_comment_end[0] = '\0';
410         strcpy(g_opaque_type, "opaque");
411
412         progname = get_progname(argv[0]);
413
414         if (argc > 1)
415         {
416                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
417                 {
418                         help(progname);
419                         exit_nicely(0);
420                 }
421                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
422                 {
423                         puts("pg_dump (PostgreSQL) " PG_VERSION);
424                         exit_nicely(0);
425                 }
426         }
427
428         InitDumpOptions(&dopt);
429
430         while ((c = getopt_long(argc, argv, "abBcCd:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxZ:",
431                                                         long_options, &optindex)) != -1)
432         {
433                 switch (c)
434                 {
435                         case 'a':                       /* Dump data only */
436                                 dopt.dataOnly = true;
437                                 break;
438
439                         case 'b':                       /* Dump blobs */
440                                 dopt.outputBlobs = true;
441                                 break;
442
443                         case 'B':                       /* Don't dump blobs */
444                                 dopt.dontOutputBlobs = true;
445                                 break;
446
447                         case 'c':                       /* clean (i.e., drop) schema prior to create */
448                                 dopt.outputClean = 1;
449                                 break;
450
451                         case 'C':                       /* Create DB */
452                                 dopt.outputCreateDB = 1;
453                                 break;
454
455                         case 'd':                       /* database name */
456                                 dopt.dbname = pg_strdup(optarg);
457                                 break;
458
459                         case 'E':                       /* Dump encoding */
460                                 dumpencoding = pg_strdup(optarg);
461                                 break;
462
463                         case 'f':
464                                 filename = pg_strdup(optarg);
465                                 break;
466
467                         case 'F':
468                                 format = pg_strdup(optarg);
469                                 break;
470
471                         case 'h':                       /* server host */
472                                 dopt.pghost = pg_strdup(optarg);
473                                 break;
474
475                         case 'j':                       /* number of dump jobs */
476                                 numWorkers = atoi(optarg);
477                                 break;
478
479                         case 'n':                       /* include schema(s) */
480                                 simple_string_list_append(&schema_include_patterns, optarg);
481                                 dopt.include_everything = false;
482                                 break;
483
484                         case 'N':                       /* exclude schema(s) */
485                                 simple_string_list_append(&schema_exclude_patterns, optarg);
486                                 break;
487
488                         case 'O':                       /* Don't reconnect to match owner */
489                                 dopt.outputNoOwner = 1;
490                                 break;
491
492                         case 'p':                       /* server port */
493                                 dopt.pgport = pg_strdup(optarg);
494                                 break;
495
496                         case 'R':
497                                 /* no-op, still accepted for backwards compatibility */
498                                 break;
499
500                         case 's':                       /* dump schema only */
501                                 dopt.schemaOnly = true;
502                                 break;
503
504                         case 'S':                       /* Username for superuser in plain text output */
505                                 dopt.outputSuperuser = pg_strdup(optarg);
506                                 break;
507
508                         case 't':                       /* include table(s) */
509                                 simple_string_list_append(&table_include_patterns, optarg);
510                                 dopt.include_everything = false;
511                                 break;
512
513                         case 'T':                       /* exclude table(s) */
514                                 simple_string_list_append(&table_exclude_patterns, optarg);
515                                 break;
516
517                         case 'U':
518                                 dopt.username = pg_strdup(optarg);
519                                 break;
520
521                         case 'v':                       /* verbose */
522                                 g_verbose = true;
523                                 pg_logging_set_level(PG_LOG_INFO);
524                                 break;
525
526                         case 'w':
527                                 prompt_password = TRI_NO;
528                                 break;
529
530                         case 'W':
531                                 prompt_password = TRI_YES;
532                                 break;
533
534                         case 'x':                       /* skip ACL dump */
535                                 dopt.aclsSkip = true;
536                                 break;
537
538                         case 'Z':                       /* Compression Level */
539                                 compressLevel = atoi(optarg);
540                                 if (compressLevel < 0 || compressLevel > 9)
541                                 {
542                                         pg_log_error("compression level must be in range 0..9");
543                                         exit_nicely(1);
544                                 }
545                                 break;
546
547                         case 0:
548                                 /* This covers the long options. */
549                                 break;
550
551                         case 2:                         /* lock-wait-timeout */
552                                 dopt.lockWaitTimeout = pg_strdup(optarg);
553                                 break;
554
555                         case 3:                         /* SET ROLE */
556                                 use_role = pg_strdup(optarg);
557                                 break;
558
559                         case 4:                         /* exclude table(s) data */
560                                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
561                                 break;
562
563                         case 5:                         /* section */
564                                 set_dump_section(optarg, &dopt.dumpSections);
565                                 break;
566
567                         case 6:                         /* snapshot */
568                                 dumpsnapshot = pg_strdup(optarg);
569                                 break;
570
571                         case 7:                         /* no-sync */
572                                 dosync = false;
573                                 break;
574
575                         case 8:
576                                 have_extra_float_digits = true;
577                                 extra_float_digits = atoi(optarg);
578                                 if (extra_float_digits < -15 || extra_float_digits > 3)
579                                 {
580                                         pg_log_error("extra_float_digits must be in range -15..3");
581                                         exit_nicely(1);
582                                 }
583                                 break;
584
585                         case 9:                         /* inserts */
586
587                                 /*
588                                  * dump_inserts also stores --rows-per-insert, careful not to
589                                  * overwrite that.
590                                  */
591                                 if (dopt.dump_inserts == 0)
592                                         dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
593                                 break;
594
595                         case 10:                        /* rows per insert */
596                                 errno = 0;
597                                 rowsPerInsert = strtol(optarg, &endptr, 10);
598
599                                 if (endptr == optarg || *endptr != '\0' ||
600                                         rowsPerInsert <= 0 || rowsPerInsert > INT_MAX ||
601                                         errno == ERANGE)
602                                 {
603                                         pg_log_error("rows-per-insert must be in range %d..%d",
604                                                                  1, INT_MAX);
605                                         exit_nicely(1);
606                                 }
607                                 dopt.dump_inserts = (int) rowsPerInsert;
608                                 break;
609
610                         default:
611                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
612                                 exit_nicely(1);
613                 }
614         }
615
616         /*
617          * Non-option argument specifies database name as long as it wasn't
618          * already specified with -d / --dbname
619          */
620         if (optind < argc && dopt.dbname == NULL)
621                 dopt.dbname = argv[optind++];
622
623         /* Complain if any arguments remain */
624         if (optind < argc)
625         {
626                 pg_log_error("too many command-line arguments (first is \"%s\")",
627                                          argv[optind]);
628                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
629                                 progname);
630                 exit_nicely(1);
631         }
632
633         /* --column-inserts implies --inserts */
634         if (dopt.column_inserts && dopt.dump_inserts == 0)
635                 dopt.dump_inserts = DUMP_DEFAULT_ROWS_PER_INSERT;
636
637         /*
638          * Binary upgrade mode implies dumping sequence data even in schema-only
639          * mode.  This is not exposed as a separate option, but kept separate
640          * internally for clarity.
641          */
642         if (dopt.binary_upgrade)
643                 dopt.sequence_data = 1;
644
645         if (dopt.dataOnly && dopt.schemaOnly)
646         {
647                 pg_log_error("options -s/--schema-only and -a/--data-only cannot be used together");
648                 exit_nicely(1);
649         }
650
651         if (dopt.dataOnly && dopt.outputClean)
652         {
653                 pg_log_error("options -c/--clean and -a/--data-only cannot be used together");
654                 exit_nicely(1);
655         }
656
657         if (dopt.if_exists && !dopt.outputClean)
658                 fatal("option --if-exists requires option -c/--clean");
659
660         /*
661          * --inserts are already implied above if --column-inserts or
662          * --rows-per-insert were specified.
663          */
664         if (dopt.do_nothing && dopt.dump_inserts == 0)
665                 fatal("option --on-conflict-do-nothing requires option --inserts, --rows-per-insert, or --column-inserts");
666
667         /* Identify archive format to emit */
668         archiveFormat = parseArchiveFormat(format, &archiveMode);
669
670         /* archiveFormat specific setup */
671         if (archiveFormat == archNull)
672                 plainText = 1;
673
674         /* Custom and directory formats are compressed by default, others not */
675         if (compressLevel == -1)
676         {
677 #ifdef HAVE_LIBZ
678                 if (archiveFormat == archCustom || archiveFormat == archDirectory)
679                         compressLevel = Z_DEFAULT_COMPRESSION;
680                 else
681 #endif
682                         compressLevel = 0;
683         }
684
685 #ifndef HAVE_LIBZ
686         if (compressLevel != 0)
687                 pg_log_warning("requested compression not available in this installation -- archive will be uncompressed");
688         compressLevel = 0;
689 #endif
690
691         /*
692          * If emitting an archive format, we always want to emit a DATABASE item,
693          * in case --create is specified at pg_restore time.
694          */
695         if (!plainText)
696                 dopt.outputCreateDB = 1;
697
698         /*
699          * On Windows we can only have at most MAXIMUM_WAIT_OBJECTS (= 64 usually)
700          * parallel jobs because that's the maximum limit for the
701          * WaitForMultipleObjects() call.
702          */
703         if (numWorkers <= 0
704 #ifdef WIN32
705                 || numWorkers > MAXIMUM_WAIT_OBJECTS
706 #endif
707                 )
708                 fatal("invalid number of parallel jobs");
709
710         /* Parallel backup only in the directory archive format so far */
711         if (archiveFormat != archDirectory && numWorkers > 1)
712                 fatal("parallel backup only supported by the directory format");
713
714         /* Open the output file */
715         fout = CreateArchive(filename, archiveFormat, compressLevel, dosync,
716                                                  archiveMode, setupDumpWorker);
717
718         /* Make dump options accessible right away */
719         SetArchiveOptions(fout, &dopt, NULL);
720
721         /* Register the cleanup hook */
722         on_exit_close_archive(fout);
723
724         /* Let the archiver know how noisy to be */
725         fout->verbose = g_verbose;
726
727
728         /*
729          * We allow the server to be back to 8.0, and up to any minor release of
730          * our own major version.  (See also version check in pg_dumpall.c.)
731          */
732         fout->minRemoteVersion = 80000;
733         fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
734
735         fout->numWorkers = numWorkers;
736
737         /*
738          * Open the database using the Archiver, so it knows about it. Errors mean
739          * death.
740          */
741         ConnectDatabase(fout, dopt.dbname, dopt.pghost, dopt.pgport, dopt.username, prompt_password);
742         setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
743
744         /*
745          * Disable security label support if server version < v9.1.x (prevents
746          * access to nonexistent pg_seclabel catalog)
747          */
748         if (fout->remoteVersion < 90100)
749                 dopt.no_security_labels = 1;
750
751         /*
752          * On hot standbys, never try to dump unlogged table data, since it will
753          * just throw an error.
754          */
755         if (fout->isStandby)
756                 dopt.no_unlogged_table_data = true;
757
758         /* Select the appropriate subquery to convert user IDs to names */
759         if (fout->remoteVersion >= 80100)
760                 username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
761         else
762                 username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
763
764         /* check the version for the synchronized snapshots feature */
765         if (numWorkers > 1 && fout->remoteVersion < 90200
766                 && !dopt.no_synchronized_snapshots)
767                 fatal("Synchronized snapshots are not supported by this server version.\n"
768                           "Run with --no-synchronized-snapshots instead if you do not need\n"
769                           "synchronized snapshots.");
770
771         /* check the version when a snapshot is explicitly specified by user */
772         if (dumpsnapshot && fout->remoteVersion < 90200)
773                 fatal("Exported snapshots are not supported by this server version.");
774
775         /*
776          * Find the last built-in OID, if needed (prior to 8.1)
777          *
778          * With 8.1 and above, we can just use FirstNormalObjectId - 1.
779          */
780         if (fout->remoteVersion < 80100)
781                 g_last_builtin_oid = findLastBuiltinOid_V71(fout);
782         else
783                 g_last_builtin_oid = FirstNormalObjectId - 1;
784
785         pg_log_info("last built-in OID is %u", g_last_builtin_oid);
786
787         /* Expand schema selection patterns into OID lists */
788         if (schema_include_patterns.head != NULL)
789         {
790                 expand_schema_name_patterns(fout, &schema_include_patterns,
791                                                                         &schema_include_oids,
792                                                                         strict_names);
793                 if (schema_include_oids.head == NULL)
794                         fatal("no matching schemas were found");
795         }
796         expand_schema_name_patterns(fout, &schema_exclude_patterns,
797                                                                 &schema_exclude_oids,
798                                                                 false);
799         /* non-matching exclusion patterns aren't an error */
800
801         /* Expand table selection patterns into OID lists */
802         if (table_include_patterns.head != NULL)
803         {
804                 expand_table_name_patterns(fout, &table_include_patterns,
805                                                                    &table_include_oids,
806                                                                    strict_names);
807                 if (table_include_oids.head == NULL)
808                         fatal("no matching tables were found");
809         }
810         expand_table_name_patterns(fout, &table_exclude_patterns,
811                                                            &table_exclude_oids,
812                                                            false);
813
814         expand_table_name_patterns(fout, &tabledata_exclude_patterns,
815                                                            &tabledata_exclude_oids,
816                                                            false);
817
818         /* non-matching exclusion patterns aren't an error */
819
820         /*
821          * Dumping blobs is the default for dumps where an inclusion switch is not
822          * used (an "include everything" dump).  -B can be used to exclude blobs
823          * from those dumps.  -b can be used to include blobs even when an
824          * inclusion switch is used.
825          *
826          * -s means "schema only" and blobs are data, not schema, so we never
827          * include blobs when -s is used.
828          */
829         if (dopt.include_everything && !dopt.schemaOnly && !dopt.dontOutputBlobs)
830                 dopt.outputBlobs = true;
831
832         /*
833          * Now scan the database and create DumpableObject structs for all the
834          * objects we intend to dump.
835          */
836         tblinfo = getSchemaData(fout, &numTables);
837
838         if (fout->remoteVersion < 80400)
839                 guessConstraintInheritance(tblinfo, numTables);
840
841         if (!dopt.schemaOnly)
842         {
843                 getTableData(&dopt, tblinfo, numTables, 0);
844                 buildMatViewRefreshDependencies(fout);
845                 if (dopt.dataOnly)
846                         getTableDataFKConstraints();
847         }
848
849         if (dopt.schemaOnly && dopt.sequence_data)
850                 getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
851
852         /*
853          * In binary-upgrade mode, we do not have to worry about the actual blob
854          * data or the associated metadata that resides in the pg_largeobject and
855          * pg_largeobject_metadata tables, respectively.
856          *
857          * However, we do need to collect blob information as there may be
858          * comments or other information on blobs that we do need to dump out.
859          */
860         if (dopt.outputBlobs || dopt.binary_upgrade)
861                 getBlobs(fout);
862
863         /*
864          * Collect dependency data to assist in ordering the objects.
865          */
866         getDependencies(fout);
867
868         /* Lastly, create dummy objects to represent the section boundaries */
869         boundaryObjs = createBoundaryObjects();
870
871         /* Get pointers to all the known DumpableObjects */
872         getDumpableObjects(&dobjs, &numObjs);
873
874         /*
875          * Add dummy dependencies to enforce the dump section ordering.
876          */
877         addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
878
879         /*
880          * Sort the objects into a safe dump order (no forward references).
881          *
882          * We rely on dependency information to help us determine a safe order, so
883          * the initial sort is mostly for cosmetic purposes: we sort by name to
884          * ensure that logically identical schemas will dump identically.
885          */
886         sortDumpableObjectsByTypeName(dobjs, numObjs);
887
888         sortDumpableObjects(dobjs, numObjs,
889                                                 boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
890
891         /*
892          * Create archive TOC entries for all the objects to be dumped, in a safe
893          * order.
894          */
895
896         /* First the special ENCODING, STDSTRINGS, and SEARCHPATH entries. */
897         dumpEncoding(fout);
898         dumpStdStrings(fout);
899         dumpSearchPath(fout);
900
901         /* The database items are always next, unless we don't want them at all */
902         if (dopt.outputCreateDB)
903                 dumpDatabase(fout);
904
905         /* Now the rearrangeable objects. */
906         for (i = 0; i < numObjs; i++)
907                 dumpDumpableObject(fout, dobjs[i]);
908
909         /*
910          * Set up options info to ensure we dump what we want.
911          */
912         ropt = NewRestoreOptions();
913         ropt->filename = filename;
914
915         /* if you change this list, see dumpOptionsFromRestoreOptions */
916         ropt->dropSchema = dopt.outputClean;
917         ropt->dataOnly = dopt.dataOnly;
918         ropt->schemaOnly = dopt.schemaOnly;
919         ropt->if_exists = dopt.if_exists;
920         ropt->column_inserts = dopt.column_inserts;
921         ropt->dumpSections = dopt.dumpSections;
922         ropt->aclsSkip = dopt.aclsSkip;
923         ropt->superuser = dopt.outputSuperuser;
924         ropt->createDB = dopt.outputCreateDB;
925         ropt->noOwner = dopt.outputNoOwner;
926         ropt->noTablespace = dopt.outputNoTablespaces;
927         ropt->disable_triggers = dopt.disable_triggers;
928         ropt->use_setsessauth = dopt.use_setsessauth;
929         ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
930         ropt->dump_inserts = dopt.dump_inserts;
931         ropt->no_comments = dopt.no_comments;
932         ropt->no_publications = dopt.no_publications;
933         ropt->no_security_labels = dopt.no_security_labels;
934         ropt->no_subscriptions = dopt.no_subscriptions;
935         ropt->lockWaitTimeout = dopt.lockWaitTimeout;
936         ropt->include_everything = dopt.include_everything;
937         ropt->enable_row_security = dopt.enable_row_security;
938         ropt->sequence_data = dopt.sequence_data;
939         ropt->binary_upgrade = dopt.binary_upgrade;
940
941         if (compressLevel == -1)
942                 ropt->compression = 0;
943         else
944                 ropt->compression = compressLevel;
945
946         ropt->suppressDumpWarnings = true;      /* We've already shown them */
947
948         SetArchiveOptions(fout, &dopt, ropt);
949
950         /* Mark which entries should be output */
951         ProcessArchiveRestoreOptions(fout);
952
953         /*
954          * The archive's TOC entries are now marked as to which ones will actually
955          * be output, so we can set up their dependency lists properly. This isn't
956          * necessary for plain-text output, though.
957          */
958         if (!plainText)
959                 BuildArchiveDependencies(fout);
960
961         /*
962          * And finally we can do the actual output.
963          *
964          * Note: for non-plain-text output formats, the output file is written
965          * inside CloseArchive().  This is, um, bizarre; but not worth changing
966          * right now.
967          */
968         if (plainText)
969                 RestoreArchive(fout);
970
971         CloseArchive(fout);
972
973         exit_nicely(0);
974 }
975
976
977 static void
978 help(const char *progname)
979 {
980         printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
981         printf(_("Usage:\n"));
982         printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
983
984         printf(_("\nGeneral options:\n"));
985         printf(_("  -f, --file=FILENAME          output file or directory name\n"));
986         printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
987                          "                               plain text (default))\n"));
988         printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
989         printf(_("  -v, --verbose                verbose mode\n"));
990         printf(_("  -V, --version                output version information, then exit\n"));
991         printf(_("  -Z, --compress=0-9           compression level for compressed formats\n"));
992         printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
993         printf(_("  --no-sync                    do not wait for changes to be written safely to disk\n"));
994         printf(_("  -?, --help                   show this help, then exit\n"));
995
996         printf(_("\nOptions controlling the output content:\n"));
997         printf(_("  -a, --data-only              dump only the data, not the schema\n"));
998         printf(_("  -b, --blobs                  include large objects in dump\n"));
999         printf(_("  -B, --no-blobs               exclude large objects in dump\n"));
1000         printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
1001         printf(_("  -C, --create                 include commands to create database in dump\n"));
1002         printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
1003         printf(_("  -n, --schema=SCHEMA          dump the named schema(s) only\n"));
1004         printf(_("  -N, --exclude-schema=SCHEMA  do NOT dump the named schema(s)\n"));
1005         printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
1006                          "                               plain-text format\n"));
1007         printf(_("  -s, --schema-only            dump only the schema, no data\n"));
1008         printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
1009         printf(_("  -t, --table=TABLE            dump the named table(s) only\n"));
1010         printf(_("  -T, --exclude-table=TABLE    do NOT dump the named table(s)\n"));
1011         printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
1012         printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
1013         printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
1014         printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
1015         printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
1016         printf(_("  --enable-row-security        enable row security (dump only content user has\n"
1017                          "                               access to)\n"));
1018         printf(_("  --exclude-table-data=TABLE   do NOT dump data for the named table(s)\n"));
1019         printf(_("  --extra-float-digits=NUM     override default setting for extra_float_digits\n"));
1020         printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
1021         printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
1022         printf(_("  --load-via-partition-root    load partitions via the root table\n"));
1023         printf(_("  --no-comments                do not dump comments\n"));
1024         printf(_("  --no-publications            do not dump publications\n"));
1025         printf(_("  --no-security-labels         do not dump security label assignments\n"));
1026         printf(_("  --no-subscriptions           do not dump subscriptions\n"));
1027         printf(_("  --no-synchronized-snapshots  do not use synchronized snapshots in parallel jobs\n"));
1028         printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
1029         printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
1030         printf(_("  --on-conflict-do-nothing     add ON CONFLICT DO NOTHING to INSERT commands\n"));
1031         printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
1032         printf(_("  --rows-per-insert=NROWS      number of rows per INSERT; implies --inserts\n"));
1033         printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
1034         printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
1035         printf(_("  --snapshot=SNAPSHOT          use given snapshot for the dump\n"));
1036         printf(_("  --strict-names               require table and/or schema include patterns to\n"
1037                          "                               match at least one entity each\n"));
1038         printf(_("  --use-set-session-authorization\n"
1039                          "                               use SET SESSION AUTHORIZATION commands instead of\n"
1040                          "                               ALTER OWNER commands to set ownership\n"));
1041
1042         printf(_("\nConnection options:\n"));
1043         printf(_("  -d, --dbname=DBNAME      database to dump\n"));
1044         printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
1045         printf(_("  -p, --port=PORT          database server port number\n"));
1046         printf(_("  -U, --username=NAME      connect as specified database user\n"));
1047         printf(_("  -w, --no-password        never prompt for password\n"));
1048         printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
1049         printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
1050
1051         printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
1052                          "variable value is used.\n\n"));
1053         printf(_("Report bugs to <pgsql-bugs@lists.postgresql.org>.\n"));
1054 }
1055
1056 static void
1057 setup_connection(Archive *AH, const char *dumpencoding,
1058                                  const char *dumpsnapshot, char *use_role)
1059 {
1060         DumpOptions *dopt = AH->dopt;
1061         PGconn     *conn = GetConnection(AH);
1062         const char *std_strings;
1063
1064         PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
1065
1066         /*
1067          * Set the client encoding if requested.
1068          */
1069         if (dumpencoding)
1070         {
1071                 if (PQsetClientEncoding(conn, dumpencoding) < 0)
1072                         fatal("invalid client encoding \"%s\" specified",
1073                                   dumpencoding);
1074         }
1075
1076         /*
1077          * Get the active encoding and the standard_conforming_strings setting, so
1078          * we know how to escape strings.
1079          */
1080         AH->encoding = PQclientEncoding(conn);
1081
1082         std_strings = PQparameterStatus(conn, "standard_conforming_strings");
1083         AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
1084
1085         /*
1086          * Set the role if requested.  In a parallel dump worker, we'll be passed
1087          * use_role == NULL, but AH->use_role is already set (if user specified it
1088          * originally) and we should use that.
1089          */
1090         if (!use_role && AH->use_role)
1091                 use_role = AH->use_role;
1092
1093         /* Set the role if requested */
1094         if (use_role && AH->remoteVersion >= 80100)
1095         {
1096                 PQExpBuffer query = createPQExpBuffer();
1097
1098                 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
1099                 ExecuteSqlStatement(AH, query->data);
1100                 destroyPQExpBuffer(query);
1101
1102                 /* save it for possible later use by parallel workers */
1103                 if (!AH->use_role)
1104                         AH->use_role = pg_strdup(use_role);
1105         }
1106
1107         /* Set the datestyle to ISO to ensure the dump's portability */
1108         ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
1109
1110         /* Likewise, avoid using sql_standard intervalstyle */
1111         if (AH->remoteVersion >= 80400)
1112                 ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
1113
1114         /*
1115          * Use an explicitly specified extra_float_digits if it has been provided.
1116          * Otherwise, set extra_float_digits so that we can dump float data
1117          * exactly (given correctly implemented float I/O code, anyway).
1118          */
1119         if (have_extra_float_digits)
1120         {
1121                 PQExpBuffer q = createPQExpBuffer();
1122
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                 appendPQExpBufferStr(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                 appendPQExpBufferStr(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         /*
2669          * Fetch the database-level properties for this database.
2670          *
2671          * The order in which privileges are in the ACL string (the order they
2672          * have been GRANT'd in, which the backend maintains) must be preserved to
2673          * ensure that GRANTs WITH GRANT OPTION and subsequent GRANTs based on
2674          * those are dumped in the correct order.  Note that initial privileges
2675          * (pg_init_privs) are not supported on databases, so this logic cannot
2676          * make use of buildACLQueries().
2677          */
2678         if (fout->remoteVersion >= 90600)
2679         {
2680                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2681                                                   "(%s datdba) AS dba, "
2682                                                   "pg_encoding_to_char(encoding) AS encoding, "
2683                                                   "datcollate, datctype, datfrozenxid, datminmxid, "
2684                                                   "(SELECT array_agg(acl ORDER BY row_n) FROM "
2685                                                   "  (SELECT acl, row_n FROM "
2686                                                   "     unnest(coalesce(datacl,acldefault('d',datdba))) "
2687                                                   "     WITH ORDINALITY AS perm(acl,row_n) "
2688                                                   "   WHERE NOT EXISTS ( "
2689                                                   "     SELECT 1 "
2690                                                   "     FROM unnest(acldefault('d',datdba)) "
2691                                                   "       AS init(init_acl) "
2692                                                   "     WHERE acl = init_acl)) AS datacls) "
2693                                                   " AS datacl, "
2694                                                   "(SELECT array_agg(acl ORDER BY row_n) FROM "
2695                                                   "  (SELECT acl, row_n FROM "
2696                                                   "     unnest(acldefault('d',datdba)) "
2697                                                   "     WITH ORDINALITY AS initp(acl,row_n) "
2698                                                   "   WHERE NOT EXISTS ( "
2699                                                   "     SELECT 1 "
2700                                                   "     FROM unnest(coalesce(datacl,acldefault('d',datdba))) "
2701                                                   "       AS permp(orig_acl) "
2702                                                   "     WHERE acl = orig_acl)) AS rdatacls) "
2703                                                   " AS rdatacl, "
2704                                                   "datistemplate, datconnlimit, "
2705                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2706                                                   "shobj_description(oid, 'pg_database') AS description "
2707
2708                                                   "FROM pg_database "
2709                                                   "WHERE datname = current_database()",
2710                                                   username_subquery);
2711         }
2712         else if (fout->remoteVersion >= 90300)
2713         {
2714                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2715                                                   "(%s datdba) AS dba, "
2716                                                   "pg_encoding_to_char(encoding) AS encoding, "
2717                                                   "datcollate, datctype, datfrozenxid, datminmxid, "
2718                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2719                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2720                                                   "shobj_description(oid, 'pg_database') AS description "
2721
2722                                                   "FROM pg_database "
2723                                                   "WHERE datname = current_database()",
2724                                                   username_subquery);
2725         }
2726         else if (fout->remoteVersion >= 80400)
2727         {
2728                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2729                                                   "(%s datdba) AS dba, "
2730                                                   "pg_encoding_to_char(encoding) AS encoding, "
2731                                                   "datcollate, datctype, datfrozenxid, 0 AS datminmxid, "
2732                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2733                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2734                                                   "shobj_description(oid, 'pg_database') AS description "
2735
2736                                                   "FROM pg_database "
2737                                                   "WHERE datname = current_database()",
2738                                                   username_subquery);
2739         }
2740         else if (fout->remoteVersion >= 80200)
2741         {
2742                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2743                                                   "(%s datdba) AS dba, "
2744                                                   "pg_encoding_to_char(encoding) AS encoding, "
2745                                                   "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2746                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2747                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2748                                                   "shobj_description(oid, 'pg_database') AS description "
2749
2750                                                   "FROM pg_database "
2751                                                   "WHERE datname = current_database()",
2752                                                   username_subquery);
2753         }
2754         else
2755         {
2756                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2757                                                   "(%s datdba) AS dba, "
2758                                                   "pg_encoding_to_char(encoding) AS encoding, "
2759                                                   "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2760                                                   "datacl, '' as rdatacl, datistemplate, "
2761                                                   "-1 as datconnlimit, "
2762                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
2763                                                   "FROM pg_database "
2764                                                   "WHERE datname = current_database()",
2765                                                   username_subquery);
2766         }
2767
2768         res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
2769
2770         i_tableoid = PQfnumber(res, "tableoid");
2771         i_oid = PQfnumber(res, "oid");
2772         i_datname = PQfnumber(res, "datname");
2773         i_dba = PQfnumber(res, "dba");
2774         i_encoding = PQfnumber(res, "encoding");
2775         i_collate = PQfnumber(res, "datcollate");
2776         i_ctype = PQfnumber(res, "datctype");
2777         i_frozenxid = PQfnumber(res, "datfrozenxid");
2778         i_minmxid = PQfnumber(res, "datminmxid");
2779         i_datacl = PQfnumber(res, "datacl");
2780         i_rdatacl = PQfnumber(res, "rdatacl");
2781         i_datistemplate = PQfnumber(res, "datistemplate");
2782         i_datconnlimit = PQfnumber(res, "datconnlimit");
2783         i_tablespace = PQfnumber(res, "tablespace");
2784
2785         dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
2786         dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
2787         datname = PQgetvalue(res, 0, i_datname);
2788         dba = PQgetvalue(res, 0, i_dba);
2789         encoding = PQgetvalue(res, 0, i_encoding);
2790         collate = PQgetvalue(res, 0, i_collate);
2791         ctype = PQgetvalue(res, 0, i_ctype);
2792         frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
2793         minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
2794         datacl = PQgetvalue(res, 0, i_datacl);
2795         rdatacl = PQgetvalue(res, 0, i_rdatacl);
2796         datistemplate = PQgetvalue(res, 0, i_datistemplate);
2797         datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
2798         tablespace = PQgetvalue(res, 0, i_tablespace);
2799
2800         qdatname = pg_strdup(fmtId(datname));
2801
2802         /*
2803          * Prepare the CREATE DATABASE command.  We must specify encoding, locale,
2804          * and tablespace since those can't be altered later.  Other DB properties
2805          * are left to the DATABASE PROPERTIES entry, so that they can be applied
2806          * after reconnecting to the target DB.
2807          */
2808         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
2809                                           qdatname);
2810         if (strlen(encoding) > 0)
2811         {
2812                 appendPQExpBufferStr(creaQry, " ENCODING = ");
2813                 appendStringLiteralAH(creaQry, encoding, fout);
2814         }
2815         if (strlen(collate) > 0 && strcmp(collate, ctype) == 0)
2816         {
2817                 appendPQExpBufferStr(creaQry, " LOCALE = ");
2818                 appendStringLiteralAH(creaQry, collate, fout);
2819         }
2820         else
2821         {
2822                 if (strlen(collate) > 0)
2823                 {
2824                         appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
2825                         appendStringLiteralAH(creaQry, collate, fout);
2826                 }
2827                 if (strlen(ctype) > 0)
2828                 {
2829                         appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
2830                         appendStringLiteralAH(creaQry, ctype, fout);
2831                 }
2832         }
2833
2834         /*
2835          * Note: looking at dopt->outputNoTablespaces here is completely the wrong
2836          * thing; the decision whether to specify a tablespace should be left till
2837          * pg_restore, so that pg_restore --no-tablespaces applies.  Ideally we'd
2838          * label the DATABASE entry with the tablespace and let the normal
2839          * tablespace selection logic work ... but CREATE DATABASE doesn't pay
2840          * attention to default_tablespace, so that won't work.
2841          */
2842         if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
2843                 !dopt->outputNoTablespaces)
2844                 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
2845                                                   fmtId(tablespace));
2846         appendPQExpBufferStr(creaQry, ";\n");
2847
2848         appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
2849                                           qdatname);
2850
2851         dbDumpId = createDumpId();
2852
2853         ArchiveEntry(fout,
2854                                  dbCatId,               /* catalog ID */
2855                                  dbDumpId,              /* dump ID */
2856                                  ARCHIVE_OPTS(.tag = datname,
2857                                                           .owner = dba,
2858                                                           .description = "DATABASE",
2859                                                           .section = SECTION_PRE_DATA,
2860                                                           .createStmt = creaQry->data,
2861                                                           .dropStmt = delQry->data));
2862
2863         /* Compute correct tag for archive entry */
2864         appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
2865
2866         /* Dump DB comment if any */
2867         if (fout->remoteVersion >= 80200)
2868         {
2869                 /*
2870                  * 8.2 and up keep comments on shared objects in a shared table, so we
2871                  * cannot use the dumpComment() code used for other database objects.
2872                  * Be careful that the ArchiveEntry parameters match that function.
2873                  */
2874                 char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
2875
2876                 if (comment && *comment && !dopt->no_comments)
2877                 {
2878                         resetPQExpBuffer(dbQry);
2879
2880                         /*
2881                          * Generates warning when loaded into a differently-named
2882                          * database.
2883                          */
2884                         appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
2885                         appendStringLiteralAH(dbQry, comment, fout);
2886                         appendPQExpBufferStr(dbQry, ";\n");
2887
2888                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2889                                                  ARCHIVE_OPTS(.tag = labelq->data,
2890                                                                           .owner = dba,
2891                                                                           .description = "COMMENT",
2892                                                                           .section = SECTION_NONE,
2893                                                                           .createStmt = dbQry->data,
2894                                                                           .deps = &dbDumpId,
2895                                                                           .nDeps = 1));
2896                 }
2897         }
2898         else
2899         {
2900                 dumpComment(fout, "DATABASE", qdatname, NULL, dba,
2901                                         dbCatId, 0, dbDumpId);
2902         }
2903
2904         /* Dump DB security label, if enabled */
2905         if (!dopt->no_security_labels && fout->remoteVersion >= 90200)
2906         {
2907                 PGresult   *shres;
2908                 PQExpBuffer seclabelQry;
2909
2910                 seclabelQry = createPQExpBuffer();
2911
2912                 buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
2913                 shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
2914                 resetPQExpBuffer(seclabelQry);
2915                 emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
2916                 if (seclabelQry->len > 0)
2917                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2918                                                  ARCHIVE_OPTS(.tag = labelq->data,
2919                                                                           .owner = dba,
2920                                                                           .description = "SECURITY LABEL",
2921                                                                           .section = SECTION_NONE,
2922                                                                           .createStmt = seclabelQry->data,
2923                                                                           .deps = &dbDumpId,
2924                                                                           .nDeps = 1));
2925                 destroyPQExpBuffer(seclabelQry);
2926                 PQclear(shres);
2927         }
2928
2929         /*
2930          * Dump ACL if any.  Note that we do not support initial privileges
2931          * (pg_init_privs) on databases.
2932          */
2933         dumpACL(fout, dbCatId, dbDumpId, "DATABASE",
2934                         qdatname, NULL, NULL,
2935                         dba, datacl, rdatacl, "", "");
2936
2937         /*
2938          * Now construct a DATABASE PROPERTIES archive entry to restore any
2939          * non-default database-level properties.  (The reason this must be
2940          * separate is that we cannot put any additional commands into the TOC
2941          * entry that has CREATE DATABASE.  pg_restore would execute such a group
2942          * in an implicit transaction block, and the backend won't allow CREATE
2943          * DATABASE in that context.)
2944          */
2945         resetPQExpBuffer(creaQry);
2946         resetPQExpBuffer(delQry);
2947
2948         if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
2949                 appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
2950                                                   qdatname, datconnlimit);
2951
2952         if (strcmp(datistemplate, "t") == 0)
2953         {
2954                 appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
2955                                                   qdatname);
2956
2957                 /*
2958                  * The backend won't accept DROP DATABASE on a template database.  We
2959                  * can deal with that by removing the template marking before the DROP
2960                  * gets issued.  We'd prefer to use ALTER DATABASE IF EXISTS here, but
2961                  * since no such command is currently supported, fake it with a direct
2962                  * UPDATE on pg_database.
2963                  */
2964                 appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
2965                                                          "SET datistemplate = false WHERE datname = ");
2966                 appendStringLiteralAH(delQry, datname, fout);
2967                 appendPQExpBufferStr(delQry, ";\n");
2968         }
2969
2970         /* Add database-specific SET options */
2971         dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
2972
2973         /*
2974          * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
2975          * entry, too, for lack of a better place.
2976          */
2977         if (dopt->binary_upgrade)
2978         {
2979                 appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
2980                 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
2981                                                   "SET datfrozenxid = '%u', datminmxid = '%u'\n"
2982                                                   "WHERE datname = ",
2983                                                   frozenxid, minmxid);
2984                 appendStringLiteralAH(creaQry, datname, fout);
2985                 appendPQExpBufferStr(creaQry, ";\n");
2986         }
2987
2988         if (creaQry->len > 0)
2989                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
2990                                          ARCHIVE_OPTS(.tag = datname,
2991                                                                   .owner = dba,
2992                                                                   .description = "DATABASE PROPERTIES",
2993                                                                   .section = SECTION_PRE_DATA,
2994                                                                   .createStmt = creaQry->data,
2995                                                                   .dropStmt = delQry->data,
2996                                                                   .deps = &dbDumpId));
2997
2998         /*
2999          * pg_largeobject comes from the old system intact, so set its
3000          * relfrozenxids and relminmxids.
3001          */
3002         if (dopt->binary_upgrade)
3003         {
3004                 PGresult   *lo_res;
3005                 PQExpBuffer loFrozenQry = createPQExpBuffer();
3006                 PQExpBuffer loOutQry = createPQExpBuffer();
3007                 int                     i_relfrozenxid,
3008                                         i_relminmxid;
3009
3010                 /*
3011                  * pg_largeobject
3012                  */
3013                 if (fout->remoteVersion >= 90300)
3014                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
3015                                                           "FROM pg_catalog.pg_class\n"
3016                                                           "WHERE oid = %u;\n",
3017                                                           LargeObjectRelationId);
3018                 else
3019                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
3020                                                           "FROM pg_catalog.pg_class\n"
3021                                                           "WHERE oid = %u;\n",
3022                                                           LargeObjectRelationId);
3023
3024                 lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
3025
3026                 i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
3027                 i_relminmxid = PQfnumber(lo_res, "relminmxid");
3028
3029                 appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
3030                 appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
3031                                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
3032                                                   "WHERE oid = %u;\n",
3033                                                   atooid(PQgetvalue(lo_res, 0, i_relfrozenxid)),
3034                                                   atooid(PQgetvalue(lo_res, 0, i_relminmxid)),
3035                                                   LargeObjectRelationId);
3036                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
3037                                          ARCHIVE_OPTS(.tag = "pg_largeobject",
3038                                                                   .description = "pg_largeobject",
3039                                                                   .section = SECTION_PRE_DATA,
3040                                                                   .createStmt = loOutQry->data));
3041
3042                 PQclear(lo_res);
3043
3044                 destroyPQExpBuffer(loFrozenQry);
3045                 destroyPQExpBuffer(loOutQry);
3046         }
3047
3048         PQclear(res);
3049
3050         free(qdatname);
3051         destroyPQExpBuffer(dbQry);
3052         destroyPQExpBuffer(delQry);
3053         destroyPQExpBuffer(creaQry);
3054         destroyPQExpBuffer(labelq);
3055 }
3056
3057 /*
3058  * Collect any database-specific or role-and-database-specific SET options
3059  * for this database, and append them to outbuf.
3060  */
3061 static void
3062 dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
3063                                    const char *dbname, Oid dboid)
3064 {
3065         PGconn     *conn = GetConnection(AH);
3066         PQExpBuffer buf = createPQExpBuffer();
3067         PGresult   *res;
3068         int                     count = 1;
3069
3070         /*
3071          * First collect database-specific options.  Pre-8.4 server versions lack
3072          * unnest(), so we do this the hard way by querying once per subscript.
3073          */
3074         for (;;)
3075         {
3076                 if (AH->remoteVersion >= 90000)
3077                         printfPQExpBuffer(buf, "SELECT setconfig[%d] FROM pg_db_role_setting "
3078                                                           "WHERE setrole = 0 AND setdatabase = '%u'::oid",
3079                                                           count, dboid);
3080                 else
3081                         printfPQExpBuffer(buf, "SELECT datconfig[%d] FROM pg_database WHERE oid = '%u'::oid", count, dboid);
3082
3083                 res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3084
3085                 if (PQntuples(res) == 1 &&
3086                         !PQgetisnull(res, 0, 0))
3087                 {
3088                         makeAlterConfigCommand(conn, PQgetvalue(res, 0, 0),
3089                                                                    "DATABASE", dbname, NULL, NULL,
3090                                                                    outbuf);
3091                         PQclear(res);
3092                         count++;
3093                 }
3094                 else
3095                 {
3096                         PQclear(res);
3097                         break;
3098                 }
3099         }
3100
3101         /* Now look for role-and-database-specific options */
3102         if (AH->remoteVersion >= 90000)
3103         {
3104                 /* Here we can assume we have unnest() */
3105                 printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
3106                                                   "FROM pg_db_role_setting s, pg_roles r "
3107                                                   "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
3108                                                   dboid);
3109
3110                 res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3111
3112                 if (PQntuples(res) > 0)
3113                 {
3114                         int                     i;
3115
3116                         for (i = 0; i < PQntuples(res); i++)
3117                                 makeAlterConfigCommand(conn, PQgetvalue(res, i, 1),
3118                                                                            "ROLE", PQgetvalue(res, i, 0),
3119                                                                            "DATABASE", dbname,
3120                                                                            outbuf);
3121                 }
3122
3123                 PQclear(res);
3124         }
3125
3126         destroyPQExpBuffer(buf);
3127 }
3128
3129 /*
3130  * dumpEncoding: put the correct encoding into the archive
3131  */
3132 static void
3133 dumpEncoding(Archive *AH)
3134 {
3135         const char *encname = pg_encoding_to_char(AH->encoding);
3136         PQExpBuffer qry = createPQExpBuffer();
3137
3138         pg_log_info("saving encoding = %s", encname);
3139
3140         appendPQExpBufferStr(qry, "SET client_encoding = ");
3141         appendStringLiteralAH(qry, encname, AH);
3142         appendPQExpBufferStr(qry, ";\n");
3143
3144         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3145                                  ARCHIVE_OPTS(.tag = "ENCODING",
3146                                                           .description = "ENCODING",
3147                                                           .section = SECTION_PRE_DATA,
3148                                                           .createStmt = qry->data));
3149
3150         destroyPQExpBuffer(qry);
3151 }
3152
3153
3154 /*
3155  * dumpStdStrings: put the correct escape string behavior into the archive
3156  */
3157 static void
3158 dumpStdStrings(Archive *AH)
3159 {
3160         const char *stdstrings = AH->std_strings ? "on" : "off";
3161         PQExpBuffer qry = createPQExpBuffer();
3162
3163         pg_log_info("saving standard_conforming_strings = %s",
3164                                 stdstrings);
3165
3166         appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
3167                                           stdstrings);
3168
3169         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3170                                  ARCHIVE_OPTS(.tag = "STDSTRINGS",
3171                                                           .description = "STDSTRINGS",
3172                                                           .section = SECTION_PRE_DATA,
3173                                                           .createStmt = qry->data));
3174
3175         destroyPQExpBuffer(qry);
3176 }
3177
3178 /*
3179  * dumpSearchPath: record the active search_path in the archive
3180  */
3181 static void
3182 dumpSearchPath(Archive *AH)
3183 {
3184         PQExpBuffer qry = createPQExpBuffer();
3185         PQExpBuffer path = createPQExpBuffer();
3186         PGresult   *res;
3187         char      **schemanames = NULL;
3188         int                     nschemanames = 0;
3189         int                     i;
3190
3191         /*
3192          * We use the result of current_schemas(), not the search_path GUC,
3193          * because that might contain wildcards such as "$user", which won't
3194          * necessarily have the same value during restore.  Also, this way avoids
3195          * listing schemas that may appear in search_path but not actually exist,
3196          * which seems like a prudent exclusion.
3197          */
3198         res = ExecuteSqlQueryForSingleRow(AH,
3199                                                                           "SELECT pg_catalog.current_schemas(false)");
3200
3201         if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
3202                 fatal("could not parse result of current_schemas()");
3203
3204         /*
3205          * We use set_config(), not a simple "SET search_path" command, because
3206          * the latter has less-clean behavior if the search path is empty.  While
3207          * that's likely to get fixed at some point, it seems like a good idea to
3208          * be as backwards-compatible as possible in what we put into archives.
3209          */
3210         for (i = 0; i < nschemanames; i++)
3211         {
3212                 if (i > 0)
3213                         appendPQExpBufferStr(path, ", ");
3214                 appendPQExpBufferStr(path, fmtId(schemanames[i]));
3215         }
3216
3217         appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
3218         appendStringLiteralAH(qry, path->data, AH);
3219         appendPQExpBufferStr(qry, ", false);\n");
3220
3221         pg_log_info("saving search_path = %s", path->data);
3222
3223         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3224                                  ARCHIVE_OPTS(.tag = "SEARCHPATH",
3225                                                           .description = "SEARCHPATH",
3226                                                           .section = SECTION_PRE_DATA,
3227                                                           .createStmt = qry->data));
3228
3229         /* Also save it in AH->searchpath, in case we're doing plain text dump */
3230         AH->searchpath = pg_strdup(qry->data);
3231
3232         if (schemanames)
3233                 free(schemanames);
3234         PQclear(res);
3235         destroyPQExpBuffer(qry);
3236         destroyPQExpBuffer(path);
3237 }
3238
3239
3240 /*
3241  * getBlobs:
3242  *      Collect schema-level data about large objects
3243  */
3244 static void
3245 getBlobs(Archive *fout)
3246 {
3247         DumpOptions *dopt = fout->dopt;
3248         PQExpBuffer blobQry = createPQExpBuffer();
3249         BlobInfo   *binfo;
3250         DumpableObject *bdata;
3251         PGresult   *res;
3252         int                     ntups;
3253         int                     i;
3254         int                     i_oid;
3255         int                     i_lomowner;
3256         int                     i_lomacl;
3257         int                     i_rlomacl;
3258         int                     i_initlomacl;
3259         int                     i_initrlomacl;
3260
3261         pg_log_info("reading large objects");
3262
3263         /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
3264         if (fout->remoteVersion >= 90600)
3265         {
3266                 PQExpBuffer acl_subquery = createPQExpBuffer();
3267                 PQExpBuffer racl_subquery = createPQExpBuffer();
3268                 PQExpBuffer init_acl_subquery = createPQExpBuffer();
3269                 PQExpBuffer init_racl_subquery = createPQExpBuffer();
3270
3271                 buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
3272                                                 init_racl_subquery, "l.lomacl", "l.lomowner", "'L'",
3273                                                 dopt->binary_upgrade);
3274
3275                 appendPQExpBuffer(blobQry,
3276                                                   "SELECT l.oid, (%s l.lomowner) AS rolname, "
3277                                                   "%s AS lomacl, "
3278                                                   "%s AS rlomacl, "
3279                                                   "%s AS initlomacl, "
3280                                                   "%s AS initrlomacl "
3281                                                   "FROM pg_largeobject_metadata l "
3282                                                   "LEFT JOIN pg_init_privs pip ON "
3283                                                   "(l.oid = pip.objoid "
3284                                                   "AND pip.classoid = 'pg_largeobject'::regclass "
3285                                                   "AND pip.objsubid = 0) ",
3286                                                   username_subquery,
3287                                                   acl_subquery->data,
3288                                                   racl_subquery->data,
3289                                                   init_acl_subquery->data,
3290                                                   init_racl_subquery->data);
3291
3292                 destroyPQExpBuffer(acl_subquery);
3293                 destroyPQExpBuffer(racl_subquery);
3294                 destroyPQExpBuffer(init_acl_subquery);
3295                 destroyPQExpBuffer(init_racl_subquery);
3296         }
3297         else if (fout->remoteVersion >= 90000)
3298                 appendPQExpBuffer(blobQry,
3299                                                   "SELECT oid, (%s lomowner) AS rolname, lomacl, "
3300                                                   "NULL AS rlomacl, NULL AS initlomacl, "
3301                                                   "NULL AS initrlomacl "
3302                                                   " FROM pg_largeobject_metadata",
3303                                                   username_subquery);
3304         else
3305                 appendPQExpBufferStr(blobQry,
3306                                                          "SELECT DISTINCT loid AS oid, "
3307                                                          "NULL::name AS rolname, NULL::oid AS lomacl, "
3308                                                          "NULL::oid AS rlomacl, NULL::oid AS initlomacl, "
3309                                                          "NULL::oid AS initrlomacl "
3310                                                          " FROM pg_largeobject");
3311
3312         res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
3313
3314         i_oid = PQfnumber(res, "oid");
3315         i_lomowner = PQfnumber(res, "rolname");
3316         i_lomacl = PQfnumber(res, "lomacl");
3317         i_rlomacl = PQfnumber(res, "rlomacl");
3318         i_initlomacl = PQfnumber(res, "initlomacl");
3319         i_initrlomacl = PQfnumber(res, "initrlomacl");
3320
3321         ntups = PQntuples(res);
3322
3323         /*
3324          * Each large object has its own BLOB archive entry.
3325          */
3326         binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
3327
3328         for (i = 0; i < ntups; i++)
3329         {
3330                 binfo[i].dobj.objType = DO_BLOB;
3331                 binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
3332                 binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3333                 AssignDumpId(&binfo[i].dobj);
3334
3335                 binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oid));
3336                 binfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_lomowner));
3337                 binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, i_lomacl));
3338                 binfo[i].rblobacl = pg_strdup(PQgetvalue(res, i, i_rlomacl));
3339                 binfo[i].initblobacl = pg_strdup(PQgetvalue(res, i, i_initlomacl));
3340                 binfo[i].initrblobacl = pg_strdup(PQgetvalue(res, i, i_initrlomacl));
3341
3342                 if (PQgetisnull(res, i, i_lomacl) &&
3343                         PQgetisnull(res, i, i_rlomacl) &&
3344                         PQgetisnull(res, i, i_initlomacl) &&
3345                         PQgetisnull(res, i, i_initrlomacl))
3346                         binfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
3347
3348                 /*
3349                  * In binary-upgrade mode for blobs, we do *not* dump out the blob
3350                  * data, as it will be copied by pg_upgrade, which simply copies the
3351                  * pg_largeobject table. We *do* however dump out anything but the
3352                  * data, as pg_upgrade copies just pg_largeobject, but not
3353                  * pg_largeobject_metadata, after the dump is restored.
3354                  */
3355                 if (dopt->binary_upgrade)
3356                         binfo[i].dobj.dump &= ~DUMP_COMPONENT_DATA;
3357         }
3358
3359         /*
3360          * If we have any large objects, a "BLOBS" archive entry is needed. This
3361          * is just a placeholder for sorting; it carries no data now.
3362          */
3363         if (ntups > 0)
3364         {
3365                 bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
3366                 bdata->objType = DO_BLOB_DATA;
3367                 bdata->catId = nilCatalogId;
3368                 AssignDumpId(bdata);
3369                 bdata->name = pg_strdup("BLOBS");
3370         }
3371
3372         PQclear(res);
3373         destroyPQExpBuffer(blobQry);
3374 }
3375
3376 /*
3377  * dumpBlob
3378  *
3379  * dump the definition (metadata) of the given large object
3380  */
3381 static void
3382 dumpBlob(Archive *fout, BlobInfo *binfo)
3383 {
3384         PQExpBuffer cquery = createPQExpBuffer();
3385         PQExpBuffer dquery = createPQExpBuffer();
3386
3387         appendPQExpBuffer(cquery,
3388                                           "SELECT pg_catalog.lo_create('%s');\n",
3389                                           binfo->dobj.name);
3390
3391         appendPQExpBuffer(dquery,
3392                                           "SELECT pg_catalog.lo_unlink('%s');\n",
3393                                           binfo->dobj.name);
3394
3395         if (binfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
3396                 ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
3397                                          ARCHIVE_OPTS(.tag = binfo->dobj.name,
3398                                                                   .owner = binfo->rolname,
3399                                                                   .description = "BLOB",
3400                                                                   .section = SECTION_PRE_DATA,
3401                                                                   .createStmt = cquery->data,
3402                                                                   .dropStmt = dquery->data));
3403
3404         /* Dump comment if any */
3405         if (binfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3406                 dumpComment(fout, "LARGE OBJECT", binfo->dobj.name,
3407                                         NULL, binfo->rolname,
3408                                         binfo->dobj.catId, 0, binfo->dobj.dumpId);
3409
3410         /* Dump security label if any */
3411         if (binfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3412                 dumpSecLabel(fout, "LARGE OBJECT", binfo->dobj.name,
3413                                          NULL, binfo->rolname,
3414                                          binfo->dobj.catId, 0, binfo->dobj.dumpId);
3415
3416         /* Dump ACL if any */
3417         if (binfo->blobacl && (binfo->dobj.dump & DUMP_COMPONENT_ACL))
3418                 dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
3419                                 binfo->dobj.name, NULL,
3420                                 NULL, binfo->rolname, binfo->blobacl, binfo->rblobacl,
3421                                 binfo->initblobacl, binfo->initrblobacl);
3422
3423         destroyPQExpBuffer(cquery);
3424         destroyPQExpBuffer(dquery);
3425 }
3426
3427 /*
3428  * dumpBlobs:
3429  *      dump the data contents of all large objects
3430  */
3431 static int
3432 dumpBlobs(Archive *fout, void *arg)
3433 {
3434         const char *blobQry;
3435         const char *blobFetchQry;
3436         PGconn     *conn = GetConnection(fout);
3437         PGresult   *res;
3438         char            buf[LOBBUFSIZE];
3439         int                     ntups;
3440         int                     i;
3441         int                     cnt;
3442
3443         pg_log_info("saving large objects");
3444
3445         /*
3446          * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
3447          * the already-in-memory dumpable objects instead...
3448          */
3449         if (fout->remoteVersion >= 90000)
3450                 blobQry =
3451                         "DECLARE bloboid CURSOR FOR "
3452                         "SELECT oid FROM pg_largeobject_metadata ORDER BY 1";
3453         else
3454                 blobQry =
3455                         "DECLARE bloboid CURSOR FOR "
3456                         "SELECT DISTINCT loid FROM pg_largeobject ORDER BY 1";
3457
3458         ExecuteSqlStatement(fout, blobQry);
3459
3460         /* Command to fetch from cursor */
3461         blobFetchQry = "FETCH 1000 IN bloboid";
3462
3463         do
3464         {
3465                 /* Do a fetch */
3466                 res = ExecuteSqlQuery(fout, blobFetchQry, PGRES_TUPLES_OK);
3467
3468                 /* Process the tuples, if any */
3469                 ntups = PQntuples(res);
3470                 for (i = 0; i < ntups; i++)
3471                 {
3472                         Oid                     blobOid;
3473                         int                     loFd;
3474
3475                         blobOid = atooid(PQgetvalue(res, i, 0));
3476                         /* Open the BLOB */
3477                         loFd = lo_open(conn, blobOid, INV_READ);
3478                         if (loFd == -1)
3479                                 fatal("could not open large object %u: %s",
3480                                           blobOid, PQerrorMessage(conn));
3481
3482                         StartBlob(fout, blobOid);
3483
3484                         /* Now read it in chunks, sending data to archive */
3485                         do
3486                         {
3487                                 cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
3488                                 if (cnt < 0)
3489                                         fatal("error reading large object %u: %s",
3490                                                   blobOid, PQerrorMessage(conn));
3491
3492                                 WriteData(fout, buf, cnt);
3493                         } while (cnt > 0);
3494
3495                         lo_close(conn, loFd);
3496
3497                         EndBlob(fout, blobOid);
3498                 }
3499
3500                 PQclear(res);
3501         } while (ntups > 0);
3502
3503         return 1;
3504 }
3505
3506 /*
3507  * getPolicies
3508  *        get information about policies on a dumpable table.
3509  */
3510 void
3511 getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
3512 {
3513         PQExpBuffer query;
3514         PGresult   *res;
3515         PolicyInfo *polinfo;
3516         int                     i_oid;
3517         int                     i_tableoid;
3518         int                     i_polname;
3519         int                     i_polcmd;
3520         int                     i_polpermissive;
3521         int                     i_polroles;
3522         int                     i_polqual;
3523         int                     i_polwithcheck;
3524         int                     i,
3525                                 j,
3526                                 ntups;
3527
3528         if (fout->remoteVersion < 90500)
3529                 return;
3530
3531         query = createPQExpBuffer();
3532
3533         for (i = 0; i < numTables; i++)
3534         {
3535                 TableInfo  *tbinfo = &tblinfo[i];
3536
3537                 /* Ignore row security on tables not to be dumped */
3538                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
3539                         continue;
3540
3541                 pg_log_info("reading row security enabled for table \"%s.%s\"",
3542                                         tbinfo->dobj.namespace->dobj.name,
3543                                         tbinfo->dobj.name);
3544
3545                 /*
3546                  * Get row security enabled information for the table. We represent
3547                  * RLS being enabled on a table by creating a PolicyInfo object with
3548                  * null polname.
3549                  */
3550                 if (tbinfo->rowsec)
3551                 {
3552                         /*
3553                          * Note: use tableoid 0 so that this object won't be mistaken for
3554                          * something that pg_depend entries apply to.
3555                          */
3556                         polinfo = pg_malloc(sizeof(PolicyInfo));
3557                         polinfo->dobj.objType = DO_POLICY;
3558                         polinfo->dobj.catId.tableoid = 0;
3559                         polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
3560                         AssignDumpId(&polinfo->dobj);
3561                         polinfo->dobj.namespace = tbinfo->dobj.namespace;
3562                         polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
3563                         polinfo->poltable = tbinfo;
3564                         polinfo->polname = NULL;
3565                         polinfo->polcmd = '\0';
3566                         polinfo->polpermissive = 0;
3567                         polinfo->polroles = NULL;
3568                         polinfo->polqual = NULL;
3569                         polinfo->polwithcheck = NULL;
3570                 }
3571
3572                 pg_log_info("reading policies for table \"%s.%s\"",
3573                                         tbinfo->dobj.namespace->dobj.name,
3574                                         tbinfo->dobj.name);
3575
3576                 resetPQExpBuffer(query);
3577
3578                 /* Get the policies for the table. */
3579                 if (fout->remoteVersion >= 100000)
3580                         appendPQExpBuffer(query,
3581                                                           "SELECT oid, tableoid, pol.polname, pol.polcmd, pol.polpermissive, "
3582                                                           "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3583                                                           "   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, "
3584                                                           "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3585                                                           "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3586                                                           "FROM pg_catalog.pg_policy pol "
3587                                                           "WHERE polrelid = '%u'",
3588                                                           tbinfo->dobj.catId.oid);
3589                 else
3590                         appendPQExpBuffer(query,
3591                                                           "SELECT oid, tableoid, pol.polname, pol.polcmd, 't' as polpermissive, "
3592                                                           "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3593                                                           "   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, "
3594                                                           "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3595                                                           "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3596                                                           "FROM pg_catalog.pg_policy pol "
3597                                                           "WHERE polrelid = '%u'",
3598                                                           tbinfo->dobj.catId.oid);
3599                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3600
3601                 ntups = PQntuples(res);
3602
3603                 if (ntups == 0)
3604                 {
3605                         /*
3606                          * No explicit policies to handle (only the default-deny policy,
3607                          * which is handled as part of the table definition).  Clean up
3608                          * and return.
3609                          */
3610                         PQclear(res);
3611                         continue;
3612                 }
3613
3614                 i_oid = PQfnumber(res, "oid");
3615                 i_tableoid = PQfnumber(res, "tableoid");
3616                 i_polname = PQfnumber(res, "polname");
3617                 i_polcmd = PQfnumber(res, "polcmd");
3618                 i_polpermissive = PQfnumber(res, "polpermissive");
3619                 i_polroles = PQfnumber(res, "polroles");
3620                 i_polqual = PQfnumber(res, "polqual");
3621                 i_polwithcheck = PQfnumber(res, "polwithcheck");
3622
3623                 polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
3624
3625                 for (j = 0; j < ntups; j++)
3626                 {
3627                         polinfo[j].dobj.objType = DO_POLICY;
3628                         polinfo[j].dobj.catId.tableoid =
3629                                 atooid(PQgetvalue(res, j, i_tableoid));
3630                         polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3631                         AssignDumpId(&polinfo[j].dobj);
3632                         polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3633                         polinfo[j].poltable = tbinfo;
3634                         polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
3635                         polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
3636
3637                         polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
3638                         polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
3639
3640                         if (PQgetisnull(res, j, i_polroles))
3641                                 polinfo[j].polroles = NULL;
3642                         else
3643                                 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
3644
3645                         if (PQgetisnull(res, j, i_polqual))
3646                                 polinfo[j].polqual = NULL;
3647                         else
3648                                 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
3649
3650                         if (PQgetisnull(res, j, i_polwithcheck))
3651                                 polinfo[j].polwithcheck = NULL;
3652                         else
3653                                 polinfo[j].polwithcheck
3654                                         = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
3655                 }
3656                 PQclear(res);
3657         }
3658         destroyPQExpBuffer(query);
3659 }
3660
3661 /*
3662  * dumpPolicy
3663  *        dump the definition of the given policy
3664  */
3665 static void
3666 dumpPolicy(Archive *fout, PolicyInfo *polinfo)
3667 {
3668         DumpOptions *dopt = fout->dopt;
3669         TableInfo  *tbinfo = polinfo->poltable;
3670         PQExpBuffer query;
3671         PQExpBuffer delqry;
3672         const char *cmd;
3673         char       *tag;
3674
3675         if (dopt->dataOnly)
3676                 return;
3677
3678         /*
3679          * If polname is NULL, then this record is just indicating that ROW LEVEL
3680          * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
3681          * ROW LEVEL SECURITY.
3682          */
3683         if (polinfo->polname == NULL)
3684         {
3685                 query = createPQExpBuffer();
3686
3687                 appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
3688                                                   fmtQualifiedDumpable(tbinfo));
3689
3690                 /*
3691                  * We must emit the ROW SECURITY object's dependency on its table
3692                  * explicitly, because it will not match anything in pg_depend (unlike
3693                  * the case for other PolicyInfo objects).
3694                  */
3695                 if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3696                         ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3697                                                  ARCHIVE_OPTS(.tag = polinfo->dobj.name,
3698                                                                           .namespace = polinfo->dobj.namespace->dobj.name,
3699                                                                           .owner = tbinfo->rolname,
3700                                                                           .description = "ROW SECURITY",
3701                                                                           .section = SECTION_POST_DATA,
3702                                                                           .createStmt = query->data,
3703                                                                           .deps = &(tbinfo->dobj.dumpId),
3704                                                                           .nDeps = 1));
3705
3706                 destroyPQExpBuffer(query);
3707                 return;
3708         }
3709
3710         if (polinfo->polcmd == '*')
3711                 cmd = "";
3712         else if (polinfo->polcmd == 'r')
3713                 cmd = " FOR SELECT";
3714         else if (polinfo->polcmd == 'a')
3715                 cmd = " FOR INSERT";
3716         else if (polinfo->polcmd == 'w')
3717                 cmd = " FOR UPDATE";
3718         else if (polinfo->polcmd == 'd')
3719                 cmd = " FOR DELETE";
3720         else
3721         {
3722                 pg_log_error("unexpected policy command type: %c",
3723                                          polinfo->polcmd);
3724                 exit_nicely(1);
3725         }
3726
3727         query = createPQExpBuffer();
3728         delqry = createPQExpBuffer();
3729
3730         appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
3731
3732         appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
3733                                           !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
3734
3735         if (polinfo->polroles != NULL)
3736                 appendPQExpBuffer(query, " TO %s", polinfo->polroles);
3737
3738         if (polinfo->polqual != NULL)
3739                 appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
3740
3741         if (polinfo->polwithcheck != NULL)
3742                 appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
3743
3744         appendPQExpBufferStr(query, ";\n");
3745
3746         appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
3747         appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
3748
3749         tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
3750
3751         if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3752                 ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3753                                          ARCHIVE_OPTS(.tag = tag,
3754                                                                   .namespace = polinfo->dobj.namespace->dobj.name,
3755                                                                   .owner = tbinfo->rolname,
3756                                                                   .description = "POLICY",
3757                                                                   .section = SECTION_POST_DATA,
3758                                                                   .createStmt = query->data,
3759                                                                   .dropStmt = delqry->data));
3760
3761         free(tag);
3762         destroyPQExpBuffer(query);
3763         destroyPQExpBuffer(delqry);
3764 }
3765
3766 /*
3767  * getPublications
3768  *        get information about publications
3769  */
3770 void
3771 getPublications(Archive *fout)
3772 {
3773         DumpOptions *dopt = fout->dopt;
3774         PQExpBuffer query;
3775         PGresult   *res;
3776         PublicationInfo *pubinfo;
3777         int                     i_tableoid;
3778         int                     i_oid;
3779         int                     i_pubname;
3780         int                     i_rolname;
3781         int                     i_puballtables;
3782         int                     i_pubinsert;
3783         int                     i_pubupdate;
3784         int                     i_pubdelete;
3785         int                     i_pubtruncate;
3786         int                     i,
3787                                 ntups;
3788
3789         if (dopt->no_publications || fout->remoteVersion < 100000)
3790                 return;
3791
3792         query = createPQExpBuffer();
3793
3794         resetPQExpBuffer(query);
3795
3796         /* Get the publications. */
3797         if (fout->remoteVersion >= 110000)
3798                 appendPQExpBuffer(query,
3799                                                   "SELECT p.tableoid, p.oid, p.pubname, "
3800                                                   "(%s p.pubowner) AS rolname, "
3801                                                   "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, p.pubtruncate "
3802                                                   "FROM pg_publication p",
3803                                                   username_subquery);
3804         else
3805                 appendPQExpBuffer(query,
3806                                                   "SELECT p.tableoid, p.oid, p.pubname, "
3807                                                   "(%s p.pubowner) AS rolname, "
3808                                                   "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, false AS pubtruncate "
3809                                                   "FROM pg_publication p",
3810                                                   username_subquery);
3811
3812         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3813
3814         ntups = PQntuples(res);
3815
3816         i_tableoid = PQfnumber(res, "tableoid");
3817         i_oid = PQfnumber(res, "oid");
3818         i_pubname = PQfnumber(res, "pubname");
3819         i_rolname = PQfnumber(res, "rolname");
3820         i_puballtables = PQfnumber(res, "puballtables");
3821         i_pubinsert = PQfnumber(res, "pubinsert");
3822         i_pubupdate = PQfnumber(res, "pubupdate");
3823         i_pubdelete = PQfnumber(res, "pubdelete");
3824         i_pubtruncate = PQfnumber(res, "pubtruncate");
3825
3826         pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
3827
3828         for (i = 0; i < ntups; i++)
3829         {
3830                 pubinfo[i].dobj.objType = DO_PUBLICATION;
3831                 pubinfo[i].dobj.catId.tableoid =
3832                         atooid(PQgetvalue(res, i, i_tableoid));
3833                 pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3834                 AssignDumpId(&pubinfo[i].dobj);
3835                 pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
3836                 pubinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3837                 pubinfo[i].puballtables =
3838                         (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
3839                 pubinfo[i].pubinsert =
3840                         (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
3841                 pubinfo[i].pubupdate =
3842                         (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
3843                 pubinfo[i].pubdelete =
3844                         (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
3845                 pubinfo[i].pubtruncate =
3846                         (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
3847
3848                 if (strlen(pubinfo[i].rolname) == 0)
3849                         pg_log_warning("owner of publication \"%s\" appears to be invalid",
3850                                                    pubinfo[i].dobj.name);
3851
3852                 /* Decide whether we want to dump it */
3853                 selectDumpableObject(&(pubinfo[i].dobj), fout);
3854         }
3855         PQclear(res);
3856
3857         destroyPQExpBuffer(query);
3858 }
3859
3860 /*
3861  * dumpPublication
3862  *        dump the definition of the given publication
3863  */
3864 static void
3865 dumpPublication(Archive *fout, PublicationInfo *pubinfo)
3866 {
3867         PQExpBuffer delq;
3868         PQExpBuffer query;
3869         char       *qpubname;
3870         bool            first = true;
3871
3872         if (!(pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3873                 return;
3874
3875         delq = createPQExpBuffer();
3876         query = createPQExpBuffer();
3877
3878         qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
3879
3880         appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
3881                                           qpubname);
3882
3883         appendPQExpBuffer(query, "CREATE PUBLICATION %s",
3884                                           qpubname);
3885
3886         if (pubinfo->puballtables)
3887                 appendPQExpBufferStr(query, " FOR ALL TABLES");
3888
3889         appendPQExpBufferStr(query, " WITH (publish = '");
3890         if (pubinfo->pubinsert)
3891         {
3892                 appendPQExpBufferStr(query, "insert");
3893                 first = false;
3894         }
3895
3896         if (pubinfo->pubupdate)
3897         {
3898                 if (!first)
3899                         appendPQExpBufferStr(query, ", ");
3900
3901                 appendPQExpBufferStr(query, "update");
3902                 first = false;
3903         }
3904
3905         if (pubinfo->pubdelete)
3906         {
3907                 if (!first)
3908                         appendPQExpBufferStr(query, ", ");
3909
3910                 appendPQExpBufferStr(query, "delete");
3911                 first = false;
3912         }
3913
3914         if (pubinfo->pubtruncate)
3915         {
3916                 if (!first)
3917                         appendPQExpBufferStr(query, ", ");
3918
3919                 appendPQExpBufferStr(query, "truncate");
3920                 first = false;
3921         }
3922
3923         appendPQExpBufferStr(query, "');\n");
3924
3925         ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
3926                                  ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
3927                                                           .owner = pubinfo->rolname,
3928                                                           .description = "PUBLICATION",
3929                                                           .section = SECTION_POST_DATA,
3930                                                           .createStmt = query->data,
3931                                                           .dropStmt = delq->data));
3932
3933         if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3934                 dumpComment(fout, "PUBLICATION", qpubname,
3935                                         NULL, pubinfo->rolname,
3936                                         pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
3937
3938         if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3939                 dumpSecLabel(fout, "PUBLICATION", qpubname,
3940                                          NULL, pubinfo->rolname,
3941                                          pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
3942
3943         destroyPQExpBuffer(delq);
3944         destroyPQExpBuffer(query);
3945         free(qpubname);
3946 }
3947
3948 /*
3949  * getPublicationTables
3950  *        get information about publication membership for dumpable tables.
3951  */
3952 void
3953 getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
3954 {
3955         PQExpBuffer query;
3956         PGresult   *res;
3957         PublicationRelInfo *pubrinfo;
3958         DumpOptions *dopt = fout->dopt;
3959         int                     i_tableoid;
3960         int                     i_oid;
3961         int                     i_pubname;
3962         int                     i,
3963                                 j,
3964                                 ntups;
3965
3966         if (dopt->no_publications || fout->remoteVersion < 100000)
3967                 return;
3968
3969         query = createPQExpBuffer();
3970
3971         for (i = 0; i < numTables; i++)
3972         {
3973                 TableInfo  *tbinfo = &tblinfo[i];
3974
3975                 /* Only plain tables can be aded to publications. */
3976                 if (tbinfo->relkind != RELKIND_RELATION)
3977                         continue;
3978
3979                 /*
3980                  * Ignore publication membership of tables whose definitions are not
3981                  * to be dumped.
3982                  */
3983                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3984                         continue;
3985
3986                 pg_log_info("reading publication membership for table \"%s.%s\"",
3987                                         tbinfo->dobj.namespace->dobj.name,
3988                                         tbinfo->dobj.name);
3989
3990                 resetPQExpBuffer(query);
3991
3992                 /* Get the publication membership for the table. */
3993                 appendPQExpBuffer(query,
3994                                                   "SELECT pr.tableoid, pr.oid, p.pubname "
3995                                                   "FROM pg_publication_rel pr, pg_publication p "
3996                                                   "WHERE pr.prrelid = '%u'"
3997                                                   "  AND p.oid = pr.prpubid",
3998                                                   tbinfo->dobj.catId.oid);
3999                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4000
4001                 ntups = PQntuples(res);
4002
4003                 if (ntups == 0)
4004                 {
4005                         /*
4006                          * Table is not member of any publications. Clean up and return.
4007                          */
4008                         PQclear(res);
4009                         continue;
4010                 }
4011
4012                 i_tableoid = PQfnumber(res, "tableoid");
4013                 i_oid = PQfnumber(res, "oid");
4014                 i_pubname = PQfnumber(res, "pubname");
4015
4016                 pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
4017
4018                 for (j = 0; j < ntups; j++)
4019                 {
4020                         pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
4021                         pubrinfo[j].dobj.catId.tableoid =
4022                                 atooid(PQgetvalue(res, j, i_tableoid));
4023                         pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
4024                         AssignDumpId(&pubrinfo[j].dobj);
4025                         pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4026                         pubrinfo[j].dobj.name = tbinfo->dobj.name;
4027                         pubrinfo[j].pubname = pg_strdup(PQgetvalue(res, j, i_pubname));
4028                         pubrinfo[j].pubtable = tbinfo;
4029
4030                         /* Decide whether we want to dump it */
4031                         selectDumpablePublicationTable(&(pubrinfo[j].dobj), fout);
4032                 }
4033                 PQclear(res);
4034         }
4035         destroyPQExpBuffer(query);
4036 }
4037
4038 /*
4039  * dumpPublicationTable
4040  *        dump the definition of the given publication table mapping
4041  */
4042 static void
4043 dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo)
4044 {
4045         TableInfo  *tbinfo = pubrinfo->pubtable;
4046         PQExpBuffer query;
4047         char       *tag;
4048
4049         if (!(pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
4050                 return;
4051
4052         tag = psprintf("%s %s", pubrinfo->pubname, tbinfo->dobj.name);
4053
4054         query = createPQExpBuffer();
4055
4056         appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
4057                                           fmtId(pubrinfo->pubname));
4058         appendPQExpBuffer(query, " %s;\n",
4059                                           fmtQualifiedDumpable(tbinfo));
4060
4061         /*
4062          * There is no point in creating drop query as the drop is done by table
4063          * drop.
4064          */
4065         ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
4066                                  ARCHIVE_OPTS(.tag = tag,
4067                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
4068                                                           .description = "PUBLICATION TABLE",
4069                                                           .section = SECTION_POST_DATA,
4070                                                           .createStmt = query->data));
4071
4072         free(tag);
4073         destroyPQExpBuffer(query);
4074 }
4075
4076 /*
4077  * Is the currently connected user a superuser?
4078  */
4079 static bool
4080 is_superuser(Archive *fout)
4081 {
4082         ArchiveHandle *AH = (ArchiveHandle *) fout;
4083         const char *val;
4084
4085         val = PQparameterStatus(AH->connection, "is_superuser");
4086
4087         if (val && strcmp(val, "on") == 0)
4088                 return true;
4089
4090         return false;
4091 }
4092
4093 /*
4094  * getSubscriptions
4095  *        get information about subscriptions
4096  */
4097 void
4098 getSubscriptions(Archive *fout)
4099 {
4100         DumpOptions *dopt = fout->dopt;
4101         PQExpBuffer query;
4102         PGresult   *res;
4103         SubscriptionInfo *subinfo;
4104         int                     i_tableoid;
4105         int                     i_oid;
4106         int                     i_subname;
4107         int                     i_rolname;
4108         int                     i_subconninfo;
4109         int                     i_subslotname;
4110         int                     i_subsynccommit;
4111         int                     i_subpublications;
4112         int                     i,
4113                                 ntups;
4114
4115         if (dopt->no_subscriptions || fout->remoteVersion < 100000)
4116                 return;
4117
4118         if (!is_superuser(fout))
4119         {
4120                 int                     n;
4121
4122                 res = ExecuteSqlQuery(fout,
4123                                                           "SELECT count(*) FROM pg_subscription "
4124                                                           "WHERE subdbid = (SELECT oid FROM pg_database"
4125                                                           "                 WHERE datname = current_database())",
4126                                                           PGRES_TUPLES_OK);
4127                 n = atoi(PQgetvalue(res, 0, 0));
4128                 if (n > 0)
4129                         pg_log_warning("subscriptions not dumped because current user is not a superuser");
4130                 PQclear(res);
4131                 return;
4132         }
4133
4134         query = createPQExpBuffer();
4135
4136         resetPQExpBuffer(query);
4137
4138         /* Get the subscriptions in current database. */
4139         appendPQExpBuffer(query,
4140                                           "SELECT s.tableoid, s.oid, s.subname,"
4141                                           "(%s s.subowner) AS rolname, "
4142                                           " s.subconninfo, s.subslotname, s.subsynccommit, "
4143                                           " s.subpublications "
4144                                           "FROM pg_subscription s "
4145                                           "WHERE s.subdbid = (SELECT oid FROM pg_database"
4146                                           "                   WHERE datname = current_database())",
4147                                           username_subquery);
4148         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4149
4150         ntups = PQntuples(res);
4151
4152         i_tableoid = PQfnumber(res, "tableoid");
4153         i_oid = PQfnumber(res, "oid");
4154         i_subname = PQfnumber(res, "subname");
4155         i_rolname = PQfnumber(res, "rolname");
4156         i_subconninfo = PQfnumber(res, "subconninfo");
4157         i_subslotname = PQfnumber(res, "subslotname");
4158         i_subsynccommit = PQfnumber(res, "subsynccommit");
4159         i_subpublications = PQfnumber(res, "subpublications");
4160
4161         subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
4162
4163         for (i = 0; i < ntups; i++)
4164         {
4165                 subinfo[i].dobj.objType = DO_SUBSCRIPTION;
4166                 subinfo[i].dobj.catId.tableoid =
4167                         atooid(PQgetvalue(res, i, i_tableoid));
4168                 subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4169                 AssignDumpId(&subinfo[i].dobj);
4170                 subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
4171                 subinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4172                 subinfo[i].subconninfo = pg_strdup(PQgetvalue(res, i, i_subconninfo));
4173                 if (PQgetisnull(res, i, i_subslotname))
4174                         subinfo[i].subslotname = NULL;
4175                 else
4176                         subinfo[i].subslotname = pg_strdup(PQgetvalue(res, i, i_subslotname));
4177                 subinfo[i].subsynccommit =
4178                         pg_strdup(PQgetvalue(res, i, i_subsynccommit));
4179                 subinfo[i].subpublications =
4180                         pg_strdup(PQgetvalue(res, i, i_subpublications));
4181
4182                 if (strlen(subinfo[i].rolname) == 0)
4183                         pg_log_warning("owner of subscription \"%s\" appears to be invalid",
4184                                                    subinfo[i].dobj.name);
4185
4186                 /* Decide whether we want to dump it */
4187                 selectDumpableObject(&(subinfo[i].dobj), fout);
4188         }
4189         PQclear(res);
4190
4191         destroyPQExpBuffer(query);
4192 }
4193
4194 /*
4195  * dumpSubscription
4196  *        dump the definition of the given subscription
4197  */
4198 static void
4199 dumpSubscription(Archive *fout, SubscriptionInfo *subinfo)
4200 {
4201         PQExpBuffer delq;
4202         PQExpBuffer query;
4203         PQExpBuffer publications;
4204         char       *qsubname;
4205         char      **pubnames = NULL;
4206         int                     npubnames = 0;
4207         int                     i;
4208
4209         if (!(subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
4210                 return;
4211
4212         delq = createPQExpBuffer();
4213         query = createPQExpBuffer();
4214
4215         qsubname = pg_strdup(fmtId(subinfo->dobj.name));
4216
4217         appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
4218                                           qsubname);
4219
4220         appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
4221                                           qsubname);
4222         appendStringLiteralAH(query, subinfo->subconninfo, fout);
4223
4224         /* Build list of quoted publications and append them to query. */
4225         if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
4226         {
4227                 pg_log_warning("could not parse subpublications array");
4228                 if (pubnames)
4229                         free(pubnames);
4230                 pubnames = NULL;
4231                 npubnames = 0;
4232         }
4233
4234         publications = createPQExpBuffer();
4235         for (i = 0; i < npubnames; i++)
4236         {
4237                 if (i > 0)
4238                         appendPQExpBufferStr(publications, ", ");
4239
4240                 appendPQExpBufferStr(publications, fmtId(pubnames[i]));
4241         }
4242
4243         appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
4244         if (subinfo->subslotname)
4245                 appendStringLiteralAH(query, subinfo->subslotname, fout);
4246         else
4247                 appendPQExpBufferStr(query, "NONE");
4248
4249         if (strcmp(subinfo->subsynccommit, "off") != 0)
4250                 appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
4251
4252         appendPQExpBufferStr(query, ");\n");
4253
4254         ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
4255                                  ARCHIVE_OPTS(.tag = subinfo->dobj.name,
4256                                                           .owner = subinfo->rolname,
4257                                                           .description = "SUBSCRIPTION",
4258                                                           .section = SECTION_POST_DATA,
4259                                                           .createStmt = query->data,
4260                                                           .dropStmt = delq->data));
4261
4262         if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4263                 dumpComment(fout, "SUBSCRIPTION", qsubname,
4264                                         NULL, subinfo->rolname,
4265                                         subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
4266
4267         if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
4268                 dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
4269                                          NULL, subinfo->rolname,
4270                                          subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
4271
4272         destroyPQExpBuffer(publications);
4273         if (pubnames)
4274                 free(pubnames);
4275
4276         destroyPQExpBuffer(delq);
4277         destroyPQExpBuffer(query);
4278         free(qsubname);
4279 }
4280
4281 static void
4282 binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
4283                                                                                  PQExpBuffer upgrade_buffer,
4284                                                                                  Oid pg_type_oid,
4285                                                                                  bool force_array_type)
4286 {
4287         PQExpBuffer upgrade_query = createPQExpBuffer();
4288         PGresult   *res;
4289         Oid                     pg_type_array_oid;
4290
4291         appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
4292         appendPQExpBuffer(upgrade_buffer,
4293                                           "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4294                                           pg_type_oid);
4295
4296         /* we only support old >= 8.3 for binary upgrades */
4297         appendPQExpBuffer(upgrade_query,
4298                                           "SELECT typarray "
4299                                           "FROM pg_catalog.pg_type "
4300                                           "WHERE oid = '%u'::pg_catalog.oid;",
4301                                           pg_type_oid);
4302
4303         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4304
4305         pg_type_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
4306
4307         PQclear(res);
4308
4309         if (!OidIsValid(pg_type_array_oid) && force_array_type)
4310         {
4311                 /*
4312                  * If the old version didn't assign an array type, but the new version
4313                  * does, we must select an unused type OID to assign.  This currently
4314                  * only happens for domains, when upgrading pre-v11 to v11 and up.
4315                  *
4316                  * Note: local state here is kind of ugly, but we must have some,
4317                  * since we mustn't choose the same unused OID more than once.
4318                  */
4319                 static Oid      next_possible_free_oid = FirstNormalObjectId;
4320                 bool            is_dup;
4321
4322                 do
4323                 {
4324                         ++next_possible_free_oid;
4325                         printfPQExpBuffer(upgrade_query,
4326                                                           "SELECT EXISTS(SELECT 1 "
4327                                                           "FROM pg_catalog.pg_type "
4328                                                           "WHERE oid = '%u'::pg_catalog.oid);",
4329                                                           next_possible_free_oid);
4330                         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4331                         is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
4332                         PQclear(res);
4333                 } while (is_dup);
4334
4335                 pg_type_array_oid = next_possible_free_oid;
4336         }
4337
4338         if (OidIsValid(pg_type_array_oid))
4339         {
4340                 appendPQExpBufferStr(upgrade_buffer,
4341                                                          "\n-- For binary upgrade, must preserve pg_type array oid\n");
4342                 appendPQExpBuffer(upgrade_buffer,
4343                                                   "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4344                                                   pg_type_array_oid);
4345         }
4346
4347         destroyPQExpBuffer(upgrade_query);
4348 }
4349
4350 static bool
4351 binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
4352                                                                                 PQExpBuffer upgrade_buffer,
4353                                                                                 Oid pg_rel_oid)
4354 {
4355         PQExpBuffer upgrade_query = createPQExpBuffer();
4356         PGresult   *upgrade_res;
4357         Oid                     pg_type_oid;
4358         bool            toast_set = false;
4359
4360         /*
4361          * We only support old >= 8.3 for binary upgrades.
4362          *
4363          * We purposefully ignore toast OIDs for partitioned tables; the reason is
4364          * that versions 10 and 11 have them, but 12 does not, so emitting them
4365          * causes the upgrade to fail.
4366          */
4367         appendPQExpBuffer(upgrade_query,
4368                                           "SELECT c.reltype AS crel, t.reltype AS trel "
4369                                           "FROM pg_catalog.pg_class c "
4370                                           "LEFT JOIN pg_catalog.pg_class t ON "
4371                                           "  (c.reltoastrelid = t.oid AND c.relkind <> '%c') "
4372                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
4373                                           RELKIND_PARTITIONED_TABLE, pg_rel_oid);
4374
4375         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4376
4377         pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
4378
4379         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
4380                                                                                          pg_type_oid, false);
4381
4382         if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
4383         {
4384                 /* Toast tables do not have pg_type array rows */
4385                 Oid                     pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
4386                                                                                                                   PQfnumber(upgrade_res, "trel")));
4387
4388                 appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
4389                 appendPQExpBuffer(upgrade_buffer,
4390                                                   "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4391                                                   pg_type_toast_oid);
4392
4393                 toast_set = true;
4394         }
4395
4396         PQclear(upgrade_res);
4397         destroyPQExpBuffer(upgrade_query);
4398
4399         return toast_set;
4400 }
4401
4402 static void
4403 binary_upgrade_set_pg_class_oids(Archive *fout,
4404                                                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid,
4405                                                                  bool is_index)
4406 {
4407         PQExpBuffer upgrade_query = createPQExpBuffer();
4408         PGresult   *upgrade_res;
4409         Oid                     pg_class_reltoastrelid;
4410         Oid                     pg_index_indexrelid;
4411
4412         appendPQExpBuffer(upgrade_query,
4413                                           "SELECT c.reltoastrelid, i.indexrelid "
4414                                           "FROM pg_catalog.pg_class c LEFT JOIN "
4415                                           "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
4416                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
4417                                           pg_class_oid);
4418
4419         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4420
4421         pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
4422         pg_index_indexrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "indexrelid")));
4423
4424         appendPQExpBufferStr(upgrade_buffer,
4425                                                  "\n-- For binary upgrade, must preserve pg_class oids\n");
4426
4427         if (!is_index)
4428         {
4429                 appendPQExpBuffer(upgrade_buffer,
4430                                                   "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
4431                                                   pg_class_oid);
4432                 /* only tables have toast tables, not indexes */
4433                 if (OidIsValid(pg_class_reltoastrelid))
4434                 {
4435                         /*
4436                          * One complexity is that the table definition might not require
4437                          * the creation of a TOAST table, and the TOAST table might have
4438                          * been created long after table creation, when the table was
4439                          * loaded with wide data.  By setting the TOAST oid we force
4440                          * creation of the TOAST heap and TOAST index by the backend so we
4441                          * can cleanly copy the files during binary upgrade.
4442                          */
4443
4444                         appendPQExpBuffer(upgrade_buffer,
4445                                                           "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
4446                                                           pg_class_reltoastrelid);
4447
4448                         /* every toast table has an index */
4449                         appendPQExpBuffer(upgrade_buffer,
4450                                                           "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
4451                                                           pg_index_indexrelid);
4452                 }
4453         }
4454         else
4455                 appendPQExpBuffer(upgrade_buffer,
4456                                                   "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
4457                                                   pg_class_oid);
4458
4459         appendPQExpBufferChar(upgrade_buffer, '\n');
4460
4461         PQclear(upgrade_res);
4462         destroyPQExpBuffer(upgrade_query);
4463 }
4464
4465 /*
4466  * If the DumpableObject is a member of an extension, add a suitable
4467  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
4468  *
4469  * For somewhat historical reasons, objname should already be quoted,
4470  * but not objnamespace (if any).
4471  */
4472 static void
4473 binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
4474                                                                 DumpableObject *dobj,
4475                                                                 const char *objtype,
4476                                                                 const char *objname,
4477                                                                 const char *objnamespace)
4478 {
4479         DumpableObject *extobj = NULL;
4480         int                     i;
4481
4482         if (!dobj->ext_member)
4483                 return;
4484
4485         /*
4486          * Find the parent extension.  We could avoid this search if we wanted to
4487          * add a link field to DumpableObject, but the space costs of that would
4488          * be considerable.  We assume that member objects could only have a
4489          * direct dependency on their own extension, not any others.
4490          */
4491         for (i = 0; i < dobj->nDeps; i++)
4492         {
4493                 extobj = findObjectByDumpId(dobj->dependencies[i]);
4494                 if (extobj && extobj->objType == DO_EXTENSION)
4495                         break;
4496                 extobj = NULL;
4497         }
4498         if (extobj == NULL)
4499                 fatal("could not find parent extension for %s %s",
4500                           objtype, objname);
4501
4502         appendPQExpBufferStr(upgrade_buffer,
4503                                                  "\n-- For binary upgrade, handle extension membership the hard way\n");
4504         appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
4505                                           fmtId(extobj->name),
4506                                           objtype);
4507         if (objnamespace && *objnamespace)
4508                 appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
4509         appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
4510 }
4511
4512 /*
4513  * getNamespaces:
4514  *        read all namespaces in the system catalogs and return them in the
4515  * NamespaceInfo* structure
4516  *
4517  *      numNamespaces is set to the number of namespaces read in
4518  */
4519 NamespaceInfo *
4520 getNamespaces(Archive *fout, int *numNamespaces)
4521 {
4522         DumpOptions *dopt = fout->dopt;
4523         PGresult   *res;
4524         int                     ntups;
4525         int                     i;
4526         PQExpBuffer query;
4527         NamespaceInfo *nsinfo;
4528         int                     i_tableoid;
4529         int                     i_oid;
4530         int                     i_nspname;
4531         int                     i_rolname;
4532         int                     i_nspacl;
4533         int                     i_rnspacl;
4534         int                     i_initnspacl;
4535         int                     i_initrnspacl;
4536
4537         query = createPQExpBuffer();
4538
4539         /*
4540          * we fetch all namespaces including system ones, so that every object we
4541          * read in can be linked to a containing namespace.
4542          */
4543         if (fout->remoteVersion >= 90600)
4544         {
4545                 PQExpBuffer acl_subquery = createPQExpBuffer();
4546                 PQExpBuffer racl_subquery = createPQExpBuffer();
4547                 PQExpBuffer init_acl_subquery = createPQExpBuffer();
4548                 PQExpBuffer init_racl_subquery = createPQExpBuffer();
4549
4550                 buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
4551                                                 init_racl_subquery, "n.nspacl", "n.nspowner", "'n'",
4552                                                 dopt->binary_upgrade);
4553
4554                 appendPQExpBuffer(query, "SELECT n.tableoid, n.oid, n.nspname, "
4555                                                   "(%s nspowner) AS rolname, "
4556                                                   "%s as nspacl, "
4557                                                   "%s as rnspacl, "
4558                                                   "%s as initnspacl, "
4559                                                   "%s as initrnspacl "
4560                                                   "FROM pg_namespace n "
4561                                                   "LEFT JOIN pg_init_privs pip "
4562                                                   "ON (n.oid = pip.objoid "
4563                                                   "AND pip.classoid = 'pg_namespace'::regclass "
4564                                                   "AND pip.objsubid = 0",
4565                                                   username_subquery,
4566                                                   acl_subquery->data,
4567                                                   racl_subquery->data,
4568                                                   init_acl_subquery->data,
4569                                                   init_racl_subquery->data);
4570
4571                 appendPQExpBufferStr(query, ") ");
4572
4573                 destroyPQExpBuffer(acl_subquery);
4574                 destroyPQExpBuffer(racl_subquery);
4575                 destroyPQExpBuffer(init_acl_subquery);
4576                 destroyPQExpBuffer(init_racl_subquery);
4577         }
4578         else
4579                 appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
4580                                                   "(%s nspowner) AS rolname, "
4581                                                   "nspacl, NULL as rnspacl, "
4582                                                   "NULL AS initnspacl, NULL as initrnspacl "
4583                                                   "FROM pg_namespace",
4584                                                   username_subquery);
4585
4586         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4587
4588         ntups = PQntuples(res);
4589
4590         nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
4591
4592         i_tableoid = PQfnumber(res, "tableoid");
4593         i_oid = PQfnumber(res, "oid");
4594         i_nspname = PQfnumber(res, "nspname");
4595         i_rolname = PQfnumber(res, "rolname");
4596         i_nspacl = PQfnumber(res, "nspacl");
4597         i_rnspacl = PQfnumber(res, "rnspacl");
4598         i_initnspacl = PQfnumber(res, "initnspacl");
4599         i_initrnspacl = PQfnumber(res, "initrnspacl");
4600
4601         for (i = 0; i < ntups; i++)
4602         {
4603                 nsinfo[i].dobj.objType = DO_NAMESPACE;
4604                 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4605                 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4606                 AssignDumpId(&nsinfo[i].dobj);
4607                 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
4608                 nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4609                 nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
4610                 nsinfo[i].rnspacl = pg_strdup(PQgetvalue(res, i, i_rnspacl));
4611                 nsinfo[i].initnspacl = pg_strdup(PQgetvalue(res, i, i_initnspacl));
4612                 nsinfo[i].initrnspacl = pg_strdup(PQgetvalue(res, i, i_initrnspacl));
4613
4614                 /* Decide whether to dump this namespace */
4615                 selectDumpableNamespace(&nsinfo[i], fout);
4616
4617                 /*
4618                  * Do not try to dump ACL if the ACL is empty or the default.
4619                  *
4620                  * This is useful because, for some schemas/objects, the only
4621                  * component we are going to try and dump is the ACL and if we can
4622                  * remove that then 'dump' goes to zero/false and we don't consider
4623                  * this object for dumping at all later on.
4624                  */
4625                 if (PQgetisnull(res, i, i_nspacl) && PQgetisnull(res, i, i_rnspacl) &&
4626                         PQgetisnull(res, i, i_initnspacl) &&
4627                         PQgetisnull(res, i, i_initrnspacl))
4628                         nsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4629
4630                 if (strlen(nsinfo[i].rolname) == 0)
4631                         pg_log_warning("owner of schema \"%s\" appears to be invalid",
4632                                                    nsinfo[i].dobj.name);
4633         }
4634
4635         PQclear(res);
4636         destroyPQExpBuffer(query);
4637
4638         *numNamespaces = ntups;
4639
4640         return nsinfo;
4641 }
4642
4643 /*
4644  * findNamespace:
4645  *              given a namespace OID, look up the info read by getNamespaces
4646  */
4647 static NamespaceInfo *
4648 findNamespace(Archive *fout, Oid nsoid)
4649 {
4650         NamespaceInfo *nsinfo;
4651
4652         nsinfo = findNamespaceByOid(nsoid);
4653         if (nsinfo == NULL)
4654                 fatal("schema with OID %u does not exist", nsoid);
4655         return nsinfo;
4656 }
4657
4658 /*
4659  * getExtensions:
4660  *        read all extensions in the system catalogs and return them in the
4661  * ExtensionInfo* structure
4662  *
4663  *      numExtensions is set to the number of extensions read in
4664  */
4665 ExtensionInfo *
4666 getExtensions(Archive *fout, int *numExtensions)
4667 {
4668         DumpOptions *dopt = fout->dopt;
4669         PGresult   *res;
4670         int                     ntups;
4671         int                     i;
4672         PQExpBuffer query;
4673         ExtensionInfo *extinfo;
4674         int                     i_tableoid;
4675         int                     i_oid;
4676         int                     i_extname;
4677         int                     i_nspname;
4678         int                     i_extrelocatable;
4679         int                     i_extversion;
4680         int                     i_extconfig;
4681         int                     i_extcondition;
4682
4683         /*
4684          * Before 9.1, there are no extensions.
4685          */
4686         if (fout->remoteVersion < 90100)
4687         {
4688                 *numExtensions = 0;
4689                 return NULL;
4690         }
4691
4692         query = createPQExpBuffer();
4693
4694         appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
4695                                                  "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
4696                                                  "FROM pg_extension x "
4697                                                  "JOIN pg_namespace n ON n.oid = x.extnamespace");
4698
4699         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4700
4701         ntups = PQntuples(res);
4702
4703         extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
4704
4705         i_tableoid = PQfnumber(res, "tableoid");
4706         i_oid = PQfnumber(res, "oid");
4707         i_extname = PQfnumber(res, "extname");
4708         i_nspname = PQfnumber(res, "nspname");
4709         i_extrelocatable = PQfnumber(res, "extrelocatable");
4710         i_extversion = PQfnumber(res, "extversion");
4711         i_extconfig = PQfnumber(res, "extconfig");
4712         i_extcondition = PQfnumber(res, "extcondition");
4713
4714         for (i = 0; i < ntups; i++)
4715         {
4716                 extinfo[i].dobj.objType = DO_EXTENSION;
4717                 extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4718                 extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4719                 AssignDumpId(&extinfo[i].dobj);
4720                 extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
4721                 extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
4722                 extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
4723                 extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
4724                 extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
4725                 extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
4726
4727                 /* Decide whether we want to dump it */
4728                 selectDumpableExtension(&(extinfo[i]), dopt);
4729         }
4730
4731         PQclear(res);
4732         destroyPQExpBuffer(query);
4733
4734         *numExtensions = ntups;
4735
4736         return extinfo;
4737 }
4738
4739 /*
4740  * getTypes:
4741  *        read all types in the system catalogs and return them in the
4742  * TypeInfo* structure
4743  *
4744  *      numTypes is set to the number of types read in
4745  *
4746  * NB: this must run after getFuncs() because we assume we can do
4747  * findFuncByOid().
4748  */
4749 TypeInfo *
4750 getTypes(Archive *fout, int *numTypes)
4751 {
4752         DumpOptions *dopt = fout->dopt;
4753         PGresult   *res;
4754         int                     ntups;
4755         int                     i;
4756         PQExpBuffer query = createPQExpBuffer();
4757         TypeInfo   *tyinfo;
4758         ShellTypeInfo *stinfo;
4759         int                     i_tableoid;
4760         int                     i_oid;
4761         int                     i_typname;
4762         int                     i_typnamespace;
4763         int                     i_typacl;
4764         int                     i_rtypacl;
4765         int                     i_inittypacl;
4766         int                     i_initrtypacl;
4767         int                     i_rolname;
4768         int                     i_typelem;
4769         int                     i_typrelid;
4770         int                     i_typrelkind;
4771         int                     i_typtype;
4772         int                     i_typisdefined;
4773         int                     i_isarray;
4774
4775         /*
4776          * we include even the built-in types because those may be used as array
4777          * elements by user-defined types
4778          *
4779          * we filter out the built-in types when we dump out the types
4780          *
4781          * same approach for undefined (shell) types and array types
4782          *
4783          * Note: as of 8.3 we can reliably detect whether a type is an
4784          * auto-generated array type by checking the element type's typarray.
4785          * (Before that the test is capable of generating false positives.) We
4786          * still check for name beginning with '_', though, so as to avoid the
4787          * cost of the subselect probe for all standard types.  This would have to
4788          * be revisited if the backend ever allows renaming of array types.
4789          */
4790
4791         if (fout->remoteVersion >= 90600)
4792         {
4793                 PQExpBuffer acl_subquery = createPQExpBuffer();
4794                 PQExpBuffer racl_subquery = createPQExpBuffer();
4795                 PQExpBuffer initacl_subquery = createPQExpBuffer();
4796                 PQExpBuffer initracl_subquery = createPQExpBuffer();
4797
4798                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
4799                                                 initracl_subquery, "t.typacl", "t.typowner", "'T'",
4800                                                 dopt->binary_upgrade);
4801
4802                 appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, t.typname, "
4803                                                   "t.typnamespace, "
4804                                                   "%s AS typacl, "
4805                                                   "%s AS rtypacl, "
4806                                                   "%s AS inittypacl, "
4807                                                   "%s AS initrtypacl, "
4808                                                   "(%s t.typowner) AS rolname, "
4809                                                   "t.typelem, t.typrelid, "
4810                                                   "CASE WHEN t.typrelid = 0 THEN ' '::\"char\" "
4811                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = t.typrelid) END AS typrelkind, "
4812                                                   "t.typtype, t.typisdefined, "
4813                                                   "t.typname[0] = '_' AND t.typelem != 0 AND "
4814                                                   "(SELECT typarray FROM pg_type te WHERE oid = t.typelem) = t.oid AS isarray "
4815                                                   "FROM pg_type t "
4816                                                   "LEFT JOIN pg_init_privs pip ON "
4817                                                   "(t.oid = pip.objoid "
4818                                                   "AND pip.classoid = 'pg_type'::regclass "
4819                                                   "AND pip.objsubid = 0) ",
4820                                                   acl_subquery->data,
4821                                                   racl_subquery->data,
4822                                                   initacl_subquery->data,
4823                                                   initracl_subquery->data,
4824                                                   username_subquery);
4825
4826                 destroyPQExpBuffer(acl_subquery);
4827                 destroyPQExpBuffer(racl_subquery);
4828                 destroyPQExpBuffer(initacl_subquery);
4829                 destroyPQExpBuffer(initracl_subquery);
4830         }
4831         else if (fout->remoteVersion >= 90200)
4832         {
4833                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4834                                                   "typnamespace, typacl, NULL as rtypacl, "
4835                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4836                                                   "(%s typowner) AS rolname, "
4837                                                   "typelem, typrelid, "
4838                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4839                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4840                                                   "typtype, typisdefined, "
4841                                                   "typname[0] = '_' AND typelem != 0 AND "
4842                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4843                                                   "FROM pg_type",
4844                                                   username_subquery);
4845         }
4846         else if (fout->remoteVersion >= 80300)
4847         {
4848                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4849                                                   "typnamespace, NULL AS typacl, NULL as rtypacl, "
4850                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4851                                                   "(%s typowner) AS rolname, "
4852                                                   "typelem, typrelid, "
4853                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4854                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4855                                                   "typtype, typisdefined, "
4856                                                   "typname[0] = '_' AND typelem != 0 AND "
4857                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4858                                                   "FROM pg_type",
4859                                                   username_subquery);
4860         }
4861         else
4862         {
4863                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4864                                                   "typnamespace, NULL AS typacl, NULL as rtypacl, "
4865                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4866                                                   "(%s typowner) AS rolname, "
4867                                                   "typelem, typrelid, "
4868                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4869                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4870                                                   "typtype, typisdefined, "
4871                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
4872                                                   "FROM pg_type",
4873                                                   username_subquery);
4874         }
4875
4876         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4877
4878         ntups = PQntuples(res);
4879
4880         tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
4881
4882         i_tableoid = PQfnumber(res, "tableoid");
4883         i_oid = PQfnumber(res, "oid");
4884         i_typname = PQfnumber(res, "typname");
4885         i_typnamespace = PQfnumber(res, "typnamespace");
4886         i_typacl = PQfnumber(res, "typacl");
4887         i_rtypacl = PQfnumber(res, "rtypacl");
4888         i_inittypacl = PQfnumber(res, "inittypacl");
4889         i_initrtypacl = PQfnumber(res, "initrtypacl");
4890         i_rolname = PQfnumber(res, "rolname");
4891         i_typelem = PQfnumber(res, "typelem");
4892         i_typrelid = PQfnumber(res, "typrelid");
4893         i_typrelkind = PQfnumber(res, "typrelkind");
4894         i_typtype = PQfnumber(res, "typtype");
4895         i_typisdefined = PQfnumber(res, "typisdefined");
4896         i_isarray = PQfnumber(res, "isarray");
4897
4898         for (i = 0; i < ntups; i++)
4899         {
4900                 tyinfo[i].dobj.objType = DO_TYPE;
4901                 tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4902                 tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4903                 AssignDumpId(&tyinfo[i].dobj);
4904                 tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
4905                 tyinfo[i].dobj.namespace =
4906                         findNamespace(fout,
4907                                                   atooid(PQgetvalue(res, i, i_typnamespace)));
4908                 tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4909                 tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
4910                 tyinfo[i].rtypacl = pg_strdup(PQgetvalue(res, i, i_rtypacl));
4911                 tyinfo[i].inittypacl = pg_strdup(PQgetvalue(res, i, i_inittypacl));
4912                 tyinfo[i].initrtypacl = pg_strdup(PQgetvalue(res, i, i_initrtypacl));
4913                 tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
4914                 tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
4915                 tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
4916                 tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
4917                 tyinfo[i].shellType = NULL;
4918
4919                 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
4920                         tyinfo[i].isDefined = true;
4921                 else
4922                         tyinfo[i].isDefined = false;
4923
4924                 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
4925                         tyinfo[i].isArray = true;
4926                 else
4927                         tyinfo[i].isArray = false;
4928
4929                 /* Decide whether we want to dump it */
4930                 selectDumpableType(&tyinfo[i], fout);
4931
4932                 /* Do not try to dump ACL if no ACL exists. */
4933                 if (PQgetisnull(res, i, i_typacl) && PQgetisnull(res, i, i_rtypacl) &&
4934                         PQgetisnull(res, i, i_inittypacl) &&
4935                         PQgetisnull(res, i, i_initrtypacl))
4936                         tyinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4937
4938                 /*
4939                  * If it's a domain, fetch info about its constraints, if any
4940                  */
4941                 tyinfo[i].nDomChecks = 0;
4942                 tyinfo[i].domChecks = NULL;
4943                 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4944                         tyinfo[i].typtype == TYPTYPE_DOMAIN)
4945                         getDomainConstraints(fout, &(tyinfo[i]));
4946
4947                 /*
4948                  * If it's a base type, make a DumpableObject representing a shell
4949                  * definition of the type.  We will need to dump that ahead of the I/O
4950                  * functions for the type.  Similarly, range types need a shell
4951                  * definition in case they have a canonicalize function.
4952                  *
4953                  * Note: the shell type doesn't have a catId.  You might think it
4954                  * should copy the base type's catId, but then it might capture the
4955                  * pg_depend entries for the type, which we don't want.
4956                  */
4957                 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4958                         (tyinfo[i].typtype == TYPTYPE_BASE ||
4959                          tyinfo[i].typtype == TYPTYPE_RANGE))
4960                 {
4961                         stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
4962                         stinfo->dobj.objType = DO_SHELL_TYPE;
4963                         stinfo->dobj.catId = nilCatalogId;
4964                         AssignDumpId(&stinfo->dobj);
4965                         stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
4966                         stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
4967                         stinfo->baseType = &(tyinfo[i]);
4968                         tyinfo[i].shellType = stinfo;
4969
4970                         /*
4971                          * Initially mark the shell type as not to be dumped.  We'll only
4972                          * dump it if the I/O or canonicalize functions need to be dumped;
4973                          * this is taken care of while sorting dependencies.
4974                          */
4975                         stinfo->dobj.dump = DUMP_COMPONENT_NONE;
4976                 }
4977
4978                 if (strlen(tyinfo[i].rolname) == 0)
4979                         pg_log_warning("owner of data type \"%s\" appears to be invalid",
4980                                                    tyinfo[i].dobj.name);
4981         }
4982
4983         *numTypes = ntups;
4984
4985         PQclear(res);
4986
4987         destroyPQExpBuffer(query);
4988
4989         return tyinfo;
4990 }
4991
4992 /*
4993  * getOperators:
4994  *        read all operators in the system catalogs and return them in the
4995  * OprInfo* structure
4996  *
4997  *      numOprs is set to the number of operators read in
4998  */
4999 OprInfo *
5000 getOperators(Archive *fout, int *numOprs)
5001 {
5002         PGresult   *res;
5003         int                     ntups;
5004         int                     i;
5005         PQExpBuffer query = createPQExpBuffer();
5006         OprInfo    *oprinfo;
5007         int                     i_tableoid;
5008         int                     i_oid;
5009         int                     i_oprname;
5010         int                     i_oprnamespace;
5011         int                     i_rolname;
5012         int                     i_oprkind;
5013         int                     i_oprcode;
5014
5015         /*
5016          * find all operators, including builtin operators; we filter out
5017          * system-defined operators at dump-out time.
5018          */
5019
5020         appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
5021                                           "oprnamespace, "
5022                                           "(%s oprowner) AS rolname, "
5023                                           "oprkind, "
5024                                           "oprcode::oid AS oprcode "
5025                                           "FROM pg_operator",
5026                                           username_subquery);
5027
5028         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5029
5030         ntups = PQntuples(res);
5031         *numOprs = ntups;
5032
5033         oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
5034
5035         i_tableoid = PQfnumber(res, "tableoid");
5036         i_oid = PQfnumber(res, "oid");
5037         i_oprname = PQfnumber(res, "oprname");
5038         i_oprnamespace = PQfnumber(res, "oprnamespace");
5039         i_rolname = PQfnumber(res, "rolname");
5040         i_oprkind = PQfnumber(res, "oprkind");
5041         i_oprcode = PQfnumber(res, "oprcode");
5042
5043         for (i = 0; i < ntups; i++)
5044         {
5045                 oprinfo[i].dobj.objType = DO_OPERATOR;
5046                 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5047                 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5048                 AssignDumpId(&oprinfo[i].dobj);
5049                 oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
5050                 oprinfo[i].dobj.namespace =
5051                         findNamespace(fout,
5052                                                   atooid(PQgetvalue(res, i, i_oprnamespace)));
5053                 oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5054                 oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
5055                 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
5056
5057                 /* Decide whether we want to dump it */
5058                 selectDumpableObject(&(oprinfo[i].dobj), fout);
5059
5060                 /* Operators do not currently have ACLs. */
5061                 oprinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5062
5063                 if (strlen(oprinfo[i].rolname) == 0)
5064                         pg_log_warning("owner of operator \"%s\" appears to be invalid",
5065                                                    oprinfo[i].dobj.name);
5066         }
5067
5068         PQclear(res);
5069
5070         destroyPQExpBuffer(query);
5071
5072         return oprinfo;
5073 }
5074
5075 /*
5076  * getCollations:
5077  *        read all collations in the system catalogs and return them in the
5078  * CollInfo* structure
5079  *
5080  *      numCollations is set to the number of collations read in
5081  */
5082 CollInfo *
5083 getCollations(Archive *fout, int *numCollations)
5084 {
5085         PGresult   *res;
5086         int                     ntups;
5087         int                     i;
5088         PQExpBuffer query;
5089         CollInfo   *collinfo;
5090         int                     i_tableoid;
5091         int                     i_oid;
5092         int                     i_collname;
5093         int                     i_collnamespace;
5094         int                     i_rolname;
5095
5096         /* Collations didn't exist pre-9.1 */
5097         if (fout->remoteVersion < 90100)
5098         {
5099                 *numCollations = 0;
5100                 return NULL;
5101         }
5102
5103         query = createPQExpBuffer();
5104
5105         /*
5106          * find all collations, including builtin collations; we filter out
5107          * system-defined collations at dump-out time.
5108          */
5109
5110         appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
5111                                           "collnamespace, "
5112                                           "(%s collowner) AS rolname "
5113                                           "FROM pg_collation",
5114                                           username_subquery);
5115
5116         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5117
5118         ntups = PQntuples(res);
5119         *numCollations = ntups;
5120
5121         collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
5122
5123         i_tableoid = PQfnumber(res, "tableoid");
5124         i_oid = PQfnumber(res, "oid");
5125         i_collname = PQfnumber(res, "collname");
5126         i_collnamespace = PQfnumber(res, "collnamespace");
5127         i_rolname = PQfnumber(res, "rolname");
5128
5129         for (i = 0; i < ntups; i++)
5130         {
5131                 collinfo[i].dobj.objType = DO_COLLATION;
5132                 collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5133                 collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5134                 AssignDumpId(&collinfo[i].dobj);
5135                 collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
5136                 collinfo[i].dobj.namespace =
5137                         findNamespace(fout,
5138                                                   atooid(PQgetvalue(res, i, i_collnamespace)));
5139                 collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5140
5141                 /* Decide whether we want to dump it */
5142                 selectDumpableObject(&(collinfo[i].dobj), fout);
5143
5144                 /* Collations do not currently have ACLs. */
5145                 collinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5146         }
5147
5148         PQclear(res);
5149
5150         destroyPQExpBuffer(query);
5151
5152         return collinfo;
5153 }
5154
5155 /*
5156  * getConversions:
5157  *        read all conversions in the system catalogs and return them in the
5158  * ConvInfo* structure
5159  *
5160  *      numConversions is set to the number of conversions read in
5161  */
5162 ConvInfo *
5163 getConversions(Archive *fout, int *numConversions)
5164 {
5165         PGresult   *res;
5166         int                     ntups;
5167         int                     i;
5168         PQExpBuffer query;
5169         ConvInfo   *convinfo;
5170         int                     i_tableoid;
5171         int                     i_oid;
5172         int                     i_conname;
5173         int                     i_connamespace;
5174         int                     i_rolname;
5175
5176         query = createPQExpBuffer();
5177
5178         /*
5179          * find all conversions, including builtin conversions; we filter out
5180          * system-defined conversions at dump-out time.
5181          */
5182
5183         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5184                                           "connamespace, "
5185                                           "(%s conowner) AS rolname "
5186                                           "FROM pg_conversion",
5187                                           username_subquery);
5188
5189         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5190
5191         ntups = PQntuples(res);
5192         *numConversions = ntups;
5193
5194         convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
5195
5196         i_tableoid = PQfnumber(res, "tableoid");
5197         i_oid = PQfnumber(res, "oid");
5198         i_conname = PQfnumber(res, "conname");
5199         i_connamespace = PQfnumber(res, "connamespace");
5200         i_rolname = PQfnumber(res, "rolname");
5201
5202         for (i = 0; i < ntups; i++)
5203         {
5204                 convinfo[i].dobj.objType = DO_CONVERSION;
5205                 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5206                 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5207                 AssignDumpId(&convinfo[i].dobj);
5208                 convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
5209                 convinfo[i].dobj.namespace =
5210                         findNamespace(fout,
5211                                                   atooid(PQgetvalue(res, i, i_connamespace)));
5212                 convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5213
5214                 /* Decide whether we want to dump it */
5215                 selectDumpableObject(&(convinfo[i].dobj), fout);
5216
5217                 /* Conversions do not currently have ACLs. */
5218                 convinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5219         }
5220
5221         PQclear(res);
5222
5223         destroyPQExpBuffer(query);
5224
5225         return convinfo;
5226 }
5227
5228 /*
5229  * getAccessMethods:
5230  *        read all user-defined access methods in the system catalogs and return
5231  *        them in the AccessMethodInfo* structure
5232  *
5233  *      numAccessMethods is set to the number of access methods read in
5234  */
5235 AccessMethodInfo *
5236 getAccessMethods(Archive *fout, int *numAccessMethods)
5237 {
5238         PGresult   *res;
5239         int                     ntups;
5240         int                     i;
5241         PQExpBuffer query;
5242         AccessMethodInfo *aminfo;
5243         int                     i_tableoid;
5244         int                     i_oid;
5245         int                     i_amname;
5246         int                     i_amhandler;
5247         int                     i_amtype;
5248
5249         /* Before 9.6, there are no user-defined access methods */
5250         if (fout->remoteVersion < 90600)
5251         {
5252                 *numAccessMethods = 0;
5253                 return NULL;
5254         }
5255
5256         query = createPQExpBuffer();
5257
5258         /* Select all access methods from pg_am table */
5259         appendPQExpBufferStr(query, "SELECT tableoid, oid, amname, amtype, "
5260                                                  "amhandler::pg_catalog.regproc AS amhandler "
5261                                                  "FROM pg_am");
5262
5263         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5264
5265         ntups = PQntuples(res);
5266         *numAccessMethods = ntups;
5267
5268         aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
5269
5270         i_tableoid = PQfnumber(res, "tableoid");
5271         i_oid = PQfnumber(res, "oid");
5272         i_amname = PQfnumber(res, "amname");
5273         i_amhandler = PQfnumber(res, "amhandler");
5274         i_amtype = PQfnumber(res, "amtype");
5275
5276         for (i = 0; i < ntups; i++)
5277         {
5278                 aminfo[i].dobj.objType = DO_ACCESS_METHOD;
5279                 aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5280                 aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5281                 AssignDumpId(&aminfo[i].dobj);
5282                 aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
5283                 aminfo[i].dobj.namespace = NULL;
5284                 aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
5285                 aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
5286
5287                 /* Decide whether we want to dump it */
5288                 selectDumpableAccessMethod(&(aminfo[i]), fout);
5289
5290                 /* Access methods do not currently have ACLs. */
5291                 aminfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5292         }
5293
5294         PQclear(res);
5295
5296         destroyPQExpBuffer(query);
5297
5298         return aminfo;
5299 }
5300
5301
5302 /*
5303  * getOpclasses:
5304  *        read all opclasses in the system catalogs and return them in the
5305  * OpclassInfo* structure
5306  *
5307  *      numOpclasses is set to the number of opclasses read in
5308  */
5309 OpclassInfo *
5310 getOpclasses(Archive *fout, int *numOpclasses)
5311 {
5312         PGresult   *res;
5313         int                     ntups;
5314         int                     i;
5315         PQExpBuffer query = createPQExpBuffer();
5316         OpclassInfo *opcinfo;
5317         int                     i_tableoid;
5318         int                     i_oid;
5319         int                     i_opcname;
5320         int                     i_opcnamespace;
5321         int                     i_rolname;
5322
5323         /*
5324          * find all opclasses, including builtin opclasses; we filter out
5325          * system-defined opclasses at dump-out time.
5326          */
5327
5328         appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
5329                                           "opcnamespace, "
5330                                           "(%s opcowner) AS rolname "
5331                                           "FROM pg_opclass",
5332                                           username_subquery);
5333
5334         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5335
5336         ntups = PQntuples(res);
5337         *numOpclasses = ntups;
5338
5339         opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
5340
5341         i_tableoid = PQfnumber(res, "tableoid");
5342         i_oid = PQfnumber(res, "oid");
5343         i_opcname = PQfnumber(res, "opcname");
5344         i_opcnamespace = PQfnumber(res, "opcnamespace");
5345         i_rolname = PQfnumber(res, "rolname");
5346
5347         for (i = 0; i < ntups; i++)
5348         {
5349                 opcinfo[i].dobj.objType = DO_OPCLASS;
5350                 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5351                 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5352                 AssignDumpId(&opcinfo[i].dobj);
5353                 opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
5354                 opcinfo[i].dobj.namespace =
5355                         findNamespace(fout,
5356                                                   atooid(PQgetvalue(res, i, i_opcnamespace)));
5357                 opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5358
5359                 /* Decide whether we want to dump it */
5360                 selectDumpableObject(&(opcinfo[i].dobj), fout);
5361
5362                 /* Op Classes do not currently have ACLs. */
5363                 opcinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5364
5365                 if (strlen(opcinfo[i].rolname) == 0)
5366                         pg_log_warning("owner of operator class \"%s\" appears to be invalid",
5367                                                    opcinfo[i].dobj.name);
5368         }
5369
5370         PQclear(res);
5371
5372         destroyPQExpBuffer(query);
5373
5374         return opcinfo;
5375 }
5376
5377 /*
5378  * getOpfamilies:
5379  *        read all opfamilies in the system catalogs and return them in the
5380  * OpfamilyInfo* structure
5381  *
5382  *      numOpfamilies is set to the number of opfamilies read in
5383  */
5384 OpfamilyInfo *
5385 getOpfamilies(Archive *fout, int *numOpfamilies)
5386 {
5387         PGresult   *res;
5388         int                     ntups;
5389         int                     i;
5390         PQExpBuffer query;
5391         OpfamilyInfo *opfinfo;
5392         int                     i_tableoid;
5393         int                     i_oid;
5394         int                     i_opfname;
5395         int                     i_opfnamespace;
5396         int                     i_rolname;
5397
5398         /* Before 8.3, there is no separate concept of opfamilies */
5399         if (fout->remoteVersion < 80300)
5400         {
5401                 *numOpfamilies = 0;
5402                 return NULL;
5403         }
5404
5405         query = createPQExpBuffer();
5406
5407         /*
5408          * find all opfamilies, including builtin opfamilies; we filter out
5409          * system-defined opfamilies at dump-out time.
5410          */
5411
5412         appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
5413                                           "opfnamespace, "
5414                                           "(%s opfowner) AS rolname "
5415                                           "FROM pg_opfamily",
5416                                           username_subquery);
5417
5418         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5419
5420         ntups = PQntuples(res);
5421         *numOpfamilies = ntups;
5422
5423         opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
5424
5425         i_tableoid = PQfnumber(res, "tableoid");
5426         i_oid = PQfnumber(res, "oid");
5427         i_opfname = PQfnumber(res, "opfname");
5428         i_opfnamespace = PQfnumber(res, "opfnamespace");
5429         i_rolname = PQfnumber(res, "rolname");
5430
5431         for (i = 0; i < ntups; i++)
5432         {
5433                 opfinfo[i].dobj.objType = DO_OPFAMILY;
5434                 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5435                 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5436                 AssignDumpId(&opfinfo[i].dobj);
5437                 opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
5438                 opfinfo[i].dobj.namespace =
5439                         findNamespace(fout,
5440                                                   atooid(PQgetvalue(res, i, i_opfnamespace)));
5441                 opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5442
5443                 /* Decide whether we want to dump it */
5444                 selectDumpableObject(&(opfinfo[i].dobj), fout);
5445
5446                 /* Extensions do not currently have ACLs. */
5447                 opfinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5448
5449                 if (strlen(opfinfo[i].rolname) == 0)
5450                         pg_log_warning("owner of operator family \"%s\" appears to be invalid",
5451                                                    opfinfo[i].dobj.name);
5452         }
5453
5454         PQclear(res);
5455
5456         destroyPQExpBuffer(query);
5457
5458         return opfinfo;
5459 }
5460
5461 /*
5462  * getAggregates:
5463  *        read all the user-defined aggregates in the system catalogs and
5464  * return them in the AggInfo* structure
5465  *
5466  * numAggs is set to the number of aggregates read in
5467  */
5468 AggInfo *
5469 getAggregates(Archive *fout, int *numAggs)
5470 {
5471         DumpOptions *dopt = fout->dopt;
5472         PGresult   *res;
5473         int                     ntups;
5474         int                     i;
5475         PQExpBuffer query = createPQExpBuffer();
5476         AggInfo    *agginfo;
5477         int                     i_tableoid;
5478         int                     i_oid;
5479         int                     i_aggname;
5480         int                     i_aggnamespace;
5481         int                     i_pronargs;
5482         int                     i_proargtypes;
5483         int                     i_rolname;
5484         int                     i_aggacl;
5485         int                     i_raggacl;
5486         int                     i_initaggacl;
5487         int                     i_initraggacl;
5488
5489         /*
5490          * Find all interesting aggregates.  See comment in getFuncs() for the
5491          * rationale behind the filtering logic.
5492          */
5493         if (fout->remoteVersion >= 90600)
5494         {
5495                 PQExpBuffer acl_subquery = createPQExpBuffer();
5496                 PQExpBuffer racl_subquery = createPQExpBuffer();
5497                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5498                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5499                 const char *agg_check;
5500
5501                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5502                                                 initracl_subquery, "p.proacl", "p.proowner", "'f'",
5503                                                 dopt->binary_upgrade);
5504
5505                 agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
5506                                          : "p.proisagg");
5507
5508                 appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
5509                                                   "p.proname AS aggname, "
5510                                                   "p.pronamespace AS aggnamespace, "
5511                                                   "p.pronargs, p.proargtypes, "
5512                                                   "(%s p.proowner) AS rolname, "
5513                                                   "%s AS aggacl, "
5514                                                   "%s AS raggacl, "
5515                                                   "%s AS initaggacl, "
5516                                                   "%s AS initraggacl "
5517                                                   "FROM pg_proc p "
5518                                                   "LEFT JOIN pg_init_privs pip ON "
5519                                                   "(p.oid = pip.objoid "
5520                                                   "AND pip.classoid = 'pg_proc'::regclass "
5521                                                   "AND pip.objsubid = 0) "
5522                                                   "WHERE %s AND ("
5523                                                   "p.pronamespace != "
5524                                                   "(SELECT oid FROM pg_namespace "
5525                                                   "WHERE nspname = 'pg_catalog') OR "
5526                                                   "p.proacl IS DISTINCT FROM pip.initprivs",
5527                                                   username_subquery,
5528                                                   acl_subquery->data,
5529                                                   racl_subquery->data,
5530                                                   initacl_subquery->data,
5531                                                   initracl_subquery->data,
5532                                                   agg_check);
5533                 if (dopt->binary_upgrade)
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                 destroyPQExpBuffer(acl_subquery);
5543                 destroyPQExpBuffer(racl_subquery);
5544                 destroyPQExpBuffer(initacl_subquery);
5545                 destroyPQExpBuffer(initracl_subquery);
5546         }
5547         else if (fout->remoteVersion >= 80200)
5548         {
5549                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
5550                                                   "pronamespace AS aggnamespace, "
5551                                                   "pronargs, proargtypes, "
5552                                                   "(%s proowner) AS rolname, "
5553                                                   "proacl AS aggacl, "
5554                                                   "NULL AS raggacl, "
5555                                                   "NULL AS initaggacl, NULL AS initraggacl "
5556                                                   "FROM pg_proc p "
5557                                                   "WHERE proisagg AND ("
5558                                                   "pronamespace != "
5559                                                   "(SELECT oid FROM pg_namespace "
5560                                                   "WHERE nspname = 'pg_catalog')",
5561                                                   username_subquery);
5562                 if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
5563                         appendPQExpBufferStr(query,
5564                                                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5565                                                                  "classid = 'pg_proc'::regclass AND "
5566                                                                  "objid = p.oid AND "
5567                                                                  "refclassid = 'pg_extension'::regclass AND "
5568                                                                  "deptype = 'e')");
5569                 appendPQExpBufferChar(query, ')');
5570         }
5571         else
5572         {
5573                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
5574                                                   "pronamespace AS aggnamespace, "
5575                                                   "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
5576                                                   "proargtypes, "
5577                                                   "(%s proowner) AS rolname, "
5578                                                   "proacl AS aggacl, "
5579                                                   "NULL AS raggacl, "
5580                                                   "NULL AS initaggacl, NULL AS initraggacl "
5581                                                   "FROM pg_proc "
5582                                                   "WHERE proisagg "
5583                                                   "AND pronamespace != "
5584                                                   "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
5585                                                   username_subquery);
5586         }
5587
5588         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5589
5590         ntups = PQntuples(res);
5591         *numAggs = ntups;
5592
5593         agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
5594
5595         i_tableoid = PQfnumber(res, "tableoid");
5596         i_oid = PQfnumber(res, "oid");
5597         i_aggname = PQfnumber(res, "aggname");
5598         i_aggnamespace = PQfnumber(res, "aggnamespace");
5599         i_pronargs = PQfnumber(res, "pronargs");
5600         i_proargtypes = PQfnumber(res, "proargtypes");
5601         i_rolname = PQfnumber(res, "rolname");
5602         i_aggacl = PQfnumber(res, "aggacl");
5603         i_raggacl = PQfnumber(res, "raggacl");
5604         i_initaggacl = PQfnumber(res, "initaggacl");
5605         i_initraggacl = PQfnumber(res, "initraggacl");
5606
5607         for (i = 0; i < ntups; i++)
5608         {
5609                 agginfo[i].aggfn.dobj.objType = DO_AGG;
5610                 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5611                 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5612                 AssignDumpId(&agginfo[i].aggfn.dobj);
5613                 agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
5614                 agginfo[i].aggfn.dobj.namespace =
5615                         findNamespace(fout,
5616                                                   atooid(PQgetvalue(res, i, i_aggnamespace)));
5617                 agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5618                 if (strlen(agginfo[i].aggfn.rolname) == 0)
5619                         pg_log_warning("owner of aggregate function \"%s\" appears to be invalid",
5620                                                    agginfo[i].aggfn.dobj.name);
5621                 agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
5622                 agginfo[i].aggfn.prorettype = InvalidOid;       /* not saved */
5623                 agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
5624                 agginfo[i].aggfn.rproacl = pg_strdup(PQgetvalue(res, i, i_raggacl));
5625                 agginfo[i].aggfn.initproacl = pg_strdup(PQgetvalue(res, i, i_initaggacl));
5626                 agginfo[i].aggfn.initrproacl = pg_strdup(PQgetvalue(res, i, i_initraggacl));
5627                 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
5628                 if (agginfo[i].aggfn.nargs == 0)
5629                         agginfo[i].aggfn.argtypes = NULL;
5630                 else
5631                 {
5632                         agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
5633                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
5634                                                   agginfo[i].aggfn.argtypes,
5635                                                   agginfo[i].aggfn.nargs);
5636                 }
5637
5638                 /* Decide whether we want to dump it */
5639                 selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
5640
5641                 /* Do not try to dump ACL if no ACL exists. */
5642                 if (PQgetisnull(res, i, i_aggacl) && PQgetisnull(res, i, i_raggacl) &&
5643                         PQgetisnull(res, i, i_initaggacl) &&
5644                         PQgetisnull(res, i, i_initraggacl))
5645                         agginfo[i].aggfn.dobj.dump &= ~DUMP_COMPONENT_ACL;
5646         }
5647
5648         PQclear(res);
5649
5650         destroyPQExpBuffer(query);
5651
5652         return agginfo;
5653 }
5654
5655 /*
5656  * getFuncs:
5657  *        read all the user-defined functions in the system catalogs and
5658  * return them in the FuncInfo* structure
5659  *
5660  * numFuncs is set to the number of functions read in
5661  */
5662 FuncInfo *
5663 getFuncs(Archive *fout, int *numFuncs)
5664 {
5665         DumpOptions *dopt = fout->dopt;
5666         PGresult   *res;
5667         int                     ntups;
5668         int                     i;
5669         PQExpBuffer query = createPQExpBuffer();
5670         FuncInfo   *finfo;
5671         int                     i_tableoid;
5672         int                     i_oid;
5673         int                     i_proname;
5674         int                     i_pronamespace;
5675         int                     i_rolname;
5676         int                     i_prolang;
5677         int                     i_pronargs;
5678         int                     i_proargtypes;
5679         int                     i_prorettype;
5680         int                     i_proacl;
5681         int                     i_rproacl;
5682         int                     i_initproacl;
5683         int                     i_initrproacl;
5684
5685         /*
5686          * Find all interesting functions.  This is a bit complicated:
5687          *
5688          * 1. Always exclude aggregates; those are handled elsewhere.
5689          *
5690          * 2. Always exclude functions that are internally dependent on something
5691          * else, since presumably those will be created as a result of creating
5692          * the something else.  This currently acts only to suppress constructor
5693          * functions for range types (so we only need it in 9.2 and up).  Note
5694          * this is OK only because the constructors don't have any dependencies
5695          * the range type doesn't have; otherwise we might not get creation
5696          * ordering correct.
5697          *
5698          * 3. Otherwise, we normally exclude functions in pg_catalog.  However, if
5699          * they're members of extensions and we are in binary-upgrade mode then
5700          * include them, since we want to dump extension members individually in
5701          * that mode.  Also, if they are used by casts or transforms then we need
5702          * to gather the information about them, though they won't be dumped if
5703          * they are built-in.  Also, in 9.6 and up, include functions in
5704          * pg_catalog if they have an ACL different from what's shown in
5705          * pg_init_privs.
5706          */
5707         if (fout->remoteVersion >= 90600)
5708         {
5709                 PQExpBuffer acl_subquery = createPQExpBuffer();
5710                 PQExpBuffer racl_subquery = createPQExpBuffer();
5711                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5712                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5713                 const char *not_agg_check;
5714
5715                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5716                                                 initracl_subquery, "p.proacl", "p.proowner", "'f'",
5717                                                 dopt->binary_upgrade);
5718
5719                 not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
5720                                                  : "NOT p.proisagg");
5721
5722                 appendPQExpBuffer(query,
5723                                                   "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
5724                                                   "p.pronargs, p.proargtypes, p.prorettype, "
5725                                                   "%s AS proacl, "
5726                                                   "%s AS rproacl, "
5727                                                   "%s AS initproacl, "
5728                                                   "%s AS initrproacl, "
5729                                                   "p.pronamespace, "
5730                                                   "(%s p.proowner) AS rolname "
5731                                                   "FROM pg_proc p "
5732                                                   "LEFT JOIN pg_init_privs pip ON "
5733                                                   "(p.oid = pip.objoid "
5734                                                   "AND pip.classoid = 'pg_proc'::regclass "
5735                                                   "AND pip.objsubid = 0) "
5736                                                   "WHERE %s"
5737                                                   "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
5738                                                   "WHERE classid = 'pg_proc'::regclass AND "
5739                                                   "objid = p.oid AND deptype = 'i')"
5740                                                   "\n  AND ("
5741                                                   "\n  pronamespace != "
5742                                                   "(SELECT oid FROM pg_namespace "
5743                                                   "WHERE nspname = 'pg_catalog')"
5744                                                   "\n  OR EXISTS (SELECT 1 FROM pg_cast"
5745                                                   "\n  WHERE pg_cast.oid > %u "
5746                                                   "\n  AND p.oid = pg_cast.castfunc)"
5747                                                   "\n  OR EXISTS (SELECT 1 FROM pg_transform"
5748                                                   "\n  WHERE pg_transform.oid > %u AND "
5749                                                   "\n  (p.oid = pg_transform.trffromsql"
5750                                                   "\n  OR p.oid = pg_transform.trftosql))",
5751                                                   acl_subquery->data,
5752                                                   racl_subquery->data,
5753                                                   initacl_subquery->data,
5754                                                   initracl_subquery->data,
5755                                                   username_subquery,
5756                                                   not_agg_check,
5757                                                   g_last_builtin_oid,
5758                                                   g_last_builtin_oid);
5759                 if (dopt->binary_upgrade)
5760                         appendPQExpBufferStr(query,
5761                                                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5762                                                                  "classid = 'pg_proc'::regclass AND "
5763                                                                  "objid = p.oid AND "
5764                                                                  "refclassid = 'pg_extension'::regclass AND "
5765                                                                  "deptype = 'e')");
5766                 appendPQExpBufferStr(query,
5767                                                          "\n  OR p.proacl IS DISTINCT FROM pip.initprivs");
5768                 appendPQExpBufferChar(query, ')');
5769
5770                 destroyPQExpBuffer(acl_subquery);
5771                 destroyPQExpBuffer(racl_subquery);
5772                 destroyPQExpBuffer(initacl_subquery);
5773                 destroyPQExpBuffer(initracl_subquery);
5774         }
5775         else
5776         {
5777                 appendPQExpBuffer(query,
5778                                                   "SELECT tableoid, oid, proname, prolang, "
5779                                                   "pronargs, proargtypes, prorettype, proacl, "
5780                                                   "NULL as rproacl, "
5781                                                   "NULL as initproacl, NULL AS initrproacl, "
5782                                                   "pronamespace, "
5783                                                   "(%s proowner) AS rolname "
5784                                                   "FROM pg_proc p "
5785                                                   "WHERE NOT proisagg",
5786                                                   username_subquery);
5787                 if (fout->remoteVersion >= 90200)
5788                         appendPQExpBufferStr(query,
5789                                                                  "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
5790                                                                  "WHERE classid = 'pg_proc'::regclass AND "
5791                                                                  "objid = p.oid AND deptype = 'i')");
5792                 appendPQExpBuffer(query,
5793                                                   "\n  AND ("
5794                                                   "\n  pronamespace != "
5795                                                   "(SELECT oid FROM pg_namespace "
5796                                                   "WHERE nspname = 'pg_catalog')"
5797                                                   "\n  OR EXISTS (SELECT 1 FROM pg_cast"
5798                                                   "\n  WHERE pg_cast.oid > '%u'::oid"
5799                                                   "\n  AND p.oid = pg_cast.castfunc)",
5800                                                   g_last_builtin_oid);
5801
5802                 if (fout->remoteVersion >= 90500)
5803                         appendPQExpBuffer(query,
5804                                                           "\n  OR EXISTS (SELECT 1 FROM pg_transform"
5805                                                           "\n  WHERE pg_transform.oid > '%u'::oid"
5806                                                           "\n  AND (p.oid = pg_transform.trffromsql"
5807                                                           "\n  OR p.oid = pg_transform.trftosql))",
5808                                                           g_last_builtin_oid);
5809
5810                 if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
5811                         appendPQExpBufferStr(query,
5812                                                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5813                                                                  "classid = 'pg_proc'::regclass AND "
5814                                                                  "objid = p.oid AND "
5815                                                                  "refclassid = 'pg_extension'::regclass AND "
5816                                                                  "deptype = 'e')");
5817                 appendPQExpBufferChar(query, ')');
5818         }
5819
5820         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5821
5822         ntups = PQntuples(res);
5823
5824         *numFuncs = ntups;
5825
5826         finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
5827
5828         i_tableoid = PQfnumber(res, "tableoid");
5829         i_oid = PQfnumber(res, "oid");
5830         i_proname = PQfnumber(res, "proname");
5831         i_pronamespace = PQfnumber(res, "pronamespace");
5832         i_rolname = PQfnumber(res, "rolname");
5833         i_prolang = PQfnumber(res, "prolang");
5834         i_pronargs = PQfnumber(res, "pronargs");
5835         i_proargtypes = PQfnumber(res, "proargtypes");
5836         i_prorettype = PQfnumber(res, "prorettype");
5837         i_proacl = PQfnumber(res, "proacl");
5838         i_rproacl = PQfnumber(res, "rproacl");
5839         i_initproacl = PQfnumber(res, "initproacl");
5840         i_initrproacl = PQfnumber(res, "initrproacl");
5841
5842         for (i = 0; i < ntups; i++)
5843         {
5844                 finfo[i].dobj.objType = DO_FUNC;
5845                 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5846                 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5847                 AssignDumpId(&finfo[i].dobj);
5848                 finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
5849                 finfo[i].dobj.namespace =
5850                         findNamespace(fout,
5851                                                   atooid(PQgetvalue(res, i, i_pronamespace)));
5852                 finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5853                 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
5854                 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
5855                 finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
5856                 finfo[i].rproacl = pg_strdup(PQgetvalue(res, i, i_rproacl));
5857                 finfo[i].initproacl = pg_strdup(PQgetvalue(res, i, i_initproacl));
5858                 finfo[i].initrproacl = pg_strdup(PQgetvalue(res, i, i_initrproacl));
5859                 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
5860                 if (finfo[i].nargs == 0)
5861                         finfo[i].argtypes = NULL;
5862                 else
5863                 {
5864                         finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
5865                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
5866                                                   finfo[i].argtypes, finfo[i].nargs);
5867                 }
5868
5869                 /* Decide whether we want to dump it */
5870                 selectDumpableObject(&(finfo[i].dobj), fout);
5871
5872                 /* Do not try to dump ACL if no ACL exists. */
5873                 if (PQgetisnull(res, i, i_proacl) && PQgetisnull(res, i, i_rproacl) &&
5874                         PQgetisnull(res, i, i_initproacl) &&
5875                         PQgetisnull(res, i, i_initrproacl))
5876                         finfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5877
5878                 if (strlen(finfo[i].rolname) == 0)
5879                         pg_log_warning("owner of function \"%s\" appears to be invalid",
5880                                                    finfo[i].dobj.name);
5881         }
5882
5883         PQclear(res);
5884
5885         destroyPQExpBuffer(query);
5886
5887         return finfo;
5888 }
5889
5890 /*
5891  * getTables
5892  *        read all the tables (no indexes)
5893  * in the system catalogs return them in the TableInfo* structure
5894  *
5895  * numTables is set to the number of tables read in
5896  */
5897 TableInfo *
5898 getTables(Archive *fout, int *numTables)
5899 {
5900         DumpOptions *dopt = fout->dopt;
5901         PGresult   *res;
5902         int                     ntups;
5903         int                     i;
5904         PQExpBuffer query = createPQExpBuffer();
5905         TableInfo  *tblinfo;
5906         int                     i_reltableoid;
5907         int                     i_reloid;
5908         int                     i_relname;
5909         int                     i_relnamespace;
5910         int                     i_relkind;
5911         int                     i_relacl;
5912         int                     i_rrelacl;
5913         int                     i_initrelacl;
5914         int                     i_initrrelacl;
5915         int                     i_rolname;
5916         int                     i_relchecks;
5917         int                     i_relhastriggers;
5918         int                     i_relhasindex;
5919         int                     i_relhasrules;
5920         int                     i_relrowsec;
5921         int                     i_relforcerowsec;
5922         int                     i_relhasoids;
5923         int                     i_relfrozenxid;
5924         int                     i_relminmxid;
5925         int                     i_toastoid;
5926         int                     i_toastfrozenxid;
5927         int                     i_toastminmxid;
5928         int                     i_relpersistence;
5929         int                     i_relispopulated;
5930         int                     i_relreplident;
5931         int                     i_owning_tab;
5932         int                     i_owning_col;
5933         int                     i_reltablespace;
5934         int                     i_reloptions;
5935         int                     i_checkoption;
5936         int                     i_toastreloptions;
5937         int                     i_reloftype;
5938         int                     i_relpages;
5939         int                     i_is_identity_sequence;
5940         int                     i_changed_acl;
5941         int                     i_partkeydef;
5942         int                     i_ispartition;
5943         int                     i_partbound;
5944         int                     i_amname;
5945
5946         /*
5947          * Find all the tables and table-like objects.
5948          *
5949          * We include system catalogs, so that we can work if a user table is
5950          * defined to inherit from a system catalog (pretty weird, but...)
5951          *
5952          * We ignore relations that are not ordinary tables, sequences, views,
5953          * materialized views, composite types, or foreign tables.
5954          *
5955          * Composite-type table entries won't be dumped as such, but we have to
5956          * make a DumpableObject for them so that we can track dependencies of the
5957          * composite type (pg_depend entries for columns of the composite type
5958          * link to the pg_class entry not the pg_type entry).
5959          *
5960          * Note: in this phase we should collect only a minimal amount of
5961          * information about each table, basically just enough to decide if it is
5962          * interesting. We must fetch all tables in this phase because otherwise
5963          * we cannot correctly identify inherited columns, owned sequences, etc.
5964          *
5965          * We purposefully ignore toast OIDs for partitioned tables; the reason is
5966          * that versions 10 and 11 have them, but 12 does not, so emitting them
5967          * causes the upgrade to fail.
5968          */
5969
5970         if (fout->remoteVersion >= 90600)
5971         {
5972                 char       *partkeydef = "NULL";
5973                 char       *ispartition = "false";
5974                 char       *partbound = "NULL";
5975                 char       *relhasoids = "c.relhasoids";
5976
5977                 PQExpBuffer acl_subquery = createPQExpBuffer();
5978                 PQExpBuffer racl_subquery = createPQExpBuffer();
5979                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5980                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5981
5982                 PQExpBuffer attacl_subquery = createPQExpBuffer();
5983                 PQExpBuffer attracl_subquery = createPQExpBuffer();
5984                 PQExpBuffer attinitacl_subquery = createPQExpBuffer();
5985                 PQExpBuffer attinitracl_subquery = createPQExpBuffer();
5986
5987                 /*
5988                  * Collect the information about any partitioned tables, which were
5989                  * added in PG10.
5990                  */
5991
5992                 if (fout->remoteVersion >= 100000)
5993                 {
5994                         partkeydef = "pg_get_partkeydef(c.oid)";
5995                         ispartition = "c.relispartition";
5996                         partbound = "pg_get_expr(c.relpartbound, c.oid)";
5997                 }
5998
5999                 /* In PG12 upwards WITH OIDS does not exist anymore. */
6000                 if (fout->remoteVersion >= 120000)
6001                         relhasoids = "'f'::bool";
6002
6003                 /*
6004                  * Left join to pick up dependency info linking sequences to their
6005                  * owning column, if any (note this dependency is AUTO as of 8.2)
6006                  *
6007                  * Left join to detect if any privileges are still as-set-at-init, in
6008                  * which case we won't dump out ACL commands for those.
6009                  */
6010
6011                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
6012                                                 initracl_subquery, "c.relacl", "c.relowner",
6013                                                 "CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
6014                                                 " THEN 's' ELSE 'r' END::\"char\"",
6015                                                 dopt->binary_upgrade);
6016
6017                 buildACLQueries(attacl_subquery, attracl_subquery, attinitacl_subquery,
6018                                                 attinitracl_subquery, "at.attacl", "c.relowner", "'c'",
6019                                                 dopt->binary_upgrade);
6020
6021                 appendPQExpBuffer(query,
6022                                                   "SELECT c.tableoid, c.oid, c.relname, "
6023                                                   "%s AS relacl, %s as rrelacl, "
6024                                                   "%s AS initrelacl, %s as initrrelacl, "
6025                                                   "c.relkind, c.relnamespace, "
6026                                                   "(%s c.relowner) AS rolname, "
6027                                                   "c.relchecks, c.relhastriggers, "
6028                                                   "c.relhasindex, c.relhasrules, %s AS relhasoids, "
6029                                                   "c.relrowsecurity, c.relforcerowsecurity, "
6030                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6031                                                   "tc.relfrozenxid AS tfrozenxid, "
6032                                                   "tc.relminmxid AS tminmxid, "
6033                                                   "c.relpersistence, c.relispopulated, "
6034                                                   "c.relreplident, c.relpages, am.amname, "
6035                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6036                                                   "d.refobjid AS owning_tab, "
6037                                                   "d.refobjsubid AS owning_col, "
6038                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6039                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6040                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6041                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6042                                                   "tc.reloptions AS toast_reloptions, "
6043                                                   "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, "
6044                                                   "EXISTS (SELECT 1 FROM pg_attribute at LEFT JOIN pg_init_privs pip ON "
6045                                                   "(c.oid = pip.objoid "
6046                                                   "AND pip.classoid = 'pg_class'::regclass "
6047                                                   "AND pip.objsubid = at.attnum)"
6048                                                   "WHERE at.attrelid = c.oid AND ("
6049                                                   "%s IS NOT NULL "
6050                                                   "OR %s IS NOT NULL "
6051                                                   "OR %s IS NOT NULL "
6052                                                   "OR %s IS NOT NULL"
6053                                                   "))"
6054                                                   "AS changed_acl, "
6055                                                   "%s AS partkeydef, "
6056                                                   "%s AS ispartition, "
6057                                                   "%s AS partbound "
6058                                                   "FROM pg_class c "
6059                                                   "LEFT JOIN pg_depend d ON "
6060                                                   "(c.relkind = '%c' AND "
6061                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6062                                                   "d.objsubid = 0 AND "
6063                                                   "d.refclassid = c.tableoid AND d.deptype IN ('a', 'i')) "
6064                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid AND c.relkind <> '%c') "
6065                                                   "LEFT JOIN pg_am am ON (c.relam = am.oid) "
6066                                                   "LEFT JOIN pg_init_privs pip ON "
6067                                                   "(c.oid = pip.objoid "
6068                                                   "AND pip.classoid = 'pg_class'::regclass "
6069                                                   "AND pip.objsubid = 0) "
6070                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c', '%c') "
6071                                                   "ORDER BY c.oid",
6072                                                   acl_subquery->data,
6073                                                   racl_subquery->data,
6074                                                   initacl_subquery->data,
6075                                                   initracl_subquery->data,
6076                                                   username_subquery,
6077                                                   relhasoids,
6078                                                   RELKIND_SEQUENCE,
6079                                                   attacl_subquery->data,
6080                                                   attracl_subquery->data,
6081                                                   attinitacl_subquery->data,
6082                                                   attinitracl_subquery->data,
6083                                                   partkeydef,
6084                                                   ispartition,
6085                                                   partbound,
6086                                                   RELKIND_SEQUENCE,
6087                                                   RELKIND_PARTITIONED_TABLE,
6088                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6089                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6090                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
6091                                                   RELKIND_PARTITIONED_TABLE);
6092
6093                 destroyPQExpBuffer(acl_subquery);
6094                 destroyPQExpBuffer(racl_subquery);
6095                 destroyPQExpBuffer(initacl_subquery);
6096                 destroyPQExpBuffer(initracl_subquery);
6097
6098                 destroyPQExpBuffer(attacl_subquery);
6099                 destroyPQExpBuffer(attracl_subquery);
6100                 destroyPQExpBuffer(attinitacl_subquery);
6101                 destroyPQExpBuffer(attinitracl_subquery);
6102         }
6103         else if (fout->remoteVersion >= 90500)
6104         {
6105                 /*
6106                  * Left join to pick up dependency info linking sequences to their
6107                  * owning column, if any (note this dependency is AUTO as of 8.2)
6108                  */
6109                 appendPQExpBuffer(query,
6110                                                   "SELECT c.tableoid, c.oid, c.relname, "
6111                                                   "c.relacl, NULL as rrelacl, "
6112                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6113                                                   "c.relkind, "
6114                                                   "c.relnamespace, "
6115                                                   "(%s c.relowner) AS rolname, "
6116                                                   "c.relchecks, c.relhastriggers, "
6117                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6118                                                   "c.relrowsecurity, c.relforcerowsecurity, "
6119                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6120                                                   "tc.relfrozenxid AS tfrozenxid, "
6121                                                   "tc.relminmxid AS tminmxid, "
6122                                                   "c.relpersistence, c.relispopulated, "
6123                                                   "c.relreplident, c.relpages, "
6124                                                   "NULL AS amname, "
6125                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6126                                                   "d.refobjid AS owning_tab, "
6127                                                   "d.refobjsubid AS owning_col, "
6128                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6129                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6130                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6131                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6132                                                   "tc.reloptions AS toast_reloptions, "
6133                                                   "NULL AS changed_acl, "
6134                                                   "NULL AS partkeydef, "
6135                                                   "false AS ispartition, "
6136                                                   "NULL AS partbound "
6137                                                   "FROM pg_class c "
6138                                                   "LEFT JOIN pg_depend d ON "
6139                                                   "(c.relkind = '%c' AND "
6140                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6141                                                   "d.objsubid = 0 AND "
6142                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6143                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6144                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6145                                                   "ORDER BY c.oid",
6146                                                   username_subquery,
6147                                                   RELKIND_SEQUENCE,
6148                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6149                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6150                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6151         }
6152         else if (fout->remoteVersion >= 90400)
6153         {
6154                 /*
6155                  * Left join to pick up dependency info linking sequences to their
6156                  * owning column, if any (note this dependency is AUTO as of 8.2)
6157                  */
6158                 appendPQExpBuffer(query,
6159                                                   "SELECT c.tableoid, c.oid, c.relname, "
6160                                                   "c.relacl, NULL as rrelacl, "
6161                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6162                                                   "c.relkind, "
6163                                                   "c.relnamespace, "
6164                                                   "(%s c.relowner) AS rolname, "
6165                                                   "c.relchecks, c.relhastriggers, "
6166                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6167                                                   "'f'::bool AS relrowsecurity, "
6168                                                   "'f'::bool AS relforcerowsecurity, "
6169                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6170                                                   "tc.relfrozenxid AS tfrozenxid, "
6171                                                   "tc.relminmxid AS tminmxid, "
6172                                                   "c.relpersistence, c.relispopulated, "
6173                                                   "c.relreplident, c.relpages, "
6174                                                   "NULL AS amname, "
6175                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6176                                                   "d.refobjid AS owning_tab, "
6177                                                   "d.refobjsubid AS owning_col, "
6178                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6179                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6180                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6181                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6182                                                   "tc.reloptions AS toast_reloptions, "
6183                                                   "NULL AS changed_acl, "
6184                                                   "NULL AS partkeydef, "
6185                                                   "false AS ispartition, "
6186                                                   "NULL AS partbound "
6187                                                   "FROM pg_class c "
6188                                                   "LEFT JOIN pg_depend d ON "
6189                                                   "(c.relkind = '%c' AND "
6190                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6191                                                   "d.objsubid = 0 AND "
6192                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6193                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6194                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6195                                                   "ORDER BY c.oid",
6196                                                   username_subquery,
6197                                                   RELKIND_SEQUENCE,
6198                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6199                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6200                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6201         }
6202         else if (fout->remoteVersion >= 90300)
6203         {
6204                 /*
6205                  * Left join to pick up dependency info linking sequences to their
6206                  * owning column, if any (note this dependency is AUTO as of 8.2)
6207                  */
6208                 appendPQExpBuffer(query,
6209                                                   "SELECT c.tableoid, c.oid, c.relname, "
6210                                                   "c.relacl, NULL as rrelacl, "
6211                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6212                                                   "c.relkind, "
6213                                                   "c.relnamespace, "
6214                                                   "(%s c.relowner) AS rolname, "
6215                                                   "c.relchecks, c.relhastriggers, "
6216                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6217                                                   "'f'::bool AS relrowsecurity, "
6218                                                   "'f'::bool AS relforcerowsecurity, "
6219                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6220                                                   "tc.relfrozenxid AS tfrozenxid, "
6221                                                   "tc.relminmxid AS tminmxid, "
6222                                                   "c.relpersistence, c.relispopulated, "
6223                                                   "'d' AS relreplident, c.relpages, "
6224                                                   "NULL AS amname, "
6225                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6226                                                   "d.refobjid AS owning_tab, "
6227                                                   "d.refobjsubid AS owning_col, "
6228                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6229                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6230                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6231                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6232                                                   "tc.reloptions AS toast_reloptions, "
6233                                                   "NULL AS changed_acl, "
6234                                                   "NULL AS partkeydef, "
6235                                                   "false AS ispartition, "
6236                                                   "NULL AS partbound "
6237                                                   "FROM pg_class c "
6238                                                   "LEFT JOIN pg_depend d ON "
6239                                                   "(c.relkind = '%c' AND "
6240                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6241                                                   "d.objsubid = 0 AND "
6242                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6243                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6244                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6245                                                   "ORDER BY c.oid",
6246                                                   username_subquery,
6247                                                   RELKIND_SEQUENCE,
6248                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6249                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6250                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6251         }
6252         else if (fout->remoteVersion >= 90100)
6253         {
6254                 /*
6255                  * Left join to pick up dependency info linking sequences to their
6256                  * owning column, if any (note this dependency is AUTO as of 8.2)
6257                  */
6258                 appendPQExpBuffer(query,
6259                                                   "SELECT c.tableoid, c.oid, c.relname, "
6260                                                   "c.relacl, NULL as rrelacl, "
6261                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6262                                                   "c.relkind, "
6263                                                   "c.relnamespace, "
6264                                                   "(%s c.relowner) AS rolname, "
6265                                                   "c.relchecks, c.relhastriggers, "
6266                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6267                                                   "'f'::bool AS relrowsecurity, "
6268                                                   "'f'::bool AS relforcerowsecurity, "
6269                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6270                                                   "tc.relfrozenxid AS tfrozenxid, "
6271                                                   "0 AS tminmxid, "
6272                                                   "c.relpersistence, 't' as relispopulated, "
6273                                                   "'d' AS relreplident, c.relpages, "
6274                                                   "NULL AS amname, "
6275                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6276                                                   "d.refobjid AS owning_tab, "
6277                                                   "d.refobjsubid AS owning_col, "
6278                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6279                                                   "c.reloptions AS reloptions, "
6280                                                   "tc.reloptions AS toast_reloptions, "
6281                                                   "NULL AS changed_acl, "
6282                                                   "NULL AS partkeydef, "
6283                                                   "false AS ispartition, "
6284                                                   "NULL AS partbound "
6285                                                   "FROM pg_class c "
6286                                                   "LEFT JOIN pg_depend d ON "
6287                                                   "(c.relkind = '%c' AND "
6288                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6289                                                   "d.objsubid = 0 AND "
6290                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6291                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6292                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6293                                                   "ORDER BY c.oid",
6294                                                   username_subquery,
6295                                                   RELKIND_SEQUENCE,
6296                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6297                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6298                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6299         }
6300         else if (fout->remoteVersion >= 90000)
6301         {
6302                 /*
6303                  * Left join to pick up dependency info linking sequences to their
6304                  * owning column, if any (note this dependency is AUTO as of 8.2)
6305                  */
6306                 appendPQExpBuffer(query,
6307                                                   "SELECT c.tableoid, c.oid, c.relname, "
6308                                                   "c.relacl, NULL as rrelacl, "
6309                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6310                                                   "c.relkind, "
6311                                                   "c.relnamespace, "
6312                                                   "(%s c.relowner) AS rolname, "
6313                                                   "c.relchecks, c.relhastriggers, "
6314                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6315                                                   "'f'::bool AS relrowsecurity, "
6316                                                   "'f'::bool AS relforcerowsecurity, "
6317                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6318                                                   "tc.relfrozenxid AS tfrozenxid, "
6319                                                   "0 AS tminmxid, "
6320                                                   "'p' AS relpersistence, 't' as relispopulated, "
6321                                                   "'d' AS relreplident, c.relpages, "
6322                                                   "NULL AS amname, "
6323                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6324                                                   "d.refobjid AS owning_tab, "
6325                                                   "d.refobjsubid AS owning_col, "
6326                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6327                                                   "c.reloptions AS reloptions, "
6328                                                   "tc.reloptions AS toast_reloptions, "
6329                                                   "NULL AS changed_acl, "
6330                                                   "NULL AS partkeydef, "
6331                                                   "false AS ispartition, "
6332                                                   "NULL AS partbound "
6333                                                   "FROM pg_class c "
6334                                                   "LEFT JOIN pg_depend d ON "
6335                                                   "(c.relkind = '%c' AND "
6336                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6337                                                   "d.objsubid = 0 AND "
6338                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6339                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6340                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6341                                                   "ORDER BY c.oid",
6342                                                   username_subquery,
6343                                                   RELKIND_SEQUENCE,
6344                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6345                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6346         }
6347         else if (fout->remoteVersion >= 80400)
6348         {
6349                 /*
6350                  * Left join to pick up dependency info linking sequences to their
6351                  * owning column, if any (note this dependency is AUTO as of 8.2)
6352                  */
6353                 appendPQExpBuffer(query,
6354                                                   "SELECT c.tableoid, c.oid, c.relname, "
6355                                                   "c.relacl, NULL as rrelacl, "
6356                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6357                                                   "c.relkind, "
6358                                                   "c.relnamespace, "
6359                                                   "(%s c.relowner) AS rolname, "
6360                                                   "c.relchecks, c.relhastriggers, "
6361                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6362                                                   "'f'::bool AS relrowsecurity, "
6363                                                   "'f'::bool AS relforcerowsecurity, "
6364                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6365                                                   "tc.relfrozenxid AS tfrozenxid, "
6366                                                   "0 AS tminmxid, "
6367                                                   "'p' AS relpersistence, 't' as relispopulated, "
6368                                                   "'d' AS relreplident, c.relpages, "
6369                                                   "NULL AS amname, "
6370                                                   "NULL AS reloftype, "
6371                                                   "d.refobjid AS owning_tab, "
6372                                                   "d.refobjsubid AS owning_col, "
6373                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6374                                                   "c.reloptions AS reloptions, "
6375                                                   "tc.reloptions AS toast_reloptions, "
6376                                                   "NULL AS changed_acl, "
6377                                                   "NULL AS partkeydef, "
6378                                                   "false AS ispartition, "
6379                                                   "NULL AS partbound "
6380                                                   "FROM pg_class c "
6381                                                   "LEFT JOIN pg_depend d ON "
6382                                                   "(c.relkind = '%c' AND "
6383                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6384                                                   "d.objsubid = 0 AND "
6385                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6386                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6387                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6388                                                   "ORDER BY c.oid",
6389                                                   username_subquery,
6390                                                   RELKIND_SEQUENCE,
6391                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6392                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6393         }
6394         else if (fout->remoteVersion >= 80200)
6395         {
6396                 /*
6397                  * Left join to pick up dependency info linking sequences to their
6398                  * owning column, if any (note this dependency is AUTO as of 8.2)
6399                  */
6400                 appendPQExpBuffer(query,
6401                                                   "SELECT c.tableoid, c.oid, c.relname, "
6402                                                   "c.relacl, NULL as rrelacl, "
6403                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6404                                                   "c.relkind, "
6405                                                   "c.relnamespace, "
6406                                                   "(%s c.relowner) AS rolname, "
6407                                                   "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
6408                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6409                                                   "'f'::bool AS relrowsecurity, "
6410                                                   "'f'::bool AS relforcerowsecurity, "
6411                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6412                                                   "tc.relfrozenxid AS tfrozenxid, "
6413                                                   "0 AS tminmxid, "
6414                                                   "'p' AS relpersistence, 't' as relispopulated, "
6415                                                   "'d' AS relreplident, c.relpages, "
6416                                                   "NULL AS amname, "
6417                                                   "NULL AS reloftype, "
6418                                                   "d.refobjid AS owning_tab, "
6419                                                   "d.refobjsubid AS owning_col, "
6420                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6421                                                   "c.reloptions AS reloptions, "
6422                                                   "NULL AS toast_reloptions, "
6423                                                   "NULL AS changed_acl, "
6424                                                   "NULL AS partkeydef, "
6425                                                   "false AS ispartition, "
6426                                                   "NULL AS partbound "
6427                                                   "FROM pg_class c "
6428                                                   "LEFT JOIN pg_depend d ON "
6429                                                   "(c.relkind = '%c' AND "
6430                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6431                                                   "d.objsubid = 0 AND "
6432                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6433                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6434                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6435                                                   "ORDER BY c.oid",
6436                                                   username_subquery,
6437                                                   RELKIND_SEQUENCE,
6438                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6439                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6440         }
6441         else
6442         {
6443                 /*
6444                  * Left join to pick up dependency info linking sequences to their
6445                  * owning column, if any
6446                  */
6447                 appendPQExpBuffer(query,
6448                                                   "SELECT c.tableoid, c.oid, relname, "
6449                                                   "relacl, NULL as rrelacl, "
6450                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6451                                                   "relkind, relnamespace, "
6452                                                   "(%s relowner) AS rolname, "
6453                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
6454                                                   "relhasindex, relhasrules, relhasoids, "
6455                                                   "'f'::bool AS relrowsecurity, "
6456                                                   "'f'::bool AS relforcerowsecurity, "
6457                                                   "0 AS relfrozenxid, 0 AS relminmxid,"
6458                                                   "0 AS toid, "
6459                                                   "0 AS tfrozenxid, 0 AS tminmxid,"
6460                                                   "'p' AS relpersistence, 't' as relispopulated, "
6461                                                   "'d' AS relreplident, relpages, "
6462                                                   "NULL AS amname, "
6463                                                   "NULL AS reloftype, "
6464                                                   "d.refobjid AS owning_tab, "
6465                                                   "d.refobjsubid AS owning_col, "
6466                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6467                                                   "NULL AS reloptions, "
6468                                                   "NULL AS toast_reloptions, "
6469                                                   "NULL AS changed_acl, "
6470                                                   "NULL AS partkeydef, "
6471                                                   "false AS ispartition, "
6472                                                   "NULL AS partbound "
6473                                                   "FROM pg_class c "
6474                                                   "LEFT JOIN pg_depend d ON "
6475                                                   "(c.relkind = '%c' AND "
6476                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6477                                                   "d.objsubid = 0 AND "
6478                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
6479                                                   "WHERE relkind in ('%c', '%c', '%c', '%c') "
6480                                                   "ORDER BY c.oid",
6481                                                   username_subquery,
6482                                                   RELKIND_SEQUENCE,
6483                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6484                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6485         }
6486
6487         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6488
6489         ntups = PQntuples(res);
6490
6491         *numTables = ntups;
6492
6493         /*
6494          * Extract data from result and lock dumpable tables.  We do the locking
6495          * before anything else, to minimize the window wherein a table could
6496          * disappear under us.
6497          *
6498          * Note that we have to save info about all tables here, even when dumping
6499          * only one, because we don't yet know which tables might be inheritance
6500          * ancestors of the target table.
6501          */
6502         tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
6503
6504         i_reltableoid = PQfnumber(res, "tableoid");
6505         i_reloid = PQfnumber(res, "oid");
6506         i_relname = PQfnumber(res, "relname");
6507         i_relnamespace = PQfnumber(res, "relnamespace");
6508         i_relacl = PQfnumber(res, "relacl");
6509         i_rrelacl = PQfnumber(res, "rrelacl");
6510         i_initrelacl = PQfnumber(res, "initrelacl");
6511         i_initrrelacl = PQfnumber(res, "initrrelacl");
6512         i_relkind = PQfnumber(res, "relkind");
6513         i_rolname = PQfnumber(res, "rolname");
6514         i_relchecks = PQfnumber(res, "relchecks");
6515         i_relhastriggers = PQfnumber(res, "relhastriggers");
6516         i_relhasindex = PQfnumber(res, "relhasindex");
6517         i_relhasrules = PQfnumber(res, "relhasrules");
6518         i_relrowsec = PQfnumber(res, "relrowsecurity");
6519         i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
6520         i_relhasoids = PQfnumber(res, "relhasoids");
6521         i_relfrozenxid = PQfnumber(res, "relfrozenxid");
6522         i_relminmxid = PQfnumber(res, "relminmxid");
6523         i_toastoid = PQfnumber(res, "toid");
6524         i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
6525         i_toastminmxid = PQfnumber(res, "tminmxid");
6526         i_relpersistence = PQfnumber(res, "relpersistence");
6527         i_relispopulated = PQfnumber(res, "relispopulated");
6528         i_relreplident = PQfnumber(res, "relreplident");
6529         i_relpages = PQfnumber(res, "relpages");
6530         i_owning_tab = PQfnumber(res, "owning_tab");
6531         i_owning_col = PQfnumber(res, "owning_col");
6532         i_reltablespace = PQfnumber(res, "reltablespace");
6533         i_reloptions = PQfnumber(res, "reloptions");
6534         i_checkoption = PQfnumber(res, "checkoption");
6535         i_toastreloptions = PQfnumber(res, "toast_reloptions");
6536         i_reloftype = PQfnumber(res, "reloftype");
6537         i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
6538         i_changed_acl = PQfnumber(res, "changed_acl");
6539         i_partkeydef = PQfnumber(res, "partkeydef");
6540         i_ispartition = PQfnumber(res, "ispartition");
6541         i_partbound = PQfnumber(res, "partbound");
6542         i_amname = PQfnumber(res, "amname");
6543
6544         if (dopt->lockWaitTimeout)
6545         {
6546                 /*
6547                  * Arrange to fail instead of waiting forever for a table lock.
6548                  *
6549                  * NB: this coding assumes that the only queries issued within the
6550                  * following loop are LOCK TABLEs; else the timeout may be undesirably
6551                  * applied to other things too.
6552                  */
6553                 resetPQExpBuffer(query);
6554                 appendPQExpBufferStr(query, "SET statement_timeout = ");
6555                 appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
6556                 ExecuteSqlStatement(fout, query->data);
6557         }
6558
6559         for (i = 0; i < ntups; i++)
6560         {
6561                 tblinfo[i].dobj.objType = DO_TABLE;
6562                 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
6563                 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
6564                 AssignDumpId(&tblinfo[i].dobj);
6565                 tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
6566                 tblinfo[i].dobj.namespace =
6567                         findNamespace(fout,
6568                                                   atooid(PQgetvalue(res, i, i_relnamespace)));
6569                 tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6570                 tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
6571                 tblinfo[i].rrelacl = pg_strdup(PQgetvalue(res, i, i_rrelacl));
6572                 tblinfo[i].initrelacl = pg_strdup(PQgetvalue(res, i, i_initrelacl));
6573                 tblinfo[i].initrrelacl = pg_strdup(PQgetvalue(res, i, i_initrrelacl));
6574                 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
6575                 tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
6576                 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
6577                 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
6578                 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
6579                 tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
6580                 tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
6581                 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
6582                 tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
6583                 tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
6584                 tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
6585                 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
6586                 tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
6587                 tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
6588                 tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
6589                 tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
6590                 if (PQgetisnull(res, i, i_reloftype))
6591                         tblinfo[i].reloftype = NULL;
6592                 else
6593                         tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
6594                 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
6595                 if (PQgetisnull(res, i, i_owning_tab))
6596                 {
6597                         tblinfo[i].owning_tab = InvalidOid;
6598                         tblinfo[i].owning_col = 0;
6599                 }
6600                 else
6601                 {
6602                         tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
6603                         tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
6604                 }
6605                 tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
6606                 tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
6607                 if (i_checkoption == -1 || PQgetisnull(res, i, i_checkoption))
6608                         tblinfo[i].checkoption = NULL;
6609                 else
6610                         tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
6611                 tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
6612                 if (PQgetisnull(res, i, i_amname))
6613                         tblinfo[i].amname = NULL;
6614                 else
6615                         tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
6616
6617                 /* other fields were zeroed above */
6618
6619                 /*
6620                  * Decide whether we want to dump this table.
6621                  */
6622                 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
6623                         tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
6624                 else
6625                         selectDumpableTable(&tblinfo[i], fout);
6626
6627                 /*
6628                  * If the table-level and all column-level ACLs for this table are
6629                  * unchanged, then we don't need to worry about including the ACLs for
6630                  * this table.  If any column-level ACLs have been changed, the
6631                  * 'changed_acl' column from the query will indicate that.
6632                  *
6633                  * This can result in a significant performance improvement in cases
6634                  * where we are only looking to dump out the ACL (eg: pg_catalog).
6635                  */
6636                 if (PQgetisnull(res, i, i_relacl) && PQgetisnull(res, i, i_rrelacl) &&
6637                         PQgetisnull(res, i, i_initrelacl) &&
6638                         PQgetisnull(res, i, i_initrrelacl) &&
6639                         strcmp(PQgetvalue(res, i, i_changed_acl), "f") == 0)
6640                         tblinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
6641
6642                 tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
6643                 tblinfo[i].dummy_view = false;  /* might get set during sort */
6644                 tblinfo[i].postponed_def = false;       /* might get set during sort */
6645
6646                 tblinfo[i].is_identity_sequence = (i_is_identity_sequence >= 0 &&
6647                                                                                    strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
6648
6649                 /* Partition key string or NULL */
6650                 tblinfo[i].partkeydef = pg_strdup(PQgetvalue(res, i, i_partkeydef));
6651                 tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
6652                 tblinfo[i].partbound = pg_strdup(PQgetvalue(res, i, i_partbound));
6653
6654                 /*
6655                  * Read-lock target tables to make sure they aren't DROPPED or altered
6656                  * in schema before we get around to dumping them.
6657                  *
6658                  * Note that we don't explicitly lock parents of the target tables; we
6659                  * assume our lock on the child is enough to prevent schema
6660                  * alterations to parent tables.
6661                  *
6662                  * NOTE: it'd be kinda nice to lock other relations too, not only
6663                  * plain or partitioned tables, but the backend doesn't presently
6664                  * allow that.
6665                  *
6666                  * We only need to lock the table for certain components; see
6667                  * pg_dump.h
6668                  */
6669                 if (tblinfo[i].dobj.dump &&
6670                         (tblinfo[i].relkind == RELKIND_RELATION ||
6671                          tblinfo->relkind == RELKIND_PARTITIONED_TABLE) &&
6672                         (tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK))
6673                 {
6674                         resetPQExpBuffer(query);
6675                         appendPQExpBuffer(query,
6676                                                           "LOCK TABLE %s IN ACCESS SHARE MODE",
6677                                                           fmtQualifiedDumpable(&tblinfo[i]));
6678                         ExecuteSqlStatement(fout, query->data);
6679                 }
6680
6681                 /* Emit notice if join for owner failed */
6682                 if (strlen(tblinfo[i].rolname) == 0)
6683                         pg_log_warning("owner of table \"%s\" appears to be invalid",
6684                                                    tblinfo[i].dobj.name);
6685         }
6686
6687         if (dopt->lockWaitTimeout)
6688         {
6689                 ExecuteSqlStatement(fout, "SET statement_timeout = 0");
6690         }
6691
6692         PQclear(res);
6693
6694         destroyPQExpBuffer(query);
6695
6696         return tblinfo;
6697 }
6698
6699 /*
6700  * getOwnedSeqs
6701  *        identify owned sequences and mark them as dumpable if owning table is
6702  *
6703  * We used to do this in getTables(), but it's better to do it after the
6704  * index used by findTableByOid() has been set up.
6705  */
6706 void
6707 getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
6708 {
6709         int                     i;
6710
6711         /*
6712          * Force sequences that are "owned" by table columns to be dumped whenever
6713          * their owning table is being dumped.
6714          */
6715         for (i = 0; i < numTables; i++)
6716         {
6717                 TableInfo  *seqinfo = &tblinfo[i];
6718                 TableInfo  *owning_tab;
6719
6720                 if (!OidIsValid(seqinfo->owning_tab))
6721                         continue;                       /* not an owned sequence */
6722
6723                 owning_tab = findTableByOid(seqinfo->owning_tab);
6724                 if (owning_tab == NULL)
6725                         fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
6726                                   seqinfo->owning_tab, seqinfo->dobj.catId.oid);
6727
6728                 /*
6729                  * Only dump identity sequences if we're going to dump the table that
6730                  * it belongs to.
6731                  */
6732                 if (owning_tab->dobj.dump == DUMP_COMPONENT_NONE &&
6733                         seqinfo->is_identity_sequence)
6734                 {
6735                         seqinfo->dobj.dump = DUMP_COMPONENT_NONE;
6736                         continue;
6737                 }
6738
6739                 /*
6740                  * Otherwise we need to dump the components that are being dumped for
6741                  * the table and any components which the sequence is explicitly
6742                  * marked with.
6743                  *
6744                  * We can't simply use the set of components which are being dumped
6745                  * for the table as the table might be in an extension (and only the
6746                  * non-extension components, eg: ACLs if changed, security labels, and
6747                  * policies, are being dumped) while the sequence is not (and
6748                  * therefore the definition and other components should also be
6749                  * dumped).
6750                  *
6751                  * If the sequence is part of the extension then it should be properly
6752                  * marked by checkExtensionMembership() and this will be a no-op as
6753                  * the table will be equivalently marked.
6754                  */
6755                 seqinfo->dobj.dump = seqinfo->dobj.dump | owning_tab->dobj.dump;
6756
6757                 if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
6758                         seqinfo->interesting = true;
6759         }
6760 }
6761
6762 /*
6763  * getInherits
6764  *        read all the inheritance information
6765  * from the system catalogs return them in the InhInfo* structure
6766  *
6767  * numInherits is set to the number of pairs read in
6768  */
6769 InhInfo *
6770 getInherits(Archive *fout, int *numInherits)
6771 {
6772         PGresult   *res;
6773         int                     ntups;
6774         int                     i;
6775         PQExpBuffer query = createPQExpBuffer();
6776         InhInfo    *inhinfo;
6777
6778         int                     i_inhrelid;
6779         int                     i_inhparent;
6780
6781         /*
6782          * Find all the inheritance information, excluding implicit inheritance
6783          * via partitioning.
6784          */
6785         appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
6786
6787         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6788
6789         ntups = PQntuples(res);
6790
6791         *numInherits = ntups;
6792
6793         inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
6794
6795         i_inhrelid = PQfnumber(res, "inhrelid");
6796         i_inhparent = PQfnumber(res, "inhparent");
6797
6798         for (i = 0; i < ntups; i++)
6799         {
6800                 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
6801                 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
6802         }
6803
6804         PQclear(res);
6805
6806         destroyPQExpBuffer(query);
6807
6808         return inhinfo;
6809 }
6810
6811 /*
6812  * getIndexes
6813  *        get information about every index on a dumpable table
6814  *
6815  * Note: index data is not returned directly to the caller, but it
6816  * does get entered into the DumpableObject tables.
6817  */
6818 void
6819 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
6820 {
6821         int                     i,
6822                                 j;
6823         PQExpBuffer query = createPQExpBuffer();
6824         PGresult   *res;
6825         IndxInfo   *indxinfo;
6826         ConstraintInfo *constrinfo;
6827         int                     i_tableoid,
6828                                 i_oid,
6829                                 i_indexname,
6830                                 i_parentidx,
6831                                 i_indexdef,
6832                                 i_indnkeyatts,
6833                                 i_indnatts,
6834                                 i_indkey,
6835                                 i_indisclustered,
6836                                 i_indisreplident,
6837                                 i_contype,
6838                                 i_conname,
6839                                 i_condeferrable,
6840                                 i_condeferred,
6841                                 i_contableoid,
6842                                 i_conoid,
6843                                 i_condef,
6844                                 i_tablespace,
6845                                 i_indreloptions,
6846                                 i_indstatcols,
6847                                 i_indstatvals;
6848         int                     ntups;
6849
6850         for (i = 0; i < numTables; i++)
6851         {
6852                 TableInfo  *tbinfo = &tblinfo[i];
6853
6854                 if (!tbinfo->hasindex)
6855                         continue;
6856
6857                 /*
6858                  * Ignore indexes of tables whose definitions are not to be dumped.
6859                  *
6860                  * We also need indexes on partitioned tables which have partitions to
6861                  * be dumped, in order to dump the indexes on the partitions.
6862                  */
6863                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION) &&
6864                         !tbinfo->interesting)
6865                         continue;
6866
6867                 pg_log_info("reading indexes for table \"%s.%s\"",
6868                                         tbinfo->dobj.namespace->dobj.name,
6869                                         tbinfo->dobj.name);
6870
6871                 /*
6872                  * The point of the messy-looking outer join is to find a constraint
6873                  * that is related by an internal dependency link to the index. If we
6874                  * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
6875                  * assume an index won't have more than one internal dependency.
6876                  *
6877                  * As of 9.0 we don't need to look at pg_depend but can check for a
6878                  * match to pg_constraint.conindid.  The check on conrelid is
6879                  * redundant but useful because that column is indexed while conindid
6880                  * is not.
6881                  */
6882                 resetPQExpBuffer(query);
6883                 if (fout->remoteVersion >= 110000)
6884                 {
6885                         appendPQExpBuffer(query,
6886                                                           "SELECT t.tableoid, t.oid, "
6887                                                           "t.relname AS indexname, "
6888                                                           "inh.inhparent AS parentidx, "
6889                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6890                                                           "i.indnkeyatts AS indnkeyatts, "
6891                                                           "i.indnatts AS indnatts, "
6892                                                           "i.indkey, i.indisclustered, "
6893                                                           "i.indisreplident, "
6894                                                           "c.contype, c.conname, "
6895                                                           "c.condeferrable, c.condeferred, "
6896                                                           "c.tableoid AS contableoid, "
6897                                                           "c.oid AS conoid, "
6898                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6899                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6900                                                           "t.reloptions AS indreloptions, "
6901                                                           "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
6902                                                           "  FROM pg_catalog.pg_attribute "
6903                                                           "  WHERE attrelid = i.indexrelid AND "
6904                                                           "    attstattarget >= 0) AS indstatcols,"
6905                                                           "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
6906                                                           "  FROM pg_catalog.pg_attribute "
6907                                                           "  WHERE attrelid = i.indexrelid AND "
6908                                                           "    attstattarget >= 0) AS indstatvals "
6909                                                           "FROM pg_catalog.pg_index i "
6910                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6911                                                           "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
6912                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6913                                                           "ON (i.indrelid = c.conrelid AND "
6914                                                           "i.indexrelid = c.conindid AND "
6915                                                           "c.contype IN ('p','u','x')) "
6916                                                           "LEFT JOIN pg_catalog.pg_inherits inh "
6917                                                           "ON (inh.inhrelid = indexrelid) "
6918                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6919                                                           "AND (i.indisvalid OR t2.relkind = 'p') "
6920                                                           "AND i.indisready "
6921                                                           "ORDER BY indexname",
6922                                                           tbinfo->dobj.catId.oid);
6923                 }
6924                 else if (fout->remoteVersion >= 90400)
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                                                           "i.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 >= 90000)
6960                 {
6961                         /*
6962                          * the test on indisready is necessary in 9.2, and harmless in
6963                          * earlier/later versions
6964                          */
6965                         appendPQExpBuffer(query,
6966                                                           "SELECT t.tableoid, t.oid, "
6967                                                           "t.relname AS indexname, "
6968                                                           "0 AS parentidx, "
6969                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6970                                                           "i.indnatts AS indnkeyatts, "
6971                                                           "i.indnatts AS indnatts, "
6972                                                           "i.indkey, i.indisclustered, "
6973                                                           "false AS indisreplident, "
6974                                                           "c.contype, c.conname, "
6975                                                           "c.condeferrable, c.condeferred, "
6976                                                           "c.tableoid AS contableoid, "
6977                                                           "c.oid AS conoid, "
6978                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6979                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6980                                                           "t.reloptions AS indreloptions, "
6981                                                           "'' AS indstatcols, "
6982                                                           "'' AS indstatvals "
6983                                                           "FROM pg_catalog.pg_index i "
6984                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6985                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6986                                                           "ON (i.indrelid = c.conrelid AND "
6987                                                           "i.indexrelid = c.conindid AND "
6988                                                           "c.contype IN ('p','u','x')) "
6989                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6990                                                           "AND i.indisvalid AND i.indisready "
6991                                                           "ORDER BY indexname",
6992                                                           tbinfo->dobj.catId.oid);
6993                 }
6994                 else if (fout->remoteVersion >= 80200)
6995                 {
6996                         appendPQExpBuffer(query,
6997                                                           "SELECT t.tableoid, t.oid, "
6998                                                           "t.relname AS indexname, "
6999                                                           "0 AS parentidx, "
7000                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
7001                                                           "i.indnatts AS indnkeyatts, "
7002                                                           "i.indnatts AS indnatts, "
7003                                                           "i.indkey, i.indisclustered, "
7004                                                           "false AS indisreplident, "
7005                                                           "c.contype, c.conname, "
7006                                                           "c.condeferrable, c.condeferred, "
7007                                                           "c.tableoid AS contableoid, "
7008                                                           "c.oid AS conoid, "
7009                                                           "null AS condef, "
7010                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
7011                                                           "t.reloptions AS indreloptions, "
7012                                                           "'' AS indstatcols, "
7013                                                           "'' AS indstatvals "
7014                                                           "FROM pg_catalog.pg_index i "
7015                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
7016                                                           "LEFT JOIN pg_catalog.pg_depend d "
7017                                                           "ON (d.classid = t.tableoid "
7018                                                           "AND d.objid = t.oid "
7019                                                           "AND d.deptype = 'i') "
7020                                                           "LEFT JOIN pg_catalog.pg_constraint c "
7021                                                           "ON (d.refclassid = c.tableoid "
7022                                                           "AND d.refobjid = c.oid) "
7023                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
7024                                                           "AND i.indisvalid "
7025                                                           "ORDER BY indexname",
7026                                                           tbinfo->dobj.catId.oid);
7027                 }
7028                 else
7029                 {
7030                         appendPQExpBuffer(query,
7031                                                           "SELECT t.tableoid, t.oid, "
7032                                                           "t.relname AS indexname, "
7033                                                           "0 AS parentidx, "
7034                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
7035                                                           "t.relnatts AS indnkeyatts, "
7036                                                           "t.relnatts AS indnatts, "
7037                                                           "i.indkey, i.indisclustered, "
7038                                                           "false AS indisreplident, "
7039                                                           "c.contype, c.conname, "
7040                                                           "c.condeferrable, c.condeferred, "
7041                                                           "c.tableoid AS contableoid, "
7042                                                           "c.oid AS conoid, "
7043                                                           "null AS condef, "
7044                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
7045                                                           "null AS indreloptions, "
7046                                                           "'' AS indstatcols, "
7047                                                           "'' AS indstatvals "
7048                                                           "FROM pg_catalog.pg_index i "
7049                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
7050                                                           "LEFT JOIN pg_catalog.pg_depend d "
7051                                                           "ON (d.classid = t.tableoid "
7052                                                           "AND d.objid = t.oid "
7053                                                           "AND d.deptype = 'i') "
7054                                                           "LEFT JOIN pg_catalog.pg_constraint c "
7055                                                           "ON (d.refclassid = c.tableoid "
7056                                                           "AND d.refobjid = c.oid) "
7057                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
7058                                                           "ORDER BY indexname",
7059                                                           tbinfo->dobj.catId.oid);
7060                 }
7061
7062                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7063
7064                 ntups = PQntuples(res);
7065
7066                 i_tableoid = PQfnumber(res, "tableoid");
7067                 i_oid = PQfnumber(res, "oid");
7068                 i_indexname = PQfnumber(res, "indexname");
7069                 i_parentidx = PQfnumber(res, "parentidx");
7070                 i_indexdef = PQfnumber(res, "indexdef");
7071                 i_indnkeyatts = PQfnumber(res, "indnkeyatts");
7072                 i_indnatts = PQfnumber(res, "indnatts");
7073                 i_indkey = PQfnumber(res, "indkey");
7074                 i_indisclustered = PQfnumber(res, "indisclustered");
7075                 i_indisreplident = PQfnumber(res, "indisreplident");
7076                 i_contype = PQfnumber(res, "contype");
7077                 i_conname = PQfnumber(res, "conname");
7078                 i_condeferrable = PQfnumber(res, "condeferrable");
7079                 i_condeferred = PQfnumber(res, "condeferred");
7080                 i_contableoid = PQfnumber(res, "contableoid");
7081                 i_conoid = PQfnumber(res, "conoid");
7082                 i_condef = PQfnumber(res, "condef");
7083                 i_tablespace = PQfnumber(res, "tablespace");
7084                 i_indreloptions = PQfnumber(res, "indreloptions");
7085                 i_indstatcols = PQfnumber(res, "indstatcols");
7086                 i_indstatvals = PQfnumber(res, "indstatvals");
7087
7088                 tbinfo->indexes = indxinfo =
7089                         (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
7090                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7091                 tbinfo->numIndexes = ntups;
7092
7093                 for (j = 0; j < ntups; j++)
7094                 {
7095                         char            contype;
7096
7097                         indxinfo[j].dobj.objType = DO_INDEX;
7098                         indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
7099                         indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7100                         AssignDumpId(&indxinfo[j].dobj);
7101                         indxinfo[j].dobj.dump = tbinfo->dobj.dump;
7102                         indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
7103                         indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7104                         indxinfo[j].indextable = tbinfo;
7105                         indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
7106                         indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
7107                         indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
7108                         indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
7109                         indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
7110                         indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
7111                         indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
7112                         indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
7113                         parseOidArray(PQgetvalue(res, j, i_indkey),
7114                                                   indxinfo[j].indkeys, indxinfo[j].indnattrs);
7115                         indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
7116                         indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
7117                         indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
7118                         contype = *(PQgetvalue(res, j, i_contype));
7119
7120                         if (contype == 'p' || contype == 'u' || contype == 'x')
7121                         {
7122                                 /*
7123                                  * If we found a constraint matching the index, create an
7124                                  * entry for it.
7125                                  */
7126                                 constrinfo[j].dobj.objType = DO_CONSTRAINT;
7127                                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7128                                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7129                                 AssignDumpId(&constrinfo[j].dobj);
7130                                 constrinfo[j].dobj.dump = tbinfo->dobj.dump;
7131                                 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7132                                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7133                                 constrinfo[j].contable = tbinfo;
7134                                 constrinfo[j].condomain = NULL;
7135                                 constrinfo[j].contype = contype;
7136                                 if (contype == 'x')
7137                                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
7138                                 else
7139                                         constrinfo[j].condef = NULL;
7140                                 constrinfo[j].confrelid = InvalidOid;
7141                                 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
7142                                 constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
7143                                 constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
7144                                 constrinfo[j].conislocal = true;
7145                                 constrinfo[j].separate = true;
7146
7147                                 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
7148                         }
7149                         else
7150                         {
7151                                 /* Plain secondary index */
7152                                 indxinfo[j].indexconstraint = 0;
7153                         }
7154                 }
7155
7156                 PQclear(res);
7157         }
7158
7159         destroyPQExpBuffer(query);
7160 }
7161
7162 /*
7163  * getExtendedStatistics
7164  *        get information about extended-statistics objects.
7165  *
7166  * Note: extended statistics data is not returned directly to the caller, but
7167  * it does get entered into the DumpableObject tables.
7168  */
7169 void
7170 getExtendedStatistics(Archive *fout)
7171 {
7172         PQExpBuffer query;
7173         PGresult   *res;
7174         StatsExtInfo *statsextinfo;
7175         int                     ntups;
7176         int                     i_tableoid;
7177         int                     i_oid;
7178         int                     i_stxname;
7179         int                     i_stxnamespace;
7180         int                     i_rolname;
7181         int                     i;
7182
7183         /* Extended statistics were new in v10 */
7184         if (fout->remoteVersion < 100000)
7185                 return;
7186
7187         query = createPQExpBuffer();
7188
7189         appendPQExpBuffer(query, "SELECT tableoid, oid, stxname, "
7190                                           "stxnamespace, (%s stxowner) AS rolname "
7191                                           "FROM pg_catalog.pg_statistic_ext",
7192                                           username_subquery);
7193
7194         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7195
7196         ntups = PQntuples(res);
7197
7198         i_tableoid = PQfnumber(res, "tableoid");
7199         i_oid = PQfnumber(res, "oid");
7200         i_stxname = PQfnumber(res, "stxname");
7201         i_stxnamespace = PQfnumber(res, "stxnamespace");
7202         i_rolname = PQfnumber(res, "rolname");
7203
7204         statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
7205
7206         for (i = 0; i < ntups; i++)
7207         {
7208                 statsextinfo[i].dobj.objType = DO_STATSEXT;
7209                 statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7210                 statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7211                 AssignDumpId(&statsextinfo[i].dobj);
7212                 statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
7213                 statsextinfo[i].dobj.namespace =
7214                         findNamespace(fout,
7215                                                   atooid(PQgetvalue(res, i, i_stxnamespace)));
7216                 statsextinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7217
7218                 /* Decide whether we want to dump it */
7219                 selectDumpableObject(&(statsextinfo[i].dobj), fout);
7220
7221                 /* Stats objects do not currently have ACLs. */
7222                 statsextinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7223         }
7224
7225         PQclear(res);
7226         destroyPQExpBuffer(query);
7227 }
7228
7229 /*
7230  * getConstraints
7231  *
7232  * Get info about constraints on dumpable tables.
7233  *
7234  * Currently handles foreign keys only.
7235  * Unique and primary key constraints are handled with indexes,
7236  * while check constraints are processed in getTableAttrs().
7237  */
7238 void
7239 getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
7240 {
7241         int                     i,
7242                                 j;
7243         ConstraintInfo *constrinfo;
7244         PQExpBuffer query;
7245         PGresult   *res;
7246         int                     i_contableoid,
7247                                 i_conoid,
7248                                 i_conname,
7249                                 i_confrelid,
7250                                 i_condef;
7251         int                     ntups;
7252
7253         query = createPQExpBuffer();
7254
7255         for (i = 0; i < numTables; i++)
7256         {
7257                 TableInfo  *tbinfo = &tblinfo[i];
7258
7259                 /*
7260                  * For partitioned tables, foreign keys have no triggers so they must
7261                  * be included anyway in case some foreign keys are defined.
7262                  */
7263                 if ((!tbinfo->hastriggers &&
7264                          tbinfo->relkind != RELKIND_PARTITIONED_TABLE) ||
7265                         !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7266                         continue;
7267
7268                 pg_log_info("reading foreign key constraints for table \"%s.%s\"",
7269                                         tbinfo->dobj.namespace->dobj.name,
7270                                         tbinfo->dobj.name);
7271
7272                 resetPQExpBuffer(query);
7273                 if (fout->remoteVersion >= 110000)
7274                         appendPQExpBuffer(query,
7275                                                           "SELECT tableoid, oid, conname, confrelid, "
7276                                                           "pg_catalog.pg_get_constraintdef(oid) AS condef "
7277                                                           "FROM pg_catalog.pg_constraint "
7278                                                           "WHERE conrelid = '%u'::pg_catalog.oid "
7279                                                           "AND conparentid = 0 "
7280                                                           "AND contype = 'f'",
7281                                                           tbinfo->dobj.catId.oid);
7282                 else
7283                         appendPQExpBuffer(query,
7284                                                           "SELECT tableoid, oid, conname, confrelid, "
7285                                                           "pg_catalog.pg_get_constraintdef(oid) AS condef "
7286                                                           "FROM pg_catalog.pg_constraint "
7287                                                           "WHERE conrelid = '%u'::pg_catalog.oid "
7288                                                           "AND contype = 'f'",
7289                                                           tbinfo->dobj.catId.oid);
7290                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7291
7292                 ntups = PQntuples(res);
7293
7294                 i_contableoid = PQfnumber(res, "tableoid");
7295                 i_conoid = PQfnumber(res, "oid");
7296                 i_conname = PQfnumber(res, "conname");
7297                 i_confrelid = PQfnumber(res, "confrelid");
7298                 i_condef = PQfnumber(res, "condef");
7299
7300                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7301
7302                 for (j = 0; j < ntups; j++)
7303                 {
7304                         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
7305                         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7306                         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7307                         AssignDumpId(&constrinfo[j].dobj);
7308                         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7309                         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7310                         constrinfo[j].contable = tbinfo;
7311                         constrinfo[j].condomain = NULL;
7312                         constrinfo[j].contype = 'f';
7313                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
7314                         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
7315                         constrinfo[j].conindex = 0;
7316                         constrinfo[j].condeferrable = false;
7317                         constrinfo[j].condeferred = false;
7318                         constrinfo[j].conislocal = true;
7319                         constrinfo[j].separate = true;
7320                 }
7321
7322                 PQclear(res);
7323         }
7324
7325         destroyPQExpBuffer(query);
7326 }
7327
7328 /*
7329  * getDomainConstraints
7330  *
7331  * Get info about constraints on a domain.
7332  */
7333 static void
7334 getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
7335 {
7336         int                     i;
7337         ConstraintInfo *constrinfo;
7338         PQExpBuffer query;
7339         PGresult   *res;
7340         int                     i_tableoid,
7341                                 i_oid,
7342                                 i_conname,
7343                                 i_consrc;
7344         int                     ntups;
7345
7346         query = createPQExpBuffer();
7347
7348         if (fout->remoteVersion >= 90100)
7349                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
7350                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7351                                                   "convalidated "
7352                                                   "FROM pg_catalog.pg_constraint "
7353                                                   "WHERE contypid = '%u'::pg_catalog.oid "
7354                                                   "ORDER BY conname",
7355                                                   tyinfo->dobj.catId.oid);
7356
7357         else
7358                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
7359                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7360                                                   "true as convalidated "
7361                                                   "FROM pg_catalog.pg_constraint "
7362                                                   "WHERE contypid = '%u'::pg_catalog.oid "
7363                                                   "ORDER BY conname",
7364                                                   tyinfo->dobj.catId.oid);
7365
7366         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7367
7368         ntups = PQntuples(res);
7369
7370         i_tableoid = PQfnumber(res, "tableoid");
7371         i_oid = PQfnumber(res, "oid");
7372         i_conname = PQfnumber(res, "conname");
7373         i_consrc = PQfnumber(res, "consrc");
7374
7375         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7376
7377         tyinfo->nDomChecks = ntups;
7378         tyinfo->domChecks = constrinfo;
7379
7380         for (i = 0; i < ntups; i++)
7381         {
7382                 bool            validated = PQgetvalue(res, i, 4)[0] == 't';
7383
7384                 constrinfo[i].dobj.objType = DO_CONSTRAINT;
7385                 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7386                 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7387                 AssignDumpId(&constrinfo[i].dobj);
7388                 constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
7389                 constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
7390                 constrinfo[i].contable = NULL;
7391                 constrinfo[i].condomain = tyinfo;
7392                 constrinfo[i].contype = 'c';
7393                 constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
7394                 constrinfo[i].confrelid = InvalidOid;
7395                 constrinfo[i].conindex = 0;
7396                 constrinfo[i].condeferrable = false;
7397                 constrinfo[i].condeferred = false;
7398                 constrinfo[i].conislocal = true;
7399
7400                 constrinfo[i].separate = !validated;
7401
7402                 /*
7403                  * Make the domain depend on the constraint, ensuring it won't be
7404                  * output till any constraint dependencies are OK.  If the constraint
7405                  * has not been validated, it's going to be dumped after the domain
7406                  * anyway, so this doesn't matter.
7407                  */
7408                 if (validated)
7409                         addObjectDependency(&tyinfo->dobj,
7410                                                                 constrinfo[i].dobj.dumpId);
7411         }
7412
7413         PQclear(res);
7414
7415         destroyPQExpBuffer(query);
7416 }
7417
7418 /*
7419  * getRules
7420  *        get basic information about every rule in the system
7421  *
7422  * numRules is set to the number of rules read in
7423  */
7424 RuleInfo *
7425 getRules(Archive *fout, int *numRules)
7426 {
7427         PGresult   *res;
7428         int                     ntups;
7429         int                     i;
7430         PQExpBuffer query = createPQExpBuffer();
7431         RuleInfo   *ruleinfo;
7432         int                     i_tableoid;
7433         int                     i_oid;
7434         int                     i_rulename;
7435         int                     i_ruletable;
7436         int                     i_ev_type;
7437         int                     i_is_instead;
7438         int                     i_ev_enabled;
7439
7440         if (fout->remoteVersion >= 80300)
7441         {
7442                 appendPQExpBufferStr(query, "SELECT "
7443                                                          "tableoid, oid, rulename, "
7444                                                          "ev_class AS ruletable, ev_type, is_instead, "
7445                                                          "ev_enabled "
7446                                                          "FROM pg_rewrite "
7447                                                          "ORDER BY oid");
7448         }
7449         else
7450         {
7451                 appendPQExpBufferStr(query, "SELECT "
7452                                                          "tableoid, oid, rulename, "
7453                                                          "ev_class AS ruletable, ev_type, is_instead, "
7454                                                          "'O'::char AS ev_enabled "
7455                                                          "FROM pg_rewrite "
7456                                                          "ORDER BY oid");
7457         }
7458
7459         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7460
7461         ntups = PQntuples(res);
7462
7463         *numRules = ntups;
7464
7465         ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
7466
7467         i_tableoid = PQfnumber(res, "tableoid");
7468         i_oid = PQfnumber(res, "oid");
7469         i_rulename = PQfnumber(res, "rulename");
7470         i_ruletable = PQfnumber(res, "ruletable");
7471         i_ev_type = PQfnumber(res, "ev_type");
7472         i_is_instead = PQfnumber(res, "is_instead");
7473         i_ev_enabled = PQfnumber(res, "ev_enabled");
7474
7475         for (i = 0; i < ntups; i++)
7476         {
7477                 Oid                     ruletableoid;
7478
7479                 ruleinfo[i].dobj.objType = DO_RULE;
7480                 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7481                 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7482                 AssignDumpId(&ruleinfo[i].dobj);
7483                 ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
7484                 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
7485                 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
7486                 if (ruleinfo[i].ruletable == NULL)
7487                         fatal("failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found",
7488                                   ruletableoid, ruleinfo[i].dobj.catId.oid);
7489                 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
7490                 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
7491                 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
7492                 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
7493                 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
7494                 if (ruleinfo[i].ruletable)
7495                 {
7496                         /*
7497                          * If the table is a view or materialized view, force its ON
7498                          * SELECT rule to be sorted before the view itself --- this
7499                          * ensures that any dependencies for the rule affect the table's
7500                          * positioning. Other rules are forced to appear after their
7501                          * table.
7502                          */
7503                         if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
7504                                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
7505                                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
7506                         {
7507                                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
7508                                                                         ruleinfo[i].dobj.dumpId);
7509                                 /* We'll merge the rule into CREATE VIEW, if possible */
7510                                 ruleinfo[i].separate = false;
7511                         }
7512                         else
7513                         {
7514                                 addObjectDependency(&ruleinfo[i].dobj,
7515                                                                         ruleinfo[i].ruletable->dobj.dumpId);
7516                                 ruleinfo[i].separate = true;
7517                         }
7518                 }
7519                 else
7520                         ruleinfo[i].separate = true;
7521         }
7522
7523         PQclear(res);
7524
7525         destroyPQExpBuffer(query);
7526
7527         return ruleinfo;
7528 }
7529
7530 /*
7531  * getTriggers
7532  *        get information about every trigger on a dumpable table
7533  *
7534  * Note: trigger data is not returned directly to the caller, but it
7535  * does get entered into the DumpableObject tables.
7536  */
7537 void
7538 getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
7539 {
7540         int                     i,
7541                                 j;
7542         PQExpBuffer query = createPQExpBuffer();
7543         PGresult   *res;
7544         TriggerInfo *tginfo;
7545         int                     i_tableoid,
7546                                 i_oid,
7547                                 i_tgname,
7548                                 i_tgfname,
7549                                 i_tgtype,
7550                                 i_tgnargs,
7551                                 i_tgargs,
7552                                 i_tgisconstraint,
7553                                 i_tgconstrname,
7554                                 i_tgconstrrelid,
7555                                 i_tgconstrrelname,
7556                                 i_tgenabled,
7557                                 i_tgdeferrable,
7558                                 i_tginitdeferred,
7559                                 i_tgdef;
7560         int                     ntups;
7561
7562         for (i = 0; i < numTables; i++)
7563         {
7564                 TableInfo  *tbinfo = &tblinfo[i];
7565
7566                 if (!tbinfo->hastriggers ||
7567                         !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7568                         continue;
7569
7570                 pg_log_info("reading triggers for table \"%s.%s\"",
7571                                         tbinfo->dobj.namespace->dobj.name,
7572                                         tbinfo->dobj.name);
7573
7574                 resetPQExpBuffer(query);
7575                 if (fout->remoteVersion >= 90000)
7576                 {
7577                         /*
7578                          * NB: think not to use pretty=true in pg_get_triggerdef.  It
7579                          * could result in non-forward-compatible dumps of WHEN clauses
7580                          * due to under-parenthesization.
7581                          */
7582                         appendPQExpBuffer(query,
7583                                                           "SELECT tgname, "
7584                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7585                                                           "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
7586                                                           "tgenabled, tableoid, oid "
7587                                                           "FROM pg_catalog.pg_trigger t "
7588                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7589                                                           "AND NOT tgisinternal",
7590                                                           tbinfo->dobj.catId.oid);
7591                 }
7592                 else if (fout->remoteVersion >= 80300)
7593                 {
7594                         /*
7595                          * We ignore triggers that are tied to a foreign-key constraint
7596                          */
7597                         appendPQExpBuffer(query,
7598                                                           "SELECT tgname, "
7599                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7600                                                           "tgtype, tgnargs, tgargs, tgenabled, "
7601                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
7602                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
7603                                                           "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
7604                                                           "FROM pg_catalog.pg_trigger t "
7605                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7606                                                           "AND tgconstraint = 0",
7607                                                           tbinfo->dobj.catId.oid);
7608                 }
7609                 else
7610                 {
7611                         /*
7612                          * We ignore triggers that are tied to a foreign-key constraint,
7613                          * but in these versions we have to grovel through pg_constraint
7614                          * to find out
7615                          */
7616                         appendPQExpBuffer(query,
7617                                                           "SELECT tgname, "
7618                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7619                                                           "tgtype, tgnargs, tgargs, tgenabled, "
7620                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
7621                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
7622                                                           "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
7623                                                           "FROM pg_catalog.pg_trigger t "
7624                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7625                                                           "AND (NOT tgisconstraint "
7626                                                           " OR NOT EXISTS"
7627                                                           "  (SELECT 1 FROM pg_catalog.pg_depend d "
7628                                                           "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
7629                                                           "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
7630                                                           tbinfo->dobj.catId.oid);
7631                 }
7632
7633                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7634
7635                 ntups = PQntuples(res);
7636
7637                 i_tableoid = PQfnumber(res, "tableoid");
7638                 i_oid = PQfnumber(res, "oid");
7639                 i_tgname = PQfnumber(res, "tgname");
7640                 i_tgfname = PQfnumber(res, "tgfname");
7641                 i_tgtype = PQfnumber(res, "tgtype");
7642                 i_tgnargs = PQfnumber(res, "tgnargs");
7643                 i_tgargs = PQfnumber(res, "tgargs");
7644                 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
7645                 i_tgconstrname = PQfnumber(res, "tgconstrname");
7646                 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
7647                 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
7648                 i_tgenabled = PQfnumber(res, "tgenabled");
7649                 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
7650                 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
7651                 i_tgdef = PQfnumber(res, "tgdef");
7652
7653                 tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
7654
7655                 tbinfo->numTriggers = ntups;
7656                 tbinfo->triggers = tginfo;
7657
7658                 for (j = 0; j < ntups; j++)
7659                 {
7660                         tginfo[j].dobj.objType = DO_TRIGGER;
7661                         tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
7662                         tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7663                         AssignDumpId(&tginfo[j].dobj);
7664                         tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
7665                         tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
7666                         tginfo[j].tgtable = tbinfo;
7667                         tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
7668                         if (i_tgdef >= 0)
7669                         {
7670                                 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
7671
7672                                 /* remaining fields are not valid if we have tgdef */
7673                                 tginfo[j].tgfname = NULL;
7674                                 tginfo[j].tgtype = 0;
7675                                 tginfo[j].tgnargs = 0;
7676                                 tginfo[j].tgargs = NULL;
7677                                 tginfo[j].tgisconstraint = false;
7678                                 tginfo[j].tgdeferrable = false;
7679                                 tginfo[j].tginitdeferred = false;
7680                                 tginfo[j].tgconstrname = NULL;
7681                                 tginfo[j].tgconstrrelid = InvalidOid;
7682                                 tginfo[j].tgconstrrelname = NULL;
7683                         }
7684                         else
7685                         {
7686                                 tginfo[j].tgdef = NULL;
7687
7688                                 tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
7689                                 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
7690                                 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
7691                                 tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
7692                                 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
7693                                 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
7694                                 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
7695
7696                                 if (tginfo[j].tgisconstraint)
7697                                 {
7698                                         tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
7699                                         tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
7700                                         if (OidIsValid(tginfo[j].tgconstrrelid))
7701                                         {
7702                                                 if (PQgetisnull(res, j, i_tgconstrrelname))
7703                                                         fatal("query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)",
7704                                                                   tginfo[j].dobj.name,
7705                                                                   tbinfo->dobj.name,
7706                                                                   tginfo[j].tgconstrrelid);
7707                                                 tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
7708                                         }
7709                                         else
7710                                                 tginfo[j].tgconstrrelname = NULL;
7711                                 }
7712                                 else
7713                                 {
7714                                         tginfo[j].tgconstrname = NULL;
7715                                         tginfo[j].tgconstrrelid = InvalidOid;
7716                                         tginfo[j].tgconstrrelname = NULL;
7717                                 }
7718                         }
7719                 }
7720
7721                 PQclear(res);
7722         }
7723
7724         destroyPQExpBuffer(query);
7725 }
7726
7727 /*
7728  * getEventTriggers
7729  *        get information about event triggers
7730  */
7731 EventTriggerInfo *
7732 getEventTriggers(Archive *fout, int *numEventTriggers)
7733 {
7734         int                     i;
7735         PQExpBuffer query;
7736         PGresult   *res;
7737         EventTriggerInfo *evtinfo;
7738         int                     i_tableoid,
7739                                 i_oid,
7740                                 i_evtname,
7741                                 i_evtevent,
7742                                 i_evtowner,
7743                                 i_evttags,
7744                                 i_evtfname,
7745                                 i_evtenabled;
7746         int                     ntups;
7747
7748         /* Before 9.3, there are no event triggers */
7749         if (fout->remoteVersion < 90300)
7750         {
7751                 *numEventTriggers = 0;
7752                 return NULL;
7753         }
7754
7755         query = createPQExpBuffer();
7756
7757         appendPQExpBuffer(query,
7758                                           "SELECT e.tableoid, e.oid, evtname, evtenabled, "
7759                                           "evtevent, (%s evtowner) AS evtowner, "
7760                                           "array_to_string(array("
7761                                           "select quote_literal(x) "
7762                                           " from unnest(evttags) as t(x)), ', ') as evttags, "
7763                                           "e.evtfoid::regproc as evtfname "
7764                                           "FROM pg_event_trigger e "
7765                                           "ORDER BY e.oid",
7766                                           username_subquery);
7767
7768         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7769
7770         ntups = PQntuples(res);
7771
7772         *numEventTriggers = ntups;
7773
7774         evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
7775
7776         i_tableoid = PQfnumber(res, "tableoid");
7777         i_oid = PQfnumber(res, "oid");
7778         i_evtname = PQfnumber(res, "evtname");
7779         i_evtevent = PQfnumber(res, "evtevent");
7780         i_evtowner = PQfnumber(res, "evtowner");
7781         i_evttags = PQfnumber(res, "evttags");
7782         i_evtfname = PQfnumber(res, "evtfname");
7783         i_evtenabled = PQfnumber(res, "evtenabled");
7784
7785         for (i = 0; i < ntups; i++)
7786         {
7787                 evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
7788                 evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7789                 evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7790                 AssignDumpId(&evtinfo[i].dobj);
7791                 evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
7792                 evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
7793                 evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
7794                 evtinfo[i].evtowner = pg_strdup(PQgetvalue(res, i, i_evtowner));
7795                 evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
7796                 evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
7797                 evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
7798
7799                 /* Decide whether we want to dump it */
7800                 selectDumpableObject(&(evtinfo[i].dobj), fout);
7801
7802                 /* Event Triggers do not currently have ACLs. */
7803                 evtinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7804         }
7805
7806         PQclear(res);
7807
7808         destroyPQExpBuffer(query);
7809
7810         return evtinfo;
7811 }
7812
7813 /*
7814  * getProcLangs
7815  *        get basic information about every procedural language in the system
7816  *
7817  * numProcLangs is set to the number of langs read in
7818  *
7819  * NB: this must run after getFuncs() because we assume we can do
7820  * findFuncByOid().
7821  */
7822 ProcLangInfo *
7823 getProcLangs(Archive *fout, int *numProcLangs)
7824 {
7825         DumpOptions *dopt = fout->dopt;
7826         PGresult   *res;
7827         int                     ntups;
7828         int                     i;
7829         PQExpBuffer query = createPQExpBuffer();
7830         ProcLangInfo *planginfo;
7831         int                     i_tableoid;
7832         int                     i_oid;
7833         int                     i_lanname;
7834         int                     i_lanpltrusted;
7835         int                     i_lanplcallfoid;
7836         int                     i_laninline;
7837         int                     i_lanvalidator;
7838         int                     i_lanacl;
7839         int                     i_rlanacl;
7840         int                     i_initlanacl;
7841         int                     i_initrlanacl;
7842         int                     i_lanowner;
7843
7844         if (fout->remoteVersion >= 90600)
7845         {
7846                 PQExpBuffer acl_subquery = createPQExpBuffer();
7847                 PQExpBuffer racl_subquery = createPQExpBuffer();
7848                 PQExpBuffer initacl_subquery = createPQExpBuffer();
7849                 PQExpBuffer initracl_subquery = createPQExpBuffer();
7850
7851                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
7852                                                 initracl_subquery, "l.lanacl", "l.lanowner", "'l'",
7853                                                 dopt->binary_upgrade);
7854
7855                 /* pg_language has a laninline column */
7856                 appendPQExpBuffer(query, "SELECT l.tableoid, l.oid, "
7857                                                   "l.lanname, l.lanpltrusted, l.lanplcallfoid, "
7858                                                   "l.laninline, l.lanvalidator, "
7859                                                   "%s AS lanacl, "
7860                                                   "%s AS rlanacl, "
7861                                                   "%s AS initlanacl, "
7862                                                   "%s AS initrlanacl, "
7863                                                   "(%s l.lanowner) AS lanowner "
7864                                                   "FROM pg_language l "
7865                                                   "LEFT JOIN pg_init_privs pip ON "
7866                                                   "(l.oid = pip.objoid "
7867                                                   "AND pip.classoid = 'pg_language'::regclass "
7868                                                   "AND pip.objsubid = 0) "
7869                                                   "WHERE l.lanispl "
7870                                                   "ORDER BY l.oid",
7871                                                   acl_subquery->data,
7872                                                   racl_subquery->data,
7873                                                   initacl_subquery->data,
7874                                                   initracl_subquery->data,
7875                                                   username_subquery);
7876
7877                 destroyPQExpBuffer(acl_subquery);
7878                 destroyPQExpBuffer(racl_subquery);
7879                 destroyPQExpBuffer(initacl_subquery);
7880                 destroyPQExpBuffer(initracl_subquery);
7881         }
7882         else if (fout->remoteVersion >= 90000)
7883         {
7884                 /* pg_language has a laninline column */
7885                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7886                                                   "lanname, lanpltrusted, lanplcallfoid, "
7887                                                   "laninline, lanvalidator, lanacl, NULL AS rlanacl, "
7888                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7889                                                   "(%s lanowner) AS lanowner "
7890                                                   "FROM pg_language "
7891                                                   "WHERE lanispl "
7892                                                   "ORDER BY oid",
7893                                                   username_subquery);
7894         }
7895         else if (fout->remoteVersion >= 80300)
7896         {
7897                 /* pg_language has a lanowner column */
7898                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7899                                                   "lanname, lanpltrusted, lanplcallfoid, "
7900                                                   "0 AS laninline, lanvalidator, lanacl, "
7901                                                   "NULL AS rlanacl, "
7902                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7903                                                   "(%s lanowner) AS lanowner "
7904                                                   "FROM pg_language "
7905                                                   "WHERE lanispl "
7906                                                   "ORDER BY oid",
7907                                                   username_subquery);
7908         }
7909         else if (fout->remoteVersion >= 80100)
7910         {
7911                 /* Languages are owned by the bootstrap superuser, OID 10 */
7912                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7913                                                   "lanname, lanpltrusted, lanplcallfoid, "
7914                                                   "0 AS laninline, lanvalidator, lanacl, "
7915                                                   "NULL AS rlanacl, "
7916                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7917                                                   "(%s '10') AS lanowner "
7918                                                   "FROM pg_language "
7919                                                   "WHERE lanispl "
7920                                                   "ORDER BY oid",
7921                                                   username_subquery);
7922         }
7923         else
7924         {
7925                 /* Languages are owned by the bootstrap superuser, sysid 1 */
7926                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7927                                                   "lanname, lanpltrusted, lanplcallfoid, "
7928                                                   "0 AS laninline, lanvalidator, lanacl, "
7929                                                   "NULL AS rlanacl, "
7930                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7931                                                   "(%s '1') AS lanowner "
7932                                                   "FROM pg_language "
7933                                                   "WHERE lanispl "
7934                                                   "ORDER BY oid",
7935                                                   username_subquery);
7936         }
7937
7938         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7939
7940         ntups = PQntuples(res);
7941
7942         *numProcLangs = ntups;
7943
7944         planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
7945
7946         i_tableoid = PQfnumber(res, "tableoid");
7947         i_oid = PQfnumber(res, "oid");
7948         i_lanname = PQfnumber(res, "lanname");
7949         i_lanpltrusted = PQfnumber(res, "lanpltrusted");
7950         i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
7951         i_laninline = PQfnumber(res, "laninline");
7952         i_lanvalidator = PQfnumber(res, "lanvalidator");
7953         i_lanacl = PQfnumber(res, "lanacl");
7954         i_rlanacl = PQfnumber(res, "rlanacl");
7955         i_initlanacl = PQfnumber(res, "initlanacl");
7956         i_initrlanacl = PQfnumber(res, "initrlanacl");
7957         i_lanowner = PQfnumber(res, "lanowner");
7958
7959         for (i = 0; i < ntups; i++)
7960         {
7961                 planginfo[i].dobj.objType = DO_PROCLANG;
7962                 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7963                 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7964                 AssignDumpId(&planginfo[i].dobj);
7965
7966                 planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
7967                 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
7968                 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
7969                 planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
7970                 planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
7971                 planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
7972                 planginfo[i].rlanacl = pg_strdup(PQgetvalue(res, i, i_rlanacl));
7973                 planginfo[i].initlanacl = pg_strdup(PQgetvalue(res, i, i_initlanacl));
7974                 planginfo[i].initrlanacl = pg_strdup(PQgetvalue(res, i, i_initrlanacl));
7975                 planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
7976
7977                 /* Decide whether we want to dump it */
7978                 selectDumpableProcLang(&(planginfo[i]), fout);
7979
7980                 /* Do not try to dump ACL if no ACL exists. */
7981                 if (PQgetisnull(res, i, i_lanacl) && PQgetisnull(res, i, i_rlanacl) &&
7982                         PQgetisnull(res, i, i_initlanacl) &&
7983                         PQgetisnull(res, i, i_initrlanacl))
7984                         planginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7985         }
7986
7987         PQclear(res);
7988
7989         destroyPQExpBuffer(query);
7990
7991         return planginfo;
7992 }
7993
7994 /*
7995  * getCasts
7996  *        get basic information about every cast in the system
7997  *
7998  * numCasts is set to the number of casts read in
7999  */
8000 CastInfo *
8001 getCasts(Archive *fout, int *numCasts)
8002 {
8003         PGresult   *res;
8004         int                     ntups;
8005         int                     i;
8006         PQExpBuffer query = createPQExpBuffer();
8007         CastInfo   *castinfo;
8008         int                     i_tableoid;
8009         int                     i_oid;
8010         int                     i_castsource;
8011         int                     i_casttarget;
8012         int                     i_castfunc;
8013         int                     i_castcontext;
8014         int                     i_castmethod;
8015
8016         if (fout->remoteVersion >= 80400)
8017         {
8018                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8019                                                          "castsource, casttarget, castfunc, castcontext, "
8020                                                          "castmethod "
8021                                                          "FROM pg_cast ORDER BY 3,4");
8022         }
8023         else
8024         {
8025                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8026                                                          "castsource, casttarget, castfunc, castcontext, "
8027                                                          "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
8028                                                          "FROM pg_cast ORDER BY 3,4");
8029         }
8030
8031         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8032
8033         ntups = PQntuples(res);
8034
8035         *numCasts = ntups;
8036
8037         castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
8038
8039         i_tableoid = PQfnumber(res, "tableoid");
8040         i_oid = PQfnumber(res, "oid");
8041         i_castsource = PQfnumber(res, "castsource");
8042         i_casttarget = PQfnumber(res, "casttarget");
8043         i_castfunc = PQfnumber(res, "castfunc");
8044         i_castcontext = PQfnumber(res, "castcontext");
8045         i_castmethod = PQfnumber(res, "castmethod");
8046
8047         for (i = 0; i < ntups; i++)
8048         {
8049                 PQExpBufferData namebuf;
8050                 TypeInfo   *sTypeInfo;
8051                 TypeInfo   *tTypeInfo;
8052
8053                 castinfo[i].dobj.objType = DO_CAST;
8054                 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8055                 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8056                 AssignDumpId(&castinfo[i].dobj);
8057                 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
8058                 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
8059                 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
8060                 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
8061                 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
8062
8063                 /*
8064                  * Try to name cast as concatenation of typnames.  This is only used
8065                  * for purposes of sorting.  If we fail to find either type, the name
8066                  * will be an empty string.
8067                  */
8068                 initPQExpBuffer(&namebuf);
8069                 sTypeInfo = findTypeByOid(castinfo[i].castsource);
8070                 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
8071                 if (sTypeInfo && tTypeInfo)
8072                         appendPQExpBuffer(&namebuf, "%s %s",
8073                                                           sTypeInfo->dobj.name, tTypeInfo->dobj.name);
8074                 castinfo[i].dobj.name = namebuf.data;
8075
8076                 /* Decide whether we want to dump it */
8077                 selectDumpableCast(&(castinfo[i]), fout);
8078
8079                 /* Casts do not currently have ACLs. */
8080                 castinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8081         }
8082
8083         PQclear(res);
8084
8085         destroyPQExpBuffer(query);
8086
8087         return castinfo;
8088 }
8089
8090 static char *
8091 get_language_name(Archive *fout, Oid langid)
8092 {
8093         PQExpBuffer query;
8094         PGresult   *res;
8095         char       *lanname;
8096
8097         query = createPQExpBuffer();
8098         appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
8099         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8100         lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
8101         destroyPQExpBuffer(query);
8102         PQclear(res);
8103
8104         return lanname;
8105 }
8106
8107 /*
8108  * getTransforms
8109  *        get basic information about every transform in the system
8110  *
8111  * numTransforms is set to the number of transforms read in
8112  */
8113 TransformInfo *
8114 getTransforms(Archive *fout, int *numTransforms)
8115 {
8116         PGresult   *res;
8117         int                     ntups;
8118         int                     i;
8119         PQExpBuffer query;
8120         TransformInfo *transforminfo;
8121         int                     i_tableoid;
8122         int                     i_oid;
8123         int                     i_trftype;
8124         int                     i_trflang;
8125         int                     i_trffromsql;
8126         int                     i_trftosql;
8127
8128         /* Transforms didn't exist pre-9.5 */
8129         if (fout->remoteVersion < 90500)
8130         {
8131                 *numTransforms = 0;
8132                 return NULL;
8133         }
8134
8135         query = createPQExpBuffer();
8136
8137         appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8138                                                  "trftype, trflang, trffromsql::oid, trftosql::oid "
8139                                                  "FROM pg_transform "
8140                                                  "ORDER BY 3,4");
8141
8142         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8143
8144         ntups = PQntuples(res);
8145
8146         *numTransforms = ntups;
8147
8148         transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
8149
8150         i_tableoid = PQfnumber(res, "tableoid");
8151         i_oid = PQfnumber(res, "oid");
8152         i_trftype = PQfnumber(res, "trftype");
8153         i_trflang = PQfnumber(res, "trflang");
8154         i_trffromsql = PQfnumber(res, "trffromsql");
8155         i_trftosql = PQfnumber(res, "trftosql");
8156
8157         for (i = 0; i < ntups; i++)
8158         {
8159                 PQExpBufferData namebuf;
8160                 TypeInfo   *typeInfo;
8161                 char       *lanname;
8162
8163                 transforminfo[i].dobj.objType = DO_TRANSFORM;
8164                 transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8165                 transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8166                 AssignDumpId(&transforminfo[i].dobj);
8167                 transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
8168                 transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
8169                 transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
8170                 transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
8171
8172                 /*
8173                  * Try to name transform as concatenation of type and language name.
8174                  * This is only used for purposes of sorting.  If we fail to find
8175                  * either, the name will be an empty string.
8176                  */
8177                 initPQExpBuffer(&namebuf);
8178                 typeInfo = findTypeByOid(transforminfo[i].trftype);
8179                 lanname = get_language_name(fout, transforminfo[i].trflang);
8180                 if (typeInfo && lanname)
8181                         appendPQExpBuffer(&namebuf, "%s %s",
8182                                                           typeInfo->dobj.name, lanname);
8183                 transforminfo[i].dobj.name = namebuf.data;
8184                 free(lanname);
8185
8186                 /* Decide whether we want to dump it */
8187                 selectDumpableObject(&(transforminfo[i].dobj), fout);
8188         }
8189
8190         PQclear(res);
8191
8192         destroyPQExpBuffer(query);
8193
8194         return transforminfo;
8195 }
8196
8197 /*
8198  * getTableAttrs -
8199  *        for each interesting table, read info about its attributes
8200  *        (names, types, default values, CHECK constraints, etc)
8201  *
8202  * This is implemented in a very inefficient way right now, looping
8203  * through the tblinfo and doing a join per table to find the attrs and their
8204  * types.  However, because we want type names and so forth to be named
8205  * relative to the schema of each table, we couldn't do it in just one
8206  * query.  (Maybe one query per schema?)
8207  *
8208  *      modifies tblinfo
8209  */
8210 void
8211 getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
8212 {
8213         DumpOptions *dopt = fout->dopt;
8214         int                     i,
8215                                 j;
8216         PQExpBuffer q = createPQExpBuffer();
8217         int                     i_attnum;
8218         int                     i_attname;
8219         int                     i_atttypname;
8220         int                     i_atttypmod;
8221         int                     i_attstattarget;
8222         int                     i_attstorage;
8223         int                     i_typstorage;
8224         int                     i_attnotnull;
8225         int                     i_atthasdef;
8226         int                     i_attidentity;
8227         int                     i_attgenerated;
8228         int                     i_attisdropped;
8229         int                     i_attlen;
8230         int                     i_attalign;
8231         int                     i_attislocal;
8232         int                     i_attoptions;
8233         int                     i_attcollation;
8234         int                     i_attfdwoptions;
8235         int                     i_attmissingval;
8236         PGresult   *res;
8237         int                     ntups;
8238         bool            hasdefaults;
8239
8240         for (i = 0; i < numTables; i++)
8241         {
8242                 TableInfo  *tbinfo = &tblinfo[i];
8243
8244                 /* Don't bother to collect info for sequences */
8245                 if (tbinfo->relkind == RELKIND_SEQUENCE)
8246                         continue;
8247
8248                 /* Don't bother with uninteresting tables, either */
8249                 if (!tbinfo->interesting)
8250                         continue;
8251
8252                 /* find all the user attributes and their types */
8253
8254                 /*
8255                  * we must read the attribute names in attribute number order! because
8256                  * we will use the attnum to index into the attnames array later.
8257                  */
8258                 pg_log_info("finding the columns and types of table \"%s.%s\"",
8259                                         tbinfo->dobj.namespace->dobj.name,
8260                                         tbinfo->dobj.name);
8261
8262                 resetPQExpBuffer(q);
8263
8264                 appendPQExpBufferStr(q,
8265                                                          "SELECT\n"
8266                                                          "a.attnum,\n"
8267                                                          "a.attname,\n"
8268                                                          "a.atttypmod,\n"
8269                                                          "a.attstattarget,\n"
8270                                                          "a.attstorage,\n"
8271                                                          "t.typstorage,\n"
8272                                                          "a.attnotnull,\n"
8273                                                          "a.atthasdef,\n"
8274                                                          "a.attisdropped,\n"
8275                                                          "a.attlen,\n"
8276                                                          "a.attalign,\n"
8277                                                          "a.attislocal,\n"
8278                                                          "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n");
8279
8280                 if (fout->remoteVersion >= 120000)
8281                         appendPQExpBufferStr(q,
8282                                                                  "a.attgenerated,\n");
8283                 else
8284                         appendPQExpBufferStr(q,
8285                                                                  "'' AS attgenerated,\n");
8286
8287                 if (fout->remoteVersion >= 110000)
8288                         appendPQExpBufferStr(q,
8289                                                                  "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
8290                                                                  "THEN a.attmissingval ELSE null END AS attmissingval,\n");
8291                 else
8292                         appendPQExpBufferStr(q,
8293                                                                  "NULL AS attmissingval,\n");
8294
8295                 if (fout->remoteVersion >= 100000)
8296                         appendPQExpBufferStr(q,
8297                                                                  "a.attidentity,\n");
8298                 else
8299                         appendPQExpBufferStr(q,
8300                                                                  "'' AS attidentity,\n");
8301
8302                 if (fout->remoteVersion >= 90200)
8303                         appendPQExpBufferStr(q,
8304                                                                  "pg_catalog.array_to_string(ARRAY("
8305                                                                  "SELECT pg_catalog.quote_ident(option_name) || "
8306                                                                  "' ' || pg_catalog.quote_literal(option_value) "
8307                                                                  "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
8308                                                                  "ORDER BY option_name"
8309                                                                  "), E',\n    ') AS attfdwoptions,\n");
8310                 else
8311                         appendPQExpBufferStr(q,
8312                                                                  "'' AS attfdwoptions,\n");
8313
8314                 if (fout->remoteVersion >= 90100)
8315                 {
8316                         /*
8317                          * Since we only want to dump COLLATE clauses for attributes whose
8318                          * collation is different from their type's default, we use a CASE
8319                          * here to suppress uninteresting attcollations cheaply.
8320                          */
8321                         appendPQExpBufferStr(q,
8322                                                                  "CASE WHEN a.attcollation <> t.typcollation "
8323                                                                  "THEN a.attcollation ELSE 0 END AS attcollation,\n");
8324                 }
8325                 else
8326                         appendPQExpBufferStr(q,
8327                                                                  "0 AS attcollation,\n");
8328
8329                 if (fout->remoteVersion >= 90000)
8330                         appendPQExpBufferStr(q,
8331                                                                  "array_to_string(a.attoptions, ', ') AS attoptions\n");
8332                 else
8333                         appendPQExpBufferStr(q,
8334                                                                  "'' AS attoptions\n");
8335
8336                 /* need left join here to not fail on dropped columns ... */
8337                 appendPQExpBuffer(q,
8338                                                   "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
8339                                                   "ON a.atttypid = t.oid\n"
8340                                                   "WHERE a.attrelid = '%u'::pg_catalog.oid "
8341                                                   "AND a.attnum > 0::pg_catalog.int2\n"
8342                                                   "ORDER BY a.attnum",
8343                                                   tbinfo->dobj.catId.oid);
8344
8345                 res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8346
8347                 ntups = PQntuples(res);
8348
8349                 i_attnum = PQfnumber(res, "attnum");
8350                 i_attname = PQfnumber(res, "attname");
8351                 i_atttypname = PQfnumber(res, "atttypname");
8352                 i_atttypmod = PQfnumber(res, "atttypmod");
8353                 i_attstattarget = PQfnumber(res, "attstattarget");
8354                 i_attstorage = PQfnumber(res, "attstorage");
8355                 i_typstorage = PQfnumber(res, "typstorage");
8356                 i_attnotnull = PQfnumber(res, "attnotnull");
8357                 i_atthasdef = PQfnumber(res, "atthasdef");
8358                 i_attidentity = PQfnumber(res, "attidentity");
8359                 i_attgenerated = PQfnumber(res, "attgenerated");
8360                 i_attisdropped = PQfnumber(res, "attisdropped");
8361                 i_attlen = PQfnumber(res, "attlen");
8362                 i_attalign = PQfnumber(res, "attalign");
8363                 i_attislocal = PQfnumber(res, "attislocal");
8364                 i_attoptions = PQfnumber(res, "attoptions");
8365                 i_attcollation = PQfnumber(res, "attcollation");
8366                 i_attfdwoptions = PQfnumber(res, "attfdwoptions");
8367                 i_attmissingval = PQfnumber(res, "attmissingval");
8368
8369                 tbinfo->numatts = ntups;
8370                 tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
8371                 tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
8372                 tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
8373                 tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
8374                 tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
8375                 tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
8376                 tbinfo->attidentity = (char *) pg_malloc(ntups * sizeof(char));
8377                 tbinfo->attgenerated = (char *) pg_malloc(ntups * sizeof(char));
8378                 tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
8379                 tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
8380                 tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
8381                 tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
8382                 tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
8383                 tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
8384                 tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
8385                 tbinfo->attmissingval = (char **) pg_malloc(ntups * sizeof(char *));
8386                 tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
8387                 tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
8388                 tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
8389                 hasdefaults = false;
8390
8391                 for (j = 0; j < ntups; j++)
8392                 {
8393                         if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
8394                                 fatal("invalid column numbering in table \"%s\"",
8395                                           tbinfo->dobj.name);
8396                         tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
8397                         tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
8398                         tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
8399                         tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
8400                         tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
8401                         tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
8402                         tbinfo->attidentity[j] = *(PQgetvalue(res, j, i_attidentity));
8403                         tbinfo->attgenerated[j] = *(PQgetvalue(res, j, i_attgenerated));
8404                         tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
8405                         tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
8406                         tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
8407                         tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
8408                         tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
8409                         tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
8410                         tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
8411                         tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
8412                         tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
8413                         tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, j, i_attmissingval));
8414                         tbinfo->attrdefs[j] = NULL; /* fix below */
8415                         if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
8416                                 hasdefaults = true;
8417                         /* these flags will be set in flagInhAttrs() */
8418                         tbinfo->inhNotNull[j] = false;
8419                 }
8420
8421                 PQclear(res);
8422
8423                 /*
8424                  * Get info about column defaults
8425                  */
8426                 if (hasdefaults)
8427                 {
8428                         AttrDefInfo *attrdefs;
8429                         int                     numDefaults;
8430
8431                         pg_log_info("finding default expressions of table \"%s.%s\"",
8432                                                 tbinfo->dobj.namespace->dobj.name,
8433                                                 tbinfo->dobj.name);
8434
8435                         printfPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
8436                                                           "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
8437                                                           "FROM pg_catalog.pg_attrdef "
8438                                                           "WHERE adrelid = '%u'::pg_catalog.oid",
8439                                                           tbinfo->dobj.catId.oid);
8440
8441                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8442
8443                         numDefaults = PQntuples(res);
8444                         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
8445
8446                         for (j = 0; j < numDefaults; j++)
8447                         {
8448                                 int                     adnum;
8449
8450                                 adnum = atoi(PQgetvalue(res, j, 2));
8451
8452                                 if (adnum <= 0 || adnum > ntups)
8453                                         fatal("invalid adnum value %d for table \"%s\"",
8454                                                   adnum, tbinfo->dobj.name);
8455
8456                                 /*
8457                                  * dropped columns shouldn't have defaults, but just in case,
8458                                  * ignore 'em
8459                                  */
8460                                 if (tbinfo->attisdropped[adnum - 1])
8461                                         continue;
8462
8463                                 attrdefs[j].dobj.objType = DO_ATTRDEF;
8464                                 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
8465                                 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
8466                                 AssignDumpId(&attrdefs[j].dobj);
8467                                 attrdefs[j].adtable = tbinfo;
8468                                 attrdefs[j].adnum = adnum;
8469                                 attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
8470
8471                                 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
8472                                 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
8473
8474                                 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
8475
8476                                 /*
8477                                  * Defaults on a VIEW must always be dumped as separate ALTER
8478                                  * TABLE commands.  Defaults on regular tables are dumped as
8479                                  * part of the CREATE TABLE if possible, which it won't be if
8480                                  * the column is not going to be emitted explicitly.
8481                                  */
8482                                 if (tbinfo->relkind == RELKIND_VIEW)
8483                                 {
8484                                         attrdefs[j].separate = true;
8485                                 }
8486                                 else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
8487                                 {
8488                                         /* column will be suppressed, print default separately */
8489                                         attrdefs[j].separate = true;
8490                                 }
8491                                 else
8492                                 {
8493                                         attrdefs[j].separate = false;
8494
8495                                         /*
8496                                          * Mark the default as needing to appear before the table,
8497                                          * so that any dependencies it has must be emitted before
8498                                          * the CREATE TABLE.  If this is not possible, we'll
8499                                          * change to "separate" mode while sorting dependencies.
8500                                          */
8501                                         addObjectDependency(&tbinfo->dobj,
8502                                                                                 attrdefs[j].dobj.dumpId);
8503                                 }
8504
8505                                 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
8506                         }
8507                         PQclear(res);
8508                 }
8509
8510                 /*
8511                  * Get info about table CHECK constraints
8512                  */
8513                 if (tbinfo->ncheck > 0)
8514                 {
8515                         ConstraintInfo *constrs;
8516                         int                     numConstrs;
8517
8518                         pg_log_info("finding check constraints for table \"%s.%s\"",
8519                                                 tbinfo->dobj.namespace->dobj.name,
8520                                                 tbinfo->dobj.name);
8521
8522                         resetPQExpBuffer(q);
8523                         if (fout->remoteVersion >= 90200)
8524                         {
8525                                 /*
8526                                  * convalidated is new in 9.2 (actually, it is there in 9.1,
8527                                  * but it wasn't ever false for check constraints until 9.2).
8528                                  */
8529                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8530                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8531                                                                   "conislocal, convalidated "
8532                                                                   "FROM pg_catalog.pg_constraint "
8533                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8534                                                                   "   AND contype = 'c' "
8535                                                                   "ORDER BY conname",
8536                                                                   tbinfo->dobj.catId.oid);
8537                         }
8538                         else if (fout->remoteVersion >= 80400)
8539                         {
8540                                 /* conislocal is new in 8.4 */
8541                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8542                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8543                                                                   "conislocal, true AS convalidated "
8544                                                                   "FROM pg_catalog.pg_constraint "
8545                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8546                                                                   "   AND contype = 'c' "
8547                                                                   "ORDER BY conname",
8548                                                                   tbinfo->dobj.catId.oid);
8549                         }
8550                         else
8551                         {
8552                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8553                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8554                                                                   "true AS conislocal, true AS convalidated "
8555                                                                   "FROM pg_catalog.pg_constraint "
8556                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8557                                                                   "   AND contype = 'c' "
8558                                                                   "ORDER BY conname",
8559                                                                   tbinfo->dobj.catId.oid);
8560                         }
8561
8562                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8563
8564                         numConstrs = PQntuples(res);
8565                         if (numConstrs != tbinfo->ncheck)
8566                         {
8567                                 pg_log_error(ngettext("expected %d check constraint on table \"%s\" but found %d",
8568                                                                           "expected %d check constraints on table \"%s\" but found %d",
8569                                                                           tbinfo->ncheck),
8570                                                          tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
8571                                 pg_log_error("(The system catalogs might be corrupted.)");
8572                                 exit_nicely(1);
8573                         }
8574
8575                         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
8576                         tbinfo->checkexprs = constrs;
8577
8578                         for (j = 0; j < numConstrs; j++)
8579                         {
8580                                 bool            validated = PQgetvalue(res, j, 5)[0] == 't';
8581
8582                                 constrs[j].dobj.objType = DO_CONSTRAINT;
8583                                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
8584                                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
8585                                 AssignDumpId(&constrs[j].dobj);
8586                                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
8587                                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
8588                                 constrs[j].contable = tbinfo;
8589                                 constrs[j].condomain = NULL;
8590                                 constrs[j].contype = 'c';
8591                                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
8592                                 constrs[j].confrelid = InvalidOid;
8593                                 constrs[j].conindex = 0;
8594                                 constrs[j].condeferrable = false;
8595                                 constrs[j].condeferred = false;
8596                                 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
8597
8598                                 /*
8599                                  * An unvalidated constraint needs to be dumped separately, so
8600                                  * that potentially-violating existing data is loaded before
8601                                  * the constraint.
8602                                  */
8603                                 constrs[j].separate = !validated;
8604
8605                                 constrs[j].dobj.dump = tbinfo->dobj.dump;
8606
8607                                 /*
8608                                  * Mark the constraint as needing to appear before the table
8609                                  * --- this is so that any other dependencies of the
8610                                  * constraint will be emitted before we try to create the
8611                                  * table.  If the constraint is to be dumped separately, it
8612                                  * will be dumped after data is loaded anyway, so don't do it.
8613                                  * (There's an automatic dependency in the opposite direction
8614                                  * anyway, so don't need to add one manually here.)
8615                                  */
8616                                 if (!constrs[j].separate)
8617                                         addObjectDependency(&tbinfo->dobj,
8618                                                                                 constrs[j].dobj.dumpId);
8619
8620                                 /*
8621                                  * If the constraint is inherited, this will be detected later
8622                                  * (in pre-8.4 databases).  We also detect later if the
8623                                  * constraint must be split out from the table definition.
8624                                  */
8625                         }
8626                         PQclear(res);
8627                 }
8628         }
8629
8630         destroyPQExpBuffer(q);
8631 }
8632
8633 /*
8634  * Test whether a column should be printed as part of table's CREATE TABLE.
8635  * Column number is zero-based.
8636  *
8637  * Normally this is always true, but it's false for dropped columns, as well
8638  * as those that were inherited without any local definition.  (If we print
8639  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
8640  * For partitions, it's always true, because we want the partitions to be
8641  * created independently and ATTACH PARTITION used afterwards.
8642  *
8643  * In binary_upgrade mode, we must print all columns and fix the attislocal/
8644  * attisdropped state later, so as to keep control of the physical column
8645  * order.
8646  *
8647  * This function exists because there are scattered nonobvious places that
8648  * must be kept in sync with this decision.
8649  */
8650 bool
8651 shouldPrintColumn(DumpOptions *dopt, TableInfo *tbinfo, int colno)
8652 {
8653         if (dopt->binary_upgrade)
8654                 return true;
8655         if (tbinfo->attisdropped[colno])
8656                 return false;
8657         return (tbinfo->attislocal[colno] || tbinfo->ispartition);
8658 }
8659
8660
8661 /*
8662  * getTSParsers:
8663  *        read all text search parsers in the system catalogs and return them
8664  *        in the TSParserInfo* structure
8665  *
8666  *      numTSParsers is set to the number of parsers read in
8667  */
8668 TSParserInfo *
8669 getTSParsers(Archive *fout, int *numTSParsers)
8670 {
8671         PGresult   *res;
8672         int                     ntups;
8673         int                     i;
8674         PQExpBuffer query;
8675         TSParserInfo *prsinfo;
8676         int                     i_tableoid;
8677         int                     i_oid;
8678         int                     i_prsname;
8679         int                     i_prsnamespace;
8680         int                     i_prsstart;
8681         int                     i_prstoken;
8682         int                     i_prsend;
8683         int                     i_prsheadline;
8684         int                     i_prslextype;
8685
8686         /* Before 8.3, there is no built-in text search support */
8687         if (fout->remoteVersion < 80300)
8688         {
8689                 *numTSParsers = 0;
8690                 return NULL;
8691         }
8692
8693         query = createPQExpBuffer();
8694
8695         /*
8696          * find all text search objects, including builtin ones; we filter out
8697          * system-defined objects at dump-out time.
8698          */
8699
8700         appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
8701                                                  "prsstart::oid, prstoken::oid, "
8702                                                  "prsend::oid, prsheadline::oid, prslextype::oid "
8703                                                  "FROM pg_ts_parser");
8704
8705         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8706
8707         ntups = PQntuples(res);
8708         *numTSParsers = ntups;
8709
8710         prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
8711
8712         i_tableoid = PQfnumber(res, "tableoid");
8713         i_oid = PQfnumber(res, "oid");
8714         i_prsname = PQfnumber(res, "prsname");
8715         i_prsnamespace = PQfnumber(res, "prsnamespace");
8716         i_prsstart = PQfnumber(res, "prsstart");
8717         i_prstoken = PQfnumber(res, "prstoken");
8718         i_prsend = PQfnumber(res, "prsend");
8719         i_prsheadline = PQfnumber(res, "prsheadline");
8720         i_prslextype = PQfnumber(res, "prslextype");
8721
8722         for (i = 0; i < ntups; i++)
8723         {
8724                 prsinfo[i].dobj.objType = DO_TSPARSER;
8725                 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8726                 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8727                 AssignDumpId(&prsinfo[i].dobj);
8728                 prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
8729                 prsinfo[i].dobj.namespace =
8730                         findNamespace(fout,
8731                                                   atooid(PQgetvalue(res, i, i_prsnamespace)));
8732                 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
8733                 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
8734                 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
8735                 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
8736                 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
8737
8738                 /* Decide whether we want to dump it */
8739                 selectDumpableObject(&(prsinfo[i].dobj), fout);
8740
8741                 /* Text Search Parsers do not currently have ACLs. */
8742                 prsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8743         }
8744
8745         PQclear(res);
8746
8747         destroyPQExpBuffer(query);
8748
8749         return prsinfo;
8750 }
8751
8752 /*
8753  * getTSDictionaries:
8754  *        read all text search dictionaries in the system catalogs and return them
8755  *        in the TSDictInfo* structure
8756  *
8757  *      numTSDicts is set to the number of dictionaries read in
8758  */
8759 TSDictInfo *
8760 getTSDictionaries(Archive *fout, int *numTSDicts)
8761 {
8762         PGresult   *res;
8763         int                     ntups;
8764         int                     i;
8765         PQExpBuffer query;
8766         TSDictInfo *dictinfo;
8767         int                     i_tableoid;
8768         int                     i_oid;
8769         int                     i_dictname;
8770         int                     i_dictnamespace;
8771         int                     i_rolname;
8772         int                     i_dicttemplate;
8773         int                     i_dictinitoption;
8774
8775         /* Before 8.3, there is no built-in text search support */
8776         if (fout->remoteVersion < 80300)
8777         {
8778                 *numTSDicts = 0;
8779                 return NULL;
8780         }
8781
8782         query = createPQExpBuffer();
8783
8784         appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
8785                                           "dictnamespace, (%s dictowner) AS rolname, "
8786                                           "dicttemplate, dictinitoption "
8787                                           "FROM pg_ts_dict",
8788                                           username_subquery);
8789
8790         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8791
8792         ntups = PQntuples(res);
8793         *numTSDicts = ntups;
8794
8795         dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
8796
8797         i_tableoid = PQfnumber(res, "tableoid");
8798         i_oid = PQfnumber(res, "oid");
8799         i_dictname = PQfnumber(res, "dictname");
8800         i_dictnamespace = PQfnumber(res, "dictnamespace");
8801         i_rolname = PQfnumber(res, "rolname");
8802         i_dictinitoption = PQfnumber(res, "dictinitoption");
8803         i_dicttemplate = PQfnumber(res, "dicttemplate");
8804
8805         for (i = 0; i < ntups; i++)
8806         {
8807                 dictinfo[i].dobj.objType = DO_TSDICT;
8808                 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8809                 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8810                 AssignDumpId(&dictinfo[i].dobj);
8811                 dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
8812                 dictinfo[i].dobj.namespace =
8813                         findNamespace(fout,
8814                                                   atooid(PQgetvalue(res, i, i_dictnamespace)));
8815                 dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8816                 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
8817                 if (PQgetisnull(res, i, i_dictinitoption))
8818                         dictinfo[i].dictinitoption = NULL;
8819                 else
8820                         dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
8821
8822                 /* Decide whether we want to dump it */
8823                 selectDumpableObject(&(dictinfo[i].dobj), fout);
8824
8825                 /* Text Search Dictionaries do not currently have ACLs. */
8826                 dictinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8827         }
8828
8829         PQclear(res);
8830
8831         destroyPQExpBuffer(query);
8832
8833         return dictinfo;
8834 }
8835
8836 /*
8837  * getTSTemplates:
8838  *        read all text search templates in the system catalogs and return them
8839  *        in the TSTemplateInfo* structure
8840  *
8841  *      numTSTemplates is set to the number of templates read in
8842  */
8843 TSTemplateInfo *
8844 getTSTemplates(Archive *fout, int *numTSTemplates)
8845 {
8846         PGresult   *res;
8847         int                     ntups;
8848         int                     i;
8849         PQExpBuffer query;
8850         TSTemplateInfo *tmplinfo;
8851         int                     i_tableoid;
8852         int                     i_oid;
8853         int                     i_tmplname;
8854         int                     i_tmplnamespace;
8855         int                     i_tmplinit;
8856         int                     i_tmpllexize;
8857
8858         /* Before 8.3, there is no built-in text search support */
8859         if (fout->remoteVersion < 80300)
8860         {
8861                 *numTSTemplates = 0;
8862                 return NULL;
8863         }
8864
8865         query = createPQExpBuffer();
8866
8867         appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
8868                                                  "tmplnamespace, tmplinit::oid, tmpllexize::oid "
8869                                                  "FROM pg_ts_template");
8870
8871         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8872
8873         ntups = PQntuples(res);
8874         *numTSTemplates = ntups;
8875
8876         tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
8877
8878         i_tableoid = PQfnumber(res, "tableoid");
8879         i_oid = PQfnumber(res, "oid");
8880         i_tmplname = PQfnumber(res, "tmplname");
8881         i_tmplnamespace = PQfnumber(res, "tmplnamespace");
8882         i_tmplinit = PQfnumber(res, "tmplinit");
8883         i_tmpllexize = PQfnumber(res, "tmpllexize");
8884
8885         for (i = 0; i < ntups; i++)
8886         {
8887                 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
8888                 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8889                 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8890                 AssignDumpId(&tmplinfo[i].dobj);
8891                 tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
8892                 tmplinfo[i].dobj.namespace =
8893                         findNamespace(fout,
8894                                                   atooid(PQgetvalue(res, i, i_tmplnamespace)));
8895                 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
8896                 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
8897
8898                 /* Decide whether we want to dump it */
8899                 selectDumpableObject(&(tmplinfo[i].dobj), fout);
8900
8901                 /* Text Search Templates do not currently have ACLs. */
8902                 tmplinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8903         }
8904
8905         PQclear(res);
8906
8907         destroyPQExpBuffer(query);
8908
8909         return tmplinfo;
8910 }
8911
8912 /*
8913  * getTSConfigurations:
8914  *        read all text search configurations in the system catalogs and return
8915  *        them in the TSConfigInfo* structure
8916  *
8917  *      numTSConfigs is set to the number of configurations read in
8918  */
8919 TSConfigInfo *
8920 getTSConfigurations(Archive *fout, int *numTSConfigs)
8921 {
8922         PGresult   *res;
8923         int                     ntups;
8924         int                     i;
8925         PQExpBuffer query;
8926         TSConfigInfo *cfginfo;
8927         int                     i_tableoid;
8928         int                     i_oid;
8929         int                     i_cfgname;
8930         int                     i_cfgnamespace;
8931         int                     i_rolname;
8932         int                     i_cfgparser;
8933
8934         /* Before 8.3, there is no built-in text search support */
8935         if (fout->remoteVersion < 80300)
8936         {
8937                 *numTSConfigs = 0;
8938                 return NULL;
8939         }
8940
8941         query = createPQExpBuffer();
8942
8943         appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
8944                                           "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
8945                                           "FROM pg_ts_config",
8946                                           username_subquery);
8947
8948         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8949
8950         ntups = PQntuples(res);
8951         *numTSConfigs = ntups;
8952
8953         cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
8954
8955         i_tableoid = PQfnumber(res, "tableoid");
8956         i_oid = PQfnumber(res, "oid");
8957         i_cfgname = PQfnumber(res, "cfgname");
8958         i_cfgnamespace = PQfnumber(res, "cfgnamespace");
8959         i_rolname = PQfnumber(res, "rolname");
8960         i_cfgparser = PQfnumber(res, "cfgparser");
8961
8962         for (i = 0; i < ntups; i++)
8963         {
8964                 cfginfo[i].dobj.objType = DO_TSCONFIG;
8965                 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8966                 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8967                 AssignDumpId(&cfginfo[i].dobj);
8968                 cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
8969                 cfginfo[i].dobj.namespace =
8970                         findNamespace(fout,
8971                                                   atooid(PQgetvalue(res, i, i_cfgnamespace)));
8972                 cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8973                 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
8974
8975                 /* Decide whether we want to dump it */
8976                 selectDumpableObject(&(cfginfo[i].dobj), fout);
8977
8978                 /* Text Search Configurations do not currently have ACLs. */
8979                 cfginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8980         }
8981
8982         PQclear(res);
8983
8984         destroyPQExpBuffer(query);
8985
8986         return cfginfo;
8987 }
8988
8989 /*
8990  * getForeignDataWrappers:
8991  *        read all foreign-data wrappers in the system catalogs and return
8992  *        them in the FdwInfo* structure
8993  *
8994  *      numForeignDataWrappers is set to the number of fdws read in
8995  */
8996 FdwInfo *
8997 getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
8998 {
8999         DumpOptions *dopt = fout->dopt;
9000         PGresult   *res;
9001         int                     ntups;
9002         int                     i;
9003         PQExpBuffer query;
9004         FdwInfo    *fdwinfo;
9005         int                     i_tableoid;
9006         int                     i_oid;
9007         int                     i_fdwname;
9008         int                     i_rolname;
9009         int                     i_fdwhandler;
9010         int                     i_fdwvalidator;
9011         int                     i_fdwacl;
9012         int                     i_rfdwacl;
9013         int                     i_initfdwacl;
9014         int                     i_initrfdwacl;
9015         int                     i_fdwoptions;
9016
9017         /* Before 8.4, there are no foreign-data wrappers */
9018         if (fout->remoteVersion < 80400)
9019         {
9020                 *numForeignDataWrappers = 0;
9021                 return NULL;
9022         }
9023
9024         query = createPQExpBuffer();
9025
9026         if (fout->remoteVersion >= 90600)
9027         {
9028                 PQExpBuffer acl_subquery = createPQExpBuffer();
9029                 PQExpBuffer racl_subquery = createPQExpBuffer();
9030                 PQExpBuffer initacl_subquery = createPQExpBuffer();
9031                 PQExpBuffer initracl_subquery = createPQExpBuffer();
9032
9033                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9034                                                 initracl_subquery, "f.fdwacl", "f.fdwowner", "'F'",
9035                                                 dopt->binary_upgrade);
9036
9037                 appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.fdwname, "
9038                                                   "(%s f.fdwowner) AS rolname, "
9039                                                   "f.fdwhandler::pg_catalog.regproc, "
9040                                                   "f.fdwvalidator::pg_catalog.regproc, "
9041                                                   "%s AS fdwacl, "
9042                                                   "%s AS rfdwacl, "
9043                                                   "%s AS initfdwacl, "
9044                                                   "%s AS initrfdwacl, "
9045                                                   "array_to_string(ARRAY("
9046                                                   "SELECT quote_ident(option_name) || ' ' || "
9047                                                   "quote_literal(option_value) "
9048                                                   "FROM pg_options_to_table(f.fdwoptions) "
9049                                                   "ORDER BY option_name"
9050                                                   "), E',\n    ') AS fdwoptions "
9051                                                   "FROM pg_foreign_data_wrapper f "
9052                                                   "LEFT JOIN pg_init_privs pip ON "
9053                                                   "(f.oid = pip.objoid "
9054                                                   "AND pip.classoid = 'pg_foreign_data_wrapper'::regclass "
9055                                                   "AND pip.objsubid = 0) ",
9056                                                   username_subquery,
9057                                                   acl_subquery->data,
9058                                                   racl_subquery->data,
9059                                                   initacl_subquery->data,
9060                                                   initracl_subquery->data);
9061
9062                 destroyPQExpBuffer(acl_subquery);
9063                 destroyPQExpBuffer(racl_subquery);
9064                 destroyPQExpBuffer(initacl_subquery);
9065                 destroyPQExpBuffer(initracl_subquery);
9066         }
9067         else if (fout->remoteVersion >= 90100)
9068         {
9069                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
9070                                                   "(%s fdwowner) AS rolname, "
9071                                                   "fdwhandler::pg_catalog.regproc, "
9072                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
9073                                                   "NULL as rfdwacl, "
9074                                                   "NULL as initfdwacl, NULL AS initrfdwacl, "
9075                                                   "array_to_string(ARRAY("
9076                                                   "SELECT quote_ident(option_name) || ' ' || "
9077                                                   "quote_literal(option_value) "
9078                                                   "FROM pg_options_to_table(fdwoptions) "
9079                                                   "ORDER BY option_name"
9080                                                   "), E',\n    ') AS fdwoptions "
9081                                                   "FROM pg_foreign_data_wrapper",
9082                                                   username_subquery);
9083         }
9084         else
9085         {
9086                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
9087                                                   "(%s fdwowner) AS rolname, "
9088                                                   "'-' AS fdwhandler, "
9089                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
9090                                                   "NULL as rfdwacl, "
9091                                                   "NULL as initfdwacl, NULL AS initrfdwacl, "
9092                                                   "array_to_string(ARRAY("
9093                                                   "SELECT quote_ident(option_name) || ' ' || "
9094                                                   "quote_literal(option_value) "
9095                                                   "FROM pg_options_to_table(fdwoptions) "
9096                                                   "ORDER BY option_name"
9097                                                   "), E',\n    ') AS fdwoptions "
9098                                                   "FROM pg_foreign_data_wrapper",
9099                                                   username_subquery);
9100         }
9101
9102         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9103
9104         ntups = PQntuples(res);
9105         *numForeignDataWrappers = ntups;
9106
9107         fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
9108
9109         i_tableoid = PQfnumber(res, "tableoid");
9110         i_oid = PQfnumber(res, "oid");
9111         i_fdwname = PQfnumber(res, "fdwname");
9112         i_rolname = PQfnumber(res, "rolname");
9113         i_fdwhandler = PQfnumber(res, "fdwhandler");
9114         i_fdwvalidator = PQfnumber(res, "fdwvalidator");
9115         i_fdwacl = PQfnumber(res, "fdwacl");
9116         i_rfdwacl = PQfnumber(res, "rfdwacl");
9117         i_initfdwacl = PQfnumber(res, "initfdwacl");
9118         i_initrfdwacl = PQfnumber(res, "initrfdwacl");
9119         i_fdwoptions = PQfnumber(res, "fdwoptions");
9120
9121         for (i = 0; i < ntups; i++)
9122         {
9123                 fdwinfo[i].dobj.objType = DO_FDW;
9124                 fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9125                 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9126                 AssignDumpId(&fdwinfo[i].dobj);
9127                 fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
9128                 fdwinfo[i].dobj.namespace = NULL;
9129                 fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
9130                 fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
9131                 fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
9132                 fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
9133                 fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
9134                 fdwinfo[i].rfdwacl = pg_strdup(PQgetvalue(res, i, i_rfdwacl));
9135                 fdwinfo[i].initfdwacl = pg_strdup(PQgetvalue(res, i, i_initfdwacl));
9136                 fdwinfo[i].initrfdwacl = pg_strdup(PQgetvalue(res, i, i_initrfdwacl));
9137
9138                 /* Decide whether we want to dump it */
9139                 selectDumpableObject(&(fdwinfo[i].dobj), fout);
9140
9141                 /* Do not try to dump ACL if no ACL exists. */
9142                 if (PQgetisnull(res, i, i_fdwacl) && PQgetisnull(res, i, i_rfdwacl) &&
9143                         PQgetisnull(res, i, i_initfdwacl) &&
9144                         PQgetisnull(res, i, i_initrfdwacl))
9145                         fdwinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
9146         }
9147
9148         PQclear(res);
9149
9150         destroyPQExpBuffer(query);
9151
9152         return fdwinfo;
9153 }
9154
9155 /*
9156  * getForeignServers:
9157  *        read all foreign servers in the system catalogs and return
9158  *        them in the ForeignServerInfo * structure
9159  *
9160  *      numForeignServers is set to the number of servers read in
9161  */
9162 ForeignServerInfo *
9163 getForeignServers(Archive *fout, int *numForeignServers)
9164 {
9165         DumpOptions *dopt = fout->dopt;
9166         PGresult   *res;
9167         int                     ntups;
9168         int                     i;
9169         PQExpBuffer query;
9170         ForeignServerInfo *srvinfo;
9171         int                     i_tableoid;
9172         int                     i_oid;
9173         int                     i_srvname;
9174         int                     i_rolname;
9175         int                     i_srvfdw;
9176         int                     i_srvtype;
9177         int                     i_srvversion;
9178         int                     i_srvacl;
9179         int                     i_rsrvacl;
9180         int                     i_initsrvacl;
9181         int                     i_initrsrvacl;
9182         int                     i_srvoptions;
9183
9184         /* Before 8.4, there are no foreign servers */
9185         if (fout->remoteVersion < 80400)
9186         {
9187                 *numForeignServers = 0;
9188                 return NULL;
9189         }
9190
9191         query = createPQExpBuffer();
9192
9193         if (fout->remoteVersion >= 90600)
9194         {
9195                 PQExpBuffer acl_subquery = createPQExpBuffer();
9196                 PQExpBuffer racl_subquery = createPQExpBuffer();
9197                 PQExpBuffer initacl_subquery = createPQExpBuffer();
9198                 PQExpBuffer initracl_subquery = createPQExpBuffer();
9199
9200                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9201                                                 initracl_subquery, "f.srvacl", "f.srvowner", "'S'",
9202                                                 dopt->binary_upgrade);
9203
9204                 appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.srvname, "
9205                                                   "(%s f.srvowner) AS rolname, "
9206                                                   "f.srvfdw, f.srvtype, f.srvversion, "
9207                                                   "%s AS srvacl, "
9208                                                   "%s AS rsrvacl, "
9209                                                   "%s AS initsrvacl, "
9210                                                   "%s AS initrsrvacl, "
9211                                                   "array_to_string(ARRAY("
9212                                                   "SELECT quote_ident(option_name) || ' ' || "
9213                                                   "quote_literal(option_value) "
9214                                                   "FROM pg_options_to_table(f.srvoptions) "
9215                                                   "ORDER BY option_name"
9216                                                   "), E',\n    ') AS srvoptions "
9217                                                   "FROM pg_foreign_server f "
9218                                                   "LEFT JOIN pg_init_privs pip "
9219                                                   "ON (f.oid = pip.objoid "
9220                                                   "AND pip.classoid = 'pg_foreign_server'::regclass "
9221                                                   "AND pip.objsubid = 0) ",
9222                                                   username_subquery,
9223                                                   acl_subquery->data,
9224                                                   racl_subquery->data,
9225                                                   initacl_subquery->data,
9226                                                   initracl_subquery->data);
9227
9228                 destroyPQExpBuffer(acl_subquery);
9229                 destroyPQExpBuffer(racl_subquery);
9230                 destroyPQExpBuffer(initacl_subquery);
9231                 destroyPQExpBuffer(initracl_subquery);
9232         }
9233         else
9234         {
9235                 appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
9236                                                   "(%s srvowner) AS rolname, "
9237                                                   "srvfdw, srvtype, srvversion, srvacl, "
9238                                                   "NULL AS rsrvacl, "
9239                                                   "NULL AS initsrvacl, NULL AS initrsrvacl, "
9240                                                   "array_to_string(ARRAY("
9241                                                   "SELECT quote_ident(option_name) || ' ' || "
9242                                                   "quote_literal(option_value) "
9243                                                   "FROM pg_options_to_table(srvoptions) "
9244                                                   "ORDER BY option_name"
9245                                                   "), E',\n    ') AS srvoptions "
9246                                                   "FROM pg_foreign_server",
9247                                                   username_subquery);
9248         }
9249
9250         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9251
9252         ntups = PQntuples(res);
9253         *numForeignServers = ntups;
9254
9255         srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
9256
9257         i_tableoid = PQfnumber(res, "tableoid");
9258         i_oid = PQfnumber(res, "oid");
9259         i_srvname = PQfnumber(res, "srvname");
9260         i_rolname = PQfnumber(res, "rolname");
9261         i_srvfdw = PQfnumber(res, "srvfdw");
9262         i_srvtype = PQfnumber(res, "srvtype");
9263         i_srvversion = PQfnumber(res, "srvversion");
9264         i_srvacl = PQfnumber(res, "srvacl");
9265         i_rsrvacl = PQfnumber(res, "rsrvacl");
9266         i_initsrvacl = PQfnumber(res, "initsrvacl");
9267         i_initrsrvacl = PQfnumber(res, "initrsrvacl");
9268         i_srvoptions = PQfnumber(res, "srvoptions");
9269
9270         for (i = 0; i < ntups; i++)
9271         {
9272                 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
9273                 srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9274                 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9275                 AssignDumpId(&srvinfo[i].dobj);
9276                 srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
9277                 srvinfo[i].dobj.namespace = NULL;
9278                 srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
9279                 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
9280                 srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
9281                 srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
9282                 srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
9283                 srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
9284                 srvinfo[i].rsrvacl = pg_strdup(PQgetvalue(res, i, i_rsrvacl));
9285                 srvinfo[i].initsrvacl = pg_strdup(PQgetvalue(res, i, i_initsrvacl));
9286                 srvinfo[i].initrsrvacl = pg_strdup(PQgetvalue(res, i, i_initrsrvacl));
9287
9288                 /* Decide whether we want to dump it */
9289                 selectDumpableObject(&(srvinfo[i].dobj), fout);
9290
9291                 /* Do not try to dump ACL if no ACL exists. */
9292                 if (PQgetisnull(res, i, i_srvacl) && PQgetisnull(res, i, i_rsrvacl) &&
9293                         PQgetisnull(res, i, i_initsrvacl) &&
9294                         PQgetisnull(res, i, i_initrsrvacl))
9295                         srvinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
9296         }
9297
9298         PQclear(res);
9299
9300         destroyPQExpBuffer(query);
9301
9302         return srvinfo;
9303 }
9304
9305 /*
9306  * getDefaultACLs:
9307  *        read all default ACL information in the system catalogs and return
9308  *        them in the DefaultACLInfo structure
9309  *
9310  *      numDefaultACLs is set to the number of ACLs read in
9311  */
9312 DefaultACLInfo *
9313 getDefaultACLs(Archive *fout, int *numDefaultACLs)
9314 {
9315         DumpOptions *dopt = fout->dopt;
9316         DefaultACLInfo *daclinfo;
9317         PQExpBuffer query;
9318         PGresult   *res;
9319         int                     i_oid;
9320         int                     i_tableoid;
9321         int                     i_defaclrole;
9322         int                     i_defaclnamespace;
9323         int                     i_defaclobjtype;
9324         int                     i_defaclacl;
9325         int                     i_rdefaclacl;
9326         int                     i_initdefaclacl;
9327         int                     i_initrdefaclacl;
9328         int                     i,
9329                                 ntups;
9330
9331         if (fout->remoteVersion < 90000)
9332         {
9333                 *numDefaultACLs = 0;
9334                 return NULL;
9335         }
9336
9337         query = createPQExpBuffer();
9338
9339         if (fout->remoteVersion >= 90600)
9340         {
9341                 PQExpBuffer acl_subquery = createPQExpBuffer();
9342                 PQExpBuffer racl_subquery = createPQExpBuffer();
9343                 PQExpBuffer initacl_subquery = createPQExpBuffer();
9344                 PQExpBuffer initracl_subquery = createPQExpBuffer();
9345
9346                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9347                                                 initracl_subquery, "defaclacl", "defaclrole",
9348                                                 "CASE WHEN defaclobjtype = 'S' THEN 's' ELSE defaclobjtype END::\"char\"",
9349                                                 dopt->binary_upgrade);
9350
9351                 appendPQExpBuffer(query, "SELECT d.oid, d.tableoid, "
9352                                                   "(%s d.defaclrole) AS defaclrole, "
9353                                                   "d.defaclnamespace, "
9354                                                   "d.defaclobjtype, "
9355                                                   "%s AS defaclacl, "
9356                                                   "%s AS rdefaclacl, "
9357                                                   "%s AS initdefaclacl, "
9358                                                   "%s AS initrdefaclacl "
9359                                                   "FROM pg_default_acl d "
9360                                                   "LEFT JOIN pg_init_privs pip ON "
9361                                                   "(d.oid = pip.objoid "
9362                                                   "AND pip.classoid = 'pg_default_acl'::regclass "
9363                                                   "AND pip.objsubid = 0) ",
9364                                                   username_subquery,
9365                                                   acl_subquery->data,
9366                                                   racl_subquery->data,
9367                                                   initacl_subquery->data,
9368                                                   initracl_subquery->data);
9369         }
9370         else
9371         {
9372                 appendPQExpBuffer(query, "SELECT oid, tableoid, "
9373                                                   "(%s defaclrole) AS defaclrole, "
9374                                                   "defaclnamespace, "
9375                                                   "defaclobjtype, "
9376                                                   "defaclacl, "
9377                                                   "NULL AS rdefaclacl, "
9378                                                   "NULL AS initdefaclacl, "
9379                                                   "NULL AS initrdefaclacl "
9380                                                   "FROM pg_default_acl",
9381                                                   username_subquery);
9382         }
9383
9384         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9385
9386         ntups = PQntuples(res);
9387         *numDefaultACLs = ntups;
9388
9389         daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
9390
9391         i_oid = PQfnumber(res, "oid");
9392         i_tableoid = PQfnumber(res, "tableoid");
9393         i_defaclrole = PQfnumber(res, "defaclrole");
9394         i_defaclnamespace = PQfnumber(res, "defaclnamespace");
9395         i_defaclobjtype = PQfnumber(res, "defaclobjtype");
9396         i_defaclacl = PQfnumber(res, "defaclacl");
9397         i_rdefaclacl = PQfnumber(res, "rdefaclacl");
9398         i_initdefaclacl = PQfnumber(res, "initdefaclacl");
9399         i_initrdefaclacl = PQfnumber(res, "initrdefaclacl");
9400
9401         for (i = 0; i < ntups; i++)
9402         {
9403                 Oid                     nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
9404
9405                 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
9406                 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9407                 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9408                 AssignDumpId(&daclinfo[i].dobj);
9409                 /* cheesy ... is it worth coming up with a better object name? */
9410                 daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
9411
9412                 if (nspid != InvalidOid)
9413                         daclinfo[i].dobj.namespace = findNamespace(fout, nspid);
9414                 else
9415                         daclinfo[i].dobj.namespace = NULL;
9416
9417                 daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
9418                 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
9419                 daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
9420                 daclinfo[i].rdefaclacl = pg_strdup(PQgetvalue(res, i, i_rdefaclacl));
9421                 daclinfo[i].initdefaclacl = pg_strdup(PQgetvalue(res, i, i_initdefaclacl));
9422                 daclinfo[i].initrdefaclacl = pg_strdup(PQgetvalue(res, i, i_initrdefaclacl));
9423
9424                 /* Decide whether we want to dump it */
9425                 selectDumpableDefaultACL(&(daclinfo[i]), dopt);
9426         }
9427
9428         PQclear(res);
9429
9430         destroyPQExpBuffer(query);
9431
9432         return daclinfo;
9433 }
9434
9435 /*
9436  * dumpComment --
9437  *
9438  * This routine is used to dump any comments associated with the
9439  * object handed to this routine. The routine takes the object type
9440  * and object name (ready to print, except for schema decoration), plus
9441  * the namespace and owner of the object (for labeling the ArchiveEntry),
9442  * plus catalog ID and subid which are the lookup key for pg_description,
9443  * plus the dump ID for the object (for setting a dependency).
9444  * If a matching pg_description entry is found, it is dumped.
9445  *
9446  * Note: in some cases, such as comments for triggers and rules, the "type"
9447  * string really looks like, e.g., "TRIGGER name ON".  This is a bit of a hack
9448  * but it doesn't seem worth complicating the API for all callers to make
9449  * it cleaner.
9450  *
9451  * Note: although this routine takes a dumpId for dependency purposes,
9452  * that purpose is just to mark the dependency in the emitted dump file
9453  * for possible future use by pg_restore.  We do NOT use it for determining
9454  * ordering of the comment in the dump file, because this routine is called
9455  * after dependency sorting occurs.  This routine should be called just after
9456  * calling ArchiveEntry() for the specified object.
9457  */
9458 static void
9459 dumpComment(Archive *fout, const char *type, const char *name,
9460                         const char *namespace, const char *owner,
9461                         CatalogId catalogId, int subid, DumpId dumpId)
9462 {
9463         DumpOptions *dopt = fout->dopt;
9464         CommentItem *comments;
9465         int                     ncomments;
9466
9467         /* do nothing, if --no-comments is supplied */
9468         if (dopt->no_comments)
9469                 return;
9470
9471         /* Comments are schema not data ... except blob comments are data */
9472         if (strcmp(type, "LARGE OBJECT") != 0)
9473         {
9474                 if (dopt->dataOnly)
9475                         return;
9476         }
9477         else
9478         {
9479                 /* We do dump blob comments in binary-upgrade mode */
9480                 if (dopt->schemaOnly && !dopt->binary_upgrade)
9481                         return;
9482         }
9483
9484         /* Search for comments associated with catalogId, using table */
9485         ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
9486                                                          &comments);
9487
9488         /* Is there one matching the subid? */
9489         while (ncomments > 0)
9490         {
9491                 if (comments->objsubid == subid)
9492                         break;
9493                 comments++;
9494                 ncomments--;
9495         }
9496
9497         /* If a comment exists, build COMMENT ON statement */
9498         if (ncomments > 0)
9499         {
9500                 PQExpBuffer query = createPQExpBuffer();
9501                 PQExpBuffer tag = createPQExpBuffer();
9502
9503                 appendPQExpBuffer(query, "COMMENT ON %s ", type);
9504                 if (namespace && *namespace)
9505                         appendPQExpBuffer(query, "%s.", fmtId(namespace));
9506                 appendPQExpBuffer(query, "%s IS ", name);
9507                 appendStringLiteralAH(query, comments->descr, fout);
9508                 appendPQExpBufferStr(query, ";\n");
9509
9510                 appendPQExpBuffer(tag, "%s %s", type, name);
9511
9512                 /*
9513                  * We mark comments as SECTION_NONE because they really belong in the
9514                  * same section as their parent, whether that is pre-data or
9515                  * post-data.
9516                  */
9517                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
9518                                          ARCHIVE_OPTS(.tag = tag->data,
9519                                                                   .namespace = namespace,
9520                                                                   .owner = owner,
9521                                                                   .description = "COMMENT",
9522                                                                   .section = SECTION_NONE,
9523                                                                   .createStmt = query->data,
9524                                                                   .deps = &dumpId,
9525                                                                   .nDeps = 1));
9526
9527                 destroyPQExpBuffer(query);
9528                 destroyPQExpBuffer(tag);
9529         }
9530 }
9531
9532 /*
9533  * dumpTableComment --
9534  *
9535  * As above, but dump comments for both the specified table (or view)
9536  * and its columns.
9537  */
9538 static void
9539 dumpTableComment(Archive *fout, TableInfo *tbinfo,
9540                                  const char *reltypename)
9541 {
9542         DumpOptions *dopt = fout->dopt;
9543         CommentItem *comments;
9544         int                     ncomments;
9545         PQExpBuffer query;
9546         PQExpBuffer tag;
9547
9548         /* do nothing, if --no-comments is supplied */
9549         if (dopt->no_comments)
9550                 return;
9551
9552         /* Comments are SCHEMA not data */
9553         if (dopt->dataOnly)
9554                 return;
9555
9556         /* Search for comments associated with relation, using table */
9557         ncomments = findComments(fout,
9558                                                          tbinfo->dobj.catId.tableoid,
9559                                                          tbinfo->dobj.catId.oid,
9560                                                          &comments);
9561
9562         /* If comments exist, build COMMENT ON statements */
9563         if (ncomments <= 0)
9564                 return;
9565
9566         query = createPQExpBuffer();
9567         tag = createPQExpBuffer();
9568
9569         while (ncomments > 0)
9570         {
9571                 const char *descr = comments->descr;
9572                 int                     objsubid = comments->objsubid;
9573
9574                 if (objsubid == 0)
9575                 {
9576                         resetPQExpBuffer(tag);
9577                         appendPQExpBuffer(tag, "%s %s", reltypename,
9578                                                           fmtId(tbinfo->dobj.name));
9579
9580                         resetPQExpBuffer(query);
9581                         appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
9582                                                           fmtQualifiedDumpable(tbinfo));
9583                         appendStringLiteralAH(query, descr, fout);
9584                         appendPQExpBufferStr(query, ";\n");
9585
9586                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
9587                                                  ARCHIVE_OPTS(.tag = tag->data,
9588                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
9589                                                                           .owner = tbinfo->rolname,
9590                                                                           .description = "COMMENT",
9591                                                                           .section = SECTION_NONE,
9592                                                                           .createStmt = query->data,
9593                                                                           .deps = &(tbinfo->dobj.dumpId),
9594                                                                           .nDeps = 1));
9595                 }
9596                 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
9597                 {
9598                         resetPQExpBuffer(tag);
9599                         appendPQExpBuffer(tag, "COLUMN %s.",
9600                                                           fmtId(tbinfo->dobj.name));
9601                         appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
9602
9603                         resetPQExpBuffer(query);
9604                         appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
9605                                                           fmtQualifiedDumpable(tbinfo));
9606                         appendPQExpBuffer(query, "%s IS ",
9607                                                           fmtId(tbinfo->attnames[objsubid - 1]));
9608                         appendStringLiteralAH(query, descr, fout);
9609                         appendPQExpBufferStr(query, ";\n");
9610
9611                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
9612                                                  ARCHIVE_OPTS(.tag = tag->data,
9613                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
9614                                                                           .owner = tbinfo->rolname,
9615                                                                           .description = "COMMENT",
9616                                                                           .section = SECTION_NONE,
9617                                                                           .createStmt = query->data,
9618                                                                           .deps = &(tbinfo->dobj.dumpId),
9619                                                                           .nDeps = 1));
9620                 }
9621
9622                 comments++;
9623                 ncomments--;
9624         }
9625
9626         destroyPQExpBuffer(query);
9627         destroyPQExpBuffer(tag);
9628 }
9629
9630 /*
9631  * findComments --
9632  *
9633  * Find the comment(s), if any, associated with the given object.  All the
9634  * objsubid values associated with the given classoid/objoid are found with
9635  * one search.
9636  */
9637 static int
9638 findComments(Archive *fout, Oid classoid, Oid objoid,
9639                          CommentItem **items)
9640 {
9641         /* static storage for table of comments */
9642         static CommentItem *comments = NULL;
9643         static int      ncomments = -1;
9644
9645         CommentItem *middle = NULL;
9646         CommentItem *low;
9647         CommentItem *high;
9648         int                     nmatch;
9649
9650         /* Get comments if we didn't already */
9651         if (ncomments < 0)
9652                 ncomments = collectComments(fout, &comments);
9653
9654         /*
9655          * Do binary search to find some item matching the object.
9656          */
9657         low = &comments[0];
9658         high = &comments[ncomments - 1];
9659         while (low <= high)
9660         {
9661                 middle = low + (high - low) / 2;
9662
9663                 if (classoid < middle->classoid)
9664                         high = middle - 1;
9665                 else if (classoid > middle->classoid)
9666                         low = middle + 1;
9667                 else if (objoid < middle->objoid)
9668                         high = middle - 1;
9669                 else if (objoid > middle->objoid)
9670                         low = middle + 1;
9671                 else
9672                         break;                          /* found a match */
9673         }
9674
9675         if (low > high)                         /* no matches */
9676         {
9677                 *items = NULL;
9678                 return 0;
9679         }
9680
9681         /*
9682          * Now determine how many items match the object.  The search loop
9683          * invariant still holds: only items between low and high inclusive could
9684          * match.
9685          */
9686         nmatch = 1;
9687         while (middle > low)
9688         {
9689                 if (classoid != middle[-1].classoid ||
9690                         objoid != middle[-1].objoid)
9691                         break;
9692                 middle--;
9693                 nmatch++;
9694         }
9695
9696         *items = middle;
9697
9698         middle += nmatch;
9699         while (middle <= high)
9700         {
9701                 if (classoid != middle->classoid ||
9702                         objoid != middle->objoid)
9703                         break;
9704                 middle++;
9705                 nmatch++;
9706         }
9707
9708         return nmatch;
9709 }
9710
9711 /*
9712  * collectComments --
9713  *
9714  * Construct a table of all comments available for database objects.
9715  * We used to do per-object queries for the comments, but it's much faster
9716  * to pull them all over at once, and on most databases the memory cost
9717  * isn't high.
9718  *
9719  * The table is sorted by classoid/objid/objsubid for speed in lookup.
9720  */
9721 static int
9722 collectComments(Archive *fout, CommentItem **items)
9723 {
9724         PGresult   *res;
9725         PQExpBuffer query;
9726         int                     i_description;
9727         int                     i_classoid;
9728         int                     i_objoid;
9729         int                     i_objsubid;
9730         int                     ntups;
9731         int                     i;
9732         CommentItem *comments;
9733
9734         query = createPQExpBuffer();
9735
9736         appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
9737                                                  "FROM pg_catalog.pg_description "
9738                                                  "ORDER BY classoid, objoid, objsubid");
9739
9740         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9741
9742         /* Construct lookup table containing OIDs in numeric form */
9743
9744         i_description = PQfnumber(res, "description");
9745         i_classoid = PQfnumber(res, "classoid");
9746         i_objoid = PQfnumber(res, "objoid");
9747         i_objsubid = PQfnumber(res, "objsubid");
9748
9749         ntups = PQntuples(res);
9750
9751         comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
9752
9753         for (i = 0; i < ntups; i++)
9754         {
9755                 comments[i].descr = PQgetvalue(res, i, i_description);
9756                 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
9757                 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
9758                 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
9759         }
9760
9761         /* Do NOT free the PGresult since we are keeping pointers into it */
9762         destroyPQExpBuffer(query);
9763
9764         *items = comments;
9765         return ntups;
9766 }
9767
9768 /*
9769  * dumpDumpableObject
9770  *
9771  * This routine and its subsidiaries are responsible for creating
9772  * ArchiveEntries (TOC objects) for each object to be dumped.
9773  */
9774 static void
9775 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
9776 {
9777         switch (dobj->objType)
9778         {
9779                 case DO_NAMESPACE:
9780                         dumpNamespace(fout, (NamespaceInfo *) dobj);
9781                         break;
9782                 case DO_EXTENSION:
9783                         dumpExtension(fout, (ExtensionInfo *) dobj);
9784                         break;
9785                 case DO_TYPE:
9786                         dumpType(fout, (TypeInfo *) dobj);
9787                         break;
9788                 case DO_SHELL_TYPE:
9789                         dumpShellType(fout, (ShellTypeInfo *) dobj);
9790                         break;
9791                 case DO_FUNC:
9792                         dumpFunc(fout, (FuncInfo *) dobj);
9793                         break;
9794                 case DO_AGG:
9795                         dumpAgg(fout, (AggInfo *) dobj);
9796                         break;
9797                 case DO_OPERATOR:
9798                         dumpOpr(fout, (OprInfo *) dobj);
9799                         break;
9800                 case DO_ACCESS_METHOD:
9801                         dumpAccessMethod(fout, (AccessMethodInfo *) dobj);
9802                         break;
9803                 case DO_OPCLASS:
9804                         dumpOpclass(fout, (OpclassInfo *) dobj);
9805                         break;
9806                 case DO_OPFAMILY:
9807                         dumpOpfamily(fout, (OpfamilyInfo *) dobj);
9808                         break;
9809                 case DO_COLLATION:
9810                         dumpCollation(fout, (CollInfo *) dobj);
9811                         break;
9812                 case DO_CONVERSION:
9813                         dumpConversion(fout, (ConvInfo *) dobj);
9814                         break;
9815                 case DO_TABLE:
9816                         dumpTable(fout, (TableInfo *) dobj);
9817                         break;
9818                 case DO_ATTRDEF:
9819                         dumpAttrDef(fout, (AttrDefInfo *) dobj);
9820                         break;
9821                 case DO_INDEX:
9822                         dumpIndex(fout, (IndxInfo *) dobj);
9823                         break;
9824                 case DO_INDEX_ATTACH:
9825                         dumpIndexAttach(fout, (IndexAttachInfo *) dobj);
9826                         break;
9827                 case DO_STATSEXT:
9828                         dumpStatisticsExt(fout, (StatsExtInfo *) dobj);
9829                         break;
9830                 case DO_REFRESH_MATVIEW:
9831                         refreshMatViewData(fout, (TableDataInfo *) dobj);
9832                         break;
9833                 case DO_RULE:
9834                         dumpRule(fout, (RuleInfo *) dobj);
9835                         break;
9836                 case DO_TRIGGER:
9837                         dumpTrigger(fout, (TriggerInfo *) dobj);
9838                         break;
9839                 case DO_EVENT_TRIGGER:
9840                         dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
9841                         break;
9842                 case DO_CONSTRAINT:
9843                         dumpConstraint(fout, (ConstraintInfo *) dobj);
9844                         break;
9845                 case DO_FK_CONSTRAINT:
9846                         dumpConstraint(fout, (ConstraintInfo *) dobj);
9847                         break;
9848                 case DO_PROCLANG:
9849                         dumpProcLang(fout, (ProcLangInfo *) dobj);
9850                         break;
9851                 case DO_CAST:
9852                         dumpCast(fout, (CastInfo *) dobj);
9853                         break;
9854                 case DO_TRANSFORM:
9855                         dumpTransform(fout, (TransformInfo *) dobj);
9856                         break;
9857                 case DO_SEQUENCE_SET:
9858                         dumpSequenceData(fout, (TableDataInfo *) dobj);
9859                         break;
9860                 case DO_TABLE_DATA:
9861                         dumpTableData(fout, (TableDataInfo *) dobj);
9862                         break;
9863                 case DO_DUMMY_TYPE:
9864                         /* table rowtypes and array types are never dumped separately */
9865                         break;
9866                 case DO_TSPARSER:
9867                         dumpTSParser(fout, (TSParserInfo *) dobj);
9868                         break;
9869                 case DO_TSDICT:
9870                         dumpTSDictionary(fout, (TSDictInfo *) dobj);
9871                         break;
9872                 case DO_TSTEMPLATE:
9873                         dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
9874                         break;
9875                 case DO_TSCONFIG:
9876                         dumpTSConfig(fout, (TSConfigInfo *) dobj);
9877                         break;
9878                 case DO_FDW:
9879                         dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
9880                         break;
9881                 case DO_FOREIGN_SERVER:
9882                         dumpForeignServer(fout, (ForeignServerInfo *) dobj);
9883                         break;
9884                 case DO_DEFAULT_ACL:
9885                         dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
9886                         break;
9887                 case DO_BLOB:
9888                         dumpBlob(fout, (BlobInfo *) dobj);
9889                         break;
9890                 case DO_BLOB_DATA:
9891                         if (dobj->dump & DUMP_COMPONENT_DATA)
9892                         {
9893                                 TocEntry   *te;
9894
9895                                 te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
9896                                                                   ARCHIVE_OPTS(.tag = dobj->name,
9897                                                                                            .description = "BLOBS",
9898                                                                                            .section = SECTION_DATA,
9899                                                                                            .dumpFn = dumpBlobs));
9900
9901                                 /*
9902                                  * Set the TocEntry's dataLength in case we are doing a
9903                                  * parallel dump and want to order dump jobs by table size.
9904                                  * (We need some size estimate for every TocEntry with a
9905                                  * DataDumper function.)  We don't currently have any cheap
9906                                  * way to estimate the size of blobs, but it doesn't matter;
9907                                  * let's just set the size to a large value so parallel dumps
9908                                  * will launch this job first.  If there's lots of blobs, we
9909                                  * win, and if there aren't, we don't lose much.  (If you want
9910                                  * to improve on this, really what you should be thinking
9911                                  * about is allowing blob dumping to be parallelized, not just
9912                                  * getting a smarter estimate for the single TOC entry.)
9913                                  */
9914                                 te->dataLength = MaxBlockNumber;
9915                         }
9916                         break;
9917                 case DO_POLICY:
9918                         dumpPolicy(fout, (PolicyInfo *) dobj);
9919                         break;
9920                 case DO_PUBLICATION:
9921                         dumpPublication(fout, (PublicationInfo *) dobj);
9922                         break;
9923                 case DO_PUBLICATION_REL:
9924                         dumpPublicationTable(fout, (PublicationRelInfo *) dobj);
9925                         break;
9926                 case DO_SUBSCRIPTION:
9927                         dumpSubscription(fout, (SubscriptionInfo *) dobj);
9928                         break;
9929                 case DO_PRE_DATA_BOUNDARY:
9930                 case DO_POST_DATA_BOUNDARY:
9931                         /* never dumped, nothing to do */
9932                         break;
9933         }
9934 }
9935
9936 /*
9937  * dumpNamespace
9938  *        writes out to fout the queries to recreate a user-defined namespace
9939  */
9940 static void
9941 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
9942 {
9943         DumpOptions *dopt = fout->dopt;
9944         PQExpBuffer q;
9945         PQExpBuffer delq;
9946         char       *qnspname;
9947
9948         /* Skip if not to be dumped */
9949         if (!nspinfo->dobj.dump || dopt->dataOnly)
9950                 return;
9951
9952         q = createPQExpBuffer();
9953         delq = createPQExpBuffer();
9954
9955         qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
9956
9957         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
9958
9959         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
9960
9961         if (dopt->binary_upgrade)
9962                 binary_upgrade_extension_member(q, &nspinfo->dobj,
9963                                                                                 "SCHEMA", qnspname, NULL);
9964
9965         if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
9966                 ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
9967                                          ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
9968                                                                   .owner = nspinfo->rolname,
9969                                                                   .description = "SCHEMA",
9970                                                                   .section = SECTION_PRE_DATA,
9971                                                                   .createStmt = q->data,
9972                                                                   .dropStmt = delq->data));
9973
9974         /* Dump Schema Comments and Security Labels */
9975         if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
9976                 dumpComment(fout, "SCHEMA", qnspname,
9977                                         NULL, nspinfo->rolname,
9978                                         nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
9979
9980         if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
9981                 dumpSecLabel(fout, "SCHEMA", qnspname,
9982                                          NULL, nspinfo->rolname,
9983                                          nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
9984
9985         if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
9986                 dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
9987                                 qnspname, NULL, NULL,
9988                                 nspinfo->rolname, nspinfo->nspacl, nspinfo->rnspacl,
9989                                 nspinfo->initnspacl, nspinfo->initrnspacl);
9990
9991         free(qnspname);
9992
9993         destroyPQExpBuffer(q);
9994         destroyPQExpBuffer(delq);
9995 }
9996
9997 /*
9998  * dumpExtension
9999  *        writes out to fout the queries to recreate an extension
10000  */
10001 static void
10002 dumpExtension(Archive *fout, ExtensionInfo *extinfo)
10003 {
10004         DumpOptions *dopt = fout->dopt;
10005         PQExpBuffer q;
10006         PQExpBuffer delq;
10007         char       *qextname;
10008
10009         /* Skip if not to be dumped */
10010         if (!extinfo->dobj.dump || dopt->dataOnly)
10011                 return;
10012
10013         q = createPQExpBuffer();
10014         delq = createPQExpBuffer();
10015
10016         qextname = pg_strdup(fmtId(extinfo->dobj.name));
10017
10018         appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
10019
10020         if (!dopt->binary_upgrade)
10021         {
10022                 /*
10023                  * In a regular dump, we simply create the extension, intentionally
10024                  * not specifying a version, so that the destination installation's
10025                  * default version is used.
10026                  *
10027                  * Use of IF NOT EXISTS here is unlike our behavior for other object
10028                  * types; but there are various scenarios in which it's convenient to
10029                  * manually create the desired extension before restoring, so we
10030                  * prefer to allow it to exist already.
10031                  */
10032                 appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
10033                                                   qextname, fmtId(extinfo->namespace));
10034         }
10035         else
10036         {
10037                 /*
10038                  * In binary-upgrade mode, it's critical to reproduce the state of the
10039                  * database exactly, so our procedure is to create an empty extension,
10040                  * restore all the contained objects normally, and add them to the
10041                  * extension one by one.  This function performs just the first of
10042                  * those steps.  binary_upgrade_extension_member() takes care of
10043                  * adding member objects as they're created.
10044                  */
10045                 int                     i;
10046                 int                     n;
10047
10048                 appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
10049
10050                 /*
10051                  * We unconditionally create the extension, so we must drop it if it
10052                  * exists.  This could happen if the user deleted 'plpgsql' and then
10053                  * readded it, causing its oid to be greater than g_last_builtin_oid.
10054                  */
10055                 appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
10056
10057                 appendPQExpBufferStr(q,
10058                                                          "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
10059                 appendStringLiteralAH(q, extinfo->dobj.name, fout);
10060                 appendPQExpBufferStr(q, ", ");
10061                 appendStringLiteralAH(q, extinfo->namespace, fout);
10062                 appendPQExpBufferStr(q, ", ");
10063                 appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
10064                 appendStringLiteralAH(q, extinfo->extversion, fout);
10065                 appendPQExpBufferStr(q, ", ");
10066
10067                 /*
10068                  * Note that we're pushing extconfig (an OID array) back into
10069                  * pg_extension exactly as-is.  This is OK because pg_class OIDs are
10070                  * preserved in binary upgrade.
10071                  */
10072                 if (strlen(extinfo->extconfig) > 2)
10073                         appendStringLiteralAH(q, extinfo->extconfig, fout);
10074                 else
10075                         appendPQExpBufferStr(q, "NULL");
10076                 appendPQExpBufferStr(q, ", ");
10077                 if (strlen(extinfo->extcondition) > 2)
10078                         appendStringLiteralAH(q, extinfo->extcondition, fout);
10079                 else
10080                         appendPQExpBufferStr(q, "NULL");
10081                 appendPQExpBufferStr(q, ", ");
10082                 appendPQExpBufferStr(q, "ARRAY[");
10083                 n = 0;
10084                 for (i = 0; i < extinfo->dobj.nDeps; i++)
10085                 {
10086                         DumpableObject *extobj;
10087
10088                         extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
10089                         if (extobj && extobj->objType == DO_EXTENSION)
10090                         {
10091                                 if (n++ > 0)
10092                                         appendPQExpBufferChar(q, ',');
10093                                 appendStringLiteralAH(q, extobj->name, fout);
10094                         }
10095                 }
10096                 appendPQExpBufferStr(q, "]::pg_catalog.text[]");
10097                 appendPQExpBufferStr(q, ");\n");
10098         }
10099
10100         if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10101                 ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
10102                                          ARCHIVE_OPTS(.tag = extinfo->dobj.name,
10103                                                                   .description = "EXTENSION",
10104                                                                   .section = SECTION_PRE_DATA,
10105                                                                   .createStmt = q->data,
10106                                                                   .dropStmt = delq->data));
10107
10108         /* Dump Extension Comments and Security Labels */
10109         if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10110                 dumpComment(fout, "EXTENSION", qextname,
10111                                         NULL, "",
10112                                         extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
10113
10114         if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10115                 dumpSecLabel(fout, "EXTENSION", qextname,
10116                                          NULL, "",
10117                                          extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
10118
10119         free(qextname);
10120
10121         destroyPQExpBuffer(q);
10122         destroyPQExpBuffer(delq);
10123 }
10124
10125 /*
10126  * dumpType
10127  *        writes out to fout the queries to recreate a user-defined type
10128  */
10129 static void
10130 dumpType(Archive *fout, TypeInfo *tyinfo)
10131 {
10132         DumpOptions *dopt = fout->dopt;
10133
10134         /* Skip if not to be dumped */
10135         if (!tyinfo->dobj.dump || dopt->dataOnly)
10136                 return;
10137
10138         /* Dump out in proper style */
10139         if (tyinfo->typtype == TYPTYPE_BASE)
10140                 dumpBaseType(fout, tyinfo);
10141         else if (tyinfo->typtype == TYPTYPE_DOMAIN)
10142                 dumpDomain(fout, tyinfo);
10143         else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
10144                 dumpCompositeType(fout, tyinfo);
10145         else if (tyinfo->typtype == TYPTYPE_ENUM)
10146                 dumpEnumType(fout, tyinfo);
10147         else if (tyinfo->typtype == TYPTYPE_RANGE)
10148                 dumpRangeType(fout, tyinfo);
10149         else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
10150                 dumpUndefinedType(fout, tyinfo);
10151         else
10152                 pg_log_warning("typtype of data type \"%s\" appears to be invalid",
10153                                            tyinfo->dobj.name);
10154 }
10155
10156 /*
10157  * dumpEnumType
10158  *        writes out to fout the queries to recreate a user-defined enum type
10159  */
10160 static void
10161 dumpEnumType(Archive *fout, TypeInfo *tyinfo)
10162 {
10163         DumpOptions *dopt = fout->dopt;
10164         PQExpBuffer q = createPQExpBuffer();
10165         PQExpBuffer delq = createPQExpBuffer();
10166         PQExpBuffer query = createPQExpBuffer();
10167         PGresult   *res;
10168         int                     num,
10169                                 i;
10170         Oid                     enum_oid;
10171         char       *qtypname;
10172         char       *qualtypname;
10173         char       *label;
10174
10175         if (fout->remoteVersion >= 90100)
10176                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
10177                                                   "FROM pg_catalog.pg_enum "
10178                                                   "WHERE enumtypid = '%u'"
10179                                                   "ORDER BY enumsortorder",
10180                                                   tyinfo->dobj.catId.oid);
10181         else
10182                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
10183                                                   "FROM pg_catalog.pg_enum "
10184                                                   "WHERE enumtypid = '%u'"
10185                                                   "ORDER BY oid",
10186                                                   tyinfo->dobj.catId.oid);
10187
10188         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10189
10190         num = PQntuples(res);
10191
10192         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10193         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10194
10195         /*
10196          * CASCADE shouldn't be required here as for normal types since the I/O
10197          * functions are generic and do not get dropped.
10198          */
10199         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10200
10201         if (dopt->binary_upgrade)
10202                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10203                                                                                                  tyinfo->dobj.catId.oid,
10204                                                                                                  false);
10205
10206         appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
10207                                           qualtypname);
10208
10209         if (!dopt->binary_upgrade)
10210         {
10211                 /* Labels with server-assigned oids */
10212                 for (i = 0; i < num; i++)
10213                 {
10214                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
10215                         if (i > 0)
10216                                 appendPQExpBufferChar(q, ',');
10217                         appendPQExpBufferStr(q, "\n    ");
10218                         appendStringLiteralAH(q, label, fout);
10219                 }
10220         }
10221
10222         appendPQExpBufferStr(q, "\n);\n");
10223
10224         if (dopt->binary_upgrade)
10225         {
10226                 /* Labels with dump-assigned (preserved) oids */
10227                 for (i = 0; i < num; i++)
10228                 {
10229                         enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
10230                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
10231
10232                         if (i == 0)
10233                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
10234                         appendPQExpBuffer(q,
10235                                                           "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
10236                                                           enum_oid);
10237                         appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
10238                         appendStringLiteralAH(q, label, fout);
10239                         appendPQExpBufferStr(q, ";\n\n");
10240                 }
10241         }
10242
10243         if (dopt->binary_upgrade)
10244                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10245                                                                                 "TYPE", qtypname,
10246                                                                                 tyinfo->dobj.namespace->dobj.name);
10247
10248         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10249                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10250                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10251                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10252                                                                   .owner = tyinfo->rolname,
10253                                                                   .description = "TYPE",
10254                                                                   .section = SECTION_PRE_DATA,
10255                                                                   .createStmt = q->data,
10256                                                                   .dropStmt = delq->data));
10257
10258         /* Dump Type Comments and Security Labels */
10259         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10260                 dumpComment(fout, "TYPE", qtypname,
10261                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10262                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10263
10264         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10265                 dumpSecLabel(fout, "TYPE", qtypname,
10266                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10267                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10268
10269         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10270                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10271                                 qtypname, NULL,
10272                                 tyinfo->dobj.namespace->dobj.name,
10273                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10274                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10275
10276         PQclear(res);
10277         destroyPQExpBuffer(q);
10278         destroyPQExpBuffer(delq);
10279         destroyPQExpBuffer(query);
10280         free(qtypname);
10281         free(qualtypname);
10282 }
10283
10284 /*
10285  * dumpRangeType
10286  *        writes out to fout the queries to recreate a user-defined range type
10287  */
10288 static void
10289 dumpRangeType(Archive *fout, TypeInfo *tyinfo)
10290 {
10291         DumpOptions *dopt = fout->dopt;
10292         PQExpBuffer q = createPQExpBuffer();
10293         PQExpBuffer delq = createPQExpBuffer();
10294         PQExpBuffer query = createPQExpBuffer();
10295         PGresult   *res;
10296         Oid                     collationOid;
10297         char       *qtypname;
10298         char       *qualtypname;
10299         char       *procname;
10300
10301         appendPQExpBuffer(query,
10302                                           "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
10303                                           "opc.opcname AS opcname, "
10304                                           "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
10305                                           "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
10306                                           "opc.opcdefault, "
10307                                           "CASE WHEN rngcollation = st.typcollation THEN 0 "
10308                                           "     ELSE rngcollation END AS collation, "
10309                                           "rngcanonical, rngsubdiff "
10310                                           "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
10311                                           "     pg_catalog.pg_opclass opc "
10312                                           "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
10313                                           "rngtypid = '%u'",
10314                                           tyinfo->dobj.catId.oid);
10315
10316         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10317
10318         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10319         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10320
10321         /*
10322          * CASCADE shouldn't be required here as for normal types since the I/O
10323          * functions are generic and do not get dropped.
10324          */
10325         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10326
10327         if (dopt->binary_upgrade)
10328                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10329                                                                                                  tyinfo->dobj.catId.oid,
10330                                                                                                  false);
10331
10332         appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
10333                                           qualtypname);
10334
10335         appendPQExpBuffer(q, "\n    subtype = %s",
10336                                           PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
10337
10338         /* print subtype_opclass only if not default for subtype */
10339         if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
10340         {
10341                 char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
10342                 char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
10343
10344                 appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
10345                                                   fmtId(nspname));
10346                 appendPQExpBufferStr(q, fmtId(opcname));
10347         }
10348
10349         collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
10350         if (OidIsValid(collationOid))
10351         {
10352                 CollInfo   *coll = findCollationByOid(collationOid);
10353
10354                 if (coll)
10355                         appendPQExpBuffer(q, ",\n    collation = %s",
10356                                                           fmtQualifiedDumpable(coll));
10357         }
10358
10359         procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
10360         if (strcmp(procname, "-") != 0)
10361                 appendPQExpBuffer(q, ",\n    canonical = %s", procname);
10362
10363         procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
10364         if (strcmp(procname, "-") != 0)
10365                 appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
10366
10367         appendPQExpBufferStr(q, "\n);\n");
10368
10369         if (dopt->binary_upgrade)
10370                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10371                                                                                 "TYPE", qtypname,
10372                                                                                 tyinfo->dobj.namespace->dobj.name);
10373
10374         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10375                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10376                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10377                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10378                                                                   .owner = tyinfo->rolname,
10379                                                                   .description = "TYPE",
10380                                                                   .section = SECTION_PRE_DATA,
10381                                                                   .createStmt = q->data,
10382                                                                   .dropStmt = delq->data));
10383
10384         /* Dump Type Comments and Security Labels */
10385         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10386                 dumpComment(fout, "TYPE", qtypname,
10387                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10388                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10389
10390         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10391                 dumpSecLabel(fout, "TYPE", qtypname,
10392                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10393                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10394
10395         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10396                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10397                                 qtypname, NULL,
10398                                 tyinfo->dobj.namespace->dobj.name,
10399                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10400                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10401
10402         PQclear(res);
10403         destroyPQExpBuffer(q);
10404         destroyPQExpBuffer(delq);
10405         destroyPQExpBuffer(query);
10406         free(qtypname);
10407         free(qualtypname);
10408 }
10409
10410 /*
10411  * dumpUndefinedType
10412  *        writes out to fout the queries to recreate a !typisdefined type
10413  *
10414  * This is a shell type, but we use different terminology to distinguish
10415  * this case from where we have to emit a shell type definition to break
10416  * circular dependencies.  An undefined type shouldn't ever have anything
10417  * depending on it.
10418  */
10419 static void
10420 dumpUndefinedType(Archive *fout, TypeInfo *tyinfo)
10421 {
10422         DumpOptions *dopt = fout->dopt;
10423         PQExpBuffer q = createPQExpBuffer();
10424         PQExpBuffer delq = createPQExpBuffer();
10425         char       *qtypname;
10426         char       *qualtypname;
10427
10428         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10429         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10430
10431         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10432
10433         if (dopt->binary_upgrade)
10434                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10435                                                                                                  tyinfo->dobj.catId.oid,
10436                                                                                                  false);
10437
10438         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
10439                                           qualtypname);
10440
10441         if (dopt->binary_upgrade)
10442                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10443                                                                                 "TYPE", qtypname,
10444                                                                                 tyinfo->dobj.namespace->dobj.name);
10445
10446         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10447                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10448                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10449                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10450                                                                   .owner = tyinfo->rolname,
10451                                                                   .description = "TYPE",
10452                                                                   .section = SECTION_PRE_DATA,
10453                                                                   .createStmt = q->data,
10454                                                                   .dropStmt = delq->data));
10455
10456         /* Dump Type Comments and Security Labels */
10457         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10458                 dumpComment(fout, "TYPE", qtypname,
10459                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10460                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10461
10462         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10463                 dumpSecLabel(fout, "TYPE", qtypname,
10464                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10465                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10466
10467         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10468                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10469                                 qtypname, NULL,
10470                                 tyinfo->dobj.namespace->dobj.name,
10471                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10472                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10473
10474         destroyPQExpBuffer(q);
10475         destroyPQExpBuffer(delq);
10476         free(qtypname);
10477         free(qualtypname);
10478 }
10479
10480 /*
10481  * dumpBaseType
10482  *        writes out to fout the queries to recreate a user-defined base type
10483  */
10484 static void
10485 dumpBaseType(Archive *fout, TypeInfo *tyinfo)
10486 {
10487         DumpOptions *dopt = fout->dopt;
10488         PQExpBuffer q = createPQExpBuffer();
10489         PQExpBuffer delq = createPQExpBuffer();
10490         PQExpBuffer query = createPQExpBuffer();
10491         PGresult   *res;
10492         char       *qtypname;
10493         char       *qualtypname;
10494         char       *typlen;
10495         char       *typinput;
10496         char       *typoutput;
10497         char       *typreceive;
10498         char       *typsend;
10499         char       *typmodin;
10500         char       *typmodout;
10501         char       *typanalyze;
10502         Oid                     typreceiveoid;
10503         Oid                     typsendoid;
10504         Oid                     typmodinoid;
10505         Oid                     typmodoutoid;
10506         Oid                     typanalyzeoid;
10507         char       *typcategory;
10508         char       *typispreferred;
10509         char       *typdelim;
10510         char       *typbyval;
10511         char       *typalign;
10512         char       *typstorage;
10513         char       *typcollatable;
10514         char       *typdefault;
10515         bool            typdefault_is_literal = false;
10516
10517         /* Fetch type-specific details */
10518         if (fout->remoteVersion >= 90100)
10519         {
10520                 appendPQExpBuffer(query, "SELECT typlen, "
10521                                                   "typinput, typoutput, typreceive, typsend, "
10522                                                   "typmodin, typmodout, typanalyze, "
10523                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10524                                                   "typsend::pg_catalog.oid AS typsendoid, "
10525                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10526                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10527                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10528                                                   "typcategory, typispreferred, "
10529                                                   "typdelim, typbyval, typalign, typstorage, "
10530                                                   "(typcollation <> 0) AS typcollatable, "
10531                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
10532                                                   "FROM pg_catalog.pg_type "
10533                                                   "WHERE oid = '%u'::pg_catalog.oid",
10534                                                   tyinfo->dobj.catId.oid);
10535         }
10536         else if (fout->remoteVersion >= 80400)
10537         {
10538                 appendPQExpBuffer(query, "SELECT typlen, "
10539                                                   "typinput, typoutput, typreceive, typsend, "
10540                                                   "typmodin, typmodout, typanalyze, "
10541                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10542                                                   "typsend::pg_catalog.oid AS typsendoid, "
10543                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10544                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10545                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10546                                                   "typcategory, typispreferred, "
10547                                                   "typdelim, typbyval, typalign, typstorage, "
10548                                                   "false AS typcollatable, "
10549                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
10550                                                   "FROM pg_catalog.pg_type "
10551                                                   "WHERE oid = '%u'::pg_catalog.oid",
10552                                                   tyinfo->dobj.catId.oid);
10553         }
10554         else if (fout->remoteVersion >= 80300)
10555         {
10556                 /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
10557                 appendPQExpBuffer(query, "SELECT typlen, "
10558                                                   "typinput, typoutput, typreceive, typsend, "
10559                                                   "typmodin, typmodout, typanalyze, "
10560                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10561                                                   "typsend::pg_catalog.oid AS typsendoid, "
10562                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10563                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10564                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10565                                                   "'U' AS typcategory, false AS typispreferred, "
10566                                                   "typdelim, typbyval, typalign, typstorage, "
10567                                                   "false AS typcollatable, "
10568                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10569                                                   "FROM pg_catalog.pg_type "
10570                                                   "WHERE oid = '%u'::pg_catalog.oid",
10571                                                   tyinfo->dobj.catId.oid);
10572         }
10573         else
10574         {
10575                 appendPQExpBuffer(query, "SELECT typlen, "
10576                                                   "typinput, typoutput, typreceive, typsend, "
10577                                                   "'-' AS typmodin, '-' AS typmodout, "
10578                                                   "typanalyze, "
10579                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10580                                                   "typsend::pg_catalog.oid AS typsendoid, "
10581                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
10582                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10583                                                   "'U' AS typcategory, false AS typispreferred, "
10584                                                   "typdelim, typbyval, typalign, typstorage, "
10585                                                   "false AS typcollatable, "
10586                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10587                                                   "FROM pg_catalog.pg_type "
10588                                                   "WHERE oid = '%u'::pg_catalog.oid",
10589                                                   tyinfo->dobj.catId.oid);
10590         }
10591
10592         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10593
10594         typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
10595         typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
10596         typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
10597         typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
10598         typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
10599         typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
10600         typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
10601         typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
10602         typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
10603         typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
10604         typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
10605         typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
10606         typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
10607         typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
10608         typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
10609         typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
10610         typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
10611         typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
10612         typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
10613         typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
10614         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
10615                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
10616         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
10617         {
10618                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
10619                 typdefault_is_literal = true;   /* it needs quotes */
10620         }
10621         else
10622                 typdefault = NULL;
10623
10624         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10625         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10626
10627         /*
10628          * The reason we include CASCADE is that the circular dependency between
10629          * the type and its I/O functions makes it impossible to drop the type any
10630          * other way.
10631          */
10632         appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
10633
10634         /*
10635          * We might already have a shell type, but setting pg_type_oid is
10636          * harmless, and in any case we'd better set the array type OID.
10637          */
10638         if (dopt->binary_upgrade)
10639                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10640                                                                                                  tyinfo->dobj.catId.oid,
10641                                                                                                  false);
10642
10643         appendPQExpBuffer(q,
10644                                           "CREATE TYPE %s (\n"
10645                                           "    INTERNALLENGTH = %s",
10646                                           qualtypname,
10647                                           (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
10648
10649         /* regproc result is sufficiently quoted already */
10650         appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
10651         appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
10652         if (OidIsValid(typreceiveoid))
10653                 appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
10654         if (OidIsValid(typsendoid))
10655                 appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
10656         if (OidIsValid(typmodinoid))
10657                 appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
10658         if (OidIsValid(typmodoutoid))
10659                 appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
10660         if (OidIsValid(typanalyzeoid))
10661                 appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
10662
10663         if (strcmp(typcollatable, "t") == 0)
10664                 appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
10665
10666         if (typdefault != NULL)
10667         {
10668                 appendPQExpBufferStr(q, ",\n    DEFAULT = ");
10669                 if (typdefault_is_literal)
10670                         appendStringLiteralAH(q, typdefault, fout);
10671                 else
10672                         appendPQExpBufferStr(q, typdefault);
10673         }
10674
10675         if (OidIsValid(tyinfo->typelem))
10676         {
10677                 char       *elemType;
10678
10679                 elemType = getFormattedTypeName(fout, tyinfo->typelem, zeroAsOpaque);
10680                 appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
10681                 free(elemType);
10682         }
10683
10684         if (strcmp(typcategory, "U") != 0)
10685         {
10686                 appendPQExpBufferStr(q, ",\n    CATEGORY = ");
10687                 appendStringLiteralAH(q, typcategory, fout);
10688         }
10689
10690         if (strcmp(typispreferred, "t") == 0)
10691                 appendPQExpBufferStr(q, ",\n    PREFERRED = true");
10692
10693         if (typdelim && strcmp(typdelim, ",") != 0)
10694         {
10695                 appendPQExpBufferStr(q, ",\n    DELIMITER = ");
10696                 appendStringLiteralAH(q, typdelim, fout);
10697         }
10698
10699         if (strcmp(typalign, "c") == 0)
10700                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
10701         else if (strcmp(typalign, "s") == 0)
10702                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
10703         else if (strcmp(typalign, "i") == 0)
10704                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
10705         else if (strcmp(typalign, "d") == 0)
10706                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
10707
10708         if (strcmp(typstorage, "p") == 0)
10709                 appendPQExpBufferStr(q, ",\n    STORAGE = plain");
10710         else if (strcmp(typstorage, "e") == 0)
10711                 appendPQExpBufferStr(q, ",\n    STORAGE = external");
10712         else if (strcmp(typstorage, "x") == 0)
10713                 appendPQExpBufferStr(q, ",\n    STORAGE = extended");
10714         else if (strcmp(typstorage, "m") == 0)
10715                 appendPQExpBufferStr(q, ",\n    STORAGE = main");
10716
10717         if (strcmp(typbyval, "t") == 0)
10718                 appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
10719
10720         appendPQExpBufferStr(q, "\n);\n");
10721
10722         if (dopt->binary_upgrade)
10723                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10724                                                                                 "TYPE", qtypname,
10725                                                                                 tyinfo->dobj.namespace->dobj.name);
10726
10727         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10728                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10729                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10730                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10731                                                                   .owner = tyinfo->rolname,
10732                                                                   .description = "TYPE",
10733                                                                   .section = SECTION_PRE_DATA,
10734                                                                   .createStmt = q->data,
10735                                                                   .dropStmt = delq->data));
10736
10737         /* Dump Type Comments and Security Labels */
10738         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10739                 dumpComment(fout, "TYPE", qtypname,
10740                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10741                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10742
10743         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10744                 dumpSecLabel(fout, "TYPE", qtypname,
10745                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10746                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10747
10748         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10749                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10750                                 qtypname, NULL,
10751                                 tyinfo->dobj.namespace->dobj.name,
10752                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10753                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10754
10755         PQclear(res);
10756         destroyPQExpBuffer(q);
10757         destroyPQExpBuffer(delq);
10758         destroyPQExpBuffer(query);
10759         free(qtypname);
10760         free(qualtypname);
10761 }
10762
10763 /*
10764  * dumpDomain
10765  *        writes out to fout the queries to recreate a user-defined domain
10766  */
10767 static void
10768 dumpDomain(Archive *fout, TypeInfo *tyinfo)
10769 {
10770         DumpOptions *dopt = fout->dopt;
10771         PQExpBuffer q = createPQExpBuffer();
10772         PQExpBuffer delq = createPQExpBuffer();
10773         PQExpBuffer query = createPQExpBuffer();
10774         PGresult   *res;
10775         int                     i;
10776         char       *qtypname;
10777         char       *qualtypname;
10778         char       *typnotnull;
10779         char       *typdefn;
10780         char       *typdefault;
10781         Oid                     typcollation;
10782         bool            typdefault_is_literal = false;
10783
10784         /* Fetch domain specific details */
10785         if (fout->remoteVersion >= 90100)
10786         {
10787                 /* typcollation is new in 9.1 */
10788                 appendPQExpBuffer(query, "SELECT t.typnotnull, "
10789                                                   "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
10790                                                   "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
10791                                                   "t.typdefault, "
10792                                                   "CASE WHEN t.typcollation <> u.typcollation "
10793                                                   "THEN t.typcollation ELSE 0 END AS typcollation "
10794                                                   "FROM pg_catalog.pg_type t "
10795                                                   "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
10796                                                   "WHERE t.oid = '%u'::pg_catalog.oid",
10797                                                   tyinfo->dobj.catId.oid);
10798         }
10799         else
10800         {
10801                 appendPQExpBuffer(query, "SELECT typnotnull, "
10802                                                   "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
10803                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
10804                                                   "typdefault, 0 AS typcollation "
10805                                                   "FROM pg_catalog.pg_type "
10806                                                   "WHERE oid = '%u'::pg_catalog.oid",
10807                                                   tyinfo->dobj.catId.oid);
10808         }
10809
10810         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10811
10812         typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
10813         typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
10814         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
10815                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
10816         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
10817         {
10818                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
10819                 typdefault_is_literal = true;   /* it needs quotes */
10820         }
10821         else
10822                 typdefault = NULL;
10823         typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
10824
10825         if (dopt->binary_upgrade)
10826                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10827                                                                                                  tyinfo->dobj.catId.oid,
10828                                                                                                  true); /* force array type */
10829
10830         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10831         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10832
10833         appendPQExpBuffer(q,
10834                                           "CREATE DOMAIN %s AS %s",
10835                                           qualtypname,
10836                                           typdefn);
10837
10838         /* Print collation only if different from base type's collation */
10839         if (OidIsValid(typcollation))
10840         {
10841                 CollInfo   *coll;
10842
10843                 coll = findCollationByOid(typcollation);
10844                 if (coll)
10845                         appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
10846         }
10847
10848         if (typnotnull[0] == 't')
10849                 appendPQExpBufferStr(q, " NOT NULL");
10850
10851         if (typdefault != NULL)
10852         {
10853                 appendPQExpBufferStr(q, " DEFAULT ");
10854                 if (typdefault_is_literal)
10855                         appendStringLiteralAH(q, typdefault, fout);
10856                 else
10857                         appendPQExpBufferStr(q, typdefault);
10858         }
10859
10860         PQclear(res);
10861
10862         /*
10863          * Add any CHECK constraints for the domain
10864          */
10865         for (i = 0; i < tyinfo->nDomChecks; i++)
10866         {
10867                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
10868
10869                 if (!domcheck->separate)
10870                         appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
10871                                                           fmtId(domcheck->dobj.name), domcheck->condef);
10872         }
10873
10874         appendPQExpBufferStr(q, ";\n");
10875
10876         appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
10877
10878         if (dopt->binary_upgrade)
10879                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10880                                                                                 "DOMAIN", qtypname,
10881                                                                                 tyinfo->dobj.namespace->dobj.name);
10882
10883         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10884                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10885                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10886                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10887                                                                   .owner = tyinfo->rolname,
10888                                                                   .description = "DOMAIN",
10889                                                                   .section = SECTION_PRE_DATA,
10890                                                                   .createStmt = q->data,
10891                                                                   .dropStmt = delq->data));
10892
10893         /* Dump Domain Comments and Security Labels */
10894         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10895                 dumpComment(fout, "DOMAIN", qtypname,
10896                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10897                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10898
10899         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10900                 dumpSecLabel(fout, "DOMAIN", qtypname,
10901                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10902                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10903
10904         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10905                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10906                                 qtypname, NULL,
10907                                 tyinfo->dobj.namespace->dobj.name,
10908                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10909                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10910
10911         /* Dump any per-constraint comments */
10912         for (i = 0; i < tyinfo->nDomChecks; i++)
10913         {
10914                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
10915                 PQExpBuffer conprefix = createPQExpBuffer();
10916
10917                 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
10918                                                   fmtId(domcheck->dobj.name));
10919
10920                 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10921                         dumpComment(fout, conprefix->data, qtypname,
10922                                                 tyinfo->dobj.namespace->dobj.name,
10923                                                 tyinfo->rolname,
10924                                                 domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
10925
10926                 destroyPQExpBuffer(conprefix);
10927         }
10928
10929         destroyPQExpBuffer(q);
10930         destroyPQExpBuffer(delq);
10931         destroyPQExpBuffer(query);
10932         free(qtypname);
10933         free(qualtypname);
10934 }
10935
10936 /*
10937  * dumpCompositeType
10938  *        writes out to fout the queries to recreate a user-defined stand-alone
10939  *        composite type
10940  */
10941 static void
10942 dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
10943 {
10944         DumpOptions *dopt = fout->dopt;
10945         PQExpBuffer q = createPQExpBuffer();
10946         PQExpBuffer dropped = createPQExpBuffer();
10947         PQExpBuffer delq = createPQExpBuffer();
10948         PQExpBuffer query = createPQExpBuffer();
10949         PGresult   *res;
10950         char       *qtypname;
10951         char       *qualtypname;
10952         int                     ntups;
10953         int                     i_attname;
10954         int                     i_atttypdefn;
10955         int                     i_attlen;
10956         int                     i_attalign;
10957         int                     i_attisdropped;
10958         int                     i_attcollation;
10959         int                     i;
10960         int                     actual_atts;
10961
10962         /* Fetch type specific details */
10963         if (fout->remoteVersion >= 90100)
10964         {
10965                 /*
10966                  * attcollation is new in 9.1.  Since we only want to dump COLLATE
10967                  * clauses for attributes whose collation is different from their
10968                  * type's default, we use a CASE here to suppress uninteresting
10969                  * attcollations cheaply.  atttypid will be 0 for dropped columns;
10970                  * collation does not matter for those.
10971                  */
10972                 appendPQExpBuffer(query, "SELECT a.attname, "
10973                                                   "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
10974                                                   "a.attlen, a.attalign, a.attisdropped, "
10975                                                   "CASE WHEN a.attcollation <> at.typcollation "
10976                                                   "THEN a.attcollation ELSE 0 END AS attcollation "
10977                                                   "FROM pg_catalog.pg_type ct "
10978                                                   "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
10979                                                   "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
10980                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
10981                                                   "ORDER BY a.attnum ",
10982                                                   tyinfo->dobj.catId.oid);
10983         }
10984         else
10985         {
10986                 /*
10987                  * Since ALTER TYPE could not drop columns until 9.1, attisdropped
10988                  * should always be false.
10989                  */
10990                 appendPQExpBuffer(query, "SELECT a.attname, "
10991                                                   "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
10992                                                   "a.attlen, a.attalign, a.attisdropped, "
10993                                                   "0 AS attcollation "
10994                                                   "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
10995                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
10996                                                   "AND a.attrelid = ct.typrelid "
10997                                                   "ORDER BY a.attnum ",
10998                                                   tyinfo->dobj.catId.oid);
10999         }
11000
11001         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11002
11003         ntups = PQntuples(res);
11004
11005         i_attname = PQfnumber(res, "attname");
11006         i_atttypdefn = PQfnumber(res, "atttypdefn");
11007         i_attlen = PQfnumber(res, "attlen");
11008         i_attalign = PQfnumber(res, "attalign");
11009         i_attisdropped = PQfnumber(res, "attisdropped");
11010         i_attcollation = PQfnumber(res, "attcollation");
11011
11012         if (dopt->binary_upgrade)
11013         {
11014                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
11015                                                                                                  tyinfo->dobj.catId.oid,
11016                                                                                                  false);
11017                 binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid, false);
11018         }
11019
11020         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
11021         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
11022
11023         appendPQExpBuffer(q, "CREATE TYPE %s AS (",
11024                                           qualtypname);
11025
11026         actual_atts = 0;
11027         for (i = 0; i < ntups; i++)
11028         {
11029                 char       *attname;
11030                 char       *atttypdefn;
11031                 char       *attlen;
11032                 char       *attalign;
11033                 bool            attisdropped;
11034                 Oid                     attcollation;
11035
11036                 attname = PQgetvalue(res, i, i_attname);
11037                 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
11038                 attlen = PQgetvalue(res, i, i_attlen);
11039                 attalign = PQgetvalue(res, i, i_attalign);
11040                 attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
11041                 attcollation = atooid(PQgetvalue(res, i, i_attcollation));
11042
11043                 if (attisdropped && !dopt->binary_upgrade)
11044                         continue;
11045
11046                 /* Format properly if not first attr */
11047                 if (actual_atts++ > 0)
11048                         appendPQExpBufferChar(q, ',');
11049                 appendPQExpBufferStr(q, "\n\t");
11050
11051                 if (!attisdropped)
11052                 {
11053                         appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
11054
11055                         /* Add collation if not default for the column type */
11056                         if (OidIsValid(attcollation))
11057                         {
11058                                 CollInfo   *coll;
11059
11060                                 coll = findCollationByOid(attcollation);
11061                                 if (coll)
11062                                         appendPQExpBuffer(q, " COLLATE %s",
11063                                                                           fmtQualifiedDumpable(coll));
11064                         }
11065                 }
11066                 else
11067                 {
11068                         /*
11069                          * This is a dropped attribute and we're in binary_upgrade mode.
11070                          * Insert a placeholder for it in the CREATE TYPE command, and set
11071                          * length and alignment with direct UPDATE to the catalogs
11072                          * afterwards. See similar code in dumpTableSchema().
11073                          */
11074                         appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
11075
11076                         /* stash separately for insertion after the CREATE TYPE */
11077                         appendPQExpBufferStr(dropped,
11078                                                                  "\n-- For binary upgrade, recreate dropped column.\n");
11079                         appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
11080                                                           "SET attlen = %s, "
11081                                                           "attalign = '%s', attbyval = false\n"
11082                                                           "WHERE attname = ", attlen, attalign);
11083                         appendStringLiteralAH(dropped, attname, fout);
11084                         appendPQExpBufferStr(dropped, "\n  AND attrelid = ");
11085                         appendStringLiteralAH(dropped, qualtypname, fout);
11086                         appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
11087
11088                         appendPQExpBuffer(dropped, "ALTER TYPE %s ",
11089                                                           qualtypname);
11090                         appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
11091                                                           fmtId(attname));
11092                 }
11093         }
11094         appendPQExpBufferStr(q, "\n);\n");
11095         appendPQExpBufferStr(q, dropped->data);
11096
11097         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
11098
11099         if (dopt->binary_upgrade)
11100                 binary_upgrade_extension_member(q, &tyinfo->dobj,
11101                                                                                 "TYPE", qtypname,
11102                                                                                 tyinfo->dobj.namespace->dobj.name);
11103
11104         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11105                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
11106                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
11107                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
11108                                                                   .owner = tyinfo->rolname,
11109                                                                   .description = "TYPE",
11110                                                                   .section = SECTION_PRE_DATA,
11111                                                                   .createStmt = q->data,
11112                                                                   .dropStmt = delq->data));
11113
11114
11115         /* Dump Type Comments and Security Labels */
11116         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11117                 dumpComment(fout, "TYPE", qtypname,
11118                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11119                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11120
11121         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11122                 dumpSecLabel(fout, "TYPE", qtypname,
11123                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11124                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11125
11126         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
11127                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
11128                                 qtypname, NULL,
11129                                 tyinfo->dobj.namespace->dobj.name,
11130                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
11131                                 tyinfo->inittypacl, tyinfo->initrtypacl);
11132
11133         PQclear(res);
11134         destroyPQExpBuffer(q);
11135         destroyPQExpBuffer(dropped);
11136         destroyPQExpBuffer(delq);
11137         destroyPQExpBuffer(query);
11138         free(qtypname);
11139         free(qualtypname);
11140
11141         /* Dump any per-column comments */
11142         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11143                 dumpCompositeTypeColComments(fout, tyinfo);
11144 }
11145
11146 /*
11147  * dumpCompositeTypeColComments
11148  *        writes out to fout the queries to recreate comments on the columns of
11149  *        a user-defined stand-alone composite type
11150  */
11151 static void
11152 dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
11153 {
11154         CommentItem *comments;
11155         int                     ncomments;
11156         PGresult   *res;
11157         PQExpBuffer query;
11158         PQExpBuffer target;
11159         Oid                     pgClassOid;
11160         int                     i;
11161         int                     ntups;
11162         int                     i_attname;
11163         int                     i_attnum;
11164
11165         /* do nothing, if --no-comments is supplied */
11166         if (fout->dopt->no_comments)
11167                 return;
11168
11169         query = createPQExpBuffer();
11170
11171         appendPQExpBuffer(query,
11172                                           "SELECT c.tableoid, a.attname, a.attnum "
11173                                           "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
11174                                           "WHERE c.oid = '%u' AND c.oid = a.attrelid "
11175                                           "  AND NOT a.attisdropped "
11176                                           "ORDER BY a.attnum ",
11177                                           tyinfo->typrelid);
11178
11179         /* Fetch column attnames */
11180         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11181
11182         ntups = PQntuples(res);
11183         if (ntups < 1)
11184         {
11185                 PQclear(res);
11186                 destroyPQExpBuffer(query);
11187                 return;
11188         }
11189
11190         pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
11191
11192         /* Search for comments associated with type's pg_class OID */
11193         ncomments = findComments(fout,
11194                                                          pgClassOid,
11195                                                          tyinfo->typrelid,
11196                                                          &comments);
11197
11198         /* If no comments exist, we're done */
11199         if (ncomments <= 0)
11200         {
11201                 PQclear(res);
11202                 destroyPQExpBuffer(query);
11203                 return;
11204         }
11205
11206         /* Build COMMENT ON statements */
11207         target = createPQExpBuffer();
11208
11209         i_attnum = PQfnumber(res, "attnum");
11210         i_attname = PQfnumber(res, "attname");
11211         while (ncomments > 0)
11212         {
11213                 const char *attname;
11214
11215                 attname = NULL;
11216                 for (i = 0; i < ntups; i++)
11217                 {
11218                         if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
11219                         {
11220                                 attname = PQgetvalue(res, i, i_attname);
11221                                 break;
11222                         }
11223                 }
11224                 if (attname)                    /* just in case we don't find it */
11225                 {
11226                         const char *descr = comments->descr;
11227
11228                         resetPQExpBuffer(target);
11229                         appendPQExpBuffer(target, "COLUMN %s.",
11230                                                           fmtId(tyinfo->dobj.name));
11231                         appendPQExpBufferStr(target, fmtId(attname));
11232
11233                         resetPQExpBuffer(query);
11234                         appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
11235                                                           fmtQualifiedDumpable(tyinfo));
11236                         appendPQExpBuffer(query, "%s IS ", fmtId(attname));
11237                         appendStringLiteralAH(query, descr, fout);
11238                         appendPQExpBufferStr(query, ";\n");
11239
11240                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
11241                                                  ARCHIVE_OPTS(.tag = target->data,
11242                                                                           .namespace = tyinfo->dobj.namespace->dobj.name,
11243                                                                           .owner = tyinfo->rolname,
11244                                                                           .description = "COMMENT",
11245                                                                           .section = SECTION_NONE,
11246                                                                           .createStmt = query->data,
11247                                                                           .deps = &(tyinfo->dobj.dumpId),
11248                                                                           .nDeps = 1));
11249                 }
11250
11251                 comments++;
11252                 ncomments--;
11253         }
11254
11255         PQclear(res);
11256         destroyPQExpBuffer(query);
11257         destroyPQExpBuffer(target);
11258 }
11259
11260 /*
11261  * dumpShellType
11262  *        writes out to fout the queries to create a shell type
11263  *
11264  * We dump a shell definition in advance of the I/O functions for the type.
11265  */
11266 static void
11267 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
11268 {
11269         DumpOptions *dopt = fout->dopt;
11270         PQExpBuffer q;
11271
11272         /* Skip if not to be dumped */
11273         if (!stinfo->dobj.dump || dopt->dataOnly)
11274                 return;
11275
11276         q = createPQExpBuffer();
11277
11278         /*
11279          * Note the lack of a DROP command for the shell type; any required DROP
11280          * is driven off the base type entry, instead.  This interacts with
11281          * _printTocEntry()'s use of the presence of a DROP command to decide
11282          * whether an entry needs an ALTER OWNER command.  We don't want to alter
11283          * the shell type's owner immediately on creation; that should happen only
11284          * after it's filled in, otherwise the backend complains.
11285          */
11286
11287         if (dopt->binary_upgrade)
11288                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
11289                                                                                                  stinfo->baseType->dobj.catId.oid,
11290                                                                                                  false);
11291
11292         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
11293                                           fmtQualifiedDumpable(stinfo));
11294
11295         if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11296                 ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
11297                                          ARCHIVE_OPTS(.tag = stinfo->dobj.name,
11298                                                                   .namespace = stinfo->dobj.namespace->dobj.name,
11299                                                                   .owner = stinfo->baseType->rolname,
11300                                                                   .description = "SHELL TYPE",
11301                                                                   .section = SECTION_PRE_DATA,
11302                                                                   .createStmt = q->data));
11303
11304         destroyPQExpBuffer(q);
11305 }
11306
11307 /*
11308  * dumpProcLang
11309  *                writes out to fout the queries to recreate a user-defined
11310  *                procedural language
11311  */
11312 static void
11313 dumpProcLang(Archive *fout, ProcLangInfo *plang)
11314 {
11315         DumpOptions *dopt = fout->dopt;
11316         PQExpBuffer defqry;
11317         PQExpBuffer delqry;
11318         bool            useParams;
11319         char       *qlanname;
11320         FuncInfo   *funcInfo;
11321         FuncInfo   *inlineInfo = NULL;
11322         FuncInfo   *validatorInfo = NULL;
11323
11324         /* Skip if not to be dumped */
11325         if (!plang->dobj.dump || dopt->dataOnly)
11326                 return;
11327
11328         /*
11329          * Try to find the support function(s).  It is not an error if we don't
11330          * find them --- if the functions are in the pg_catalog schema, as is
11331          * standard in 8.1 and up, then we won't have loaded them. (In this case
11332          * we will emit a parameterless CREATE LANGUAGE command, which will
11333          * require PL template knowledge in the backend to reload.)
11334          */
11335
11336         funcInfo = findFuncByOid(plang->lanplcallfoid);
11337         if (funcInfo != NULL && !funcInfo->dobj.dump)
11338                 funcInfo = NULL;                /* treat not-dumped same as not-found */
11339
11340         if (OidIsValid(plang->laninline))
11341         {
11342                 inlineInfo = findFuncByOid(plang->laninline);
11343                 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
11344                         inlineInfo = NULL;
11345         }
11346
11347         if (OidIsValid(plang->lanvalidator))
11348         {
11349                 validatorInfo = findFuncByOid(plang->lanvalidator);
11350                 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
11351                         validatorInfo = NULL;
11352         }
11353
11354         /*
11355          * If the functions are dumpable then emit a traditional CREATE LANGUAGE
11356          * with parameters.  Otherwise, we'll write a parameterless command, which
11357          * will rely on data from pg_pltemplate.
11358          */
11359         useParams = (funcInfo != NULL &&
11360                                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
11361                                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
11362
11363         defqry = createPQExpBuffer();
11364         delqry = createPQExpBuffer();
11365
11366         qlanname = pg_strdup(fmtId(plang->dobj.name));
11367
11368         appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
11369                                           qlanname);
11370
11371         if (useParams)
11372         {
11373                 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
11374                                                   plang->lanpltrusted ? "TRUSTED " : "",
11375                                                   qlanname);
11376                 appendPQExpBuffer(defqry, " HANDLER %s",
11377                                                   fmtQualifiedDumpable(funcInfo));
11378                 if (OidIsValid(plang->laninline))
11379                         appendPQExpBuffer(defqry, " INLINE %s",
11380                                                           fmtQualifiedDumpable(inlineInfo));
11381                 if (OidIsValid(plang->lanvalidator))
11382                         appendPQExpBuffer(defqry, " VALIDATOR %s",
11383                                                           fmtQualifiedDumpable(validatorInfo));
11384         }
11385         else
11386         {
11387                 /*
11388                  * If not dumping parameters, then use CREATE OR REPLACE so that the
11389                  * command will not fail if the language is preinstalled in the target
11390                  * database.  We restrict the use of REPLACE to this case so as to
11391                  * eliminate the risk of replacing a language with incompatible
11392                  * parameter settings: this command will only succeed at all if there
11393                  * is a pg_pltemplate entry, and if there is one, the existing entry
11394                  * must match it too.
11395                  */
11396                 appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
11397                                                   qlanname);
11398         }
11399         appendPQExpBufferStr(defqry, ";\n");
11400
11401         if (dopt->binary_upgrade)
11402                 binary_upgrade_extension_member(defqry, &plang->dobj,
11403                                                                                 "LANGUAGE", qlanname, NULL);
11404
11405         if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
11406                 ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
11407                                          ARCHIVE_OPTS(.tag = plang->dobj.name,
11408                                                                   .owner = plang->lanowner,
11409                                                                   .description = "PROCEDURAL LANGUAGE",
11410                                                                   .section = SECTION_PRE_DATA,
11411                                                                   .createStmt = defqry->data,
11412                                                                   .dropStmt = delqry->data,
11413                                                                   ));
11414
11415         /* Dump Proc Lang Comments and Security Labels */
11416         if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
11417                 dumpComment(fout, "LANGUAGE", qlanname,
11418                                         NULL, plang->lanowner,
11419                                         plang->dobj.catId, 0, plang->dobj.dumpId);
11420
11421         if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
11422                 dumpSecLabel(fout, "LANGUAGE", qlanname,
11423                                          NULL, plang->lanowner,
11424                                          plang->dobj.catId, 0, plang->dobj.dumpId);
11425
11426         if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
11427                 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
11428                                 qlanname, NULL, NULL,
11429                                 plang->lanowner, plang->lanacl, plang->rlanacl,
11430                                 plang->initlanacl, plang->initrlanacl);
11431
11432         free(qlanname);
11433
11434         destroyPQExpBuffer(defqry);
11435         destroyPQExpBuffer(delqry);
11436 }
11437
11438 /*
11439  * format_function_arguments: generate function name and argument list
11440  *
11441  * This is used when we can rely on pg_get_function_arguments to format
11442  * the argument list.  Note, however, that pg_get_function_arguments
11443  * does not special-case zero-argument aggregates.
11444  */
11445 static char *
11446 format_function_arguments(FuncInfo *finfo, char *funcargs, bool is_agg)
11447 {
11448         PQExpBufferData fn;
11449
11450         initPQExpBuffer(&fn);
11451         appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
11452         if (is_agg && finfo->nargs == 0)
11453                 appendPQExpBufferStr(&fn, "(*)");
11454         else
11455                 appendPQExpBuffer(&fn, "(%s)", funcargs);
11456         return fn.data;
11457 }
11458
11459 /*
11460  * format_function_arguments_old: generate function name and argument list
11461  *
11462  * The argument type names are qualified if needed.  The function name
11463  * is never qualified.
11464  *
11465  * This is used only with pre-8.4 servers, so we aren't expecting to see
11466  * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
11467  *
11468  * Any or all of allargtypes, argmodes, argnames may be NULL.
11469  */
11470 static char *
11471 format_function_arguments_old(Archive *fout,
11472                                                           FuncInfo *finfo, int nallargs,
11473                                                           char **allargtypes,
11474                                                           char **argmodes,
11475                                                           char **argnames)
11476 {
11477         PQExpBufferData fn;
11478         int                     j;
11479
11480         initPQExpBuffer(&fn);
11481         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11482         for (j = 0; j < nallargs; j++)
11483         {
11484                 Oid                     typid;
11485                 char       *typname;
11486                 const char *argmode;
11487                 const char *argname;
11488
11489                 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
11490                 typname = getFormattedTypeName(fout, typid, zeroAsOpaque);
11491
11492                 if (argmodes)
11493                 {
11494                         switch (argmodes[j][0])
11495                         {
11496                                 case PROARGMODE_IN:
11497                                         argmode = "";
11498                                         break;
11499                                 case PROARGMODE_OUT:
11500                                         argmode = "OUT ";
11501                                         break;
11502                                 case PROARGMODE_INOUT:
11503                                         argmode = "INOUT ";
11504                                         break;
11505                                 default:
11506                                         pg_log_warning("bogus value in proargmodes array");
11507                                         argmode = "";
11508                                         break;
11509                         }
11510                 }
11511                 else
11512                         argmode = "";
11513
11514                 argname = argnames ? argnames[j] : (char *) NULL;
11515                 if (argname && argname[0] == '\0')
11516                         argname = NULL;
11517
11518                 appendPQExpBuffer(&fn, "%s%s%s%s%s",
11519                                                   (j > 0) ? ", " : "",
11520                                                   argmode,
11521                                                   argname ? fmtId(argname) : "",
11522                                                   argname ? " " : "",
11523                                                   typname);
11524                 free(typname);
11525         }
11526         appendPQExpBufferChar(&fn, ')');
11527         return fn.data;
11528 }
11529
11530 /*
11531  * format_function_signature: generate function name and argument list
11532  *
11533  * This is like format_function_arguments_old except that only a minimal
11534  * list of input argument types is generated; this is sufficient to
11535  * reference the function, but not to define it.
11536  *
11537  * If honor_quotes is false then the function name is never quoted.
11538  * This is appropriate for use in TOC tags, but not in SQL commands.
11539  */
11540 static char *
11541 format_function_signature(Archive *fout, FuncInfo *finfo, bool honor_quotes)
11542 {
11543         PQExpBufferData fn;
11544         int                     j;
11545
11546         initPQExpBuffer(&fn);
11547         if (honor_quotes)
11548                 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11549         else
11550                 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
11551         for (j = 0; j < finfo->nargs; j++)
11552         {
11553                 char       *typname;
11554
11555                 if (j > 0)
11556                         appendPQExpBufferStr(&fn, ", ");
11557
11558                 typname = getFormattedTypeName(fout, finfo->argtypes[j],
11559                                                                            zeroAsOpaque);
11560                 appendPQExpBufferStr(&fn, typname);
11561                 free(typname);
11562         }
11563         appendPQExpBufferChar(&fn, ')');
11564         return fn.data;
11565 }
11566
11567
11568 /*
11569  * dumpFunc:
11570  *        dump out one function
11571  */
11572 static void
11573 dumpFunc(Archive *fout, FuncInfo *finfo)
11574 {
11575         DumpOptions *dopt = fout->dopt;
11576         PQExpBuffer query;
11577         PQExpBuffer q;
11578         PQExpBuffer delqry;
11579         PQExpBuffer asPart;
11580         PGresult   *res;
11581         char       *funcsig;            /* identity signature */
11582         char       *funcfullsig = NULL; /* full signature */
11583         char       *funcsig_tag;
11584         char       *proretset;
11585         char       *prosrc;
11586         char       *probin;
11587         char       *funcargs;
11588         char       *funciargs;
11589         char       *funcresult;
11590         char       *proallargtypes;
11591         char       *proargmodes;
11592         char       *proargnames;
11593         char       *protrftypes;
11594         char       *prokind;
11595         char       *provolatile;
11596         char       *proisstrict;
11597         char       *prosecdef;
11598         char       *proleakproof;
11599         char       *proconfig;
11600         char       *procost;
11601         char       *prorows;
11602         char       *prosupport;
11603         char       *proparallel;
11604         char       *lanname;
11605         char       *rettypename;
11606         int                     nallargs;
11607         char      **allargtypes = NULL;
11608         char      **argmodes = NULL;
11609         char      **argnames = NULL;
11610         char      **configitems = NULL;
11611         int                     nconfigitems = 0;
11612         const char *keyword;
11613         int                     i;
11614
11615         /* Skip if not to be dumped */
11616         if (!finfo->dobj.dump || dopt->dataOnly)
11617                 return;
11618
11619         query = createPQExpBuffer();
11620         q = createPQExpBuffer();
11621         delqry = createPQExpBuffer();
11622         asPart = createPQExpBuffer();
11623
11624         /* Fetch function-specific details */
11625         if (fout->remoteVersion >= 120000)
11626         {
11627                 /*
11628                  * prosupport was added in 12
11629                  */
11630                 appendPQExpBuffer(query,
11631                                                   "SELECT proretset, prosrc, probin, "
11632                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11633                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11634                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11635                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11636                                                   "prokind, provolatile, proisstrict, prosecdef, "
11637                                                   "proleakproof, proconfig, procost, prorows, "
11638                                                   "prosupport, proparallel, "
11639                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11640                                                   "FROM pg_catalog.pg_proc "
11641                                                   "WHERE oid = '%u'::pg_catalog.oid",
11642                                                   finfo->dobj.catId.oid);
11643         }
11644         else if (fout->remoteVersion >= 110000)
11645         {
11646                 /*
11647                  * prokind was added in 11
11648                  */
11649                 appendPQExpBuffer(query,
11650                                                   "SELECT proretset, prosrc, probin, "
11651                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11652                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11653                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11654                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11655                                                   "prokind, provolatile, proisstrict, prosecdef, "
11656                                                   "proleakproof, proconfig, procost, prorows, "
11657                                                   "'-' AS prosupport, proparallel, "
11658                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11659                                                   "FROM pg_catalog.pg_proc "
11660                                                   "WHERE oid = '%u'::pg_catalog.oid",
11661                                                   finfo->dobj.catId.oid);
11662         }
11663         else if (fout->remoteVersion >= 90600)
11664         {
11665                 /*
11666                  * proparallel was added in 9.6
11667                  */
11668                 appendPQExpBuffer(query,
11669                                                   "SELECT proretset, prosrc, probin, "
11670                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11671                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11672                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11673                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11674                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11675                                                   "provolatile, proisstrict, prosecdef, "
11676                                                   "proleakproof, proconfig, procost, prorows, "
11677                                                   "'-' AS prosupport, proparallel, "
11678                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11679                                                   "FROM pg_catalog.pg_proc "
11680                                                   "WHERE oid = '%u'::pg_catalog.oid",
11681                                                   finfo->dobj.catId.oid);
11682         }
11683         else if (fout->remoteVersion >= 90500)
11684         {
11685                 /*
11686                  * protrftypes was added in 9.5
11687                  */
11688                 appendPQExpBuffer(query,
11689                                                   "SELECT proretset, prosrc, probin, "
11690                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11691                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11692                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11693                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11694                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11695                                                   "provolatile, proisstrict, prosecdef, "
11696                                                   "proleakproof, proconfig, procost, prorows, "
11697                                                   "'-' AS prosupport, "
11698                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11699                                                   "FROM pg_catalog.pg_proc "
11700                                                   "WHERE oid = '%u'::pg_catalog.oid",
11701                                                   finfo->dobj.catId.oid);
11702         }
11703         else if (fout->remoteVersion >= 90200)
11704         {
11705                 /*
11706                  * proleakproof was added in 9.2
11707                  */
11708                 appendPQExpBuffer(query,
11709                                                   "SELECT proretset, prosrc, probin, "
11710                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11711                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11712                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11713                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11714                                                   "provolatile, proisstrict, prosecdef, "
11715                                                   "proleakproof, proconfig, procost, prorows, "
11716                                                   "'-' AS prosupport, "
11717                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11718                                                   "FROM pg_catalog.pg_proc "
11719                                                   "WHERE oid = '%u'::pg_catalog.oid",
11720                                                   finfo->dobj.catId.oid);
11721         }
11722         else if (fout->remoteVersion >= 80400)
11723         {
11724                 /*
11725                  * In 8.4 and up we rely on pg_get_function_arguments and
11726                  * pg_get_function_result instead of examining proallargtypes etc.
11727                  */
11728                 appendPQExpBuffer(query,
11729                                                   "SELECT proretset, prosrc, probin, "
11730                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11731                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11732                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11733                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11734                                                   "provolatile, proisstrict, prosecdef, "
11735                                                   "false AS proleakproof, "
11736                                                   " proconfig, procost, prorows, "
11737                                                   "'-' AS prosupport, "
11738                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11739                                                   "FROM pg_catalog.pg_proc "
11740                                                   "WHERE oid = '%u'::pg_catalog.oid",
11741                                                   finfo->dobj.catId.oid);
11742         }
11743         else if (fout->remoteVersion >= 80300)
11744         {
11745                 appendPQExpBuffer(query,
11746                                                   "SELECT proretset, prosrc, probin, "
11747                                                   "proallargtypes, proargmodes, proargnames, "
11748                                                   "'f' AS prokind, "
11749                                                   "provolatile, proisstrict, prosecdef, "
11750                                                   "false AS proleakproof, "
11751                                                   "proconfig, procost, prorows, "
11752                                                   "'-' AS prosupport, "
11753                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11754                                                   "FROM pg_catalog.pg_proc "
11755                                                   "WHERE oid = '%u'::pg_catalog.oid",
11756                                                   finfo->dobj.catId.oid);
11757         }
11758         else if (fout->remoteVersion >= 80100)
11759         {
11760                 appendPQExpBuffer(query,
11761                                                   "SELECT proretset, prosrc, probin, "
11762                                                   "proallargtypes, proargmodes, proargnames, "
11763                                                   "'f' AS prokind, "
11764                                                   "provolatile, proisstrict, prosecdef, "
11765                                                   "false AS proleakproof, "
11766                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
11767                                                   "'-' AS prosupport, "
11768                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11769                                                   "FROM pg_catalog.pg_proc "
11770                                                   "WHERE oid = '%u'::pg_catalog.oid",
11771                                                   finfo->dobj.catId.oid);
11772         }
11773         else
11774         {
11775                 appendPQExpBuffer(query,
11776                                                   "SELECT proretset, prosrc, probin, "
11777                                                   "null AS proallargtypes, "
11778                                                   "null AS proargmodes, "
11779                                                   "proargnames, "
11780                                                   "'f' AS prokind, "
11781                                                   "provolatile, proisstrict, prosecdef, "
11782                                                   "false AS proleakproof, "
11783                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
11784                                                   "'-' AS prosupport, "
11785                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11786                                                   "FROM pg_catalog.pg_proc "
11787                                                   "WHERE oid = '%u'::pg_catalog.oid",
11788                                                   finfo->dobj.catId.oid);
11789         }
11790
11791         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11792
11793         proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
11794         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
11795         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
11796         if (fout->remoteVersion >= 80400)
11797         {
11798                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
11799                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
11800                 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
11801                 proallargtypes = proargmodes = proargnames = NULL;
11802         }
11803         else
11804         {
11805                 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
11806                 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
11807                 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
11808                 funcargs = funciargs = funcresult = NULL;
11809         }
11810         if (PQfnumber(res, "protrftypes") != -1)
11811                 protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
11812         else
11813                 protrftypes = NULL;
11814         prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
11815         provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
11816         proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
11817         prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
11818         proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
11819         proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
11820         procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
11821         prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
11822         prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
11823
11824         if (PQfnumber(res, "proparallel") != -1)
11825                 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
11826         else
11827                 proparallel = NULL;
11828
11829         lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
11830
11831         /*
11832          * See backend/commands/functioncmds.c for details of how the 'AS' clause
11833          * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
11834          * versions would set it to "-".  There are no known cases in which prosrc
11835          * is unused, so the tests below for "-" are probably useless.
11836          */
11837         if (probin[0] != '\0' && strcmp(probin, "-") != 0)
11838         {
11839                 appendPQExpBufferStr(asPart, "AS ");
11840                 appendStringLiteralAH(asPart, probin, fout);
11841                 if (strcmp(prosrc, "-") != 0)
11842                 {
11843                         appendPQExpBufferStr(asPart, ", ");
11844
11845                         /*
11846                          * where we have bin, use dollar quoting if allowed and src
11847                          * contains quote or backslash; else use regular quoting.
11848                          */
11849                         if (dopt->disable_dollar_quoting ||
11850                                 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
11851                                 appendStringLiteralAH(asPart, prosrc, fout);
11852                         else
11853                                 appendStringLiteralDQ(asPart, prosrc, NULL);
11854                 }
11855         }
11856         else
11857         {
11858                 if (strcmp(prosrc, "-") != 0)
11859                 {
11860                         appendPQExpBufferStr(asPart, "AS ");
11861                         /* with no bin, dollar quote src unconditionally if allowed */
11862                         if (dopt->disable_dollar_quoting)
11863                                 appendStringLiteralAH(asPart, prosrc, fout);
11864                         else
11865                                 appendStringLiteralDQ(asPart, prosrc, NULL);
11866                 }
11867         }
11868
11869         nallargs = finfo->nargs;        /* unless we learn different from allargs */
11870
11871         if (proallargtypes && *proallargtypes)
11872         {
11873                 int                     nitems = 0;
11874
11875                 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
11876                         nitems < finfo->nargs)
11877                 {
11878                         pg_log_warning("could not parse proallargtypes array");
11879                         if (allargtypes)
11880                                 free(allargtypes);
11881                         allargtypes = NULL;
11882                 }
11883                 else
11884                         nallargs = nitems;
11885         }
11886
11887         if (proargmodes && *proargmodes)
11888         {
11889                 int                     nitems = 0;
11890
11891                 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
11892                         nitems != nallargs)
11893                 {
11894                         pg_log_warning("could not parse proargmodes array");
11895                         if (argmodes)
11896                                 free(argmodes);
11897                         argmodes = NULL;
11898                 }
11899         }
11900
11901         if (proargnames && *proargnames)
11902         {
11903                 int                     nitems = 0;
11904
11905                 if (!parsePGArray(proargnames, &argnames, &nitems) ||
11906                         nitems != nallargs)
11907                 {
11908                         pg_log_warning("could not parse proargnames array");
11909                         if (argnames)
11910                                 free(argnames);
11911                         argnames = NULL;
11912                 }
11913         }
11914
11915         if (proconfig && *proconfig)
11916         {
11917                 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
11918                 {
11919                         pg_log_warning("could not parse proconfig array");
11920                         if (configitems)
11921                                 free(configitems);
11922                         configitems = NULL;
11923                         nconfigitems = 0;
11924                 }
11925         }
11926
11927         if (funcargs)
11928         {
11929                 /* 8.4 or later; we rely on server-side code for most of the work */
11930                 funcfullsig = format_function_arguments(finfo, funcargs, false);
11931                 funcsig = format_function_arguments(finfo, funciargs, false);
11932         }
11933         else
11934                 /* pre-8.4, do it ourselves */
11935                 funcsig = format_function_arguments_old(fout,
11936                                                                                                 finfo, nallargs, allargtypes,
11937                                                                                                 argmodes, argnames);
11938
11939         funcsig_tag = format_function_signature(fout, finfo, false);
11940
11941         if (prokind[0] == PROKIND_PROCEDURE)
11942                 keyword = "PROCEDURE";
11943         else
11944                 keyword = "FUNCTION";   /* works for window functions too */
11945
11946         appendPQExpBuffer(delqry, "DROP %s %s.%s;\n",
11947                                           keyword,
11948                                           fmtId(finfo->dobj.namespace->dobj.name),
11949                                           funcsig);
11950
11951         appendPQExpBuffer(q, "CREATE %s %s.%s",
11952                                           keyword,
11953                                           fmtId(finfo->dobj.namespace->dobj.name),
11954                                           funcfullsig ? funcfullsig :
11955                                           funcsig);
11956
11957         if (prokind[0] == PROKIND_PROCEDURE)
11958                  /* no result type to output */ ;
11959         else if (funcresult)
11960                 appendPQExpBuffer(q, " RETURNS %s", funcresult);
11961         else
11962         {
11963                 rettypename = getFormattedTypeName(fout, finfo->prorettype,
11964                                                                                    zeroAsOpaque);
11965                 appendPQExpBuffer(q, " RETURNS %s%s",
11966                                                   (proretset[0] == 't') ? "SETOF " : "",
11967                                                   rettypename);
11968                 free(rettypename);
11969         }
11970
11971         appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
11972
11973         if (protrftypes != NULL && strcmp(protrftypes, "") != 0)
11974         {
11975                 Oid                *typeids = palloc(FUNC_MAX_ARGS * sizeof(Oid));
11976                 int                     i;
11977
11978                 appendPQExpBufferStr(q, " TRANSFORM ");
11979                 parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
11980                 for (i = 0; typeids[i]; i++)
11981                 {
11982                         if (i != 0)
11983                                 appendPQExpBufferStr(q, ", ");
11984                         appendPQExpBuffer(q, "FOR TYPE %s",
11985                                                           getFormattedTypeName(fout, typeids[i], zeroAsNone));
11986                 }
11987         }
11988
11989         if (prokind[0] == PROKIND_WINDOW)
11990                 appendPQExpBufferStr(q, " WINDOW");
11991
11992         if (provolatile[0] != PROVOLATILE_VOLATILE)
11993         {
11994                 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
11995                         appendPQExpBufferStr(q, " IMMUTABLE");
11996                 else if (provolatile[0] == PROVOLATILE_STABLE)
11997                         appendPQExpBufferStr(q, " STABLE");
11998                 else if (provolatile[0] != PROVOLATILE_VOLATILE)
11999                         fatal("unrecognized provolatile value for function \"%s\"",
12000                                   finfo->dobj.name);
12001         }
12002
12003         if (proisstrict[0] == 't')
12004                 appendPQExpBufferStr(q, " STRICT");
12005
12006         if (prosecdef[0] == 't')
12007                 appendPQExpBufferStr(q, " SECURITY DEFINER");
12008
12009         if (proleakproof[0] == 't')
12010                 appendPQExpBufferStr(q, " LEAKPROOF");
12011
12012         /*
12013          * COST and ROWS are emitted only if present and not default, so as not to
12014          * break backwards-compatibility of the dump without need.  Keep this code
12015          * in sync with the defaults in functioncmds.c.
12016          */
12017         if (strcmp(procost, "0") != 0)
12018         {
12019                 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
12020                 {
12021                         /* default cost is 1 */
12022                         if (strcmp(procost, "1") != 0)
12023                                 appendPQExpBuffer(q, " COST %s", procost);
12024                 }
12025                 else
12026                 {
12027                         /* default cost is 100 */
12028                         if (strcmp(procost, "100") != 0)
12029                                 appendPQExpBuffer(q, " COST %s", procost);
12030                 }
12031         }
12032         if (proretset[0] == 't' &&
12033                 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
12034                 appendPQExpBuffer(q, " ROWS %s", prorows);
12035
12036         if (strcmp(prosupport, "-") != 0)
12037         {
12038                 /* We rely on regprocout to provide quoting and qualification */
12039                 appendPQExpBuffer(q, " SUPPORT %s", prosupport);
12040         }
12041
12042         if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
12043         {
12044                 if (proparallel[0] == PROPARALLEL_SAFE)
12045                         appendPQExpBufferStr(q, " PARALLEL SAFE");
12046                 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
12047                         appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
12048                 else if (proparallel[0] != PROPARALLEL_UNSAFE)
12049                         fatal("unrecognized proparallel value for function \"%s\"",
12050                                   finfo->dobj.name);
12051         }
12052
12053         for (i = 0; i < nconfigitems; i++)
12054         {
12055                 /* we feel free to scribble on configitems[] here */
12056                 char       *configitem = configitems[i];
12057                 char       *pos;
12058
12059                 pos = strchr(configitem, '=');
12060                 if (pos == NULL)
12061                         continue;
12062                 *pos++ = '\0';
12063                 appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
12064
12065                 /*
12066                  * Variables that are marked GUC_LIST_QUOTE were already fully quoted
12067                  * by flatten_set_variable_args() before they were put into the
12068                  * proconfig array.  However, because the quoting rules used there
12069                  * aren't exactly like SQL's, we have to break the list value apart
12070                  * and then quote the elements as string literals.  (The elements may
12071                  * be double-quoted as-is, but we can't just feed them to the SQL
12072                  * parser; it would do the wrong thing with elements that are
12073                  * zero-length or longer than NAMEDATALEN.)
12074                  *
12075                  * Variables that are not so marked should just be emitted as simple
12076                  * string literals.  If the variable is not known to
12077                  * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
12078                  * to use GUC_LIST_QUOTE for extension variables.
12079                  */
12080                 if (variable_is_guc_list_quote(configitem))
12081                 {
12082                         char      **namelist;
12083                         char      **nameptr;
12084
12085                         /* Parse string into list of identifiers */
12086                         /* this shouldn't fail really */
12087                         if (SplitGUCList(pos, ',', &namelist))
12088                         {
12089                                 for (nameptr = namelist; *nameptr; nameptr++)
12090                                 {
12091                                         if (nameptr != namelist)
12092                                                 appendPQExpBufferStr(q, ", ");
12093                                         appendStringLiteralAH(q, *nameptr, fout);
12094                                 }
12095                         }
12096                         pg_free(namelist);
12097                 }
12098                 else
12099                         appendStringLiteralAH(q, pos, fout);
12100         }
12101
12102         appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
12103
12104         if (dopt->binary_upgrade)
12105                 binary_upgrade_extension_member(q, &finfo->dobj,
12106                                                                                 keyword, funcsig,
12107                                                                                 finfo->dobj.namespace->dobj.name);
12108
12109         if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12110                 ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
12111                                          ARCHIVE_OPTS(.tag = funcsig_tag,
12112                                                                   .namespace = finfo->dobj.namespace->dobj.name,
12113                                                                   .owner = finfo->rolname,
12114                                                                   .description = keyword,
12115                                                                   .section = SECTION_PRE_DATA,
12116                                                                   .createStmt = q->data,
12117                                                                   .dropStmt = delqry->data));
12118
12119         /* Dump Function Comments and Security Labels */
12120         if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12121                 dumpComment(fout, keyword, funcsig,
12122                                         finfo->dobj.namespace->dobj.name, finfo->rolname,
12123                                         finfo->dobj.catId, 0, finfo->dobj.dumpId);
12124
12125         if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
12126                 dumpSecLabel(fout, keyword, funcsig,
12127                                          finfo->dobj.namespace->dobj.name, finfo->rolname,
12128                                          finfo->dobj.catId, 0, finfo->dobj.dumpId);
12129
12130         if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
12131                 dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, keyword,
12132                                 funcsig, NULL,
12133                                 finfo->dobj.namespace->dobj.name,
12134                                 finfo->rolname, finfo->proacl, finfo->rproacl,
12135                                 finfo->initproacl, finfo->initrproacl);
12136
12137         PQclear(res);
12138
12139         destroyPQExpBuffer(query);
12140         destroyPQExpBuffer(q);
12141         destroyPQExpBuffer(delqry);
12142         destroyPQExpBuffer(asPart);
12143         free(funcsig);
12144         if (funcfullsig)
12145                 free(funcfullsig);
12146         free(funcsig_tag);
12147         if (allargtypes)
12148                 free(allargtypes);
12149         if (argmodes)
12150                 free(argmodes);
12151         if (argnames)
12152                 free(argnames);
12153         if (configitems)
12154                 free(configitems);
12155 }
12156
12157
12158 /*
12159  * Dump a user-defined cast
12160  */
12161 static void
12162 dumpCast(Archive *fout, CastInfo *cast)
12163 {
12164         DumpOptions *dopt = fout->dopt;
12165         PQExpBuffer defqry;
12166         PQExpBuffer delqry;
12167         PQExpBuffer labelq;
12168         PQExpBuffer castargs;
12169         FuncInfo   *funcInfo = NULL;
12170         char       *sourceType;
12171         char       *targetType;
12172
12173         /* Skip if not to be dumped */
12174         if (!cast->dobj.dump || dopt->dataOnly)
12175                 return;
12176
12177         /* Cannot dump if we don't have the cast function's info */
12178         if (OidIsValid(cast->castfunc))
12179         {
12180                 funcInfo = findFuncByOid(cast->castfunc);
12181                 if (funcInfo == NULL)
12182                         fatal("could not find function definition for function with OID %u",
12183                                   cast->castfunc);
12184         }
12185
12186         defqry = createPQExpBuffer();
12187         delqry = createPQExpBuffer();
12188         labelq = createPQExpBuffer();
12189         castargs = createPQExpBuffer();
12190
12191         sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
12192         targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
12193         appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
12194                                           sourceType, targetType);
12195
12196         appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
12197                                           sourceType, targetType);
12198
12199         switch (cast->castmethod)
12200         {
12201                 case COERCION_METHOD_BINARY:
12202                         appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
12203                         break;
12204                 case COERCION_METHOD_INOUT:
12205                         appendPQExpBufferStr(defqry, "WITH INOUT");
12206                         break;
12207                 case COERCION_METHOD_FUNCTION:
12208                         if (funcInfo)
12209                         {
12210                                 char       *fsig = format_function_signature(fout, funcInfo, true);
12211
12212                                 /*
12213                                  * Always qualify the function name (format_function_signature
12214                                  * won't qualify it).
12215                                  */
12216                                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
12217                                                                   fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
12218                                 free(fsig);
12219                         }
12220                         else
12221                                 pg_log_warning("bogus value in pg_cast.castfunc or pg_cast.castmethod field");
12222                         break;
12223                 default:
12224                         pg_log_warning("bogus value in pg_cast.castmethod field");
12225         }
12226
12227         if (cast->castcontext == 'a')
12228                 appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
12229         else if (cast->castcontext == 'i')
12230                 appendPQExpBufferStr(defqry, " AS IMPLICIT");
12231         appendPQExpBufferStr(defqry, ";\n");
12232
12233         appendPQExpBuffer(labelq, "CAST (%s AS %s)",
12234                                           sourceType, targetType);
12235
12236         appendPQExpBuffer(castargs, "(%s AS %s)",
12237                                           sourceType, targetType);
12238
12239         if (dopt->binary_upgrade)
12240                 binary_upgrade_extension_member(defqry, &cast->dobj,
12241                                                                                 "CAST", castargs->data, NULL);
12242
12243         if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
12244                 ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
12245                                          ARCHIVE_OPTS(.tag = labelq->data,
12246                                                                   .description = "CAST",
12247                                                                   .section = SECTION_PRE_DATA,
12248                                                                   .createStmt = defqry->data,
12249                                                                   .dropStmt = delqry->data));
12250
12251         /* Dump Cast Comments */
12252         if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
12253                 dumpComment(fout, "CAST", castargs->data,
12254                                         NULL, "",
12255                                         cast->dobj.catId, 0, cast->dobj.dumpId);
12256
12257         free(sourceType);
12258         free(targetType);
12259
12260         destroyPQExpBuffer(defqry);
12261         destroyPQExpBuffer(delqry);
12262         destroyPQExpBuffer(labelq);
12263         destroyPQExpBuffer(castargs);
12264 }
12265
12266 /*
12267  * Dump a transform
12268  */
12269 static void
12270 dumpTransform(Archive *fout, TransformInfo *transform)
12271 {
12272         DumpOptions *dopt = fout->dopt;
12273         PQExpBuffer defqry;
12274         PQExpBuffer delqry;
12275         PQExpBuffer labelq;
12276         PQExpBuffer transformargs;
12277         FuncInfo   *fromsqlFuncInfo = NULL;
12278         FuncInfo   *tosqlFuncInfo = NULL;
12279         char       *lanname;
12280         char       *transformType;
12281
12282         /* Skip if not to be dumped */
12283         if (!transform->dobj.dump || dopt->dataOnly)
12284                 return;
12285
12286         /* Cannot dump if we don't have the transform functions' info */
12287         if (OidIsValid(transform->trffromsql))
12288         {
12289                 fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
12290                 if (fromsqlFuncInfo == NULL)
12291                         fatal("could not find function definition for function with OID %u",
12292                                   transform->trffromsql);
12293         }
12294         if (OidIsValid(transform->trftosql))
12295         {
12296                 tosqlFuncInfo = findFuncByOid(transform->trftosql);
12297                 if (tosqlFuncInfo == NULL)
12298                         fatal("could not find function definition for function with OID %u",
12299                                   transform->trftosql);
12300         }
12301
12302         defqry = createPQExpBuffer();
12303         delqry = createPQExpBuffer();
12304         labelq = createPQExpBuffer();
12305         transformargs = createPQExpBuffer();
12306
12307         lanname = get_language_name(fout, transform->trflang);
12308         transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
12309
12310         appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
12311                                           transformType, lanname);
12312
12313         appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
12314                                           transformType, lanname);
12315
12316         if (!transform->trffromsql && !transform->trftosql)
12317                 pg_log_warning("bogus transform definition, at least one of trffromsql and trftosql should be nonzero");
12318
12319         if (transform->trffromsql)
12320         {
12321                 if (fromsqlFuncInfo)
12322                 {
12323                         char       *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
12324
12325                         /*
12326                          * Always qualify the function name (format_function_signature
12327                          * won't qualify it).
12328                          */
12329                         appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
12330                                                           fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
12331                         free(fsig);
12332                 }
12333                 else
12334                         pg_log_warning("bogus value in pg_transform.trffromsql field");
12335         }
12336
12337         if (transform->trftosql)
12338         {
12339                 if (transform->trffromsql)
12340                         appendPQExpBufferStr(defqry, ", ");
12341
12342                 if (tosqlFuncInfo)
12343                 {
12344                         char       *fsig = format_function_signature(fout, tosqlFuncInfo, true);
12345
12346                         /*
12347                          * Always qualify the function name (format_function_signature
12348                          * won't qualify it).
12349                          */
12350                         appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
12351                                                           fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
12352                         free(fsig);
12353                 }
12354                 else
12355                         pg_log_warning("bogus value in pg_transform.trftosql field");
12356         }
12357
12358         appendPQExpBufferStr(defqry, ");\n");
12359
12360         appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
12361                                           transformType, lanname);
12362
12363         appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
12364                                           transformType, lanname);
12365
12366         if (dopt->binary_upgrade)
12367                 binary_upgrade_extension_member(defqry, &transform->dobj,
12368                                                                                 "TRANSFORM", transformargs->data, NULL);
12369
12370         if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
12371                 ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
12372                                          ARCHIVE_OPTS(.tag = labelq->data,
12373                                                                   .description = "TRANSFORM",
12374                                                                   .section = SECTION_PRE_DATA,
12375                                                                   .createStmt = defqry->data,
12376                                                                   .dropStmt = delqry->data,
12377                                                                   .deps = transform->dobj.dependencies,
12378                                                                   .nDeps = transform->dobj.nDeps));
12379
12380         /* Dump Transform Comments */
12381         if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
12382                 dumpComment(fout, "TRANSFORM", transformargs->data,
12383                                         NULL, "",
12384                                         transform->dobj.catId, 0, transform->dobj.dumpId);
12385
12386         free(lanname);
12387         free(transformType);
12388         destroyPQExpBuffer(defqry);
12389         destroyPQExpBuffer(delqry);
12390         destroyPQExpBuffer(labelq);
12391         destroyPQExpBuffer(transformargs);
12392 }
12393
12394
12395 /*
12396  * dumpOpr
12397  *        write out a single operator definition
12398  */
12399 static void
12400 dumpOpr(Archive *fout, OprInfo *oprinfo)
12401 {
12402         DumpOptions *dopt = fout->dopt;
12403         PQExpBuffer query;
12404         PQExpBuffer q;
12405         PQExpBuffer delq;
12406         PQExpBuffer oprid;
12407         PQExpBuffer details;
12408         PGresult   *res;
12409         int                     i_oprkind;
12410         int                     i_oprcode;
12411         int                     i_oprleft;
12412         int                     i_oprright;
12413         int                     i_oprcom;
12414         int                     i_oprnegate;
12415         int                     i_oprrest;
12416         int                     i_oprjoin;
12417         int                     i_oprcanmerge;
12418         int                     i_oprcanhash;
12419         char       *oprkind;
12420         char       *oprcode;
12421         char       *oprleft;
12422         char       *oprright;
12423         char       *oprcom;
12424         char       *oprnegate;
12425         char       *oprrest;
12426         char       *oprjoin;
12427         char       *oprcanmerge;
12428         char       *oprcanhash;
12429         char       *oprregproc;
12430         char       *oprref;
12431
12432         /* Skip if not to be dumped */
12433         if (!oprinfo->dobj.dump || dopt->dataOnly)
12434                 return;
12435
12436         /*
12437          * some operators are invalid because they were the result of user
12438          * defining operators before commutators exist
12439          */
12440         if (!OidIsValid(oprinfo->oprcode))
12441                 return;
12442
12443         query = createPQExpBuffer();
12444         q = createPQExpBuffer();
12445         delq = createPQExpBuffer();
12446         oprid = createPQExpBuffer();
12447         details = createPQExpBuffer();
12448
12449         if (fout->remoteVersion >= 80300)
12450         {
12451                 appendPQExpBuffer(query, "SELECT oprkind, "
12452                                                   "oprcode::pg_catalog.regprocedure, "
12453                                                   "oprleft::pg_catalog.regtype, "
12454                                                   "oprright::pg_catalog.regtype, "
12455                                                   "oprcom, "
12456                                                   "oprnegate, "
12457                                                   "oprrest::pg_catalog.regprocedure, "
12458                                                   "oprjoin::pg_catalog.regprocedure, "
12459                                                   "oprcanmerge, oprcanhash "
12460                                                   "FROM pg_catalog.pg_operator "
12461                                                   "WHERE oid = '%u'::pg_catalog.oid",
12462                                                   oprinfo->dobj.catId.oid);
12463         }
12464         else
12465         {
12466                 appendPQExpBuffer(query, "SELECT oprkind, "
12467                                                   "oprcode::pg_catalog.regprocedure, "
12468                                                   "oprleft::pg_catalog.regtype, "
12469                                                   "oprright::pg_catalog.regtype, "
12470                                                   "oprcom, "
12471                                                   "oprnegate, "
12472                                                   "oprrest::pg_catalog.regprocedure, "
12473                                                   "oprjoin::pg_catalog.regprocedure, "
12474                                                   "(oprlsortop != 0) AS oprcanmerge, "
12475                                                   "oprcanhash "
12476                                                   "FROM pg_catalog.pg_operator "
12477                                                   "WHERE oid = '%u'::pg_catalog.oid",
12478                                                   oprinfo->dobj.catId.oid);
12479         }
12480
12481         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12482
12483         i_oprkind = PQfnumber(res, "oprkind");
12484         i_oprcode = PQfnumber(res, "oprcode");
12485         i_oprleft = PQfnumber(res, "oprleft");
12486         i_oprright = PQfnumber(res, "oprright");
12487         i_oprcom = PQfnumber(res, "oprcom");
12488         i_oprnegate = PQfnumber(res, "oprnegate");
12489         i_oprrest = PQfnumber(res, "oprrest");
12490         i_oprjoin = PQfnumber(res, "oprjoin");
12491         i_oprcanmerge = PQfnumber(res, "oprcanmerge");
12492         i_oprcanhash = PQfnumber(res, "oprcanhash");
12493
12494         oprkind = PQgetvalue(res, 0, i_oprkind);
12495         oprcode = PQgetvalue(res, 0, i_oprcode);
12496         oprleft = PQgetvalue(res, 0, i_oprleft);
12497         oprright = PQgetvalue(res, 0, i_oprright);
12498         oprcom = PQgetvalue(res, 0, i_oprcom);
12499         oprnegate = PQgetvalue(res, 0, i_oprnegate);
12500         oprrest = PQgetvalue(res, 0, i_oprrest);
12501         oprjoin = PQgetvalue(res, 0, i_oprjoin);
12502         oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
12503         oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
12504
12505         oprregproc = convertRegProcReference(fout, oprcode);
12506         if (oprregproc)
12507         {
12508                 appendPQExpBuffer(details, "    FUNCTION = %s", oprregproc);
12509                 free(oprregproc);
12510         }
12511
12512         appendPQExpBuffer(oprid, "%s (",
12513                                           oprinfo->dobj.name);
12514
12515         /*
12516          * right unary means there's a left arg and left unary means there's a
12517          * right arg
12518          */
12519         if (strcmp(oprkind, "r") == 0 ||
12520                 strcmp(oprkind, "b") == 0)
12521         {
12522                 appendPQExpBuffer(details, ",\n    LEFTARG = %s", oprleft);
12523                 appendPQExpBufferStr(oprid, oprleft);
12524         }
12525         else
12526                 appendPQExpBufferStr(oprid, "NONE");
12527
12528         if (strcmp(oprkind, "l") == 0 ||
12529                 strcmp(oprkind, "b") == 0)
12530         {
12531                 appendPQExpBuffer(details, ",\n    RIGHTARG = %s", oprright);
12532                 appendPQExpBuffer(oprid, ", %s)", oprright);
12533         }
12534         else
12535                 appendPQExpBufferStr(oprid, ", NONE)");
12536
12537         oprref = getFormattedOperatorName(fout, oprcom);
12538         if (oprref)
12539         {
12540                 appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", oprref);
12541                 free(oprref);
12542         }
12543
12544         oprref = getFormattedOperatorName(fout, oprnegate);
12545         if (oprref)
12546         {
12547                 appendPQExpBuffer(details, ",\n    NEGATOR = %s", oprref);
12548                 free(oprref);
12549         }
12550
12551         if (strcmp(oprcanmerge, "t") == 0)
12552                 appendPQExpBufferStr(details, ",\n    MERGES");
12553
12554         if (strcmp(oprcanhash, "t") == 0)
12555                 appendPQExpBufferStr(details, ",\n    HASHES");
12556
12557         oprregproc = convertRegProcReference(fout, oprrest);
12558         if (oprregproc)
12559         {
12560                 appendPQExpBuffer(details, ",\n    RESTRICT = %s", oprregproc);
12561                 free(oprregproc);
12562         }
12563
12564         oprregproc = convertRegProcReference(fout, oprjoin);
12565         if (oprregproc)
12566         {
12567                 appendPQExpBuffer(details, ",\n    JOIN = %s", oprregproc);
12568                 free(oprregproc);
12569         }
12570
12571         appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
12572                                           fmtId(oprinfo->dobj.namespace->dobj.name),
12573                                           oprid->data);
12574
12575         appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
12576                                           fmtId(oprinfo->dobj.namespace->dobj.name),
12577                                           oprinfo->dobj.name, details->data);
12578
12579         if (dopt->binary_upgrade)
12580                 binary_upgrade_extension_member(q, &oprinfo->dobj,
12581                                                                                 "OPERATOR", oprid->data,
12582                                                                                 oprinfo->dobj.namespace->dobj.name);
12583
12584         if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12585                 ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
12586                                          ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
12587                                                                   .namespace = oprinfo->dobj.namespace->dobj.name,
12588                                                                   .owner = oprinfo->rolname,
12589                                                                   .description = "OPERATOR",
12590                                                                   .section = SECTION_PRE_DATA,
12591                                                                   .createStmt = q->data,
12592                                                                   .dropStmt = delq->data));
12593
12594         /* Dump Operator Comments */
12595         if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12596                 dumpComment(fout, "OPERATOR", oprid->data,
12597                                         oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
12598                                         oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
12599
12600         PQclear(res);
12601
12602         destroyPQExpBuffer(query);
12603         destroyPQExpBuffer(q);
12604         destroyPQExpBuffer(delq);
12605         destroyPQExpBuffer(oprid);
12606         destroyPQExpBuffer(details);
12607 }
12608
12609 /*
12610  * Convert a function reference obtained from pg_operator
12611  *
12612  * Returns allocated string of what to print, or NULL if function references
12613  * is InvalidOid. Returned string is expected to be free'd by the caller.
12614  *
12615  * The input is a REGPROCEDURE display; we have to strip the argument-types
12616  * part.
12617  */
12618 static char *
12619 convertRegProcReference(Archive *fout, const char *proc)
12620 {
12621         char       *name;
12622         char       *paren;
12623         bool            inquote;
12624
12625         /* In all cases "-" means a null reference */
12626         if (strcmp(proc, "-") == 0)
12627                 return NULL;
12628
12629         name = pg_strdup(proc);
12630         /* find non-double-quoted left paren */
12631         inquote = false;
12632         for (paren = name; *paren; paren++)
12633         {
12634                 if (*paren == '(' && !inquote)
12635                 {
12636                         *paren = '\0';
12637                         break;
12638                 }
12639                 if (*paren == '"')
12640                         inquote = !inquote;
12641         }
12642         return name;
12643 }
12644
12645 /*
12646  * getFormattedOperatorName - retrieve the operator name for the
12647  * given operator OID (presented in string form).
12648  *
12649  * Returns an allocated string, or NULL if the given OID is invalid.
12650  * Caller is responsible for free'ing result string.
12651  *
12652  * What we produce has the format "OPERATOR(schema.oprname)".  This is only
12653  * useful in commands where the operator's argument types can be inferred from
12654  * context.  We always schema-qualify the name, though.  The predecessor to
12655  * this code tried to skip the schema qualification if possible, but that led
12656  * to wrong results in corner cases, such as if an operator and its negator
12657  * are in different schemas.
12658  */
12659 static char *
12660 getFormattedOperatorName(Archive *fout, const char *oproid)
12661 {
12662         OprInfo    *oprInfo;
12663
12664         /* In all cases "0" means a null reference */
12665         if (strcmp(oproid, "0") == 0)
12666                 return NULL;
12667
12668         oprInfo = findOprByOid(atooid(oproid));
12669         if (oprInfo == NULL)
12670         {
12671                 pg_log_warning("could not find operator with OID %s",
12672                                            oproid);
12673                 return NULL;
12674         }
12675
12676         return psprintf("OPERATOR(%s.%s)",
12677                                         fmtId(oprInfo->dobj.namespace->dobj.name),
12678                                         oprInfo->dobj.name);
12679 }
12680
12681 /*
12682  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
12683  *
12684  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
12685  * argument lists of these functions are predetermined.  Note that the
12686  * caller should ensure we are in the proper schema, because the results
12687  * are search path dependent!
12688  */
12689 static char *
12690 convertTSFunction(Archive *fout, Oid funcOid)
12691 {
12692         char       *result;
12693         char            query[128];
12694         PGresult   *res;
12695
12696         snprintf(query, sizeof(query),
12697                          "SELECT '%u'::pg_catalog.regproc", funcOid);
12698         res = ExecuteSqlQueryForSingleRow(fout, query);
12699
12700         result = pg_strdup(PQgetvalue(res, 0, 0));
12701
12702         PQclear(res);
12703
12704         return result;
12705 }
12706
12707 /*
12708  * dumpAccessMethod
12709  *        write out a single access method definition
12710  */
12711 static void
12712 dumpAccessMethod(Archive *fout, AccessMethodInfo *aminfo)
12713 {
12714         DumpOptions *dopt = fout->dopt;
12715         PQExpBuffer q;
12716         PQExpBuffer delq;
12717         char       *qamname;
12718
12719         /* Skip if not to be dumped */
12720         if (!aminfo->dobj.dump || dopt->dataOnly)
12721                 return;
12722
12723         q = createPQExpBuffer();
12724         delq = createPQExpBuffer();
12725
12726         qamname = pg_strdup(fmtId(aminfo->dobj.name));
12727
12728         appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
12729
12730         switch (aminfo->amtype)
12731         {
12732                 case AMTYPE_INDEX:
12733                         appendPQExpBufferStr(q, "TYPE INDEX ");
12734                         break;
12735                 case AMTYPE_TABLE:
12736                         appendPQExpBufferStr(q, "TYPE TABLE ");
12737                         break;
12738                 default:
12739                         pg_log_warning("invalid type \"%c\" of access method \"%s\"",
12740                                                    aminfo->amtype, qamname);
12741                         destroyPQExpBuffer(q);
12742                         destroyPQExpBuffer(delq);
12743                         free(qamname);
12744                         return;
12745         }
12746
12747         appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
12748
12749         appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
12750                                           qamname);
12751
12752         if (dopt->binary_upgrade)
12753                 binary_upgrade_extension_member(q, &aminfo->dobj,
12754                                                                                 "ACCESS METHOD", qamname, NULL);
12755
12756         if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12757                 ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
12758                                          ARCHIVE_OPTS(.tag = aminfo->dobj.name,
12759                                                                   .description = "ACCESS METHOD",
12760                                                                   .section = SECTION_PRE_DATA,
12761                                                                   .createStmt = q->data,
12762                                                                   .dropStmt = delq->data));
12763
12764         /* Dump Access Method Comments */
12765         if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12766                 dumpComment(fout, "ACCESS METHOD", qamname,
12767                                         NULL, "",
12768                                         aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
12769
12770         destroyPQExpBuffer(q);
12771         destroyPQExpBuffer(delq);
12772         free(qamname);
12773 }
12774
12775 /*
12776  * dumpOpclass
12777  *        write out a single operator class definition
12778  */
12779 static void
12780 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
12781 {
12782         DumpOptions *dopt = fout->dopt;
12783         PQExpBuffer query;
12784         PQExpBuffer q;
12785         PQExpBuffer delq;
12786         PQExpBuffer nameusing;
12787         PGresult   *res;
12788         int                     ntups;
12789         int                     i_opcintype;
12790         int                     i_opckeytype;
12791         int                     i_opcdefault;
12792         int                     i_opcfamily;
12793         int                     i_opcfamilyname;
12794         int                     i_opcfamilynsp;
12795         int                     i_amname;
12796         int                     i_amopstrategy;
12797         int                     i_amopreqcheck;
12798         int                     i_amopopr;
12799         int                     i_sortfamily;
12800         int                     i_sortfamilynsp;
12801         int                     i_amprocnum;
12802         int                     i_amproc;
12803         int                     i_amproclefttype;
12804         int                     i_amprocrighttype;
12805         char       *opcintype;
12806         char       *opckeytype;
12807         char       *opcdefault;
12808         char       *opcfamily;
12809         char       *opcfamilyname;
12810         char       *opcfamilynsp;
12811         char       *amname;
12812         char       *amopstrategy;
12813         char       *amopreqcheck;
12814         char       *amopopr;
12815         char       *sortfamily;
12816         char       *sortfamilynsp;
12817         char       *amprocnum;
12818         char       *amproc;
12819         char       *amproclefttype;
12820         char       *amprocrighttype;
12821         bool            needComma;
12822         int                     i;
12823
12824         /* Skip if not to be dumped */
12825         if (!opcinfo->dobj.dump || dopt->dataOnly)
12826                 return;
12827
12828         query = createPQExpBuffer();
12829         q = createPQExpBuffer();
12830         delq = createPQExpBuffer();
12831         nameusing = createPQExpBuffer();
12832
12833         /* Get additional fields from the pg_opclass row */
12834         if (fout->remoteVersion >= 80300)
12835         {
12836                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
12837                                                   "opckeytype::pg_catalog.regtype, "
12838                                                   "opcdefault, opcfamily, "
12839                                                   "opfname AS opcfamilyname, "
12840                                                   "nspname AS opcfamilynsp, "
12841                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
12842                                                   "FROM pg_catalog.pg_opclass c "
12843                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
12844                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12845                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
12846                                                   opcinfo->dobj.catId.oid);
12847         }
12848         else
12849         {
12850                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
12851                                                   "opckeytype::pg_catalog.regtype, "
12852                                                   "opcdefault, NULL AS opcfamily, "
12853                                                   "NULL AS opcfamilyname, "
12854                                                   "NULL AS opcfamilynsp, "
12855                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
12856                                                   "FROM pg_catalog.pg_opclass "
12857                                                   "WHERE oid = '%u'::pg_catalog.oid",
12858                                                   opcinfo->dobj.catId.oid);
12859         }
12860
12861         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12862
12863         i_opcintype = PQfnumber(res, "opcintype");
12864         i_opckeytype = PQfnumber(res, "opckeytype");
12865         i_opcdefault = PQfnumber(res, "opcdefault");
12866         i_opcfamily = PQfnumber(res, "opcfamily");
12867         i_opcfamilyname = PQfnumber(res, "opcfamilyname");
12868         i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
12869         i_amname = PQfnumber(res, "amname");
12870
12871         /* opcintype may still be needed after we PQclear res */
12872         opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
12873         opckeytype = PQgetvalue(res, 0, i_opckeytype);
12874         opcdefault = PQgetvalue(res, 0, i_opcdefault);
12875         /* opcfamily will still be needed after we PQclear res */
12876         opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
12877         opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
12878         opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
12879         /* amname will still be needed after we PQclear res */
12880         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
12881
12882         appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
12883                                           fmtQualifiedDumpable(opcinfo));
12884         appendPQExpBuffer(delq, " USING %s;\n",
12885                                           fmtId(amname));
12886
12887         /* Build the fixed portion of the CREATE command */
12888         appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
12889                                           fmtQualifiedDumpable(opcinfo));
12890         if (strcmp(opcdefault, "t") == 0)
12891                 appendPQExpBufferStr(q, "DEFAULT ");
12892         appendPQExpBuffer(q, "FOR TYPE %s USING %s",
12893                                           opcintype,
12894                                           fmtId(amname));
12895         if (strlen(opcfamilyname) > 0)
12896         {
12897                 appendPQExpBufferStr(q, " FAMILY ");
12898                 appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
12899                 appendPQExpBufferStr(q, fmtId(opcfamilyname));
12900         }
12901         appendPQExpBufferStr(q, " AS\n    ");
12902
12903         needComma = false;
12904
12905         if (strcmp(opckeytype, "-") != 0)
12906         {
12907                 appendPQExpBuffer(q, "STORAGE %s",
12908                                                   opckeytype);
12909                 needComma = true;
12910         }
12911
12912         PQclear(res);
12913
12914         /*
12915          * Now fetch and print the OPERATOR entries (pg_amop rows).
12916          *
12917          * Print only those opfamily members that are tied to the opclass by
12918          * pg_depend entries.
12919          *
12920          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
12921          * older server's opclass in which it is used.  This is to avoid
12922          * hard-to-detect breakage if a newer pg_dump is used to dump from an
12923          * older server and then reload into that old version.  This can go away
12924          * once 8.3 is so old as to not be of interest to anyone.
12925          */
12926         resetPQExpBuffer(query);
12927
12928         if (fout->remoteVersion >= 90100)
12929         {
12930                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12931                                                   "amopopr::pg_catalog.regoperator, "
12932                                                   "opfname AS sortfamily, "
12933                                                   "nspname AS sortfamilynsp "
12934                                                   "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
12935                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
12936                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
12937                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12938                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12939                                                   "AND refobjid = '%u'::pg_catalog.oid "
12940                                                   "AND amopfamily = '%s'::pg_catalog.oid "
12941                                                   "ORDER BY amopstrategy",
12942                                                   opcinfo->dobj.catId.oid,
12943                                                   opcfamily);
12944         }
12945         else if (fout->remoteVersion >= 80400)
12946         {
12947                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12948                                                   "amopopr::pg_catalog.regoperator, "
12949                                                   "NULL AS sortfamily, "
12950                                                   "NULL AS sortfamilynsp "
12951                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12952                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12953                                                   "AND refobjid = '%u'::pg_catalog.oid "
12954                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12955                                                   "AND objid = ao.oid "
12956                                                   "ORDER BY amopstrategy",
12957                                                   opcinfo->dobj.catId.oid);
12958         }
12959         else if (fout->remoteVersion >= 80300)
12960         {
12961                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
12962                                                   "amopopr::pg_catalog.regoperator, "
12963                                                   "NULL AS sortfamily, "
12964                                                   "NULL AS sortfamilynsp "
12965                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12966                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12967                                                   "AND refobjid = '%u'::pg_catalog.oid "
12968                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12969                                                   "AND objid = ao.oid "
12970                                                   "ORDER BY amopstrategy",
12971                                                   opcinfo->dobj.catId.oid);
12972         }
12973         else
12974         {
12975                 /*
12976                  * Here, we print all entries since there are no opfamilies and hence
12977                  * no loose operators to worry about.
12978                  */
12979                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
12980                                                   "amopopr::pg_catalog.regoperator, "
12981                                                   "NULL AS sortfamily, "
12982                                                   "NULL AS sortfamilynsp "
12983                                                   "FROM pg_catalog.pg_amop "
12984                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
12985                                                   "ORDER BY amopstrategy",
12986                                                   opcinfo->dobj.catId.oid);
12987         }
12988
12989         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12990
12991         ntups = PQntuples(res);
12992
12993         i_amopstrategy = PQfnumber(res, "amopstrategy");
12994         i_amopreqcheck = PQfnumber(res, "amopreqcheck");
12995         i_amopopr = PQfnumber(res, "amopopr");
12996         i_sortfamily = PQfnumber(res, "sortfamily");
12997         i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
12998
12999         for (i = 0; i < ntups; i++)
13000         {
13001                 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
13002                 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
13003                 amopopr = PQgetvalue(res, i, i_amopopr);
13004                 sortfamily = PQgetvalue(res, i, i_sortfamily);
13005                 sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
13006
13007                 if (needComma)
13008                         appendPQExpBufferStr(q, " ,\n    ");
13009
13010                 appendPQExpBuffer(q, "OPERATOR %s %s",
13011                                                   amopstrategy, amopopr);
13012
13013                 if (strlen(sortfamily) > 0)
13014                 {
13015                         appendPQExpBufferStr(q, " FOR ORDER BY ");
13016                         appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
13017                         appendPQExpBufferStr(q, fmtId(sortfamily));
13018                 }
13019
13020                 if (strcmp(amopreqcheck, "t") == 0)
13021                         appendPQExpBufferStr(q, " RECHECK");
13022
13023                 needComma = true;
13024         }
13025
13026         PQclear(res);
13027
13028         /*
13029          * Now fetch and print the FUNCTION entries (pg_amproc rows).
13030          *
13031          * Print only those opfamily members that are tied to the opclass by
13032          * pg_depend entries.
13033          *
13034          * We print the amproclefttype/amprocrighttype even though in most cases
13035          * the backend could deduce the right values, because of the corner case
13036          * of a btree sort support function for a cross-type comparison.  That's
13037          * only allowed in 9.2 and later, but for simplicity print them in all
13038          * versions that have the columns.
13039          */
13040         resetPQExpBuffer(query);
13041
13042         if (fout->remoteVersion >= 80300)
13043         {
13044                 appendPQExpBuffer(query, "SELECT amprocnum, "
13045                                                   "amproc::pg_catalog.regprocedure, "
13046                                                   "amproclefttype::pg_catalog.regtype, "
13047                                                   "amprocrighttype::pg_catalog.regtype "
13048                                                   "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
13049                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
13050                                                   "AND refobjid = '%u'::pg_catalog.oid "
13051                                                   "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
13052                                                   "AND objid = ap.oid "
13053                                                   "ORDER BY amprocnum",
13054                                                   opcinfo->dobj.catId.oid);
13055         }
13056         else
13057         {
13058                 appendPQExpBuffer(query, "SELECT amprocnum, "
13059                                                   "amproc::pg_catalog.regprocedure, "
13060                                                   "'' AS amproclefttype, "
13061                                                   "'' AS amprocrighttype "
13062                                                   "FROM pg_catalog.pg_amproc "
13063                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
13064                                                   "ORDER BY amprocnum",
13065                                                   opcinfo->dobj.catId.oid);
13066         }
13067
13068         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13069
13070         ntups = PQntuples(res);
13071
13072         i_amprocnum = PQfnumber(res, "amprocnum");
13073         i_amproc = PQfnumber(res, "amproc");
13074         i_amproclefttype = PQfnumber(res, "amproclefttype");
13075         i_amprocrighttype = PQfnumber(res, "amprocrighttype");
13076
13077         for (i = 0; i < ntups; i++)
13078         {
13079                 amprocnum = PQgetvalue(res, i, i_amprocnum);
13080                 amproc = PQgetvalue(res, i, i_amproc);
13081                 amproclefttype = PQgetvalue(res, i, i_amproclefttype);
13082                 amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
13083
13084                 if (needComma)
13085                         appendPQExpBufferStr(q, " ,\n    ");
13086
13087                 appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
13088
13089                 if (*amproclefttype && *amprocrighttype)
13090                         appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
13091
13092                 appendPQExpBuffer(q, " %s", amproc);
13093
13094                 needComma = true;
13095         }
13096
13097         PQclear(res);
13098
13099         /*
13100          * If needComma is still false it means we haven't added anything after
13101          * the AS keyword.  To avoid printing broken SQL, append a dummy STORAGE
13102          * clause with the same datatype.  This isn't sanctioned by the
13103          * documentation, but actually DefineOpClass will treat it as a no-op.
13104          */
13105         if (!needComma)
13106                 appendPQExpBuffer(q, "STORAGE %s", opcintype);
13107
13108         appendPQExpBufferStr(q, ";\n");
13109
13110         appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
13111         appendPQExpBuffer(nameusing, " USING %s",
13112                                           fmtId(amname));
13113
13114         if (dopt->binary_upgrade)
13115                 binary_upgrade_extension_member(q, &opcinfo->dobj,
13116                                                                                 "OPERATOR CLASS", nameusing->data,
13117                                                                                 opcinfo->dobj.namespace->dobj.name);
13118
13119         if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13120                 ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
13121                                          ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
13122                                                                   .namespace = opcinfo->dobj.namespace->dobj.name,
13123                                                                   .owner = opcinfo->rolname,
13124                                                                   .description = "OPERATOR CLASS",
13125                                                                   .section = SECTION_PRE_DATA,
13126                                                                   .createStmt = q->data,
13127                                                                   .dropStmt = delq->data));
13128
13129         /* Dump Operator Class Comments */
13130         if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13131                 dumpComment(fout, "OPERATOR CLASS", nameusing->data,
13132                                         opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
13133                                         opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
13134
13135         free(opcintype);
13136         free(opcfamily);
13137         free(amname);
13138         destroyPQExpBuffer(query);
13139         destroyPQExpBuffer(q);
13140         destroyPQExpBuffer(delq);
13141         destroyPQExpBuffer(nameusing);
13142 }
13143
13144 /*
13145  * dumpOpfamily
13146  *        write out a single operator family definition
13147  *
13148  * Note: this also dumps any "loose" operator members that aren't bound to a
13149  * specific opclass within the opfamily.
13150  */
13151 static void
13152 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
13153 {
13154         DumpOptions *dopt = fout->dopt;
13155         PQExpBuffer query;
13156         PQExpBuffer q;
13157         PQExpBuffer delq;
13158         PQExpBuffer nameusing;
13159         PGresult   *res;
13160         PGresult   *res_ops;
13161         PGresult   *res_procs;
13162         int                     ntups;
13163         int                     i_amname;
13164         int                     i_amopstrategy;
13165         int                     i_amopreqcheck;
13166         int                     i_amopopr;
13167         int                     i_sortfamily;
13168         int                     i_sortfamilynsp;
13169         int                     i_amprocnum;
13170         int                     i_amproc;
13171         int                     i_amproclefttype;
13172         int                     i_amprocrighttype;
13173         char       *amname;
13174         char       *amopstrategy;
13175         char       *amopreqcheck;
13176         char       *amopopr;
13177         char       *sortfamily;
13178         char       *sortfamilynsp;
13179         char       *amprocnum;
13180         char       *amproc;
13181         char       *amproclefttype;
13182         char       *amprocrighttype;
13183         bool            needComma;
13184         int                     i;
13185
13186         /* Skip if not to be dumped */
13187         if (!opfinfo->dobj.dump || dopt->dataOnly)
13188                 return;
13189
13190         query = createPQExpBuffer();
13191         q = createPQExpBuffer();
13192         delq = createPQExpBuffer();
13193         nameusing = createPQExpBuffer();
13194
13195         /*
13196          * Fetch only those opfamily members that are tied directly to the
13197          * opfamily by pg_depend entries.
13198          *
13199          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
13200          * older server's opclass in which it is used.  This is to avoid
13201          * hard-to-detect breakage if a newer pg_dump is used to dump from an
13202          * older server and then reload into that old version.  This can go away
13203          * once 8.3 is so old as to not be of interest to anyone.
13204          */
13205         if (fout->remoteVersion >= 90100)
13206         {
13207                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
13208                                                   "amopopr::pg_catalog.regoperator, "
13209                                                   "opfname AS sortfamily, "
13210                                                   "nspname AS sortfamilynsp "
13211                                                   "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
13212                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
13213                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
13214                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
13215                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13216                                                   "AND refobjid = '%u'::pg_catalog.oid "
13217                                                   "AND amopfamily = '%u'::pg_catalog.oid "
13218                                                   "ORDER BY amopstrategy",
13219                                                   opfinfo->dobj.catId.oid,
13220                                                   opfinfo->dobj.catId.oid);
13221         }
13222         else if (fout->remoteVersion >= 80400)
13223         {
13224                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
13225                                                   "amopopr::pg_catalog.regoperator, "
13226                                                   "NULL AS sortfamily, "
13227                                                   "NULL AS sortfamilynsp "
13228                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
13229                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13230                                                   "AND refobjid = '%u'::pg_catalog.oid "
13231                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
13232                                                   "AND objid = ao.oid "
13233                                                   "ORDER BY amopstrategy",
13234                                                   opfinfo->dobj.catId.oid);
13235         }
13236         else
13237         {
13238                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
13239                                                   "amopopr::pg_catalog.regoperator, "
13240                                                   "NULL AS sortfamily, "
13241                                                   "NULL AS sortfamilynsp "
13242                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
13243                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13244                                                   "AND refobjid = '%u'::pg_catalog.oid "
13245                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
13246                                                   "AND objid = ao.oid "
13247                                                   "ORDER BY amopstrategy",
13248                                                   opfinfo->dobj.catId.oid);
13249         }
13250
13251         res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13252
13253         resetPQExpBuffer(query);
13254
13255         appendPQExpBuffer(query, "SELECT amprocnum, "
13256                                           "amproc::pg_catalog.regprocedure, "
13257                                           "amproclefttype::pg_catalog.regtype, "
13258                                           "amprocrighttype::pg_catalog.regtype "
13259                                           "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
13260                                           "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13261                                           "AND refobjid = '%u'::pg_catalog.oid "
13262                                           "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
13263                                           "AND objid = ap.oid "
13264                                           "ORDER BY amprocnum",
13265                                           opfinfo->dobj.catId.oid);
13266
13267         res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13268
13269         /* Get additional fields from the pg_opfamily row */
13270         resetPQExpBuffer(query);
13271
13272         appendPQExpBuffer(query, "SELECT "
13273                                           "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
13274                                           "FROM pg_catalog.pg_opfamily "
13275                                           "WHERE oid = '%u'::pg_catalog.oid",
13276                                           opfinfo->dobj.catId.oid);
13277
13278         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13279
13280         i_amname = PQfnumber(res, "amname");
13281
13282         /* amname will still be needed after we PQclear res */
13283         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
13284
13285         appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
13286                                           fmtQualifiedDumpable(opfinfo));
13287         appendPQExpBuffer(delq, " USING %s;\n",
13288                                           fmtId(amname));
13289
13290         /* Build the fixed portion of the CREATE command */
13291         appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
13292                                           fmtQualifiedDumpable(opfinfo));
13293         appendPQExpBuffer(q, " USING %s;\n",
13294                                           fmtId(amname));
13295
13296         PQclear(res);
13297
13298         /* Do we need an ALTER to add loose members? */
13299         if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
13300         {
13301                 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
13302                                                   fmtQualifiedDumpable(opfinfo));
13303                 appendPQExpBuffer(q, " USING %s ADD\n    ",
13304                                                   fmtId(amname));
13305
13306                 needComma = false;
13307
13308                 /*
13309                  * Now fetch and print the OPERATOR entries (pg_amop rows).
13310                  */
13311                 ntups = PQntuples(res_ops);
13312
13313                 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
13314                 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
13315                 i_amopopr = PQfnumber(res_ops, "amopopr");
13316                 i_sortfamily = PQfnumber(res_ops, "sortfamily");
13317                 i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
13318
13319                 for (i = 0; i < ntups; i++)
13320                 {
13321                         amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
13322                         amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
13323                         amopopr = PQgetvalue(res_ops, i, i_amopopr);
13324                         sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
13325                         sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
13326
13327                         if (needComma)
13328                                 appendPQExpBufferStr(q, " ,\n    ");
13329
13330                         appendPQExpBuffer(q, "OPERATOR %s %s",
13331                                                           amopstrategy, amopopr);
13332
13333                         if (strlen(sortfamily) > 0)
13334                         {
13335                                 appendPQExpBufferStr(q, " FOR ORDER BY ");
13336                                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
13337                                 appendPQExpBufferStr(q, fmtId(sortfamily));
13338                         }
13339
13340                         if (strcmp(amopreqcheck, "t") == 0)
13341                                 appendPQExpBufferStr(q, " RECHECK");
13342
13343                         needComma = true;
13344                 }
13345
13346                 /*
13347                  * Now fetch and print the FUNCTION entries (pg_amproc rows).
13348                  */
13349                 ntups = PQntuples(res_procs);
13350
13351                 i_amprocnum = PQfnumber(res_procs, "amprocnum");
13352                 i_amproc = PQfnumber(res_procs, "amproc");
13353                 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
13354                 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
13355
13356                 for (i = 0; i < ntups; i++)
13357                 {
13358                         amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
13359                         amproc = PQgetvalue(res_procs, i, i_amproc);
13360                         amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
13361                         amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
13362
13363                         if (needComma)
13364                                 appendPQExpBufferStr(q, " ,\n    ");
13365
13366                         appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
13367                                                           amprocnum, amproclefttype, amprocrighttype,
13368                                                           amproc);
13369
13370                         needComma = true;
13371                 }
13372
13373                 appendPQExpBufferStr(q, ";\n");
13374         }
13375
13376         appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
13377         appendPQExpBuffer(nameusing, " USING %s",
13378                                           fmtId(amname));
13379
13380         if (dopt->binary_upgrade)
13381                 binary_upgrade_extension_member(q, &opfinfo->dobj,
13382                                                                                 "OPERATOR FAMILY", nameusing->data,
13383                                                                                 opfinfo->dobj.namespace->dobj.name);
13384
13385         if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13386                 ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
13387                                          ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
13388                                                                   .namespace = opfinfo->dobj.namespace->dobj.name,
13389                                                                   .owner = opfinfo->rolname,
13390                                                                   .description = "OPERATOR FAMILY",
13391                                                                   .section = SECTION_PRE_DATA,
13392                                                                   .createStmt = q->data,
13393                                                                   .dropStmt = delq->data));
13394
13395         /* Dump Operator Family Comments */
13396         if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13397                 dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
13398                                         opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
13399                                         opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
13400
13401         free(amname);
13402         PQclear(res_ops);
13403         PQclear(res_procs);
13404         destroyPQExpBuffer(query);
13405         destroyPQExpBuffer(q);
13406         destroyPQExpBuffer(delq);
13407         destroyPQExpBuffer(nameusing);
13408 }
13409
13410 /*
13411  * dumpCollation
13412  *        write out a single collation definition
13413  */
13414 static void
13415 dumpCollation(Archive *fout, CollInfo *collinfo)
13416 {
13417         DumpOptions *dopt = fout->dopt;
13418         PQExpBuffer query;
13419         PQExpBuffer q;
13420         PQExpBuffer delq;
13421         char       *qcollname;
13422         PGresult   *res;
13423         int                     i_collprovider;
13424         int                     i_collisdeterministic;
13425         int                     i_collcollate;
13426         int                     i_collctype;
13427         const char *collprovider;
13428         const char *collcollate;
13429         const char *collctype;
13430
13431         /* Skip if not to be dumped */
13432         if (!collinfo->dobj.dump || dopt->dataOnly)
13433                 return;
13434
13435         query = createPQExpBuffer();
13436         q = createPQExpBuffer();
13437         delq = createPQExpBuffer();
13438
13439         qcollname = pg_strdup(fmtId(collinfo->dobj.name));
13440
13441         /* Get collation-specific details */
13442         appendPQExpBufferStr(query, "SELECT ");
13443
13444         if (fout->remoteVersion >= 100000)
13445                 appendPQExpBufferStr(query,
13446                                                          "collprovider, "
13447                                                          "collversion, ");
13448         else
13449                 appendPQExpBufferStr(query,
13450                                                          "'c' AS collprovider, "
13451                                                          "NULL AS collversion, ");
13452
13453         if (fout->remoteVersion >= 120000)
13454                 appendPQExpBufferStr(query,
13455                                                          "collisdeterministic, ");
13456         else
13457                 appendPQExpBufferStr(query,
13458                                                          "true AS collisdeterministic, ");
13459
13460         appendPQExpBuffer(query,
13461                                           "collcollate, "
13462                                           "collctype "
13463                                           "FROM pg_catalog.pg_collation c "
13464                                           "WHERE c.oid = '%u'::pg_catalog.oid",
13465                                           collinfo->dobj.catId.oid);
13466
13467         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13468
13469         i_collprovider = PQfnumber(res, "collprovider");
13470         i_collisdeterministic = PQfnumber(res, "collisdeterministic");
13471         i_collcollate = PQfnumber(res, "collcollate");
13472         i_collctype = PQfnumber(res, "collctype");
13473
13474         collprovider = PQgetvalue(res, 0, i_collprovider);
13475         collcollate = PQgetvalue(res, 0, i_collcollate);
13476         collctype = PQgetvalue(res, 0, i_collctype);
13477
13478         appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
13479                                           fmtQualifiedDumpable(collinfo));
13480
13481         appendPQExpBuffer(q, "CREATE COLLATION %s (",
13482                                           fmtQualifiedDumpable(collinfo));
13483
13484         appendPQExpBufferStr(q, "provider = ");
13485         if (collprovider[0] == 'c')
13486                 appendPQExpBufferStr(q, "libc");
13487         else if (collprovider[0] == 'i')
13488                 appendPQExpBufferStr(q, "icu");
13489         else if (collprovider[0] == 'd')
13490                 /* to allow dumping pg_catalog; not accepted on input */
13491                 appendPQExpBufferStr(q, "default");
13492         else
13493                 fatal("unrecognized collation provider: %s",
13494                           collprovider);
13495
13496         if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
13497                 appendPQExpBufferStr(q, ", deterministic = false");
13498
13499         if (strcmp(collcollate, collctype) == 0)
13500         {
13501                 appendPQExpBufferStr(q, ", locale = ");
13502                 appendStringLiteralAH(q, collcollate, fout);
13503         }
13504         else
13505         {
13506                 appendPQExpBufferStr(q, ", lc_collate = ");
13507                 appendStringLiteralAH(q, collcollate, fout);
13508                 appendPQExpBufferStr(q, ", lc_ctype = ");
13509                 appendStringLiteralAH(q, collctype, fout);
13510         }
13511
13512         /*
13513          * For binary upgrade, carry over the collation version.  For normal
13514          * dump/restore, omit the version, so that it is computed upon restore.
13515          */
13516         if (dopt->binary_upgrade)
13517         {
13518                 int                     i_collversion;
13519
13520                 i_collversion = PQfnumber(res, "collversion");
13521                 if (!PQgetisnull(res, 0, i_collversion))
13522                 {
13523                         appendPQExpBufferStr(q, ", version = ");
13524                         appendStringLiteralAH(q,
13525                                                                   PQgetvalue(res, 0, i_collversion),
13526                                                                   fout);
13527                 }
13528         }
13529
13530         appendPQExpBufferStr(q, ");\n");
13531
13532         if (dopt->binary_upgrade)
13533                 binary_upgrade_extension_member(q, &collinfo->dobj,
13534                                                                                 "COLLATION", qcollname,
13535                                                                                 collinfo->dobj.namespace->dobj.name);
13536
13537         if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13538                 ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
13539                                          ARCHIVE_OPTS(.tag = collinfo->dobj.name,
13540                                                                   .namespace = collinfo->dobj.namespace->dobj.name,
13541                                                                   .owner = collinfo->rolname,
13542                                                                   .description = "COLLATION",
13543                                                                   .section = SECTION_PRE_DATA,
13544                                                                   .createStmt = q->data,
13545                                                                   .dropStmt = delq->data));
13546
13547         /* Dump Collation Comments */
13548         if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13549                 dumpComment(fout, "COLLATION", qcollname,
13550                                         collinfo->dobj.namespace->dobj.name, collinfo->rolname,
13551                                         collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
13552
13553         PQclear(res);
13554
13555         destroyPQExpBuffer(query);
13556         destroyPQExpBuffer(q);
13557         destroyPQExpBuffer(delq);
13558         free(qcollname);
13559 }
13560
13561 /*
13562  * dumpConversion
13563  *        write out a single conversion definition
13564  */
13565 static void
13566 dumpConversion(Archive *fout, ConvInfo *convinfo)
13567 {
13568         DumpOptions *dopt = fout->dopt;
13569         PQExpBuffer query;
13570         PQExpBuffer q;
13571         PQExpBuffer delq;
13572         char       *qconvname;
13573         PGresult   *res;
13574         int                     i_conforencoding;
13575         int                     i_contoencoding;
13576         int                     i_conproc;
13577         int                     i_condefault;
13578         const char *conforencoding;
13579         const char *contoencoding;
13580         const char *conproc;
13581         bool            condefault;
13582
13583         /* Skip if not to be dumped */
13584         if (!convinfo->dobj.dump || dopt->dataOnly)
13585                 return;
13586
13587         query = createPQExpBuffer();
13588         q = createPQExpBuffer();
13589         delq = createPQExpBuffer();
13590
13591         qconvname = pg_strdup(fmtId(convinfo->dobj.name));
13592
13593         /* Get conversion-specific details */
13594         appendPQExpBuffer(query, "SELECT "
13595                                           "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
13596                                           "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
13597                                           "conproc, condefault "
13598                                           "FROM pg_catalog.pg_conversion c "
13599                                           "WHERE c.oid = '%u'::pg_catalog.oid",
13600                                           convinfo->dobj.catId.oid);
13601
13602         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13603
13604         i_conforencoding = PQfnumber(res, "conforencoding");
13605         i_contoencoding = PQfnumber(res, "contoencoding");
13606         i_conproc = PQfnumber(res, "conproc");
13607         i_condefault = PQfnumber(res, "condefault");
13608
13609         conforencoding = PQgetvalue(res, 0, i_conforencoding);
13610         contoencoding = PQgetvalue(res, 0, i_contoencoding);
13611         conproc = PQgetvalue(res, 0, i_conproc);
13612         condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
13613
13614         appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
13615                                           fmtQualifiedDumpable(convinfo));
13616
13617         appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
13618                                           (condefault) ? "DEFAULT " : "",
13619                                           fmtQualifiedDumpable(convinfo));
13620         appendStringLiteralAH(q, conforencoding, fout);
13621         appendPQExpBufferStr(q, " TO ");
13622         appendStringLiteralAH(q, contoencoding, fout);
13623         /* regproc output is already sufficiently quoted */
13624         appendPQExpBuffer(q, " FROM %s;\n", conproc);
13625
13626         if (dopt->binary_upgrade)
13627                 binary_upgrade_extension_member(q, &convinfo->dobj,
13628                                                                                 "CONVERSION", qconvname,
13629                                                                                 convinfo->dobj.namespace->dobj.name);
13630
13631         if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13632                 ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
13633                                          ARCHIVE_OPTS(.tag = convinfo->dobj.name,
13634                                                                   .namespace = convinfo->dobj.namespace->dobj.name,
13635                                                                   .owner = convinfo->rolname,
13636                                                                   .description = "CONVERSION",
13637                                                                   .section = SECTION_PRE_DATA,
13638                                                                   .createStmt = q->data,
13639                                                                   .dropStmt = delq->data));
13640
13641         /* Dump Conversion Comments */
13642         if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13643                 dumpComment(fout, "CONVERSION", qconvname,
13644                                         convinfo->dobj.namespace->dobj.name, convinfo->rolname,
13645                                         convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
13646
13647         PQclear(res);
13648
13649         destroyPQExpBuffer(query);
13650         destroyPQExpBuffer(q);
13651         destroyPQExpBuffer(delq);
13652         free(qconvname);
13653 }
13654
13655 /*
13656  * format_aggregate_signature: generate aggregate name and argument list
13657  *
13658  * The argument type names are qualified if needed.  The aggregate name
13659  * is never qualified.
13660  */
13661 static char *
13662 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
13663 {
13664         PQExpBufferData buf;
13665         int                     j;
13666
13667         initPQExpBuffer(&buf);
13668         if (honor_quotes)
13669                 appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
13670         else
13671                 appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
13672
13673         if (agginfo->aggfn.nargs == 0)
13674                 appendPQExpBufferStr(&buf, "(*)");
13675         else
13676         {
13677                 appendPQExpBufferChar(&buf, '(');
13678                 for (j = 0; j < agginfo->aggfn.nargs; j++)
13679                 {
13680                         char       *typname;
13681
13682                         typname = getFormattedTypeName(fout, agginfo->aggfn.argtypes[j],
13683                                                                                    zeroAsOpaque);
13684
13685                         appendPQExpBuffer(&buf, "%s%s",
13686                                                           (j > 0) ? ", " : "",
13687                                                           typname);
13688                         free(typname);
13689                 }
13690                 appendPQExpBufferChar(&buf, ')');
13691         }
13692         return buf.data;
13693 }
13694
13695 /*
13696  * dumpAgg
13697  *        write out a single aggregate definition
13698  */
13699 static void
13700 dumpAgg(Archive *fout, AggInfo *agginfo)
13701 {
13702         DumpOptions *dopt = fout->dopt;
13703         PQExpBuffer query;
13704         PQExpBuffer q;
13705         PQExpBuffer delq;
13706         PQExpBuffer details;
13707         char       *aggsig;                     /* identity signature */
13708         char       *aggfullsig = NULL;  /* full signature */
13709         char       *aggsig_tag;
13710         PGresult   *res;
13711         int                     i_aggtransfn;
13712         int                     i_aggfinalfn;
13713         int                     i_aggcombinefn;
13714         int                     i_aggserialfn;
13715         int                     i_aggdeserialfn;
13716         int                     i_aggmtransfn;
13717         int                     i_aggminvtransfn;
13718         int                     i_aggmfinalfn;
13719         int                     i_aggfinalextra;
13720         int                     i_aggmfinalextra;
13721         int                     i_aggfinalmodify;
13722         int                     i_aggmfinalmodify;
13723         int                     i_aggsortop;
13724         int                     i_aggkind;
13725         int                     i_aggtranstype;
13726         int                     i_aggtransspace;
13727         int                     i_aggmtranstype;
13728         int                     i_aggmtransspace;
13729         int                     i_agginitval;
13730         int                     i_aggminitval;
13731         int                     i_convertok;
13732         int                     i_proparallel;
13733         const char *aggtransfn;
13734         const char *aggfinalfn;
13735         const char *aggcombinefn;
13736         const char *aggserialfn;
13737         const char *aggdeserialfn;
13738         const char *aggmtransfn;
13739         const char *aggminvtransfn;
13740         const char *aggmfinalfn;
13741         bool            aggfinalextra;
13742         bool            aggmfinalextra;
13743         char            aggfinalmodify;
13744         char            aggmfinalmodify;
13745         const char *aggsortop;
13746         char       *aggsortconvop;
13747         char            aggkind;
13748         const char *aggtranstype;
13749         const char *aggtransspace;
13750         const char *aggmtranstype;
13751         const char *aggmtransspace;
13752         const char *agginitval;
13753         const char *aggminitval;
13754         bool            convertok;
13755         const char *proparallel;
13756         char            defaultfinalmodify;
13757
13758         /* Skip if not to be dumped */
13759         if (!agginfo->aggfn.dobj.dump || dopt->dataOnly)
13760                 return;
13761
13762         query = createPQExpBuffer();
13763         q = createPQExpBuffer();
13764         delq = createPQExpBuffer();
13765         details = createPQExpBuffer();
13766
13767         /* Get aggregate-specific details */
13768         if (fout->remoteVersion >= 110000)
13769         {
13770                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13771                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13772                                                   "aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
13773                                                   "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13774                                                   "aggfinalextra, aggmfinalextra, "
13775                                                   "aggfinalmodify, aggmfinalmodify, "
13776                                                   "aggsortop, "
13777                                                   "aggkind, "
13778                                                   "aggtransspace, agginitval, "
13779                                                   "aggmtransspace, aggminitval, "
13780                                                   "true AS convertok, "
13781                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13782                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs, "
13783                                                   "p.proparallel "
13784                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13785                                                   "WHERE a.aggfnoid = p.oid "
13786                                                   "AND p.oid = '%u'::pg_catalog.oid",
13787                                                   agginfo->aggfn.dobj.catId.oid);
13788         }
13789         else if (fout->remoteVersion >= 90600)
13790         {
13791                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13792                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13793                                                   "aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
13794                                                   "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13795                                                   "aggfinalextra, aggmfinalextra, "
13796                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13797                                                   "aggsortop, "
13798                                                   "aggkind, "
13799                                                   "aggtransspace, agginitval, "
13800                                                   "aggmtransspace, aggminitval, "
13801                                                   "true AS convertok, "
13802                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13803                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs, "
13804                                                   "p.proparallel "
13805                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13806                                                   "WHERE a.aggfnoid = p.oid "
13807                                                   "AND p.oid = '%u'::pg_catalog.oid",
13808                                                   agginfo->aggfn.dobj.catId.oid);
13809         }
13810         else if (fout->remoteVersion >= 90400)
13811         {
13812                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13813                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13814                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13815                                                   "'-' AS aggdeserialfn, aggmtransfn, aggminvtransfn, "
13816                                                   "aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13817                                                   "aggfinalextra, aggmfinalextra, "
13818                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13819                                                   "aggsortop, "
13820                                                   "aggkind, "
13821                                                   "aggtransspace, agginitval, "
13822                                                   "aggmtransspace, aggminitval, "
13823                                                   "true AS convertok, "
13824                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13825                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
13826                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13827                                                   "WHERE a.aggfnoid = p.oid "
13828                                                   "AND p.oid = '%u'::pg_catalog.oid",
13829                                                   agginfo->aggfn.dobj.catId.oid);
13830         }
13831         else if (fout->remoteVersion >= 80400)
13832         {
13833                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13834                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13835                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13836                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13837                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13838                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13839                                                   "false AS aggmfinalextra, "
13840                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13841                                                   "aggsortop, "
13842                                                   "'n' AS aggkind, "
13843                                                   "0 AS aggtransspace, agginitval, "
13844                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13845                                                   "true AS convertok, "
13846                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13847                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
13848                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13849                                                   "WHERE a.aggfnoid = p.oid "
13850                                                   "AND p.oid = '%u'::pg_catalog.oid",
13851                                                   agginfo->aggfn.dobj.catId.oid);
13852         }
13853         else if (fout->remoteVersion >= 80100)
13854         {
13855                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13856                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13857                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13858                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13859                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13860                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13861                                                   "false AS aggmfinalextra, "
13862                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13863                                                   "aggsortop, "
13864                                                   "'n' AS aggkind, "
13865                                                   "0 AS aggtransspace, agginitval, "
13866                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13867                                                   "true AS convertok "
13868                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13869                                                   "WHERE a.aggfnoid = p.oid "
13870                                                   "AND p.oid = '%u'::pg_catalog.oid",
13871                                                   agginfo->aggfn.dobj.catId.oid);
13872         }
13873         else
13874         {
13875                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13876                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13877                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13878                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13879                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13880                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13881                                                   "false AS aggmfinalextra, "
13882                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13883                                                   "0 AS aggsortop, "
13884                                                   "'n' AS aggkind, "
13885                                                   "0 AS aggtransspace, agginitval, "
13886                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13887                                                   "true AS convertok "
13888                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13889                                                   "WHERE a.aggfnoid = p.oid "
13890                                                   "AND p.oid = '%u'::pg_catalog.oid",
13891                                                   agginfo->aggfn.dobj.catId.oid);
13892         }
13893
13894         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13895
13896         i_aggtransfn = PQfnumber(res, "aggtransfn");
13897         i_aggfinalfn = PQfnumber(res, "aggfinalfn");
13898         i_aggcombinefn = PQfnumber(res, "aggcombinefn");
13899         i_aggserialfn = PQfnumber(res, "aggserialfn");
13900         i_aggdeserialfn = PQfnumber(res, "aggdeserialfn");
13901         i_aggmtransfn = PQfnumber(res, "aggmtransfn");
13902         i_aggminvtransfn = PQfnumber(res, "aggminvtransfn");
13903         i_aggmfinalfn = PQfnumber(res, "aggmfinalfn");
13904         i_aggfinalextra = PQfnumber(res, "aggfinalextra");
13905         i_aggmfinalextra = PQfnumber(res, "aggmfinalextra");
13906         i_aggfinalmodify = PQfnumber(res, "aggfinalmodify");
13907         i_aggmfinalmodify = PQfnumber(res, "aggmfinalmodify");
13908         i_aggsortop = PQfnumber(res, "aggsortop");
13909         i_aggkind = PQfnumber(res, "aggkind");
13910         i_aggtranstype = PQfnumber(res, "aggtranstype");
13911         i_aggtransspace = PQfnumber(res, "aggtransspace");
13912         i_aggmtranstype = PQfnumber(res, "aggmtranstype");
13913         i_aggmtransspace = PQfnumber(res, "aggmtransspace");
13914         i_agginitval = PQfnumber(res, "agginitval");
13915         i_aggminitval = PQfnumber(res, "aggminitval");
13916         i_convertok = PQfnumber(res, "convertok");
13917         i_proparallel = PQfnumber(res, "proparallel");
13918
13919         aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
13920         aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
13921         aggcombinefn = PQgetvalue(res, 0, i_aggcombinefn);
13922         aggserialfn = PQgetvalue(res, 0, i_aggserialfn);
13923         aggdeserialfn = PQgetvalue(res, 0, i_aggdeserialfn);
13924         aggmtransfn = PQgetvalue(res, 0, i_aggmtransfn);
13925         aggminvtransfn = PQgetvalue(res, 0, i_aggminvtransfn);
13926         aggmfinalfn = PQgetvalue(res, 0, i_aggmfinalfn);
13927         aggfinalextra = (PQgetvalue(res, 0, i_aggfinalextra)[0] == 't');
13928         aggmfinalextra = (PQgetvalue(res, 0, i_aggmfinalextra)[0] == 't');
13929         aggfinalmodify = PQgetvalue(res, 0, i_aggfinalmodify)[0];
13930         aggmfinalmodify = PQgetvalue(res, 0, i_aggmfinalmodify)[0];
13931         aggsortop = PQgetvalue(res, 0, i_aggsortop);
13932         aggkind = PQgetvalue(res, 0, i_aggkind)[0];
13933         aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
13934         aggtransspace = PQgetvalue(res, 0, i_aggtransspace);
13935         aggmtranstype = PQgetvalue(res, 0, i_aggmtranstype);
13936         aggmtransspace = PQgetvalue(res, 0, i_aggmtransspace);
13937         agginitval = PQgetvalue(res, 0, i_agginitval);
13938         aggminitval = PQgetvalue(res, 0, i_aggminitval);
13939         convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
13940
13941         if (fout->remoteVersion >= 80400)
13942         {
13943                 /* 8.4 or later; we rely on server-side code for most of the work */
13944                 char       *funcargs;
13945                 char       *funciargs;
13946
13947                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
13948                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
13949                 aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
13950                 aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
13951         }
13952         else
13953                 /* pre-8.4, do it ourselves */
13954                 aggsig = format_aggregate_signature(agginfo, fout, true);
13955
13956         aggsig_tag = format_aggregate_signature(agginfo, fout, false);
13957
13958         if (i_proparallel != -1)
13959                 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
13960         else
13961                 proparallel = NULL;
13962
13963         if (!convertok)
13964         {
13965                 pg_log_warning("aggregate function %s could not be dumped correctly for this database version; ignored",
13966                                            aggsig);
13967
13968                 if (aggfullsig)
13969                         free(aggfullsig);
13970
13971                 free(aggsig);
13972
13973                 return;
13974         }
13975
13976         /* identify default modify flag for aggkind (must match DefineAggregate) */
13977         defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
13978         /* replace omitted flags for old versions */
13979         if (aggfinalmodify == '0')
13980                 aggfinalmodify = defaultfinalmodify;
13981         if (aggmfinalmodify == '0')
13982                 aggmfinalmodify = defaultfinalmodify;
13983
13984         /* regproc and regtype output is already sufficiently quoted */
13985         appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
13986                                           aggtransfn, aggtranstype);
13987
13988         if (strcmp(aggtransspace, "0") != 0)
13989         {
13990                 appendPQExpBuffer(details, ",\n    SSPACE = %s",
13991                                                   aggtransspace);
13992         }
13993
13994         if (!PQgetisnull(res, 0, i_agginitval))
13995         {
13996                 appendPQExpBufferStr(details, ",\n    INITCOND = ");
13997                 appendStringLiteralAH(details, agginitval, fout);
13998         }
13999
14000         if (strcmp(aggfinalfn, "-") != 0)
14001         {
14002                 appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
14003                                                   aggfinalfn);
14004                 if (aggfinalextra)
14005                         appendPQExpBufferStr(details, ",\n    FINALFUNC_EXTRA");
14006                 if (aggfinalmodify != defaultfinalmodify)
14007                 {
14008                         switch (aggfinalmodify)
14009                         {
14010                                 case AGGMODIFY_READ_ONLY:
14011                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_ONLY");
14012                                         break;
14013                                 case AGGMODIFY_SHAREABLE:
14014                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = SHAREABLE");
14015                                         break;
14016                                 case AGGMODIFY_READ_WRITE:
14017                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_WRITE");
14018                                         break;
14019                                 default:
14020                                         fatal("unrecognized aggfinalmodify value for aggregate \"%s\"",
14021                                                   agginfo->aggfn.dobj.name);
14022                                         break;
14023                         }
14024                 }
14025         }
14026
14027         if (strcmp(aggcombinefn, "-") != 0)
14028                 appendPQExpBuffer(details, ",\n    COMBINEFUNC = %s", aggcombinefn);
14029
14030         if (strcmp(aggserialfn, "-") != 0)
14031                 appendPQExpBuffer(details, ",\n    SERIALFUNC = %s", aggserialfn);
14032
14033         if (strcmp(aggdeserialfn, "-") != 0)
14034                 appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s", aggdeserialfn);
14035
14036         if (strcmp(aggmtransfn, "-") != 0)
14037         {
14038                 appendPQExpBuffer(details, ",\n    MSFUNC = %s,\n    MINVFUNC = %s,\n    MSTYPE = %s",
14039                                                   aggmtransfn,
14040                                                   aggminvtransfn,
14041                                                   aggmtranstype);
14042         }
14043
14044         if (strcmp(aggmtransspace, "0") != 0)
14045         {
14046                 appendPQExpBuffer(details, ",\n    MSSPACE = %s",
14047                                                   aggmtransspace);
14048         }
14049
14050         if (!PQgetisnull(res, 0, i_aggminitval))
14051         {
14052                 appendPQExpBufferStr(details, ",\n    MINITCOND = ");
14053                 appendStringLiteralAH(details, aggminitval, fout);
14054         }
14055
14056         if (strcmp(aggmfinalfn, "-") != 0)
14057         {
14058                 appendPQExpBuffer(details, ",\n    MFINALFUNC = %s",
14059                                                   aggmfinalfn);
14060                 if (aggmfinalextra)
14061                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_EXTRA");
14062                 if (aggmfinalmodify != defaultfinalmodify)
14063                 {
14064                         switch (aggmfinalmodify)
14065                         {
14066                                 case AGGMODIFY_READ_ONLY:
14067                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_ONLY");
14068                                         break;
14069                                 case AGGMODIFY_SHAREABLE:
14070                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = SHAREABLE");
14071                                         break;
14072                                 case AGGMODIFY_READ_WRITE:
14073                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_WRITE");
14074                                         break;
14075                                 default:
14076                                         fatal("unrecognized aggmfinalmodify value for aggregate \"%s\"",
14077                                                   agginfo->aggfn.dobj.name);
14078                                         break;
14079                         }
14080                 }
14081         }
14082
14083         aggsortconvop = getFormattedOperatorName(fout, aggsortop);
14084         if (aggsortconvop)
14085         {
14086                 appendPQExpBuffer(details, ",\n    SORTOP = %s",
14087                                                   aggsortconvop);
14088                 free(aggsortconvop);
14089         }
14090
14091         if (aggkind == AGGKIND_HYPOTHETICAL)
14092                 appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
14093
14094         if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
14095         {
14096                 if (proparallel[0] == PROPARALLEL_SAFE)
14097                         appendPQExpBufferStr(details, ",\n    PARALLEL = safe");
14098                 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
14099                         appendPQExpBufferStr(details, ",\n    PARALLEL = restricted");
14100                 else if (proparallel[0] != PROPARALLEL_UNSAFE)
14101                         fatal("unrecognized proparallel value for function \"%s\"",
14102                                   agginfo->aggfn.dobj.name);
14103         }
14104
14105         appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
14106                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
14107                                           aggsig);
14108
14109         appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
14110                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
14111                                           aggfullsig ? aggfullsig : aggsig, details->data);
14112
14113         if (dopt->binary_upgrade)
14114                 binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
14115                                                                                 "AGGREGATE", aggsig,
14116                                                                                 agginfo->aggfn.dobj.namespace->dobj.name);
14117
14118         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
14119                 ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
14120                                          agginfo->aggfn.dobj.dumpId,
14121                                          ARCHIVE_OPTS(.tag = aggsig_tag,
14122                                                                   .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
14123                                                                   .owner = agginfo->aggfn.rolname,
14124                                                                   .description = "AGGREGATE",
14125                                                                   .section = SECTION_PRE_DATA,
14126                                                                   .createStmt = q->data,
14127                                                                   .dropStmt = delq->data));
14128
14129         /* Dump Aggregate Comments */
14130         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
14131                 dumpComment(fout, "AGGREGATE", aggsig,
14132                                         agginfo->aggfn.dobj.namespace->dobj.name,
14133                                         agginfo->aggfn.rolname,
14134                                         agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
14135
14136         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
14137                 dumpSecLabel(fout, "AGGREGATE", aggsig,
14138                                          agginfo->aggfn.dobj.namespace->dobj.name,
14139                                          agginfo->aggfn.rolname,
14140                                          agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
14141
14142         /*
14143          * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
14144          * command look like a function's GRANT; in particular this affects the
14145          * syntax for zero-argument aggregates and ordered-set aggregates.
14146          */
14147         free(aggsig);
14148
14149         aggsig = format_function_signature(fout, &agginfo->aggfn, true);
14150
14151         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
14152                 dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
14153                                 "FUNCTION", aggsig, NULL,
14154                                 agginfo->aggfn.dobj.namespace->dobj.name,
14155                                 agginfo->aggfn.rolname, agginfo->aggfn.proacl,
14156                                 agginfo->aggfn.rproacl,
14157                                 agginfo->aggfn.initproacl, agginfo->aggfn.initrproacl);
14158
14159         free(aggsig);
14160         if (aggfullsig)
14161                 free(aggfullsig);
14162         free(aggsig_tag);
14163
14164         PQclear(res);
14165
14166         destroyPQExpBuffer(query);
14167         destroyPQExpBuffer(q);
14168         destroyPQExpBuffer(delq);
14169         destroyPQExpBuffer(details);
14170 }
14171
14172 /*
14173  * dumpTSParser
14174  *        write out a single text search parser
14175  */
14176 static void
14177 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
14178 {
14179         DumpOptions *dopt = fout->dopt;
14180         PQExpBuffer q;
14181         PQExpBuffer delq;
14182         char       *qprsname;
14183
14184         /* Skip if not to be dumped */
14185         if (!prsinfo->dobj.dump || dopt->dataOnly)
14186                 return;
14187
14188         q = createPQExpBuffer();
14189         delq = createPQExpBuffer();
14190
14191         qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
14192
14193         appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
14194                                           fmtQualifiedDumpable(prsinfo));
14195
14196         appendPQExpBuffer(q, "    START = %s,\n",
14197                                           convertTSFunction(fout, prsinfo->prsstart));
14198         appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
14199                                           convertTSFunction(fout, prsinfo->prstoken));
14200         appendPQExpBuffer(q, "    END = %s,\n",
14201                                           convertTSFunction(fout, prsinfo->prsend));
14202         if (prsinfo->prsheadline != InvalidOid)
14203                 appendPQExpBuffer(q, "    HEADLINE = %s,\n",
14204                                                   convertTSFunction(fout, prsinfo->prsheadline));
14205         appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
14206                                           convertTSFunction(fout, prsinfo->prslextype));
14207
14208         appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
14209                                           fmtQualifiedDumpable(prsinfo));
14210
14211         if (dopt->binary_upgrade)
14212                 binary_upgrade_extension_member(q, &prsinfo->dobj,
14213                                                                                 "TEXT SEARCH PARSER", qprsname,
14214                                                                                 prsinfo->dobj.namespace->dobj.name);
14215
14216         if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14217                 ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
14218                                          ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
14219                                                                   .namespace = prsinfo->dobj.namespace->dobj.name,
14220                                                                   .description = "TEXT SEARCH PARSER",
14221                                                                   .section = SECTION_PRE_DATA,
14222                                                                   .createStmt = q->data,
14223                                                                   .dropStmt = delq->data));
14224
14225         /* Dump Parser Comments */
14226         if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14227                 dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
14228                                         prsinfo->dobj.namespace->dobj.name, "",
14229                                         prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
14230
14231         destroyPQExpBuffer(q);
14232         destroyPQExpBuffer(delq);
14233         free(qprsname);
14234 }
14235
14236 /*
14237  * dumpTSDictionary
14238  *        write out a single text search dictionary
14239  */
14240 static void
14241 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
14242 {
14243         DumpOptions *dopt = fout->dopt;
14244         PQExpBuffer q;
14245         PQExpBuffer delq;
14246         PQExpBuffer query;
14247         char       *qdictname;
14248         PGresult   *res;
14249         char       *nspname;
14250         char       *tmplname;
14251
14252         /* Skip if not to be dumped */
14253         if (!dictinfo->dobj.dump || dopt->dataOnly)
14254                 return;
14255
14256         q = createPQExpBuffer();
14257         delq = createPQExpBuffer();
14258         query = createPQExpBuffer();
14259
14260         qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
14261
14262         /* Fetch name and namespace of the dictionary's template */
14263         appendPQExpBuffer(query, "SELECT nspname, tmplname "
14264                                           "FROM pg_ts_template p, pg_namespace n "
14265                                           "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
14266                                           dictinfo->dicttemplate);
14267         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14268         nspname = PQgetvalue(res, 0, 0);
14269         tmplname = PQgetvalue(res, 0, 1);
14270
14271         appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
14272                                           fmtQualifiedDumpable(dictinfo));
14273
14274         appendPQExpBufferStr(q, "    TEMPLATE = ");
14275         appendPQExpBuffer(q, "%s.", fmtId(nspname));
14276         appendPQExpBufferStr(q, fmtId(tmplname));
14277
14278         PQclear(res);
14279
14280         /* the dictinitoption can be dumped straight into the command */
14281         if (dictinfo->dictinitoption)
14282                 appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
14283
14284         appendPQExpBufferStr(q, " );\n");
14285
14286         appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
14287                                           fmtQualifiedDumpable(dictinfo));
14288
14289         if (dopt->binary_upgrade)
14290                 binary_upgrade_extension_member(q, &dictinfo->dobj,
14291                                                                                 "TEXT SEARCH DICTIONARY", qdictname,
14292                                                                                 dictinfo->dobj.namespace->dobj.name);
14293
14294         if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14295                 ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
14296                                          ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
14297                                                                   .namespace = dictinfo->dobj.namespace->dobj.name,
14298                                                                   .owner = dictinfo->rolname,
14299                                                                   .description = "TEXT SEARCH DICTIONARY",
14300                                                                   .section = SECTION_PRE_DATA,
14301                                                                   .createStmt = q->data,
14302                                                                   .dropStmt = delq->data));
14303
14304         /* Dump Dictionary Comments */
14305         if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14306                 dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
14307                                         dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
14308                                         dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
14309
14310         destroyPQExpBuffer(q);
14311         destroyPQExpBuffer(delq);
14312         destroyPQExpBuffer(query);
14313         free(qdictname);
14314 }
14315
14316 /*
14317  * dumpTSTemplate
14318  *        write out a single text search template
14319  */
14320 static void
14321 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
14322 {
14323         DumpOptions *dopt = fout->dopt;
14324         PQExpBuffer q;
14325         PQExpBuffer delq;
14326         char       *qtmplname;
14327
14328         /* Skip if not to be dumped */
14329         if (!tmplinfo->dobj.dump || dopt->dataOnly)
14330                 return;
14331
14332         q = createPQExpBuffer();
14333         delq = createPQExpBuffer();
14334
14335         qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
14336
14337         appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
14338                                           fmtQualifiedDumpable(tmplinfo));
14339
14340         if (tmplinfo->tmplinit != InvalidOid)
14341                 appendPQExpBuffer(q, "    INIT = %s,\n",
14342                                                   convertTSFunction(fout, tmplinfo->tmplinit));
14343         appendPQExpBuffer(q, "    LEXIZE = %s );\n",
14344                                           convertTSFunction(fout, tmplinfo->tmpllexize));
14345
14346         appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
14347                                           fmtQualifiedDumpable(tmplinfo));
14348
14349         if (dopt->binary_upgrade)
14350                 binary_upgrade_extension_member(q, &tmplinfo->dobj,
14351                                                                                 "TEXT SEARCH TEMPLATE", qtmplname,
14352                                                                                 tmplinfo->dobj.namespace->dobj.name);
14353
14354         if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14355                 ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
14356                                          ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
14357                                                                   .namespace = tmplinfo->dobj.namespace->dobj.name,
14358                                                                   .description = "TEXT SEARCH TEMPLATE",
14359                                                                   .section = SECTION_PRE_DATA,
14360                                                                   .createStmt = q->data,
14361                                                                   .dropStmt = delq->data));
14362
14363         /* Dump Template Comments */
14364         if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14365                 dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
14366                                         tmplinfo->dobj.namespace->dobj.name, "",
14367                                         tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
14368
14369         destroyPQExpBuffer(q);
14370         destroyPQExpBuffer(delq);
14371         free(qtmplname);
14372 }
14373
14374 /*
14375  * dumpTSConfig
14376  *        write out a single text search configuration
14377  */
14378 static void
14379 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
14380 {
14381         DumpOptions *dopt = fout->dopt;
14382         PQExpBuffer q;
14383         PQExpBuffer delq;
14384         PQExpBuffer query;
14385         char       *qcfgname;
14386         PGresult   *res;
14387         char       *nspname;
14388         char       *prsname;
14389         int                     ntups,
14390                                 i;
14391         int                     i_tokenname;
14392         int                     i_dictname;
14393
14394         /* Skip if not to be dumped */
14395         if (!cfginfo->dobj.dump || dopt->dataOnly)
14396                 return;
14397
14398         q = createPQExpBuffer();
14399         delq = createPQExpBuffer();
14400         query = createPQExpBuffer();
14401
14402         qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
14403
14404         /* Fetch name and namespace of the config's parser */
14405         appendPQExpBuffer(query, "SELECT nspname, prsname "
14406                                           "FROM pg_ts_parser p, pg_namespace n "
14407                                           "WHERE p.oid = '%u' AND n.oid = prsnamespace",
14408                                           cfginfo->cfgparser);
14409         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14410         nspname = PQgetvalue(res, 0, 0);
14411         prsname = PQgetvalue(res, 0, 1);
14412
14413         appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
14414                                           fmtQualifiedDumpable(cfginfo));
14415
14416         appendPQExpBuffer(q, "    PARSER = %s.", fmtId(nspname));
14417         appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
14418
14419         PQclear(res);
14420
14421         resetPQExpBuffer(query);
14422         appendPQExpBuffer(query,
14423                                           "SELECT\n"
14424                                           "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
14425                                           "    WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
14426                                           "  m.mapdict::pg_catalog.regdictionary AS dictname\n"
14427                                           "FROM pg_catalog.pg_ts_config_map AS m\n"
14428                                           "WHERE m.mapcfg = '%u'\n"
14429                                           "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
14430                                           cfginfo->cfgparser, cfginfo->dobj.catId.oid);
14431
14432         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14433         ntups = PQntuples(res);
14434
14435         i_tokenname = PQfnumber(res, "tokenname");
14436         i_dictname = PQfnumber(res, "dictname");
14437
14438         for (i = 0; i < ntups; i++)
14439         {
14440                 char       *tokenname = PQgetvalue(res, i, i_tokenname);
14441                 char       *dictname = PQgetvalue(res, i, i_dictname);
14442
14443                 if (i == 0 ||
14444                         strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
14445                 {
14446                         /* starting a new token type, so start a new command */
14447                         if (i > 0)
14448                                 appendPQExpBufferStr(q, ";\n");
14449                         appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
14450                                                           fmtQualifiedDumpable(cfginfo));
14451                         /* tokenname needs quoting, dictname does NOT */
14452                         appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
14453                                                           fmtId(tokenname), dictname);
14454                 }
14455                 else
14456                         appendPQExpBuffer(q, ", %s", dictname);
14457         }
14458
14459         if (ntups > 0)
14460                 appendPQExpBufferStr(q, ";\n");
14461
14462         PQclear(res);
14463
14464         appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
14465                                           fmtQualifiedDumpable(cfginfo));
14466
14467         if (dopt->binary_upgrade)
14468                 binary_upgrade_extension_member(q, &cfginfo->dobj,
14469                                                                                 "TEXT SEARCH CONFIGURATION", qcfgname,
14470                                                                                 cfginfo->dobj.namespace->dobj.name);
14471
14472         if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14473                 ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
14474                                          ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
14475                                                                   .namespace = cfginfo->dobj.namespace->dobj.name,
14476                                                                   .owner = cfginfo->rolname,
14477                                                                   .description = "TEXT SEARCH CONFIGURATION",
14478                                                                   .section = SECTION_PRE_DATA,
14479                                                                   .createStmt = q->data,
14480                                                                   .dropStmt = delq->data));
14481
14482         /* Dump Configuration Comments */
14483         if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14484                 dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
14485                                         cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
14486                                         cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
14487
14488         destroyPQExpBuffer(q);
14489         destroyPQExpBuffer(delq);
14490         destroyPQExpBuffer(query);
14491         free(qcfgname);
14492 }
14493
14494 /*
14495  * dumpForeignDataWrapper
14496  *        write out a single foreign-data wrapper definition
14497  */
14498 static void
14499 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
14500 {
14501         DumpOptions *dopt = fout->dopt;
14502         PQExpBuffer q;
14503         PQExpBuffer delq;
14504         char       *qfdwname;
14505
14506         /* Skip if not to be dumped */
14507         if (!fdwinfo->dobj.dump || dopt->dataOnly)
14508                 return;
14509
14510         q = createPQExpBuffer();
14511         delq = createPQExpBuffer();
14512
14513         qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
14514
14515         appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
14516                                           qfdwname);
14517
14518         if (strcmp(fdwinfo->fdwhandler, "-") != 0)
14519                 appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
14520
14521         if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
14522                 appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
14523
14524         if (strlen(fdwinfo->fdwoptions) > 0)
14525                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
14526
14527         appendPQExpBufferStr(q, ";\n");
14528
14529         appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
14530                                           qfdwname);
14531
14532         if (dopt->binary_upgrade)
14533                 binary_upgrade_extension_member(q, &fdwinfo->dobj,
14534                                                                                 "FOREIGN DATA WRAPPER", qfdwname,
14535                                                                                 NULL);
14536
14537         if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14538                 ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14539                                          ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
14540                                                                   .owner = fdwinfo->rolname,
14541                                                                   .description = "FOREIGN DATA WRAPPER",
14542                                                                   .section = SECTION_PRE_DATA,
14543                                                                   .createStmt = q->data,
14544                                                                   .dropStmt = delq->data));
14545
14546         /* Dump Foreign Data Wrapper Comments */
14547         if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14548                 dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
14549                                         NULL, fdwinfo->rolname,
14550                                         fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
14551
14552         /* Handle the ACL */
14553         if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
14554                 dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14555                                 "FOREIGN DATA WRAPPER", qfdwname, NULL,
14556                                 NULL, fdwinfo->rolname,
14557                                 fdwinfo->fdwacl, fdwinfo->rfdwacl,
14558                                 fdwinfo->initfdwacl, fdwinfo->initrfdwacl);
14559
14560         free(qfdwname);
14561
14562         destroyPQExpBuffer(q);
14563         destroyPQExpBuffer(delq);
14564 }
14565
14566 /*
14567  * dumpForeignServer
14568  *        write out a foreign server definition
14569  */
14570 static void
14571 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
14572 {
14573         DumpOptions *dopt = fout->dopt;
14574         PQExpBuffer q;
14575         PQExpBuffer delq;
14576         PQExpBuffer query;
14577         PGresult   *res;
14578         char       *qsrvname;
14579         char       *fdwname;
14580
14581         /* Skip if not to be dumped */
14582         if (!srvinfo->dobj.dump || dopt->dataOnly)
14583                 return;
14584
14585         q = createPQExpBuffer();
14586         delq = createPQExpBuffer();
14587         query = createPQExpBuffer();
14588
14589         qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
14590
14591         /* look up the foreign-data wrapper */
14592         appendPQExpBuffer(query, "SELECT fdwname "
14593                                           "FROM pg_foreign_data_wrapper w "
14594                                           "WHERE w.oid = '%u'",
14595                                           srvinfo->srvfdw);
14596         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14597         fdwname = PQgetvalue(res, 0, 0);
14598
14599         appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
14600         if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
14601         {
14602                 appendPQExpBufferStr(q, " TYPE ");
14603                 appendStringLiteralAH(q, srvinfo->srvtype, fout);
14604         }
14605         if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
14606         {
14607                 appendPQExpBufferStr(q, " VERSION ");
14608                 appendStringLiteralAH(q, srvinfo->srvversion, fout);
14609         }
14610
14611         appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
14612         appendPQExpBufferStr(q, fmtId(fdwname));
14613
14614         if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
14615                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
14616
14617         appendPQExpBufferStr(q, ";\n");
14618
14619         appendPQExpBuffer(delq, "DROP SERVER %s;\n",
14620                                           qsrvname);
14621
14622         if (dopt->binary_upgrade)
14623                 binary_upgrade_extension_member(q, &srvinfo->dobj,
14624                                                                                 "SERVER", qsrvname, NULL);
14625
14626         if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14627                 ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14628                                          ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
14629                                                                   .owner = srvinfo->rolname,
14630                                                                   .description = "SERVER",
14631                                                                   .section = SECTION_PRE_DATA,
14632                                                                   .createStmt = q->data,
14633                                                                   .dropStmt = delq->data));
14634
14635         /* Dump Foreign Server Comments */
14636         if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14637                 dumpComment(fout, "SERVER", qsrvname,
14638                                         NULL, srvinfo->rolname,
14639                                         srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
14640
14641         /* Handle the ACL */
14642         if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
14643                 dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14644                                 "FOREIGN SERVER", qsrvname, NULL,
14645                                 NULL, srvinfo->rolname,
14646                                 srvinfo->srvacl, srvinfo->rsrvacl,
14647                                 srvinfo->initsrvacl, srvinfo->initrsrvacl);
14648
14649         /* Dump user mappings */
14650         if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
14651                 dumpUserMappings(fout,
14652                                                  srvinfo->dobj.name, NULL,
14653                                                  srvinfo->rolname,
14654                                                  srvinfo->dobj.catId, srvinfo->dobj.dumpId);
14655
14656         free(qsrvname);
14657
14658         destroyPQExpBuffer(q);
14659         destroyPQExpBuffer(delq);
14660         destroyPQExpBuffer(query);
14661 }
14662
14663 /*
14664  * dumpUserMappings
14665  *
14666  * This routine is used to dump any user mappings associated with the
14667  * server handed to this routine. Should be called after ArchiveEntry()
14668  * for the server.
14669  */
14670 static void
14671 dumpUserMappings(Archive *fout,
14672                                  const char *servername, const char *namespace,
14673                                  const char *owner,
14674                                  CatalogId catalogId, DumpId dumpId)
14675 {
14676         PQExpBuffer q;
14677         PQExpBuffer delq;
14678         PQExpBuffer query;
14679         PQExpBuffer tag;
14680         PGresult   *res;
14681         int                     ntups;
14682         int                     i_usename;
14683         int                     i_umoptions;
14684         int                     i;
14685
14686         q = createPQExpBuffer();
14687         tag = createPQExpBuffer();
14688         delq = createPQExpBuffer();
14689         query = createPQExpBuffer();
14690
14691         /*
14692          * We read from the publicly accessible view pg_user_mappings, so as not
14693          * to fail if run by a non-superuser.  Note that the view will show
14694          * umoptions as null if the user hasn't got privileges for the associated
14695          * server; this means that pg_dump will dump such a mapping, but with no
14696          * OPTIONS clause.  A possible alternative is to skip such mappings
14697          * altogether, but it's not clear that that's an improvement.
14698          */
14699         appendPQExpBuffer(query,
14700                                           "SELECT usename, "
14701                                           "array_to_string(ARRAY("
14702                                           "SELECT quote_ident(option_name) || ' ' || "
14703                                           "quote_literal(option_value) "
14704                                           "FROM pg_options_to_table(umoptions) "
14705                                           "ORDER BY option_name"
14706                                           "), E',\n    ') AS umoptions "
14707                                           "FROM pg_user_mappings "
14708                                           "WHERE srvid = '%u' "
14709                                           "ORDER BY usename",
14710                                           catalogId.oid);
14711
14712         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14713
14714         ntups = PQntuples(res);
14715         i_usename = PQfnumber(res, "usename");
14716         i_umoptions = PQfnumber(res, "umoptions");
14717
14718         for (i = 0; i < ntups; i++)
14719         {
14720                 char       *usename;
14721                 char       *umoptions;
14722
14723                 usename = PQgetvalue(res, i, i_usename);
14724                 umoptions = PQgetvalue(res, i, i_umoptions);
14725
14726                 resetPQExpBuffer(q);
14727                 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
14728                 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
14729
14730                 if (umoptions && strlen(umoptions) > 0)
14731                         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
14732
14733                 appendPQExpBufferStr(q, ";\n");
14734
14735                 resetPQExpBuffer(delq);
14736                 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
14737                 appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
14738
14739                 resetPQExpBuffer(tag);
14740                 appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
14741                                                   usename, servername);
14742
14743                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14744                                          ARCHIVE_OPTS(.tag = tag->data,
14745                                                                   .namespace = namespace,
14746                                                                   .owner = owner,
14747                                                                   .description = "USER MAPPING",
14748                                                                   .section = SECTION_PRE_DATA,
14749                                                                   .createStmt = q->data,
14750                                                                   .dropStmt = delq->data));
14751         }
14752
14753         PQclear(res);
14754
14755         destroyPQExpBuffer(query);
14756         destroyPQExpBuffer(delq);
14757         destroyPQExpBuffer(tag);
14758         destroyPQExpBuffer(q);
14759 }
14760
14761 /*
14762  * Write out default privileges information
14763  */
14764 static void
14765 dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
14766 {
14767         DumpOptions *dopt = fout->dopt;
14768         PQExpBuffer q;
14769         PQExpBuffer tag;
14770         const char *type;
14771
14772         /* Skip if not to be dumped */
14773         if (!daclinfo->dobj.dump || dopt->dataOnly || dopt->aclsSkip)
14774                 return;
14775
14776         q = createPQExpBuffer();
14777         tag = createPQExpBuffer();
14778
14779         switch (daclinfo->defaclobjtype)
14780         {
14781                 case DEFACLOBJ_RELATION:
14782                         type = "TABLES";
14783                         break;
14784                 case DEFACLOBJ_SEQUENCE:
14785                         type = "SEQUENCES";
14786                         break;
14787                 case DEFACLOBJ_FUNCTION:
14788                         type = "FUNCTIONS";
14789                         break;
14790                 case DEFACLOBJ_TYPE:
14791                         type = "TYPES";
14792                         break;
14793                 case DEFACLOBJ_NAMESPACE:
14794                         type = "SCHEMAS";
14795                         break;
14796                 default:
14797                         /* shouldn't get here */
14798                         fatal("unrecognized object type in default privileges: %d",
14799                                   (int) daclinfo->defaclobjtype);
14800                         type = "";                      /* keep compiler quiet */
14801         }
14802
14803         appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
14804
14805         /* build the actual command(s) for this tuple */
14806         if (!buildDefaultACLCommands(type,
14807                                                                  daclinfo->dobj.namespace != NULL ?
14808                                                                  daclinfo->dobj.namespace->dobj.name : NULL,
14809                                                                  daclinfo->defaclacl,
14810                                                                  daclinfo->rdefaclacl,
14811                                                                  daclinfo->initdefaclacl,
14812                                                                  daclinfo->initrdefaclacl,
14813                                                                  daclinfo->defaclrole,
14814                                                                  fout->remoteVersion,
14815                                                                  q))
14816                 fatal("could not parse default ACL list (%s)",
14817                           daclinfo->defaclacl);
14818
14819         if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
14820                 ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
14821                                          ARCHIVE_OPTS(.tag = tag->data,
14822                                                                   .namespace = daclinfo->dobj.namespace ?
14823                                                                   daclinfo->dobj.namespace->dobj.name : NULL,
14824                                                                   .owner = daclinfo->defaclrole,
14825                                                                   .description = "DEFAULT ACL",
14826                                                                   .section = SECTION_POST_DATA,
14827                                                                   .createStmt = q->data));
14828
14829         destroyPQExpBuffer(tag);
14830         destroyPQExpBuffer(q);
14831 }
14832
14833 /*----------
14834  * Write out grant/revoke information
14835  *
14836  * 'objCatId' is the catalog ID of the underlying object.
14837  * 'objDumpId' is the dump ID of the underlying object.
14838  * 'type' must be one of
14839  *              TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
14840  *              FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
14841  * 'name' is the formatted name of the object.  Must be quoted etc. already.
14842  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
14843  *              (Currently we assume that subname is only provided for table columns.)
14844  * 'nspname' is the namespace the object is in (NULL if none).
14845  * 'owner' is the owner, NULL if there is no owner (for languages).
14846  * 'acls' contains the ACL string of the object from the appropriate system
14847  *              catalog field; it will be passed to buildACLCommands for building the
14848  *              appropriate GRANT commands.
14849  * 'racls' contains the ACL string of any initial-but-now-revoked ACLs of the
14850  *              object; it will be passed to buildACLCommands for building the
14851  *              appropriate REVOKE commands.
14852  * 'initacls' In binary-upgrade mode, ACL string of the object's initial
14853  *              privileges, to be recorded into pg_init_privs
14854  * 'initracls' In binary-upgrade mode, ACL string of the object's
14855  *              revoked-from-default privileges, to be recorded into pg_init_privs
14856  *
14857  * NB: initacls/initracls are needed because extensions can set privileges on
14858  * an object during the extension's script file and we record those into
14859  * pg_init_privs as that object's initial privileges.
14860  *----------
14861  */
14862 static void
14863 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
14864                 const char *type, const char *name, const char *subname,
14865                 const char *nspname, const char *owner,
14866                 const char *acls, const char *racls,
14867                 const char *initacls, const char *initracls)
14868 {
14869         DumpOptions *dopt = fout->dopt;
14870         PQExpBuffer sql;
14871
14872         /* Do nothing if ACL dump is not enabled */
14873         if (dopt->aclsSkip)
14874                 return;
14875
14876         /* --data-only skips ACLs *except* BLOB ACLs */
14877         if (dopt->dataOnly && strcmp(type, "LARGE OBJECT") != 0)
14878                 return;
14879
14880         sql = createPQExpBuffer();
14881
14882         /*
14883          * Check to see if this object has had any initial ACLs included for it.
14884          * If so, we are in binary upgrade mode and these are the ACLs to turn
14885          * into GRANT and REVOKE statements to set and record the initial
14886          * privileges for an extension object.  Let the backend know that these
14887          * are to be recorded by calling binary_upgrade_set_record_init_privs()
14888          * before and after.
14889          */
14890         if (strlen(initacls) != 0 || strlen(initracls) != 0)
14891         {
14892                 appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
14893                 if (!buildACLCommands(name, subname, nspname, type,
14894                                                           initacls, initracls, owner,
14895                                                           "", fout->remoteVersion, sql))
14896                         fatal("could not parse initial GRANT ACL list (%s) or initial REVOKE ACL list (%s) for object \"%s\" (%s)",
14897                                   initacls, initracls, name, type);
14898                 appendPQExpBufferStr(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
14899         }
14900
14901         if (!buildACLCommands(name, subname, nspname, type,
14902                                                   acls, racls, owner,
14903                                                   "", fout->remoteVersion, sql))
14904                 fatal("could not parse GRANT ACL list (%s) or REVOKE ACL list (%s) for object \"%s\" (%s)",
14905                           acls, racls, name, type);
14906
14907         if (sql->len > 0)
14908         {
14909                 PQExpBuffer tag = createPQExpBuffer();
14910
14911                 if (subname)
14912                         appendPQExpBuffer(tag, "COLUMN %s.%s", name, subname);
14913                 else
14914                         appendPQExpBuffer(tag, "%s %s", type, name);
14915
14916                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14917                                          ARCHIVE_OPTS(.tag = tag->data,
14918                                                                   .namespace = nspname,
14919                                                                   .owner = owner,
14920                                                                   .description = "ACL",
14921                                                                   .section = SECTION_NONE,
14922                                                                   .createStmt = sql->data,
14923                                                                   .deps = &objDumpId,
14924                                                                   .nDeps = 1));
14925                 destroyPQExpBuffer(tag);
14926         }
14927
14928         destroyPQExpBuffer(sql);
14929 }
14930
14931 /*
14932  * dumpSecLabel
14933  *
14934  * This routine is used to dump any security labels associated with the
14935  * object handed to this routine. The routine takes the object type
14936  * and object name (ready to print, except for schema decoration), plus
14937  * the namespace and owner of the object (for labeling the ArchiveEntry),
14938  * plus catalog ID and subid which are the lookup key for pg_seclabel,
14939  * plus the dump ID for the object (for setting a dependency).
14940  * If a matching pg_seclabel entry is found, it is dumped.
14941  *
14942  * Note: although this routine takes a dumpId for dependency purposes,
14943  * that purpose is just to mark the dependency in the emitted dump file
14944  * for possible future use by pg_restore.  We do NOT use it for determining
14945  * ordering of the label in the dump file, because this routine is called
14946  * after dependency sorting occurs.  This routine should be called just after
14947  * calling ArchiveEntry() for the specified object.
14948  */
14949 static void
14950 dumpSecLabel(Archive *fout, const char *type, const char *name,
14951                          const char *namespace, const char *owner,
14952                          CatalogId catalogId, int subid, DumpId dumpId)
14953 {
14954         DumpOptions *dopt = fout->dopt;
14955         SecLabelItem *labels;
14956         int                     nlabels;
14957         int                     i;
14958         PQExpBuffer query;
14959
14960         /* do nothing, if --no-security-labels is supplied */
14961         if (dopt->no_security_labels)
14962                 return;
14963
14964         /* Security labels are schema not data ... except blob labels are data */
14965         if (strcmp(type, "LARGE OBJECT") != 0)
14966         {
14967                 if (dopt->dataOnly)
14968                         return;
14969         }
14970         else
14971         {
14972                 /* We do dump blob security labels in binary-upgrade mode */
14973                 if (dopt->schemaOnly && !dopt->binary_upgrade)
14974                         return;
14975         }
14976
14977         /* Search for security labels associated with catalogId, using table */
14978         nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
14979
14980         query = createPQExpBuffer();
14981
14982         for (i = 0; i < nlabels; i++)
14983         {
14984                 /*
14985                  * Ignore label entries for which the subid doesn't match.
14986                  */
14987                 if (labels[i].objsubid != subid)
14988                         continue;
14989
14990                 appendPQExpBuffer(query,
14991                                                   "SECURITY LABEL FOR %s ON %s ",
14992                                                   fmtId(labels[i].provider), type);
14993                 if (namespace && *namespace)
14994                         appendPQExpBuffer(query, "%s.", fmtId(namespace));
14995                 appendPQExpBuffer(query, "%s IS ", name);
14996                 appendStringLiteralAH(query, labels[i].label, fout);
14997                 appendPQExpBufferStr(query, ";\n");
14998         }
14999
15000         if (query->len > 0)
15001         {
15002                 PQExpBuffer tag = createPQExpBuffer();
15003
15004                 appendPQExpBuffer(tag, "%s %s", type, name);
15005                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
15006                                          ARCHIVE_OPTS(.tag = tag->data,
15007                                                                   .namespace = namespace,
15008                                                                   .owner = owner,
15009                                                                   .description = "SECURITY LABEL",
15010                                                                   .section = SECTION_NONE,
15011                                                                   .createStmt = query->data,
15012                                                                   .deps = &dumpId,
15013                                                                   .nDeps = 1));
15014                 destroyPQExpBuffer(tag);
15015         }
15016
15017         destroyPQExpBuffer(query);
15018 }
15019
15020 /*
15021  * dumpTableSecLabel
15022  *
15023  * As above, but dump security label for both the specified table (or view)
15024  * and its columns.
15025  */
15026 static void
15027 dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
15028 {
15029         DumpOptions *dopt = fout->dopt;
15030         SecLabelItem *labels;
15031         int                     nlabels;
15032         int                     i;
15033         PQExpBuffer query;
15034         PQExpBuffer target;
15035
15036         /* do nothing, if --no-security-labels is supplied */
15037         if (dopt->no_security_labels)
15038                 return;
15039
15040         /* SecLabel are SCHEMA not data */
15041         if (dopt->dataOnly)
15042                 return;
15043
15044         /* Search for comments associated with relation, using table */
15045         nlabels = findSecLabels(fout,
15046                                                         tbinfo->dobj.catId.tableoid,
15047                                                         tbinfo->dobj.catId.oid,
15048                                                         &labels);
15049
15050         /* If security labels exist, build SECURITY LABEL statements */
15051         if (nlabels <= 0)
15052                 return;
15053
15054         query = createPQExpBuffer();
15055         target = createPQExpBuffer();
15056
15057         for (i = 0; i < nlabels; i++)
15058         {
15059                 const char *colname;
15060                 const char *provider = labels[i].provider;
15061                 const char *label = labels[i].label;
15062                 int                     objsubid = labels[i].objsubid;
15063
15064                 resetPQExpBuffer(target);
15065                 if (objsubid == 0)
15066                 {
15067                         appendPQExpBuffer(target, "%s %s", reltypename,
15068                                                           fmtQualifiedDumpable(tbinfo));
15069                 }
15070                 else
15071                 {
15072                         colname = getAttrName(objsubid, tbinfo);
15073                         /* first fmtXXX result must be consumed before calling again */
15074                         appendPQExpBuffer(target, "COLUMN %s",
15075                                                           fmtQualifiedDumpable(tbinfo));
15076                         appendPQExpBuffer(target, ".%s", fmtId(colname));
15077                 }
15078                 appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
15079                                                   fmtId(provider), target->data);
15080                 appendStringLiteralAH(query, label, fout);
15081                 appendPQExpBufferStr(query, ";\n");
15082         }
15083         if (query->len > 0)
15084         {
15085                 resetPQExpBuffer(target);
15086                 appendPQExpBuffer(target, "%s %s", reltypename,
15087                                                   fmtId(tbinfo->dobj.name));
15088                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
15089                                          ARCHIVE_OPTS(.tag = target->data,
15090                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
15091                                                                   .owner = tbinfo->rolname,
15092                                                                   .description = "SECURITY LABEL",
15093                                                                   .section = SECTION_NONE,
15094                                                                   .createStmt = query->data,
15095                                                                   .deps = &(tbinfo->dobj.dumpId),
15096                                                                   .nDeps = 1));
15097         }
15098         destroyPQExpBuffer(query);
15099         destroyPQExpBuffer(target);
15100 }
15101
15102 /*
15103  * findSecLabels
15104  *
15105  * Find the security label(s), if any, associated with the given object.
15106  * All the objsubid values associated with the given classoid/objoid are
15107  * found with one search.
15108  */
15109 static int
15110 findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
15111 {
15112         /* static storage for table of security labels */
15113         static SecLabelItem *labels = NULL;
15114         static int      nlabels = -1;
15115
15116         SecLabelItem *middle = NULL;
15117         SecLabelItem *low;
15118         SecLabelItem *high;
15119         int                     nmatch;
15120
15121         /* Get security labels if we didn't already */
15122         if (nlabels < 0)
15123                 nlabels = collectSecLabels(fout, &labels);
15124
15125         if (nlabels <= 0)                       /* no labels, so no match is possible */
15126         {
15127                 *items = NULL;
15128                 return 0;
15129         }
15130
15131         /*
15132          * Do binary search to find some item matching the object.
15133          */
15134         low = &labels[0];
15135         high = &labels[nlabels - 1];
15136         while (low <= high)
15137         {
15138                 middle = low + (high - low) / 2;
15139
15140                 if (classoid < middle->classoid)
15141                         high = middle - 1;
15142                 else if (classoid > middle->classoid)
15143                         low = middle + 1;
15144                 else if (objoid < middle->objoid)
15145                         high = middle - 1;
15146                 else if (objoid > middle->objoid)
15147                         low = middle + 1;
15148                 else
15149                         break;                          /* found a match */
15150         }
15151
15152         if (low > high)                         /* no matches */
15153         {
15154                 *items = NULL;
15155                 return 0;
15156         }
15157
15158         /*
15159          * Now determine how many items match the object.  The search loop
15160          * invariant still holds: only items between low and high inclusive could
15161          * match.
15162          */
15163         nmatch = 1;
15164         while (middle > low)
15165         {
15166                 if (classoid != middle[-1].classoid ||
15167                         objoid != middle[-1].objoid)
15168                         break;
15169                 middle--;
15170                 nmatch++;
15171         }
15172
15173         *items = middle;
15174
15175         middle += nmatch;
15176         while (middle <= high)
15177         {
15178                 if (classoid != middle->classoid ||
15179                         objoid != middle->objoid)
15180                         break;
15181                 middle++;
15182                 nmatch++;
15183         }
15184
15185         return nmatch;
15186 }
15187
15188 /*
15189  * collectSecLabels
15190  *
15191  * Construct a table of all security labels available for database objects.
15192  * It's much faster to pull them all at once.
15193  *
15194  * The table is sorted by classoid/objid/objsubid for speed in lookup.
15195  */
15196 static int
15197 collectSecLabels(Archive *fout, SecLabelItem **items)
15198 {
15199         PGresult   *res;
15200         PQExpBuffer query;
15201         int                     i_label;
15202         int                     i_provider;
15203         int                     i_classoid;
15204         int                     i_objoid;
15205         int                     i_objsubid;
15206         int                     ntups;
15207         int                     i;
15208         SecLabelItem *labels;
15209
15210         query = createPQExpBuffer();
15211
15212         appendPQExpBufferStr(query,
15213                                                  "SELECT label, provider, classoid, objoid, objsubid "
15214                                                  "FROM pg_catalog.pg_seclabel "
15215                                                  "ORDER BY classoid, objoid, objsubid");
15216
15217         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15218
15219         /* Construct lookup table containing OIDs in numeric form */
15220         i_label = PQfnumber(res, "label");
15221         i_provider = PQfnumber(res, "provider");
15222         i_classoid = PQfnumber(res, "classoid");
15223         i_objoid = PQfnumber(res, "objoid");
15224         i_objsubid = PQfnumber(res, "objsubid");
15225
15226         ntups = PQntuples(res);
15227
15228         labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
15229
15230         for (i = 0; i < ntups; i++)
15231         {
15232                 labels[i].label = PQgetvalue(res, i, i_label);
15233                 labels[i].provider = PQgetvalue(res, i, i_provider);
15234                 labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
15235                 labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
15236                 labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
15237         }
15238
15239         /* Do NOT free the PGresult since we are keeping pointers into it */
15240         destroyPQExpBuffer(query);
15241
15242         *items = labels;
15243         return ntups;
15244 }
15245
15246 /*
15247  * dumpTable
15248  *        write out to fout the declarations (not data) of a user-defined table
15249  */
15250 static void
15251 dumpTable(Archive *fout, TableInfo *tbinfo)
15252 {
15253         DumpOptions *dopt = fout->dopt;
15254         char       *namecopy;
15255
15256         /*
15257          * noop if we are not dumping anything about this table, or if we are
15258          * doing a data-only dump
15259          */
15260         if (!tbinfo->dobj.dump || dopt->dataOnly)
15261                 return;
15262
15263         if (tbinfo->relkind == RELKIND_SEQUENCE)
15264                 dumpSequence(fout, tbinfo);
15265         else
15266                 dumpTableSchema(fout, tbinfo);
15267
15268         /* Handle the ACL here */
15269         namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
15270         if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15271         {
15272                 const char *objtype =
15273                 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
15274
15275                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
15276                                 objtype, namecopy, NULL,
15277                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15278                                 tbinfo->relacl, tbinfo->rrelacl,
15279                                 tbinfo->initrelacl, tbinfo->initrrelacl);
15280         }
15281
15282         /*
15283          * Handle column ACLs, if any.  Note: we pull these with a separate query
15284          * rather than trying to fetch them during getTableAttrs, so that we won't
15285          * miss ACLs on system columns.
15286          */
15287         if (fout->remoteVersion >= 80400 && tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15288         {
15289                 PQExpBuffer query = createPQExpBuffer();
15290                 PGresult   *res;
15291                 int                     i;
15292
15293                 if (fout->remoteVersion >= 90600)
15294                 {
15295                         PQExpBuffer acl_subquery = createPQExpBuffer();
15296                         PQExpBuffer racl_subquery = createPQExpBuffer();
15297                         PQExpBuffer initacl_subquery = createPQExpBuffer();
15298                         PQExpBuffer initracl_subquery = createPQExpBuffer();
15299
15300                         buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
15301                                                         initracl_subquery, "at.attacl", "c.relowner", "'c'",
15302                                                         dopt->binary_upgrade);
15303
15304                         appendPQExpBuffer(query,
15305                                                           "SELECT at.attname, "
15306                                                           "%s AS attacl, "
15307                                                           "%s AS rattacl, "
15308                                                           "%s AS initattacl, "
15309                                                           "%s AS initrattacl "
15310                                                           "FROM pg_catalog.pg_attribute at "
15311                                                           "JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
15312                                                           "LEFT JOIN pg_catalog.pg_init_privs pip ON "
15313                                                           "(at.attrelid = pip.objoid "
15314                                                           "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
15315                                                           "AND at.attnum = pip.objsubid) "
15316                                                           "WHERE at.attrelid = '%u'::pg_catalog.oid AND "
15317                                                           "NOT at.attisdropped "
15318                                                           "AND ("
15319                                                           "%s IS NOT NULL OR "
15320                                                           "%s IS NOT NULL OR "
15321                                                           "%s IS NOT NULL OR "
15322                                                           "%s IS NOT NULL)"
15323                                                           "ORDER BY at.attnum",
15324                                                           acl_subquery->data,
15325                                                           racl_subquery->data,
15326                                                           initacl_subquery->data,
15327                                                           initracl_subquery->data,
15328                                                           tbinfo->dobj.catId.oid,
15329                                                           acl_subquery->data,
15330                                                           racl_subquery->data,
15331                                                           initacl_subquery->data,
15332                                                           initracl_subquery->data);
15333
15334                         destroyPQExpBuffer(acl_subquery);
15335                         destroyPQExpBuffer(racl_subquery);
15336                         destroyPQExpBuffer(initacl_subquery);
15337                         destroyPQExpBuffer(initracl_subquery);
15338                 }
15339                 else
15340                 {
15341                         appendPQExpBuffer(query,
15342                                                           "SELECT attname, attacl, NULL as rattacl, "
15343                                                           "NULL AS initattacl, NULL AS initrattacl "
15344                                                           "FROM pg_catalog.pg_attribute "
15345                                                           "WHERE attrelid = '%u'::pg_catalog.oid AND NOT attisdropped "
15346                                                           "AND attacl IS NOT NULL "
15347                                                           "ORDER BY attnum",
15348                                                           tbinfo->dobj.catId.oid);
15349                 }
15350
15351                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15352
15353                 for (i = 0; i < PQntuples(res); i++)
15354                 {
15355                         char       *attname = PQgetvalue(res, i, 0);
15356                         char       *attacl = PQgetvalue(res, i, 1);
15357                         char       *rattacl = PQgetvalue(res, i, 2);
15358                         char       *initattacl = PQgetvalue(res, i, 3);
15359                         char       *initrattacl = PQgetvalue(res, i, 4);
15360                         char       *attnamecopy;
15361
15362                         attnamecopy = pg_strdup(fmtId(attname));
15363                         /* Column's GRANT type is always TABLE */
15364                         dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
15365                                         "TABLE", namecopy, attnamecopy,
15366                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15367                                         attacl, rattacl, initattacl, initrattacl);
15368                         free(attnamecopy);
15369                 }
15370                 PQclear(res);
15371                 destroyPQExpBuffer(query);
15372         }
15373
15374         free(namecopy);
15375
15376         return;
15377 }
15378
15379 /*
15380  * Create the AS clause for a view or materialized view. The semicolon is
15381  * stripped because a materialized view must add a WITH NO DATA clause.
15382  *
15383  * This returns a new buffer which must be freed by the caller.
15384  */
15385 static PQExpBuffer
15386 createViewAsClause(Archive *fout, TableInfo *tbinfo)
15387 {
15388         PQExpBuffer query = createPQExpBuffer();
15389         PQExpBuffer result = createPQExpBuffer();
15390         PGresult   *res;
15391         int                     len;
15392
15393         /* Fetch the view definition */
15394         appendPQExpBuffer(query,
15395                                           "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
15396                                           tbinfo->dobj.catId.oid);
15397
15398         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15399
15400         if (PQntuples(res) != 1)
15401         {
15402                 if (PQntuples(res) < 1)
15403                         fatal("query to obtain definition of view \"%s\" returned no data",
15404                                   tbinfo->dobj.name);
15405                 else
15406                         fatal("query to obtain definition of view \"%s\" returned more than one definition",
15407                                   tbinfo->dobj.name);
15408         }
15409
15410         len = PQgetlength(res, 0, 0);
15411
15412         if (len == 0)
15413                 fatal("definition of view \"%s\" appears to be empty (length zero)",
15414                           tbinfo->dobj.name);
15415
15416         /* Strip off the trailing semicolon so that other things may follow. */
15417         Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
15418         appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
15419
15420         PQclear(res);
15421         destroyPQExpBuffer(query);
15422
15423         return result;
15424 }
15425
15426 /*
15427  * Create a dummy AS clause for a view.  This is used when the real view
15428  * definition has to be postponed because of circular dependencies.
15429  * We must duplicate the view's external properties -- column names and types
15430  * (including collation) -- so that it works for subsequent references.
15431  *
15432  * This returns a new buffer which must be freed by the caller.
15433  */
15434 static PQExpBuffer
15435 createDummyViewAsClause(Archive *fout, TableInfo *tbinfo)
15436 {
15437         PQExpBuffer result = createPQExpBuffer();
15438         int                     j;
15439
15440         appendPQExpBufferStr(result, "SELECT");
15441
15442         for (j = 0; j < tbinfo->numatts; j++)
15443         {
15444                 if (j > 0)
15445                         appendPQExpBufferChar(result, ',');
15446                 appendPQExpBufferStr(result, "\n    ");
15447
15448                 appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
15449
15450                 /*
15451                  * Must add collation if not default for the type, because CREATE OR
15452                  * REPLACE VIEW won't change it
15453                  */
15454                 if (OidIsValid(tbinfo->attcollation[j]))
15455                 {
15456                         CollInfo   *coll;
15457
15458                         coll = findCollationByOid(tbinfo->attcollation[j]);
15459                         if (coll)
15460                                 appendPQExpBuffer(result, " COLLATE %s",
15461                                                                   fmtQualifiedDumpable(coll));
15462                 }
15463
15464                 appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
15465         }
15466
15467         return result;
15468 }
15469
15470 /*
15471  * dumpTableSchema
15472  *        write the declaration (not data) of one user-defined table or view
15473  */
15474 static void
15475 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
15476 {
15477         DumpOptions *dopt = fout->dopt;
15478         PQExpBuffer q = createPQExpBuffer();
15479         PQExpBuffer delq = createPQExpBuffer();
15480         char       *qrelname;
15481         char       *qualrelname;
15482         int                     numParents;
15483         TableInfo **parents;
15484         int                     actual_atts;    /* number of attrs in this CREATE statement */
15485         const char *reltypename;
15486         char       *storage;
15487         int                     j,
15488                                 k;
15489
15490         qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
15491         qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
15492
15493
15494         if (tbinfo->hasoids)
15495                 pg_log_warning("WITH OIDS is not supported anymore (table \"%s\")",
15496                                            qrelname);
15497
15498         if (dopt->binary_upgrade)
15499                 binary_upgrade_set_type_oids_by_rel_oid(fout, q,
15500                                                                                                 tbinfo->dobj.catId.oid);
15501
15502         /* Is it a table or a view? */
15503         if (tbinfo->relkind == RELKIND_VIEW)
15504         {
15505                 PQExpBuffer result;
15506
15507                 /*
15508                  * Note: keep this code in sync with the is_view case in dumpRule()
15509                  */
15510
15511                 reltypename = "VIEW";
15512
15513                 appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
15514
15515                 if (dopt->binary_upgrade)
15516                         binary_upgrade_set_pg_class_oids(fout, q,
15517                                                                                          tbinfo->dobj.catId.oid, false);
15518
15519                 appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
15520
15521                 if (tbinfo->dummy_view)
15522                         result = createDummyViewAsClause(fout, tbinfo);
15523                 else
15524                 {
15525                         if (nonemptyReloptions(tbinfo->reloptions))
15526                         {
15527                                 appendPQExpBufferStr(q, " WITH (");
15528                                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15529                                 appendPQExpBufferChar(q, ')');
15530                         }
15531                         result = createViewAsClause(fout, tbinfo);
15532                 }
15533                 appendPQExpBuffer(q, " AS\n%s", result->data);
15534                 destroyPQExpBuffer(result);
15535
15536                 if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
15537                         appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
15538                 appendPQExpBufferStr(q, ";\n");
15539         }
15540         else
15541         {
15542                 char       *ftoptions = NULL;
15543                 char       *srvname = NULL;
15544
15545                 switch (tbinfo->relkind)
15546                 {
15547                         case RELKIND_FOREIGN_TABLE:
15548                                 {
15549                                         PQExpBuffer query = createPQExpBuffer();
15550                                         PGresult   *res;
15551                                         int                     i_srvname;
15552                                         int                     i_ftoptions;
15553
15554                                         reltypename = "FOREIGN TABLE";
15555
15556                                         /* retrieve name of foreign server and generic options */
15557                                         appendPQExpBuffer(query,
15558                                                                           "SELECT fs.srvname, "
15559                                                                           "pg_catalog.array_to_string(ARRAY("
15560                                                                           "SELECT pg_catalog.quote_ident(option_name) || "
15561                                                                           "' ' || pg_catalog.quote_literal(option_value) "
15562                                                                           "FROM pg_catalog.pg_options_to_table(ftoptions) "
15563                                                                           "ORDER BY option_name"
15564                                                                           "), E',\n    ') AS ftoptions "
15565                                                                           "FROM pg_catalog.pg_foreign_table ft "
15566                                                                           "JOIN pg_catalog.pg_foreign_server fs "
15567                                                                           "ON (fs.oid = ft.ftserver) "
15568                                                                           "WHERE ft.ftrelid = '%u'",
15569                                                                           tbinfo->dobj.catId.oid);
15570                                         res = ExecuteSqlQueryForSingleRow(fout, query->data);
15571                                         i_srvname = PQfnumber(res, "srvname");
15572                                         i_ftoptions = PQfnumber(res, "ftoptions");
15573                                         srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
15574                                         ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
15575                                         PQclear(res);
15576                                         destroyPQExpBuffer(query);
15577                                         break;
15578                                 }
15579                         case RELKIND_MATVIEW:
15580                                 reltypename = "MATERIALIZED VIEW";
15581                                 break;
15582                         default:
15583                                 reltypename = "TABLE";
15584                 }
15585
15586                 numParents = tbinfo->numParents;
15587                 parents = tbinfo->parents;
15588
15589                 appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
15590
15591                 if (dopt->binary_upgrade)
15592                         binary_upgrade_set_pg_class_oids(fout, q,
15593                                                                                          tbinfo->dobj.catId.oid, false);
15594
15595                 appendPQExpBuffer(q, "CREATE %s%s %s",
15596                                                   tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
15597                                                   "UNLOGGED " : "",
15598                                                   reltypename,
15599                                                   qualrelname);
15600
15601                 /*
15602                  * Attach to type, if reloftype; except in case of a binary upgrade,
15603                  * we dump the table normally and attach it to the type afterward.
15604                  */
15605                 if (tbinfo->reloftype && !dopt->binary_upgrade)
15606                         appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
15607
15608                 if (tbinfo->relkind != RELKIND_MATVIEW)
15609                 {
15610                         /* Dump the attributes */
15611                         actual_atts = 0;
15612                         for (j = 0; j < tbinfo->numatts; j++)
15613                         {
15614                                 /*
15615                                  * Normally, dump if it's locally defined in this table, and
15616                                  * not dropped.  But for binary upgrade, we'll dump all the
15617                                  * columns, and then fix up the dropped and nonlocal cases
15618                                  * below.
15619                                  */
15620                                 if (shouldPrintColumn(dopt, tbinfo, j))
15621                                 {
15622                                         bool            print_default;
15623                                         bool            print_notnull;
15624
15625                                         /*
15626                                          * Default value --- suppress if to be printed separately.
15627                                          */
15628                                         print_default = (tbinfo->attrdefs[j] != NULL &&
15629                                                                          !tbinfo->attrdefs[j]->separate);
15630
15631                                         /*
15632                                          * Not Null constraint --- suppress if inherited, except
15633                                          * if partition, or in binary-upgrade case where that
15634                                          * won't work.
15635                                          */
15636                                         print_notnull = (tbinfo->notnull[j] &&
15637                                                                          (!tbinfo->inhNotNull[j] ||
15638                                                                           tbinfo->ispartition || dopt->binary_upgrade));
15639
15640                                         /*
15641                                          * Skip column if fully defined by reloftype, except in
15642                                          * binary upgrade
15643                                          */
15644                                         if (tbinfo->reloftype && !print_default && !print_notnull &&
15645                                                 !dopt->binary_upgrade)
15646                                                 continue;
15647
15648                                         /* Format properly if not first attr */
15649                                         if (actual_atts == 0)
15650                                                 appendPQExpBufferStr(q, " (");
15651                                         else
15652                                                 appendPQExpBufferChar(q, ',');
15653                                         appendPQExpBufferStr(q, "\n    ");
15654                                         actual_atts++;
15655
15656                                         /* Attribute name */
15657                                         appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
15658
15659                                         if (tbinfo->attisdropped[j])
15660                                         {
15661                                                 /*
15662                                                  * ALTER TABLE DROP COLUMN clears
15663                                                  * pg_attribute.atttypid, so we will not have gotten a
15664                                                  * valid type name; insert INTEGER as a stopgap. We'll
15665                                                  * clean things up later.
15666                                                  */
15667                                                 appendPQExpBufferStr(q, " INTEGER /* dummy */");
15668                                                 /* and skip to the next column */
15669                                                 continue;
15670                                         }
15671
15672                                         /*
15673                                          * Attribute type; print it except when creating a typed
15674                                          * table ('OF type_name'), but in binary-upgrade mode,
15675                                          * print it in that case too.
15676                                          */
15677                                         if (dopt->binary_upgrade || !tbinfo->reloftype)
15678                                         {
15679                                                 appendPQExpBuffer(q, " %s",
15680                                                                                   tbinfo->atttypnames[j]);
15681                                         }
15682
15683                                         if (print_default)
15684                                         {
15685                                                 if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
15686                                                         appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
15687                                                                                           tbinfo->attrdefs[j]->adef_expr);
15688                                                 else
15689                                                         appendPQExpBuffer(q, " DEFAULT %s",
15690                                                                                           tbinfo->attrdefs[j]->adef_expr);
15691                                         }
15692
15693
15694                                         if (print_notnull)
15695                                                 appendPQExpBufferStr(q, " NOT NULL");
15696
15697                                         /* Add collation if not default for the type */
15698                                         if (OidIsValid(tbinfo->attcollation[j]))
15699                                         {
15700                                                 CollInfo   *coll;
15701
15702                                                 coll = findCollationByOid(tbinfo->attcollation[j]);
15703                                                 if (coll)
15704                                                         appendPQExpBuffer(q, " COLLATE %s",
15705                                                                                           fmtQualifiedDumpable(coll));
15706                                         }
15707                                 }
15708                         }
15709
15710                         /*
15711                          * Add non-inherited CHECK constraints, if any.
15712                          *
15713                          * For partitions, we need to include check constraints even if
15714                          * they're not defined locally, because the ALTER TABLE ATTACH
15715                          * PARTITION that we'll emit later expects the constraint to be
15716                          * there.  (No need to fix conislocal: ATTACH PARTITION does that)
15717                          */
15718                         for (j = 0; j < tbinfo->ncheck; j++)
15719                         {
15720                                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
15721
15722                                 if (constr->separate ||
15723                                         (!constr->conislocal && !tbinfo->ispartition))
15724                                         continue;
15725
15726                                 if (actual_atts == 0)
15727                                         appendPQExpBufferStr(q, " (\n    ");
15728                                 else
15729                                         appendPQExpBufferStr(q, ",\n    ");
15730
15731                                 appendPQExpBuffer(q, "CONSTRAINT %s ",
15732                                                                   fmtId(constr->dobj.name));
15733                                 appendPQExpBufferStr(q, constr->condef);
15734
15735                                 actual_atts++;
15736                         }
15737
15738                         if (actual_atts)
15739                                 appendPQExpBufferStr(q, "\n)");
15740                         else if (!(tbinfo->reloftype && !dopt->binary_upgrade))
15741                         {
15742                                 /*
15743                                  * No attributes? we must have a parenthesized attribute list,
15744                                  * even though empty, when not using the OF TYPE syntax.
15745                                  */
15746                                 appendPQExpBufferStr(q, " (\n)");
15747                         }
15748
15749                         /*
15750                          * Emit the INHERITS clause (not for partitions), except in
15751                          * binary-upgrade mode.
15752                          */
15753                         if (numParents > 0 && !tbinfo->ispartition &&
15754                                 !dopt->binary_upgrade)
15755                         {
15756                                 appendPQExpBufferStr(q, "\nINHERITS (");
15757                                 for (k = 0; k < numParents; k++)
15758                                 {
15759                                         TableInfo  *parentRel = parents[k];
15760
15761                                         if (k > 0)
15762                                                 appendPQExpBufferStr(q, ", ");
15763                                         appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
15764                                 }
15765                                 appendPQExpBufferChar(q, ')');
15766                         }
15767
15768                         if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15769                                 appendPQExpBuffer(q, "\nPARTITION BY %s", tbinfo->partkeydef);
15770
15771                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
15772                                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
15773                 }
15774
15775                 if (nonemptyReloptions(tbinfo->reloptions) ||
15776                         nonemptyReloptions(tbinfo->toast_reloptions))
15777                 {
15778                         bool            addcomma = false;
15779
15780                         appendPQExpBufferStr(q, "\nWITH (");
15781                         if (nonemptyReloptions(tbinfo->reloptions))
15782                         {
15783                                 addcomma = true;
15784                                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15785                         }
15786                         if (nonemptyReloptions(tbinfo->toast_reloptions))
15787                         {
15788                                 if (addcomma)
15789                                         appendPQExpBufferStr(q, ", ");
15790                                 appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
15791                                                                                 fout);
15792                         }
15793                         appendPQExpBufferChar(q, ')');
15794                 }
15795
15796                 /* Dump generic options if any */
15797                 if (ftoptions && ftoptions[0])
15798                         appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
15799
15800                 /*
15801                  * For materialized views, create the AS clause just like a view. At
15802                  * this point, we always mark the view as not populated.
15803                  */
15804                 if (tbinfo->relkind == RELKIND_MATVIEW)
15805                 {
15806                         PQExpBuffer result;
15807
15808                         result = createViewAsClause(fout, tbinfo);
15809                         appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
15810                                                           result->data);
15811                         destroyPQExpBuffer(result);
15812                 }
15813                 else
15814                         appendPQExpBufferStr(q, ";\n");
15815
15816                 /*
15817                  * in binary upgrade mode, update the catalog with any missing values
15818                  * that might be present.
15819                  */
15820                 if (dopt->binary_upgrade)
15821                 {
15822                         for (j = 0; j < tbinfo->numatts; j++)
15823                         {
15824                                 if (tbinfo->attmissingval[j][0] != '\0')
15825                                 {
15826                                         appendPQExpBufferStr(q, "\n-- set missing value.\n");
15827                                         appendPQExpBufferStr(q,
15828                                                                                  "SELECT pg_catalog.binary_upgrade_set_missing_value(");
15829                                         appendStringLiteralAH(q, qualrelname, fout);
15830                                         appendPQExpBufferStr(q, "::pg_catalog.regclass,");
15831                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15832                                         appendPQExpBufferStr(q, ",");
15833                                         appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
15834                                         appendPQExpBufferStr(q, ");\n\n");
15835                                 }
15836                         }
15837                 }
15838
15839                 /*
15840                  * To create binary-compatible heap files, we have to ensure the same
15841                  * physical column order, including dropped columns, as in the
15842                  * original.  Therefore, we create dropped columns above and drop them
15843                  * here, also updating their attlen/attalign values so that the
15844                  * dropped column can be skipped properly.  (We do not bother with
15845                  * restoring the original attbyval setting.)  Also, inheritance
15846                  * relationships are set up by doing ALTER TABLE INHERIT rather than
15847                  * using an INHERITS clause --- the latter would possibly mess up the
15848                  * column order.  That also means we have to take care about setting
15849                  * attislocal correctly, plus fix up any inherited CHECK constraints.
15850                  * Analogously, we set up typed tables using ALTER TABLE / OF here.
15851                  *
15852                  * We process foreign and partitioned tables here, even though they
15853                  * lack heap storage, because they can participate in inheritance
15854                  * relationships and we want this stuff to be consistent across the
15855                  * inheritance tree.  We can exclude indexes, toast tables, sequences
15856                  * and matviews, even though they have storage, because we don't
15857                  * support altering or dropping columns in them, nor can they be part
15858                  * of inheritance trees.
15859                  */
15860                 if (dopt->binary_upgrade &&
15861                         (tbinfo->relkind == RELKIND_RELATION ||
15862                          tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
15863                          tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
15864                 {
15865                         for (j = 0; j < tbinfo->numatts; j++)
15866                         {
15867                                 if (tbinfo->attisdropped[j])
15868                                 {
15869                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
15870                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
15871                                                                           "SET attlen = %d, "
15872                                                                           "attalign = '%c', attbyval = false\n"
15873                                                                           "WHERE attname = ",
15874                                                                           tbinfo->attlen[j],
15875                                                                           tbinfo->attalign[j]);
15876                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15877                                         appendPQExpBufferStr(q, "\n  AND attrelid = ");
15878                                         appendStringLiteralAH(q, qualrelname, fout);
15879                                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15880
15881                                         if (tbinfo->relkind == RELKIND_RELATION ||
15882                                                 tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15883                                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15884                                                                                   qualrelname);
15885                                         else
15886                                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE ONLY %s ",
15887                                                                                   qualrelname);
15888                                         appendPQExpBuffer(q, "DROP COLUMN %s;\n",
15889                                                                           fmtId(tbinfo->attnames[j]));
15890                                 }
15891                                 else if (!tbinfo->attislocal[j])
15892                                 {
15893                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
15894                                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
15895                                                                                  "SET attislocal = false\n"
15896                                                                                  "WHERE attname = ");
15897                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15898                                         appendPQExpBufferStr(q, "\n  AND attrelid = ");
15899                                         appendStringLiteralAH(q, qualrelname, fout);
15900                                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15901                                 }
15902                         }
15903
15904                         /*
15905                          * Add inherited CHECK constraints, if any.
15906                          *
15907                          * For partitions, they were already dumped, and conislocal
15908                          * doesn't need fixing.
15909                          */
15910                         for (k = 0; k < tbinfo->ncheck; k++)
15911                         {
15912                                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
15913
15914                                 if (constr->separate || constr->conislocal || tbinfo->ispartition)
15915                                         continue;
15916
15917                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
15918                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15919                                                                   qualrelname);
15920                                 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
15921                                                                   fmtId(constr->dobj.name));
15922                                 appendPQExpBuffer(q, "%s;\n", constr->condef);
15923                                 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
15924                                                                          "SET conislocal = false\n"
15925                                                                          "WHERE contype = 'c' AND conname = ");
15926                                 appendStringLiteralAH(q, constr->dobj.name, fout);
15927                                 appendPQExpBufferStr(q, "\n  AND conrelid = ");
15928                                 appendStringLiteralAH(q, qualrelname, fout);
15929                                 appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15930                         }
15931
15932                         if (numParents > 0 && !tbinfo->ispartition)
15933                         {
15934                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
15935                                 for (k = 0; k < numParents; k++)
15936                                 {
15937                                         TableInfo  *parentRel = parents[k];
15938
15939                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT %s;\n",
15940                                                                           qualrelname,
15941                                                                           fmtQualifiedDumpable(parentRel));
15942                                 }
15943                         }
15944
15945                         if (tbinfo->reloftype)
15946                         {
15947                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
15948                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
15949                                                                   qualrelname,
15950                                                                   tbinfo->reloftype);
15951                         }
15952                 }
15953
15954                 /*
15955                  * For partitioned tables, emit the ATTACH PARTITION clause.  Note
15956                  * that we always want to create partitions this way instead of using
15957                  * CREATE TABLE .. PARTITION OF, mainly to preserve a possible column
15958                  * layout discrepancy with the parent, but also to ensure it gets the
15959                  * correct tablespace setting if it differs from the parent's.
15960                  */
15961                 if (tbinfo->ispartition)
15962                 {
15963                         /* With partitions there can only be one parent */
15964                         if (tbinfo->numParents != 1)
15965                                 fatal("invalid number of parents %d for table \"%s\"",
15966                                           tbinfo->numParents, tbinfo->dobj.name);
15967
15968                         /* Perform ALTER TABLE on the parent */
15969                         appendPQExpBuffer(q,
15970                                                           "ALTER TABLE ONLY %s ATTACH PARTITION %s %s;\n",
15971                                                           fmtQualifiedDumpable(parents[0]),
15972                                                           qualrelname, tbinfo->partbound);
15973                 }
15974
15975                 /*
15976                  * In binary_upgrade mode, arrange to restore the old relfrozenxid and
15977                  * relminmxid of all vacuumable relations.  (While vacuum.c processes
15978                  * TOAST tables semi-independently, here we see them only as children
15979                  * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
15980                  * child toast table is handled below.)
15981                  */
15982                 if (dopt->binary_upgrade &&
15983                         (tbinfo->relkind == RELKIND_RELATION ||
15984                          tbinfo->relkind == RELKIND_MATVIEW))
15985                 {
15986                         appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
15987                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
15988                                                           "SET relfrozenxid = '%u', relminmxid = '%u'\n"
15989                                                           "WHERE oid = ",
15990                                                           tbinfo->frozenxid, tbinfo->minmxid);
15991                         appendStringLiteralAH(q, qualrelname, fout);
15992                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15993
15994                         if (tbinfo->toast_oid)
15995                         {
15996                                 /*
15997                                  * The toast table will have the same OID at restore, so we
15998                                  * can safely target it by OID.
15999                                  */
16000                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
16001                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
16002                                                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
16003                                                                   "WHERE oid = '%u';\n",
16004                                                                   tbinfo->toast_frozenxid,
16005                                                                   tbinfo->toast_minmxid, tbinfo->toast_oid);
16006                         }
16007                 }
16008
16009                 /*
16010                  * In binary_upgrade mode, restore matviews' populated status by
16011                  * poking pg_class directly.  This is pretty ugly, but we can't use
16012                  * REFRESH MATERIALIZED VIEW since it's possible that some underlying
16013                  * matview is not populated even though this matview is; in any case,
16014                  * we want to transfer the matview's heap storage, not run REFRESH.
16015                  */
16016                 if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
16017                         tbinfo->relispopulated)
16018                 {
16019                         appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
16020                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
16021                                                                  "SET relispopulated = 't'\n"
16022                                                                  "WHERE oid = ");
16023                         appendStringLiteralAH(q, qualrelname, fout);
16024                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16025                 }
16026
16027                 /*
16028                  * Dump additional per-column properties that we can't handle in the
16029                  * main CREATE TABLE command.
16030                  */
16031                 for (j = 0; j < tbinfo->numatts; j++)
16032                 {
16033                         /* None of this applies to dropped columns */
16034                         if (tbinfo->attisdropped[j])
16035                                 continue;
16036
16037                         /*
16038                          * If we didn't dump the column definition explicitly above, and
16039                          * it is NOT NULL and did not inherit that property from a parent,
16040                          * we have to mark it separately.
16041                          */
16042                         if (!shouldPrintColumn(dopt, tbinfo, j) &&
16043                                 tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
16044                         {
16045                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16046                                                                   qualrelname);
16047                                 appendPQExpBuffer(q, "ALTER COLUMN %s SET NOT NULL;\n",
16048                                                                   fmtId(tbinfo->attnames[j]));
16049                         }
16050
16051                         /*
16052                          * Dump per-column statistics information. We only issue an ALTER
16053                          * TABLE statement if the attstattarget entry for this column is
16054                          * non-negative (i.e. it's not the default value)
16055                          */
16056                         if (tbinfo->attstattarget[j] >= 0)
16057                         {
16058                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16059                                                                   qualrelname);
16060                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
16061                                                                   fmtId(tbinfo->attnames[j]));
16062                                 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
16063                                                                   tbinfo->attstattarget[j]);
16064                         }
16065
16066                         /*
16067                          * Dump per-column storage information.  The statement is only
16068                          * dumped if the storage has been changed from the type's default.
16069                          */
16070                         if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
16071                         {
16072                                 switch (tbinfo->attstorage[j])
16073                                 {
16074                                         case 'p':
16075                                                 storage = "PLAIN";
16076                                                 break;
16077                                         case 'e':
16078                                                 storage = "EXTERNAL";
16079                                                 break;
16080                                         case 'm':
16081                                                 storage = "MAIN";
16082                                                 break;
16083                                         case 'x':
16084                                                 storage = "EXTENDED";
16085                                                 break;
16086                                         default:
16087                                                 storage = NULL;
16088                                 }
16089
16090                                 /*
16091                                  * Only dump the statement if it's a storage type we recognize
16092                                  */
16093                                 if (storage != NULL)
16094                                 {
16095                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16096                                                                           qualrelname);
16097                                         appendPQExpBuffer(q, "ALTER COLUMN %s ",
16098                                                                           fmtId(tbinfo->attnames[j]));
16099                                         appendPQExpBuffer(q, "SET STORAGE %s;\n",
16100                                                                           storage);
16101                                 }
16102                         }
16103
16104                         /*
16105                          * Dump per-column attributes.
16106                          */
16107                         if (tbinfo->attoptions[j][0] != '\0')
16108                         {
16109                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16110                                                                   qualrelname);
16111                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
16112                                                                   fmtId(tbinfo->attnames[j]));
16113                                 appendPQExpBuffer(q, "SET (%s);\n",
16114                                                                   tbinfo->attoptions[j]);
16115                         }
16116
16117                         /*
16118                          * Dump per-column fdw options.
16119                          */
16120                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
16121                                 tbinfo->attfdwoptions[j][0] != '\0')
16122                         {
16123                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
16124                                                                   qualrelname);
16125                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
16126                                                                   fmtId(tbinfo->attnames[j]));
16127                                 appendPQExpBuffer(q, "OPTIONS (\n    %s\n);\n",
16128                                                                   tbinfo->attfdwoptions[j]);
16129                         }
16130                 }
16131
16132                 if (ftoptions)
16133                         free(ftoptions);
16134                 if (srvname)
16135                         free(srvname);
16136         }
16137
16138         /*
16139          * dump properties we only have ALTER TABLE syntax for
16140          */
16141         if ((tbinfo->relkind == RELKIND_RELATION ||
16142                  tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
16143                  tbinfo->relkind == RELKIND_MATVIEW) &&
16144                 tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
16145         {
16146                 if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
16147                 {
16148                         /* nothing to do, will be set when the index is dumped */
16149                 }
16150                 else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
16151                 {
16152                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
16153                                                           qualrelname);
16154                 }
16155                 else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
16156                 {
16157                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
16158                                                           qualrelname);
16159                 }
16160         }
16161
16162         if (tbinfo->forcerowsec)
16163                 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
16164                                                   qualrelname);
16165
16166         if (dopt->binary_upgrade)
16167                 binary_upgrade_extension_member(q, &tbinfo->dobj,
16168                                                                                 reltypename, qrelname,
16169                                                                                 tbinfo->dobj.namespace->dobj.name);
16170
16171         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16172         {
16173                 char       *tableam = NULL;
16174
16175                 if (tbinfo->relkind == RELKIND_RELATION ||
16176                         tbinfo->relkind == RELKIND_MATVIEW)
16177                         tableam = tbinfo->amname;
16178
16179                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
16180                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
16181                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
16182                                                                   .tablespace = (tbinfo->relkind == RELKIND_VIEW) ?
16183                                                                   NULL : tbinfo->reltablespace,
16184                                                                   .tableam = tableam,
16185                                                                   .owner = tbinfo->rolname,
16186                                                                   .description = reltypename,
16187                                                                   .section = tbinfo->postponed_def ?
16188                                                                   SECTION_POST_DATA : SECTION_PRE_DATA,
16189                                                                   .createStmt = q->data,
16190                                                                   .dropStmt = delq->data));
16191         }
16192
16193         /* Dump Table Comments */
16194         if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16195                 dumpTableComment(fout, tbinfo, reltypename);
16196
16197         /* Dump Table Security Labels */
16198         if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
16199                 dumpTableSecLabel(fout, tbinfo, reltypename);
16200
16201         /* Dump comments on inlined table constraints */
16202         for (j = 0; j < tbinfo->ncheck; j++)
16203         {
16204                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
16205
16206                 if (constr->separate || !constr->conislocal)
16207                         continue;
16208
16209                 if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16210                         dumpTableConstraintComment(fout, constr);
16211         }
16212
16213         destroyPQExpBuffer(q);
16214         destroyPQExpBuffer(delq);
16215         free(qrelname);
16216         free(qualrelname);
16217 }
16218
16219 /*
16220  * dumpAttrDef --- dump an attribute's default-value declaration
16221  */
16222 static void
16223 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
16224 {
16225         DumpOptions *dopt = fout->dopt;
16226         TableInfo  *tbinfo = adinfo->adtable;
16227         int                     adnum = adinfo->adnum;
16228         PQExpBuffer q;
16229         PQExpBuffer delq;
16230         char       *qualrelname;
16231         char       *tag;
16232
16233         /* Skip if table definition not to be dumped */
16234         if (!tbinfo->dobj.dump || dopt->dataOnly)
16235                 return;
16236
16237         /* Skip if not "separate"; it was dumped in the table's definition */
16238         if (!adinfo->separate)
16239                 return;
16240
16241         q = createPQExpBuffer();
16242         delq = createPQExpBuffer();
16243
16244         qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
16245
16246         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16247                                           qualrelname);
16248         appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
16249                                           fmtId(tbinfo->attnames[adnum - 1]),
16250                                           adinfo->adef_expr);
16251
16252         appendPQExpBuffer(delq, "ALTER TABLE %s ",
16253                                           qualrelname);
16254         appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
16255                                           fmtId(tbinfo->attnames[adnum - 1]));
16256
16257         tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
16258
16259         if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16260                 ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
16261                                          ARCHIVE_OPTS(.tag = tag,
16262                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
16263                                                                   .owner = tbinfo->rolname,
16264                                                                   .description = "DEFAULT",
16265                                                                   .section = SECTION_PRE_DATA,
16266                                                                   .createStmt = q->data,
16267                                                                   .dropStmt = delq->data));
16268
16269         free(tag);
16270         destroyPQExpBuffer(q);
16271         destroyPQExpBuffer(delq);
16272         free(qualrelname);
16273 }
16274
16275 /*
16276  * getAttrName: extract the correct name for an attribute
16277  *
16278  * The array tblInfo->attnames[] only provides names of user attributes;
16279  * if a system attribute number is supplied, we have to fake it.
16280  * We also do a little bit of bounds checking for safety's sake.
16281  */
16282 static const char *
16283 getAttrName(int attrnum, TableInfo *tblInfo)
16284 {
16285         if (attrnum > 0 && attrnum <= tblInfo->numatts)
16286                 return tblInfo->attnames[attrnum - 1];
16287         switch (attrnum)
16288         {
16289                 case SelfItemPointerAttributeNumber:
16290                         return "ctid";
16291                 case MinTransactionIdAttributeNumber:
16292                         return "xmin";
16293                 case MinCommandIdAttributeNumber:
16294                         return "cmin";
16295                 case MaxTransactionIdAttributeNumber:
16296                         return "xmax";
16297                 case MaxCommandIdAttributeNumber:
16298                         return "cmax";
16299                 case TableOidAttributeNumber:
16300                         return "tableoid";
16301         }
16302         fatal("invalid column number %d for table \"%s\"",
16303                   attrnum, tblInfo->dobj.name);
16304         return NULL;                            /* keep compiler quiet */
16305 }
16306
16307 /*
16308  * dumpIndex
16309  *        write out to fout a user-defined index
16310  */
16311 static void
16312 dumpIndex(Archive *fout, IndxInfo *indxinfo)
16313 {
16314         DumpOptions *dopt = fout->dopt;
16315         TableInfo  *tbinfo = indxinfo->indextable;
16316         bool            is_constraint = (indxinfo->indexconstraint != 0);
16317         PQExpBuffer q;
16318         PQExpBuffer delq;
16319         char       *qindxname;
16320
16321         if (dopt->dataOnly)
16322                 return;
16323
16324         q = createPQExpBuffer();
16325         delq = createPQExpBuffer();
16326
16327         qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
16328
16329         /*
16330          * If there's an associated constraint, don't dump the index per se, but
16331          * do dump any comment for it.  (This is safe because dependency ordering
16332          * will have ensured the constraint is emitted first.)  Note that the
16333          * emitted comment has to be shown as depending on the constraint, not the
16334          * index, in such cases.
16335          */
16336         if (!is_constraint)
16337         {
16338                 char       *indstatcols = indxinfo->indstatcols;
16339                 char       *indstatvals = indxinfo->indstatvals;
16340                 char      **indstatcolsarray = NULL;
16341                 char      **indstatvalsarray = NULL;
16342                 int                     nstatcols;
16343                 int                     nstatvals;
16344
16345                 if (dopt->binary_upgrade)
16346                         binary_upgrade_set_pg_class_oids(fout, q,
16347                                                                                          indxinfo->dobj.catId.oid, true);
16348
16349                 /* Plain secondary index */
16350                 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
16351
16352                 /*
16353                  * Append ALTER TABLE commands as needed to set properties that we
16354                  * only have ALTER TABLE syntax for.  Keep this in sync with the
16355                  * similar code in dumpConstraint!
16356                  */
16357
16358                 /* If the index is clustered, we need to record that. */
16359                 if (indxinfo->indisclustered)
16360                 {
16361                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16362                                                           fmtQualifiedDumpable(tbinfo));
16363                         /* index name is not qualified in this syntax */
16364                         appendPQExpBuffer(q, " ON %s;\n",
16365                                                           qindxname);
16366                 }
16367
16368                 /*
16369                  * If the index has any statistics on some of its columns, generate
16370                  * the associated ALTER INDEX queries.
16371                  */
16372                 if (parsePGArray(indstatcols, &indstatcolsarray, &nstatcols) &&
16373                         parsePGArray(indstatvals, &indstatvalsarray, &nstatvals) &&
16374                         nstatcols == nstatvals)
16375                 {
16376                         int                     j;
16377
16378                         for (j = 0; j < nstatcols; j++)
16379                         {
16380                                 appendPQExpBuffer(q, "ALTER INDEX %s ",
16381                                                                   fmtQualifiedDumpable(indxinfo));
16382
16383                                 /*
16384                                  * Note that this is a column number, so no quotes should be
16385                                  * used.
16386                                  */
16387                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
16388                                                                   indstatcolsarray[j]);
16389                                 appendPQExpBuffer(q, "SET STATISTICS %s;\n",
16390                                                                   indstatvalsarray[j]);
16391                         }
16392                 }
16393
16394                 /* If the index defines identity, we need to record that. */
16395                 if (indxinfo->indisreplident)
16396                 {
16397                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
16398                                                           fmtQualifiedDumpable(tbinfo));
16399                         /* index name is not qualified in this syntax */
16400                         appendPQExpBuffer(q, " INDEX %s;\n",
16401                                                           qindxname);
16402                 }
16403
16404                 appendPQExpBuffer(delq, "DROP INDEX %s;\n",
16405                                                   fmtQualifiedDumpable(indxinfo));
16406
16407                 if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16408                         ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
16409                                                  ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
16410                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
16411                                                                           .tablespace = indxinfo->tablespace,
16412                                                                           .owner = tbinfo->rolname,
16413                                                                           .description = "INDEX",
16414                                                                           .section = SECTION_POST_DATA,
16415                                                                           .createStmt = q->data,
16416                                                                           .dropStmt = delq->data));
16417
16418                 if (indstatcolsarray)
16419                         free(indstatcolsarray);
16420                 if (indstatvalsarray)
16421                         free(indstatvalsarray);
16422         }
16423
16424         /* Dump Index Comments */
16425         if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16426                 dumpComment(fout, "INDEX", qindxname,
16427                                         tbinfo->dobj.namespace->dobj.name,
16428                                         tbinfo->rolname,
16429                                         indxinfo->dobj.catId, 0,
16430                                         is_constraint ? indxinfo->indexconstraint :
16431                                         indxinfo->dobj.dumpId);
16432
16433         destroyPQExpBuffer(q);
16434         destroyPQExpBuffer(delq);
16435         free(qindxname);
16436 }
16437
16438 /*
16439  * dumpIndexAttach
16440  *        write out to fout a partitioned-index attachment clause
16441  */
16442 static void
16443 dumpIndexAttach(Archive *fout, IndexAttachInfo *attachinfo)
16444 {
16445         if (fout->dopt->dataOnly)
16446                 return;
16447
16448         if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
16449         {
16450                 PQExpBuffer q = createPQExpBuffer();
16451
16452                 appendPQExpBuffer(q, "ALTER INDEX %s ",
16453                                                   fmtQualifiedDumpable(attachinfo->parentIdx));
16454                 appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
16455                                                   fmtQualifiedDumpable(attachinfo->partitionIdx));
16456
16457                 ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
16458                                          ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
16459                                                                   .namespace = attachinfo->dobj.namespace->dobj.name,
16460                                                                   .description = "INDEX ATTACH",
16461                                                                   .section = SECTION_POST_DATA,
16462                                                                   .createStmt = q->data));
16463
16464                 destroyPQExpBuffer(q);
16465         }
16466 }
16467
16468 /*
16469  * dumpStatisticsExt
16470  *        write out to fout an extended statistics object
16471  */
16472 static void
16473 dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo)
16474 {
16475         DumpOptions *dopt = fout->dopt;
16476         PQExpBuffer q;
16477         PQExpBuffer delq;
16478         PQExpBuffer query;
16479         char       *qstatsextname;
16480         PGresult   *res;
16481         char       *stxdef;
16482
16483         /* Skip if not to be dumped */
16484         if (!statsextinfo->dobj.dump || dopt->dataOnly)
16485                 return;
16486
16487         q = createPQExpBuffer();
16488         delq = createPQExpBuffer();
16489         query = createPQExpBuffer();
16490
16491         qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
16492
16493         appendPQExpBuffer(query, "SELECT "
16494                                           "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
16495                                           statsextinfo->dobj.catId.oid);
16496
16497         res = ExecuteSqlQueryForSingleRow(fout, query->data);
16498
16499         stxdef = PQgetvalue(res, 0, 0);
16500
16501         /* Result of pg_get_statisticsobjdef is complete except for semicolon */
16502         appendPQExpBuffer(q, "%s;\n", stxdef);
16503
16504         appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
16505                                           fmtQualifiedDumpable(statsextinfo));
16506
16507         if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16508                 ArchiveEntry(fout, statsextinfo->dobj.catId,
16509                                          statsextinfo->dobj.dumpId,
16510                                          ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
16511                                                                   .namespace = statsextinfo->dobj.namespace->dobj.name,
16512                                                                   .owner = statsextinfo->rolname,
16513                                                                   .description = "STATISTICS",
16514                                                                   .section = SECTION_POST_DATA,
16515                                                                   .createStmt = q->data,
16516                                                                   .dropStmt = delq->data));
16517
16518         /* Dump Statistics Comments */
16519         if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16520                 dumpComment(fout, "STATISTICS", qstatsextname,
16521                                         statsextinfo->dobj.namespace->dobj.name,
16522                                         statsextinfo->rolname,
16523                                         statsextinfo->dobj.catId, 0,
16524                                         statsextinfo->dobj.dumpId);
16525
16526         PQclear(res);
16527         destroyPQExpBuffer(q);
16528         destroyPQExpBuffer(delq);
16529         destroyPQExpBuffer(query);
16530         free(qstatsextname);
16531 }
16532
16533 /*
16534  * dumpConstraint
16535  *        write out to fout a user-defined constraint
16536  */
16537 static void
16538 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
16539 {
16540         DumpOptions *dopt = fout->dopt;
16541         TableInfo  *tbinfo = coninfo->contable;
16542         PQExpBuffer q;
16543         PQExpBuffer delq;
16544         char       *tag = NULL;
16545
16546         /* Skip if not to be dumped */
16547         if (!coninfo->dobj.dump || dopt->dataOnly)
16548                 return;
16549
16550         q = createPQExpBuffer();
16551         delq = createPQExpBuffer();
16552
16553         if (coninfo->contype == 'p' ||
16554                 coninfo->contype == 'u' ||
16555                 coninfo->contype == 'x')
16556         {
16557                 /* Index-related constraint */
16558                 IndxInfo   *indxinfo;
16559                 int                     k;
16560
16561                 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
16562
16563                 if (indxinfo == NULL)
16564                         fatal("missing index for constraint \"%s\"",
16565                                   coninfo->dobj.name);
16566
16567                 if (dopt->binary_upgrade)
16568                         binary_upgrade_set_pg_class_oids(fout, q,
16569                                                                                          indxinfo->dobj.catId.oid, true);
16570
16571                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
16572                                                   fmtQualifiedDumpable(tbinfo));
16573                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
16574                                                   fmtId(coninfo->dobj.name));
16575
16576                 if (coninfo->condef)
16577                 {
16578                         /* pg_get_constraintdef should have provided everything */
16579                         appendPQExpBuffer(q, "%s;\n", coninfo->condef);
16580                 }
16581                 else
16582                 {
16583                         appendPQExpBuffer(q, "%s (",
16584                                                           coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
16585                         for (k = 0; k < indxinfo->indnkeyattrs; k++)
16586                         {
16587                                 int                     indkey = (int) indxinfo->indkeys[k];
16588                                 const char *attname;
16589
16590                                 if (indkey == InvalidAttrNumber)
16591                                         break;
16592                                 attname = getAttrName(indkey, tbinfo);
16593
16594                                 appendPQExpBuffer(q, "%s%s",
16595                                                                   (k == 0) ? "" : ", ",
16596                                                                   fmtId(attname));
16597                         }
16598
16599                         if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
16600                                 appendPQExpBufferStr(q, ") INCLUDE (");
16601
16602                         for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
16603                         {
16604                                 int                     indkey = (int) indxinfo->indkeys[k];
16605                                 const char *attname;
16606
16607                                 if (indkey == InvalidAttrNumber)
16608                                         break;
16609                                 attname = getAttrName(indkey, tbinfo);
16610
16611                                 appendPQExpBuffer(q, "%s%s",
16612                                                                   (k == indxinfo->indnkeyattrs) ? "" : ", ",
16613                                                                   fmtId(attname));
16614                         }
16615
16616                         appendPQExpBufferChar(q, ')');
16617
16618                         if (nonemptyReloptions(indxinfo->indreloptions))
16619                         {
16620                                 appendPQExpBufferStr(q, " WITH (");
16621                                 appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
16622                                 appendPQExpBufferChar(q, ')');
16623                         }
16624
16625                         if (coninfo->condeferrable)
16626                         {
16627                                 appendPQExpBufferStr(q, " DEFERRABLE");
16628                                 if (coninfo->condeferred)
16629                                         appendPQExpBufferStr(q, " INITIALLY DEFERRED");
16630                         }
16631
16632                         appendPQExpBufferStr(q, ";\n");
16633                 }
16634
16635                 /*
16636                  * Append ALTER TABLE commands as needed to set properties that we
16637                  * only have ALTER TABLE syntax for.  Keep this in sync with the
16638                  * similar code in dumpIndex!
16639                  */
16640
16641                 /* If the index is clustered, we need to record that. */
16642                 if (indxinfo->indisclustered)
16643                 {
16644                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16645                                                           fmtQualifiedDumpable(tbinfo));
16646                         /* index name is not qualified in this syntax */
16647                         appendPQExpBuffer(q, " ON %s;\n",
16648                                                           fmtId(indxinfo->dobj.name));
16649                 }
16650
16651                 /* If the index defines identity, we need to record that. */
16652                 if (indxinfo->indisreplident)
16653                 {
16654                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
16655                                                           fmtQualifiedDumpable(tbinfo));
16656                         /* index name is not qualified in this syntax */
16657                         appendPQExpBuffer(q, " INDEX %s;\n",
16658                                                           fmtId(indxinfo->dobj.name));
16659                 }
16660
16661                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s ",
16662                                                   fmtQualifiedDumpable(tbinfo));
16663                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16664                                                   fmtId(coninfo->dobj.name));
16665
16666                 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16667
16668                 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16669                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16670                                                  ARCHIVE_OPTS(.tag = tag,
16671                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
16672                                                                           .tablespace = indxinfo->tablespace,
16673                                                                           .owner = tbinfo->rolname,
16674                                                                           .description = "CONSTRAINT",
16675                                                                           .section = SECTION_POST_DATA,
16676                                                                           .createStmt = q->data,
16677                                                                           .dropStmt = delq->data));
16678         }
16679         else if (coninfo->contype == 'f')
16680         {
16681                 char       *only;
16682
16683                 /*
16684                  * Foreign keys on partitioned tables are always declared as
16685                  * inheriting to partitions; for all other cases, emit them as
16686                  * applying ONLY directly to the named table, because that's how they
16687                  * work for regular inherited tables.
16688                  */
16689                 only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
16690
16691                 /*
16692                  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
16693                  * current table data is not processed
16694                  */
16695                 appendPQExpBuffer(q, "ALTER TABLE %s%s\n",
16696                                                   only, fmtQualifiedDumpable(tbinfo));
16697                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16698                                                   fmtId(coninfo->dobj.name),
16699                                                   coninfo->condef);
16700
16701                 appendPQExpBuffer(delq, "ALTER TABLE %s%s ",
16702                                                   only, fmtQualifiedDumpable(tbinfo));
16703                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16704                                                   fmtId(coninfo->dobj.name));
16705
16706                 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16707
16708                 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16709                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16710                                                  ARCHIVE_OPTS(.tag = tag,
16711                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
16712                                                                           .owner = tbinfo->rolname,
16713                                                                           .description = "FK CONSTRAINT",
16714                                                                           .section = SECTION_POST_DATA,
16715                                                                           .createStmt = q->data,
16716                                                                           .dropStmt = delq->data));
16717         }
16718         else if (coninfo->contype == 'c' && tbinfo)
16719         {
16720                 /* CHECK constraint on a table */
16721
16722                 /* Ignore if not to be dumped separately, or if it was inherited */
16723                 if (coninfo->separate && coninfo->conislocal)
16724                 {
16725                         /* not ONLY since we want it to propagate to children */
16726                         appendPQExpBuffer(q, "ALTER TABLE %s\n",
16727                                                           fmtQualifiedDumpable(tbinfo));
16728                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16729                                                           fmtId(coninfo->dobj.name),
16730                                                           coninfo->condef);
16731
16732                         appendPQExpBuffer(delq, "ALTER TABLE %s ",
16733                                                           fmtQualifiedDumpable(tbinfo));
16734                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16735                                                           fmtId(coninfo->dobj.name));
16736
16737                         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16738
16739                         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16740                                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16741                                                          ARCHIVE_OPTS(.tag = tag,
16742                                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
16743                                                                                   .owner = tbinfo->rolname,
16744                                                                                   .description = "CHECK CONSTRAINT",
16745                                                                                   .section = SECTION_POST_DATA,
16746                                                                                   .createStmt = q->data,
16747                                                                                   .dropStmt = delq->data));
16748                 }
16749         }
16750         else if (coninfo->contype == 'c' && tbinfo == NULL)
16751         {
16752                 /* CHECK constraint on a domain */
16753                 TypeInfo   *tyinfo = coninfo->condomain;
16754
16755                 /* Ignore if not to be dumped separately */
16756                 if (coninfo->separate)
16757                 {
16758                         appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
16759                                                           fmtQualifiedDumpable(tyinfo));
16760                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16761                                                           fmtId(coninfo->dobj.name),
16762                                                           coninfo->condef);
16763
16764                         appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
16765                                                           fmtQualifiedDumpable(tyinfo));
16766                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16767                                                           fmtId(coninfo->dobj.name));
16768
16769                         tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
16770
16771                         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16772                                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16773                                                          ARCHIVE_OPTS(.tag = tag,
16774                                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
16775                                                                                   .owner = tyinfo->rolname,
16776                                                                                   .description = "CHECK CONSTRAINT",
16777                                                                                   .section = SECTION_POST_DATA,
16778                                                                                   .createStmt = q->data,
16779                                                                                   .dropStmt = delq->data));
16780                 }
16781         }
16782         else
16783         {
16784                 fatal("unrecognized constraint type: %c",
16785                           coninfo->contype);
16786         }
16787
16788         /* Dump Constraint Comments --- only works for table constraints */
16789         if (tbinfo && coninfo->separate &&
16790                 coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16791                 dumpTableConstraintComment(fout, coninfo);
16792
16793         free(tag);
16794         destroyPQExpBuffer(q);
16795         destroyPQExpBuffer(delq);
16796 }
16797
16798 /*
16799  * dumpTableConstraintComment --- dump a constraint's comment if any
16800  *
16801  * This is split out because we need the function in two different places
16802  * depending on whether the constraint is dumped as part of CREATE TABLE
16803  * or as a separate ALTER command.
16804  */
16805 static void
16806 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
16807 {
16808         TableInfo  *tbinfo = coninfo->contable;
16809         PQExpBuffer conprefix = createPQExpBuffer();
16810         char       *qtabname;
16811
16812         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
16813
16814         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
16815                                           fmtId(coninfo->dobj.name));
16816
16817         if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16818                 dumpComment(fout, conprefix->data, qtabname,
16819                                         tbinfo->dobj.namespace->dobj.name,
16820                                         tbinfo->rolname,
16821                                         coninfo->dobj.catId, 0,
16822                                         coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
16823
16824         destroyPQExpBuffer(conprefix);
16825         free(qtabname);
16826 }
16827
16828 /*
16829  * findLastBuiltinOid_V71 -
16830  *
16831  * find the last built in oid
16832  *
16833  * For 7.1 through 8.0, we do this by retrieving datlastsysoid from the
16834  * pg_database entry for the current database.  (Note: current_database()
16835  * requires 7.3; pg_dump requires 8.0 now.)
16836  */
16837 static Oid
16838 findLastBuiltinOid_V71(Archive *fout)
16839 {
16840         PGresult   *res;
16841         Oid                     last_oid;
16842
16843         res = ExecuteSqlQueryForSingleRow(fout,
16844                                                                           "SELECT datlastsysoid FROM pg_database WHERE datname = current_database()");
16845         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
16846         PQclear(res);
16847
16848         return last_oid;
16849 }
16850
16851 /*
16852  * dumpSequence
16853  *        write the declaration (not data) of one user-defined sequence
16854  */
16855 static void
16856 dumpSequence(Archive *fout, TableInfo *tbinfo)
16857 {
16858         DumpOptions *dopt = fout->dopt;
16859         PGresult   *res;
16860         char       *startv,
16861                            *incby,
16862                            *maxv,
16863                            *minv,
16864                            *cache,
16865                            *seqtype;
16866         bool            cycled;
16867         bool            is_ascending;
16868         int64           default_minv,
16869                                 default_maxv;
16870         char            bufm[32],
16871                                 bufx[32];
16872         PQExpBuffer query = createPQExpBuffer();
16873         PQExpBuffer delqry = createPQExpBuffer();
16874         char       *qseqname;
16875
16876         qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
16877
16878         if (fout->remoteVersion >= 100000)
16879         {
16880                 appendPQExpBuffer(query,
16881                                                   "SELECT format_type(seqtypid, NULL), "
16882                                                   "seqstart, seqincrement, "
16883                                                   "seqmax, seqmin, "
16884                                                   "seqcache, seqcycle "
16885                                                   "FROM pg_catalog.pg_sequence "
16886                                                   "WHERE seqrelid = '%u'::oid",
16887                                                   tbinfo->dobj.catId.oid);
16888         }
16889         else if (fout->remoteVersion >= 80400)
16890         {
16891                 /*
16892                  * Before PostgreSQL 10, sequence metadata is in the sequence itself.
16893                  *
16894                  * Note: it might seem that 'bigint' potentially needs to be
16895                  * schema-qualified, but actually that's a keyword.
16896                  */
16897                 appendPQExpBuffer(query,
16898                                                   "SELECT 'bigint' AS sequence_type, "
16899                                                   "start_value, increment_by, max_value, min_value, "
16900                                                   "cache_value, is_cycled FROM %s",
16901                                                   fmtQualifiedDumpable(tbinfo));
16902         }
16903         else
16904         {
16905                 appendPQExpBuffer(query,
16906                                                   "SELECT 'bigint' AS sequence_type, "
16907                                                   "0 AS start_value, increment_by, max_value, min_value, "
16908                                                   "cache_value, is_cycled FROM %s",
16909                                                   fmtQualifiedDumpable(tbinfo));
16910         }
16911
16912         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16913
16914         if (PQntuples(res) != 1)
16915         {
16916                 pg_log_error(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
16917                                                           "query to get data of sequence \"%s\" returned %d rows (expected 1)",
16918                                                           PQntuples(res)),
16919                                          tbinfo->dobj.name, PQntuples(res));
16920                 exit_nicely(1);
16921         }
16922
16923         seqtype = PQgetvalue(res, 0, 0);
16924         startv = PQgetvalue(res, 0, 1);
16925         incby = PQgetvalue(res, 0, 2);
16926         maxv = PQgetvalue(res, 0, 3);
16927         minv = PQgetvalue(res, 0, 4);
16928         cache = PQgetvalue(res, 0, 5);
16929         cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
16930
16931         /* Calculate default limits for a sequence of this type */
16932         is_ascending = (incby[0] != '-');
16933         if (strcmp(seqtype, "smallint") == 0)
16934         {
16935                 default_minv = is_ascending ? 1 : PG_INT16_MIN;
16936                 default_maxv = is_ascending ? PG_INT16_MAX : -1;
16937         }
16938         else if (strcmp(seqtype, "integer") == 0)
16939         {
16940                 default_minv = is_ascending ? 1 : PG_INT32_MIN;
16941                 default_maxv = is_ascending ? PG_INT32_MAX : -1;
16942         }
16943         else if (strcmp(seqtype, "bigint") == 0)
16944         {
16945                 default_minv = is_ascending ? 1 : PG_INT64_MIN;
16946                 default_maxv = is_ascending ? PG_INT64_MAX : -1;
16947         }
16948         else
16949         {
16950                 fatal("unrecognized sequence type: %s", seqtype);
16951                 default_minv = default_maxv = 0;        /* keep compiler quiet */
16952         }
16953
16954         /*
16955          * 64-bit strtol() isn't very portable, so convert the limits to strings
16956          * and compare that way.
16957          */
16958         snprintf(bufm, sizeof(bufm), INT64_FORMAT, default_minv);
16959         snprintf(bufx, sizeof(bufx), INT64_FORMAT, default_maxv);
16960
16961         /* Don't print minv/maxv if they match the respective default limit */
16962         if (strcmp(minv, bufm) == 0)
16963                 minv = NULL;
16964         if (strcmp(maxv, bufx) == 0)
16965                 maxv = NULL;
16966
16967         /*
16968          * Identity sequences are not to be dropped separately.
16969          */
16970         if (!tbinfo->is_identity_sequence)
16971         {
16972                 appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
16973                                                   fmtQualifiedDumpable(tbinfo));
16974         }
16975
16976         resetPQExpBuffer(query);
16977
16978         if (dopt->binary_upgrade)
16979         {
16980                 binary_upgrade_set_pg_class_oids(fout, query,
16981                                                                                  tbinfo->dobj.catId.oid, false);
16982                 binary_upgrade_set_type_oids_by_rel_oid(fout, query,
16983                                                                                                 tbinfo->dobj.catId.oid);
16984         }
16985
16986         if (tbinfo->is_identity_sequence)
16987         {
16988                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
16989
16990                 appendPQExpBuffer(query,
16991                                                   "ALTER TABLE %s ",
16992                                                   fmtQualifiedDumpable(owning_tab));
16993                 appendPQExpBuffer(query,
16994                                                   "ALTER COLUMN %s ADD GENERATED ",
16995                                                   fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
16996                 if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
16997                         appendPQExpBufferStr(query, "ALWAYS");
16998                 else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
16999                         appendPQExpBufferStr(query, "BY DEFAULT");
17000                 appendPQExpBuffer(query, " AS IDENTITY (\n    SEQUENCE NAME %s\n",
17001                                                   fmtQualifiedDumpable(tbinfo));
17002         }
17003         else
17004         {
17005                 appendPQExpBuffer(query,
17006                                                   "CREATE SEQUENCE %s\n",
17007                                                   fmtQualifiedDumpable(tbinfo));
17008
17009                 if (strcmp(seqtype, "bigint") != 0)
17010                         appendPQExpBuffer(query, "    AS %s\n", seqtype);
17011         }
17012
17013         if (fout->remoteVersion >= 80400)
17014                 appendPQExpBuffer(query, "    START WITH %s\n", startv);
17015
17016         appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
17017
17018         if (minv)
17019                 appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
17020         else
17021                 appendPQExpBufferStr(query, "    NO MINVALUE\n");
17022
17023         if (maxv)
17024                 appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
17025         else
17026                 appendPQExpBufferStr(query, "    NO MAXVALUE\n");
17027
17028         appendPQExpBuffer(query,
17029                                           "    CACHE %s%s",
17030                                           cache, (cycled ? "\n    CYCLE" : ""));
17031
17032         if (tbinfo->is_identity_sequence)
17033                 appendPQExpBufferStr(query, "\n);\n");
17034         else
17035                 appendPQExpBufferStr(query, ";\n");
17036
17037         /* binary_upgrade:      no need to clear TOAST table oid */
17038
17039         if (dopt->binary_upgrade)
17040                 binary_upgrade_extension_member(query, &tbinfo->dobj,
17041                                                                                 "SEQUENCE", qseqname,
17042                                                                                 tbinfo->dobj.namespace->dobj.name);
17043
17044         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17045                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
17046                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17047                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17048                                                                   .owner = tbinfo->rolname,
17049                                                                   .description = "SEQUENCE",
17050                                                                   .section = SECTION_PRE_DATA,
17051                                                                   .createStmt = query->data,
17052                                                                   .dropStmt = delqry->data));
17053
17054         /*
17055          * If the sequence is owned by a table column, emit the ALTER for it as a
17056          * separate TOC entry immediately following the sequence's own entry. It's
17057          * OK to do this rather than using full sorting logic, because the
17058          * dependency that tells us it's owned will have forced the table to be
17059          * created first.  We can't just include the ALTER in the TOC entry
17060          * because it will fail if we haven't reassigned the sequence owner to
17061          * match the table's owner.
17062          *
17063          * We need not schema-qualify the table reference because both sequence
17064          * and table must be in the same schema.
17065          */
17066         if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
17067         {
17068                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
17069
17070                 if (owning_tab == NULL)
17071                         fatal("failed sanity check, parent table with OID %u of sequence with OID %u not found",
17072                                   tbinfo->owning_tab, tbinfo->dobj.catId.oid);
17073
17074                 if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
17075                 {
17076                         resetPQExpBuffer(query);
17077                         appendPQExpBuffer(query, "ALTER SEQUENCE %s",
17078                                                           fmtQualifiedDumpable(tbinfo));
17079                         appendPQExpBuffer(query, " OWNED BY %s",
17080                                                           fmtQualifiedDumpable(owning_tab));
17081                         appendPQExpBuffer(query, ".%s;\n",
17082                                                           fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
17083
17084                         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17085                                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
17086                                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17087                                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17088                                                                                   .owner = tbinfo->rolname,
17089                                                                                   .description = "SEQUENCE OWNED BY",
17090                                                                                   .section = SECTION_PRE_DATA,
17091                                                                                   .createStmt = query->data,
17092                                                                                   .deps = &(tbinfo->dobj.dumpId),
17093                                                                                   .nDeps = 1));
17094                 }
17095         }
17096
17097         /* Dump Sequence Comments and Security Labels */
17098         if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17099                 dumpComment(fout, "SEQUENCE", qseqname,
17100                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17101                                         tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
17102
17103         if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
17104                 dumpSecLabel(fout, "SEQUENCE", qseqname,
17105                                          tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17106                                          tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
17107
17108         PQclear(res);
17109
17110         destroyPQExpBuffer(query);
17111         destroyPQExpBuffer(delqry);
17112         free(qseqname);
17113 }
17114
17115 /*
17116  * dumpSequenceData
17117  *        write the data of one user-defined sequence
17118  */
17119 static void
17120 dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
17121 {
17122         TableInfo  *tbinfo = tdinfo->tdtable;
17123         PGresult   *res;
17124         char       *last;
17125         bool            called;
17126         PQExpBuffer query = createPQExpBuffer();
17127
17128         appendPQExpBuffer(query,
17129                                           "SELECT last_value, is_called FROM %s",
17130                                           fmtQualifiedDumpable(tbinfo));
17131
17132         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17133
17134         if (PQntuples(res) != 1)
17135         {
17136                 pg_log_error(ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)",
17137                                                           "query to get data of sequence \"%s\" returned %d rows (expected 1)",
17138                                                           PQntuples(res)),
17139                                          tbinfo->dobj.name, PQntuples(res));
17140                 exit_nicely(1);
17141         }
17142
17143         last = PQgetvalue(res, 0, 0);
17144         called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
17145
17146         resetPQExpBuffer(query);
17147         appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
17148         appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
17149         appendPQExpBuffer(query, ", %s, %s);\n",
17150                                           last, (called ? "true" : "false"));
17151
17152         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
17153                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
17154                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17155                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17156                                                                   .owner = tbinfo->rolname,
17157                                                                   .description = "SEQUENCE SET",
17158                                                                   .section = SECTION_DATA,
17159                                                                   .createStmt = query->data,
17160                                                                   .deps = &(tbinfo->dobj.dumpId),
17161                                                                   .nDeps = 1));
17162
17163         PQclear(res);
17164
17165         destroyPQExpBuffer(query);
17166 }
17167
17168 /*
17169  * dumpTrigger
17170  *        write the declaration of one user-defined table trigger
17171  */
17172 static void
17173 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
17174 {
17175         DumpOptions *dopt = fout->dopt;
17176         TableInfo  *tbinfo = tginfo->tgtable;
17177         PQExpBuffer query;
17178         PQExpBuffer delqry;
17179         PQExpBuffer trigprefix;
17180         char       *qtabname;
17181         char       *tgargs;
17182         size_t          lentgargs;
17183         const char *p;
17184         int                     findx;
17185         char       *tag;
17186
17187         /*
17188          * we needn't check dobj.dump because TriggerInfo wouldn't have been
17189          * created in the first place for non-dumpable triggers
17190          */
17191         if (dopt->dataOnly)
17192                 return;
17193
17194         query = createPQExpBuffer();
17195         delqry = createPQExpBuffer();
17196         trigprefix = createPQExpBuffer();
17197
17198         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17199
17200         appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
17201                                           fmtId(tginfo->dobj.name));
17202         appendPQExpBuffer(delqry, "ON %s;\n",
17203                                           fmtQualifiedDumpable(tbinfo));
17204
17205         if (tginfo->tgdef)
17206         {
17207                 appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
17208         }
17209         else
17210         {
17211                 if (tginfo->tgisconstraint)
17212                 {
17213                         appendPQExpBufferStr(query, "CREATE CONSTRAINT TRIGGER ");
17214                         appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
17215                 }
17216                 else
17217                 {
17218                         appendPQExpBufferStr(query, "CREATE TRIGGER ");
17219                         appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
17220                 }
17221                 appendPQExpBufferStr(query, "\n    ");
17222
17223                 /* Trigger type */
17224                 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
17225                         appendPQExpBufferStr(query, "BEFORE");
17226                 else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
17227                         appendPQExpBufferStr(query, "AFTER");
17228                 else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
17229                         appendPQExpBufferStr(query, "INSTEAD OF");
17230                 else
17231                 {
17232                         pg_log_error("unexpected tgtype value: %d", tginfo->tgtype);
17233                         exit_nicely(1);
17234                 }
17235
17236                 findx = 0;
17237                 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
17238                 {
17239                         appendPQExpBufferStr(query, " INSERT");
17240                         findx++;
17241                 }
17242                 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
17243                 {
17244                         if (findx > 0)
17245                                 appendPQExpBufferStr(query, " OR DELETE");
17246                         else
17247                                 appendPQExpBufferStr(query, " DELETE");
17248                         findx++;
17249                 }
17250                 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
17251                 {
17252                         if (findx > 0)
17253                                 appendPQExpBufferStr(query, " OR UPDATE");
17254                         else
17255                                 appendPQExpBufferStr(query, " UPDATE");
17256                         findx++;
17257                 }
17258                 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
17259                 {
17260                         if (findx > 0)
17261                                 appendPQExpBufferStr(query, " OR TRUNCATE");
17262                         else
17263                                 appendPQExpBufferStr(query, " TRUNCATE");
17264                         findx++;
17265                 }
17266                 appendPQExpBuffer(query, " ON %s\n",
17267                                                   fmtQualifiedDumpable(tbinfo));
17268
17269                 if (tginfo->tgisconstraint)
17270                 {
17271                         if (OidIsValid(tginfo->tgconstrrelid))
17272                         {
17273                                 /* regclass output is already quoted */
17274                                 appendPQExpBuffer(query, "    FROM %s\n    ",
17275                                                                   tginfo->tgconstrrelname);
17276                         }
17277                         if (!tginfo->tgdeferrable)
17278                                 appendPQExpBufferStr(query, "NOT ");
17279                         appendPQExpBufferStr(query, "DEFERRABLE INITIALLY ");
17280                         if (tginfo->tginitdeferred)
17281                                 appendPQExpBufferStr(query, "DEFERRED\n");
17282                         else
17283                                 appendPQExpBufferStr(query, "IMMEDIATE\n");
17284                 }
17285
17286                 if (TRIGGER_FOR_ROW(tginfo->tgtype))
17287                         appendPQExpBufferStr(query, "    FOR EACH ROW\n    ");
17288                 else
17289                         appendPQExpBufferStr(query, "    FOR EACH STATEMENT\n    ");
17290
17291                 /* regproc output is already sufficiently quoted */
17292                 appendPQExpBuffer(query, "EXECUTE FUNCTION %s(",
17293                                                   tginfo->tgfname);
17294
17295                 tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
17296                                                                                   &lentgargs);
17297                 p = tgargs;
17298                 for (findx = 0; findx < tginfo->tgnargs; findx++)
17299                 {
17300                         /* find the embedded null that terminates this trigger argument */
17301                         size_t          tlen = strlen(p);
17302
17303                         if (p + tlen >= tgargs + lentgargs)
17304                         {
17305                                 /* hm, not found before end of bytea value... */
17306                                 pg_log_error("invalid argument string (%s) for trigger \"%s\" on table \"%s\"",
17307                                                          tginfo->tgargs,
17308                                                          tginfo->dobj.name,
17309                                                          tbinfo->dobj.name);
17310                                 exit_nicely(1);
17311                         }
17312
17313                         if (findx > 0)
17314                                 appendPQExpBufferStr(query, ", ");
17315                         appendStringLiteralAH(query, p, fout);
17316                         p += tlen + 1;
17317                 }
17318                 free(tgargs);
17319                 appendPQExpBufferStr(query, ");\n");
17320         }
17321
17322         if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
17323         {
17324                 appendPQExpBuffer(query, "\nALTER TABLE %s ",
17325                                                   fmtQualifiedDumpable(tbinfo));
17326                 switch (tginfo->tgenabled)
17327                 {
17328                         case 'D':
17329                         case 'f':
17330                                 appendPQExpBufferStr(query, "DISABLE");
17331                                 break;
17332                         case 'A':
17333                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
17334                                 break;
17335                         case 'R':
17336                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
17337                                 break;
17338                         default:
17339                                 appendPQExpBufferStr(query, "ENABLE");
17340                                 break;
17341                 }
17342                 appendPQExpBuffer(query, " TRIGGER %s;\n",
17343                                                   fmtId(tginfo->dobj.name));
17344         }
17345
17346         appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
17347                                           fmtId(tginfo->dobj.name));
17348
17349         tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
17350
17351         if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17352                 ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
17353                                          ARCHIVE_OPTS(.tag = tag,
17354                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17355                                                                   .owner = tbinfo->rolname,
17356                                                                   .description = "TRIGGER",
17357                                                                   .section = SECTION_POST_DATA,
17358                                                                   .createStmt = query->data,
17359                                                                   .dropStmt = delqry->data));
17360
17361         if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17362                 dumpComment(fout, trigprefix->data, qtabname,
17363                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17364                                         tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
17365
17366         free(tag);
17367         destroyPQExpBuffer(query);
17368         destroyPQExpBuffer(delqry);
17369         destroyPQExpBuffer(trigprefix);
17370         free(qtabname);
17371 }
17372
17373 /*
17374  * dumpEventTrigger
17375  *        write the declaration of one user-defined event trigger
17376  */
17377 static void
17378 dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
17379 {
17380         DumpOptions *dopt = fout->dopt;
17381         PQExpBuffer query;
17382         PQExpBuffer delqry;
17383         char       *qevtname;
17384
17385         /* Skip if not to be dumped */
17386         if (!evtinfo->dobj.dump || dopt->dataOnly)
17387                 return;
17388
17389         query = createPQExpBuffer();
17390         delqry = createPQExpBuffer();
17391
17392         qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
17393
17394         appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
17395         appendPQExpBufferStr(query, qevtname);
17396         appendPQExpBufferStr(query, " ON ");
17397         appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
17398
17399         if (strcmp("", evtinfo->evttags) != 0)
17400         {
17401                 appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
17402                 appendPQExpBufferStr(query, evtinfo->evttags);
17403                 appendPQExpBufferChar(query, ')');
17404         }
17405
17406         appendPQExpBufferStr(query, "\n   EXECUTE FUNCTION ");
17407         appendPQExpBufferStr(query, evtinfo->evtfname);
17408         appendPQExpBufferStr(query, "();\n");
17409
17410         if (evtinfo->evtenabled != 'O')
17411         {
17412                 appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
17413                                                   qevtname);
17414                 switch (evtinfo->evtenabled)
17415                 {
17416                         case 'D':
17417                                 appendPQExpBufferStr(query, "DISABLE");
17418                                 break;
17419                         case 'A':
17420                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
17421                                 break;
17422                         case 'R':
17423                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
17424                                 break;
17425                         default:
17426                                 appendPQExpBufferStr(query, "ENABLE");
17427                                 break;
17428                 }
17429                 appendPQExpBufferStr(query, ";\n");
17430         }
17431
17432         appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
17433                                           qevtname);
17434
17435         if (dopt->binary_upgrade)
17436                 binary_upgrade_extension_member(query, &evtinfo->dobj,
17437                                                                                 "EVENT TRIGGER", qevtname, NULL);
17438
17439         if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17440                 ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
17441                                          ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
17442                                                                   .owner = evtinfo->evtowner,
17443                                                                   .description = "EVENT TRIGGER",
17444                                                                   .section = SECTION_POST_DATA,
17445                                                                   .createStmt = query->data,
17446                                                                   .dropStmt = delqry->data));
17447
17448         if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17449                 dumpComment(fout, "EVENT TRIGGER", qevtname,
17450                                         NULL, evtinfo->evtowner,
17451                                         evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
17452
17453         destroyPQExpBuffer(query);
17454         destroyPQExpBuffer(delqry);
17455         free(qevtname);
17456 }
17457
17458 /*
17459  * dumpRule
17460  *              Dump a rule
17461  */
17462 static void
17463 dumpRule(Archive *fout, RuleInfo *rinfo)
17464 {
17465         DumpOptions *dopt = fout->dopt;
17466         TableInfo  *tbinfo = rinfo->ruletable;
17467         bool            is_view;
17468         PQExpBuffer query;
17469         PQExpBuffer cmd;
17470         PQExpBuffer delcmd;
17471         PQExpBuffer ruleprefix;
17472         char       *qtabname;
17473         PGresult   *res;
17474         char       *tag;
17475
17476         /* Skip if not to be dumped */
17477         if (!rinfo->dobj.dump || dopt->dataOnly)
17478                 return;
17479
17480         /*
17481          * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
17482          * we do not want to dump it as a separate object.
17483          */
17484         if (!rinfo->separate)
17485                 return;
17486
17487         /*
17488          * If it's an ON SELECT rule, we want to print it as a view definition,
17489          * instead of a rule.
17490          */
17491         is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
17492
17493         query = createPQExpBuffer();
17494         cmd = createPQExpBuffer();
17495         delcmd = createPQExpBuffer();
17496         ruleprefix = createPQExpBuffer();
17497
17498         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17499
17500         if (is_view)
17501         {
17502                 PQExpBuffer result;
17503
17504                 /*
17505                  * We need OR REPLACE here because we'll be replacing a dummy view.
17506                  * Otherwise this should look largely like the regular view dump code.
17507                  */
17508                 appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
17509                                                   fmtQualifiedDumpable(tbinfo));
17510                 if (nonemptyReloptions(tbinfo->reloptions))
17511                 {
17512                         appendPQExpBufferStr(cmd, " WITH (");
17513                         appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
17514                         appendPQExpBufferChar(cmd, ')');
17515                 }
17516                 result = createViewAsClause(fout, tbinfo);
17517                 appendPQExpBuffer(cmd, " AS\n%s", result->data);
17518                 destroyPQExpBuffer(result);
17519                 if (tbinfo->checkoption != NULL)
17520                         appendPQExpBuffer(cmd, "\n  WITH %s CHECK OPTION",
17521                                                           tbinfo->checkoption);
17522                 appendPQExpBufferStr(cmd, ";\n");
17523         }
17524         else
17525         {
17526                 /* In the rule case, just print pg_get_ruledef's result verbatim */
17527                 appendPQExpBuffer(query,
17528                                                   "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
17529                                                   rinfo->dobj.catId.oid);
17530
17531                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17532
17533                 if (PQntuples(res) != 1)
17534                 {
17535                         pg_log_error("query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
17536                                                  rinfo->dobj.name, tbinfo->dobj.name);
17537                         exit_nicely(1);
17538                 }
17539
17540                 printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
17541
17542                 PQclear(res);
17543         }
17544
17545         /*
17546          * Add the command to alter the rules replication firing semantics if it
17547          * differs from the default.
17548          */
17549         if (rinfo->ev_enabled != 'O')
17550         {
17551                 appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
17552                 switch (rinfo->ev_enabled)
17553                 {
17554                         case 'A':
17555                                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
17556                                                                   fmtId(rinfo->dobj.name));
17557                                 break;
17558                         case 'R':
17559                                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
17560                                                                   fmtId(rinfo->dobj.name));
17561                                 break;
17562                         case 'D':
17563                                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
17564                                                                   fmtId(rinfo->dobj.name));
17565                                 break;
17566                 }
17567         }
17568
17569         if (is_view)
17570         {
17571                 /*
17572                  * We can't DROP a view's ON SELECT rule.  Instead, use CREATE OR
17573                  * REPLACE VIEW to replace the rule with something with minimal
17574                  * dependencies.
17575                  */
17576                 PQExpBuffer result;
17577
17578                 appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
17579                                                   fmtQualifiedDumpable(tbinfo));
17580                 result = createDummyViewAsClause(fout, tbinfo);
17581                 appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
17582                 destroyPQExpBuffer(result);
17583         }
17584         else
17585         {
17586                 appendPQExpBuffer(delcmd, "DROP RULE %s ",
17587                                                   fmtId(rinfo->dobj.name));
17588                 appendPQExpBuffer(delcmd, "ON %s;\n",
17589                                                   fmtQualifiedDumpable(tbinfo));
17590         }
17591
17592         appendPQExpBuffer(ruleprefix, "RULE %s ON",
17593                                           fmtId(rinfo->dobj.name));
17594
17595         tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
17596
17597         if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17598                 ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
17599                                          ARCHIVE_OPTS(.tag = tag,
17600                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17601                                                                   .owner = tbinfo->rolname,
17602                                                                   .description = "RULE",
17603                                                                   .section = SECTION_POST_DATA,
17604                                                                   .createStmt = cmd->data,
17605                                                                   .dropStmt = delcmd->data));
17606
17607         /* Dump rule comments */
17608         if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17609                 dumpComment(fout, ruleprefix->data, qtabname,
17610                                         tbinfo->dobj.namespace->dobj.name,
17611                                         tbinfo->rolname,
17612                                         rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
17613
17614         free(tag);
17615         destroyPQExpBuffer(query);
17616         destroyPQExpBuffer(cmd);
17617         destroyPQExpBuffer(delcmd);
17618         destroyPQExpBuffer(ruleprefix);
17619         free(qtabname);
17620 }
17621
17622 /*
17623  * getExtensionMembership --- obtain extension membership data
17624  *
17625  * We need to identify objects that are extension members as soon as they're
17626  * loaded, so that we can correctly determine whether they need to be dumped.
17627  * Generally speaking, extension member objects will get marked as *not* to
17628  * be dumped, as they will be recreated by the single CREATE EXTENSION
17629  * command.  However, in binary upgrade mode we still need to dump the members
17630  * individually.
17631  */
17632 void
17633 getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
17634                                            int numExtensions)
17635 {
17636         PQExpBuffer query;
17637         PGresult   *res;
17638         int                     ntups,
17639                                 nextmembers,
17640                                 i;
17641         int                     i_classid,
17642                                 i_objid,
17643                                 i_refobjid;
17644         ExtensionMemberId *extmembers;
17645         ExtensionInfo *ext;
17646
17647         /* Nothing to do if no extensions */
17648         if (numExtensions == 0)
17649                 return;
17650
17651         query = createPQExpBuffer();
17652
17653         /* refclassid constraint is redundant but may speed the search */
17654         appendPQExpBufferStr(query, "SELECT "
17655                                                  "classid, objid, refobjid "
17656                                                  "FROM pg_depend "
17657                                                  "WHERE refclassid = 'pg_extension'::regclass "
17658                                                  "AND deptype = 'e' "
17659                                                  "ORDER BY 3");
17660
17661         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17662
17663         ntups = PQntuples(res);
17664
17665         i_classid = PQfnumber(res, "classid");
17666         i_objid = PQfnumber(res, "objid");
17667         i_refobjid = PQfnumber(res, "refobjid");
17668
17669         extmembers = (ExtensionMemberId *) pg_malloc(ntups * sizeof(ExtensionMemberId));
17670         nextmembers = 0;
17671
17672         /*
17673          * Accumulate data into extmembers[].
17674          *
17675          * Since we ordered the SELECT by referenced ID, we can expect that
17676          * multiple entries for the same extension will appear together; this
17677          * saves on searches.
17678          */
17679         ext = NULL;
17680
17681         for (i = 0; i < ntups; i++)
17682         {
17683                 CatalogId       objId;
17684                 Oid                     extId;
17685
17686                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17687                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
17688                 extId = atooid(PQgetvalue(res, i, i_refobjid));
17689
17690                 if (ext == NULL ||
17691                         ext->dobj.catId.oid != extId)
17692                         ext = findExtensionByOid(extId);
17693
17694                 if (ext == NULL)
17695                 {
17696                         /* shouldn't happen */
17697                         pg_log_warning("could not find referenced extension %u", extId);
17698                         continue;
17699                 }
17700
17701                 extmembers[nextmembers].catId = objId;
17702                 extmembers[nextmembers].ext = ext;
17703                 nextmembers++;
17704         }
17705
17706         PQclear(res);
17707
17708         /* Remember the data for use later */
17709         setExtensionMembership(extmembers, nextmembers);
17710
17711         destroyPQExpBuffer(query);
17712 }
17713
17714 /*
17715  * processExtensionTables --- deal with extension configuration tables
17716  *
17717  * There are two parts to this process:
17718  *
17719  * 1. Identify and create dump records for extension configuration tables.
17720  *
17721  *        Extensions can mark tables as "configuration", which means that the user
17722  *        is able and expected to modify those tables after the extension has been
17723  *        loaded.  For these tables, we dump out only the data- the structure is
17724  *        expected to be handled at CREATE EXTENSION time, including any indexes or
17725  *        foreign keys, which brings us to-
17726  *
17727  * 2. Record FK dependencies between configuration tables.
17728  *
17729  *        Due to the FKs being created at CREATE EXTENSION time and therefore before
17730  *        the data is loaded, we have to work out what the best order for reloading
17731  *        the data is, to avoid FK violations when the tables are restored.  This is
17732  *        not perfect- we can't handle circular dependencies and if any exist they
17733  *        will cause an invalid dump to be produced (though at least all of the data
17734  *        is included for a user to manually restore).  This is currently documented
17735  *        but perhaps we can provide a better solution in the future.
17736  */
17737 void
17738 processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
17739                                            int numExtensions)
17740 {
17741         DumpOptions *dopt = fout->dopt;
17742         PQExpBuffer query;
17743         PGresult   *res;
17744         int                     ntups,
17745                                 i;
17746         int                     i_conrelid,
17747                                 i_confrelid;
17748
17749         /* Nothing to do if no extensions */
17750         if (numExtensions == 0)
17751                 return;
17752
17753         /*
17754          * Identify extension configuration tables and create TableDataInfo
17755          * objects for them, ensuring their data will be dumped even though the
17756          * tables themselves won't be.
17757          *
17758          * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
17759          * user data in a configuration table is treated like schema data. This
17760          * seems appropriate since system data in a config table would get
17761          * reloaded by CREATE EXTENSION.
17762          */
17763         for (i = 0; i < numExtensions; i++)
17764         {
17765                 ExtensionInfo *curext = &(extinfo[i]);
17766                 char       *extconfig = curext->extconfig;
17767                 char       *extcondition = curext->extcondition;
17768                 char      **extconfigarray = NULL;
17769                 char      **extconditionarray = NULL;
17770                 int                     nconfigitems;
17771                 int                     nconditionitems;
17772
17773                 if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
17774                         parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
17775                         nconfigitems == nconditionitems)
17776                 {
17777                         int                     j;
17778
17779                         for (j = 0; j < nconfigitems; j++)
17780                         {
17781                                 TableInfo  *configtbl;
17782                                 Oid                     configtbloid = atooid(extconfigarray[j]);
17783                                 bool            dumpobj =
17784                                 curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
17785
17786                                 configtbl = findTableByOid(configtbloid);
17787                                 if (configtbl == NULL)
17788                                         continue;
17789
17790                                 /*
17791                                  * Tables of not-to-be-dumped extensions shouldn't be dumped
17792                                  * unless the table or its schema is explicitly included
17793                                  */
17794                                 if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
17795                                 {
17796                                         /* check table explicitly requested */
17797                                         if (table_include_oids.head != NULL &&
17798                                                 simple_oid_list_member(&table_include_oids,
17799                                                                                            configtbloid))
17800                                                 dumpobj = true;
17801
17802                                         /* check table's schema explicitly requested */
17803                                         if (configtbl->dobj.namespace->dobj.dump &
17804                                                 DUMP_COMPONENT_DATA)
17805                                                 dumpobj = true;
17806                                 }
17807
17808                                 /* check table excluded by an exclusion switch */
17809                                 if (table_exclude_oids.head != NULL &&
17810                                         simple_oid_list_member(&table_exclude_oids,
17811                                                                                    configtbloid))
17812                                         dumpobj = false;
17813
17814                                 /* check schema excluded by an exclusion switch */
17815                                 if (simple_oid_list_member(&schema_exclude_oids,
17816                                                                                    configtbl->dobj.namespace->dobj.catId.oid))
17817                                         dumpobj = false;
17818
17819                                 if (dumpobj)
17820                                 {
17821                                         makeTableDataInfo(dopt, configtbl);
17822                                         if (configtbl->dataObj != NULL)
17823                                         {
17824                                                 if (strlen(extconditionarray[j]) > 0)
17825                                                         configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
17826                                         }
17827                                 }
17828                         }
17829                 }
17830                 if (extconfigarray)
17831                         free(extconfigarray);
17832                 if (extconditionarray)
17833                         free(extconditionarray);
17834         }
17835
17836         /*
17837          * Now that all the TableInfoData objects have been created for all the
17838          * extensions, check their FK dependencies and register them to try and
17839          * dump the data out in an order that they can be restored in.
17840          *
17841          * Note that this is not a problem for user tables as their FKs are
17842          * recreated after the data has been loaded.
17843          */
17844
17845         query = createPQExpBuffer();
17846
17847         printfPQExpBuffer(query,
17848                                           "SELECT conrelid, confrelid "
17849                                           "FROM pg_constraint "
17850                                           "JOIN pg_depend ON (objid = confrelid) "
17851                                           "WHERE contype = 'f' "
17852                                           "AND refclassid = 'pg_extension'::regclass "
17853                                           "AND classid = 'pg_class'::regclass;");
17854
17855         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17856         ntups = PQntuples(res);
17857
17858         i_conrelid = PQfnumber(res, "conrelid");
17859         i_confrelid = PQfnumber(res, "confrelid");
17860
17861         /* Now get the dependencies and register them */
17862         for (i = 0; i < ntups; i++)
17863         {
17864                 Oid                     conrelid,
17865                                         confrelid;
17866                 TableInfo  *reftable,
17867                                    *contable;
17868
17869                 conrelid = atooid(PQgetvalue(res, i, i_conrelid));
17870                 confrelid = atooid(PQgetvalue(res, i, i_confrelid));
17871                 contable = findTableByOid(conrelid);
17872                 reftable = findTableByOid(confrelid);
17873
17874                 if (reftable == NULL ||
17875                         reftable->dataObj == NULL ||
17876                         contable == NULL ||
17877                         contable->dataObj == NULL)
17878                         continue;
17879
17880                 /*
17881                  * Make referencing TABLE_DATA object depend on the referenced table's
17882                  * TABLE_DATA object.
17883                  */
17884                 addObjectDependency(&contable->dataObj->dobj,
17885                                                         reftable->dataObj->dobj.dumpId);
17886         }
17887         PQclear(res);
17888         destroyPQExpBuffer(query);
17889 }
17890
17891 /*
17892  * getDependencies --- obtain available dependency data
17893  */
17894 static void
17895 getDependencies(Archive *fout)
17896 {
17897         PQExpBuffer query;
17898         PGresult   *res;
17899         int                     ntups,
17900                                 i;
17901         int                     i_classid,
17902                                 i_objid,
17903                                 i_refclassid,
17904                                 i_refobjid,
17905                                 i_deptype;
17906         DumpableObject *dobj,
17907                            *refdobj;
17908
17909         pg_log_info("reading dependency data");
17910
17911         query = createPQExpBuffer();
17912
17913         /*
17914          * Messy query to collect the dependency data we need.  Note that we
17915          * ignore the sub-object column, so that dependencies of or on a column
17916          * look the same as dependencies of or on a whole table.
17917          *
17918          * PIN dependencies aren't interesting, and EXTENSION dependencies were
17919          * already processed by getExtensionMembership.
17920          */
17921         appendPQExpBufferStr(query, "SELECT "
17922                                                  "classid, objid, refclassid, refobjid, deptype "
17923                                                  "FROM pg_depend "
17924                                                  "WHERE deptype != 'p' AND deptype != 'e'\n");
17925
17926         /*
17927          * Since we don't treat pg_amop entries as separate DumpableObjects, we
17928          * have to translate their dependencies into dependencies of their parent
17929          * opfamily.  Ignore internal dependencies though, as those will point to
17930          * their parent opclass, which we needn't consider here (and if we did,
17931          * it'd just result in circular dependencies).  Also, "loose" opfamily
17932          * entries will have dependencies on their parent opfamily, which we
17933          * should drop since they'd likewise become useless self-dependencies.
17934          * (But be sure to keep deps on *other* opfamilies; see amopsortfamily.)
17935          *
17936          * Skip this for pre-8.3 source servers: pg_opfamily doesn't exist there,
17937          * and the (known) cases where it would matter to have these dependencies
17938          * can't arise anyway.
17939          */
17940         if (fout->remoteVersion >= 80300)
17941         {
17942                 appendPQExpBufferStr(query, "UNION ALL\n"
17943                                                          "SELECT 'pg_opfamily'::regclass AS classid, amopfamily AS objid, refclassid, refobjid, deptype "
17944                                                          "FROM pg_depend d, pg_amop o "
17945                                                          "WHERE deptype NOT IN ('p', 'e', 'i') AND "
17946                                                          "classid = 'pg_amop'::regclass AND objid = o.oid "
17947                                                          "AND NOT (refclassid = 'pg_opfamily'::regclass AND amopfamily = refobjid)\n");
17948
17949                 /* Likewise for pg_amproc entries */
17950                 appendPQExpBufferStr(query, "UNION ALL\n"
17951                                                          "SELECT 'pg_opfamily'::regclass AS classid, amprocfamily AS objid, refclassid, refobjid, deptype "
17952                                                          "FROM pg_depend d, pg_amproc p "
17953                                                          "WHERE deptype NOT IN ('p', 'e', 'i') AND "
17954                                                          "classid = 'pg_amproc'::regclass AND objid = p.oid "
17955                                                          "AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n");
17956         }
17957
17958         /* Sort the output for efficiency below */
17959         appendPQExpBufferStr(query, "ORDER BY 1,2");
17960
17961         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17962
17963         ntups = PQntuples(res);
17964
17965         i_classid = PQfnumber(res, "classid");
17966         i_objid = PQfnumber(res, "objid");
17967         i_refclassid = PQfnumber(res, "refclassid");
17968         i_refobjid = PQfnumber(res, "refobjid");
17969         i_deptype = PQfnumber(res, "deptype");
17970
17971         /*
17972          * Since we ordered the SELECT by referencing ID, we can expect that
17973          * multiple entries for the same object will appear together; this saves
17974          * on searches.
17975          */
17976         dobj = NULL;
17977
17978         for (i = 0; i < ntups; i++)
17979         {
17980                 CatalogId       objId;
17981                 CatalogId       refobjId;
17982                 char            deptype;
17983
17984                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17985                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
17986                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
17987                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
17988                 deptype = *(PQgetvalue(res, i, i_deptype));
17989
17990                 if (dobj == NULL ||
17991                         dobj->catId.tableoid != objId.tableoid ||
17992                         dobj->catId.oid != objId.oid)
17993                         dobj = findObjectByCatalogId(objId);
17994
17995                 /*
17996                  * Failure to find objects mentioned in pg_depend is not unexpected,
17997                  * since for example we don't collect info about TOAST tables.
17998                  */
17999                 if (dobj == NULL)
18000                 {
18001 #ifdef NOT_USED
18002                         pg_log_warning("no referencing object %u %u",
18003                                                    objId.tableoid, objId.oid);
18004 #endif
18005                         continue;
18006                 }
18007
18008                 refdobj = findObjectByCatalogId(refobjId);
18009
18010                 if (refdobj == NULL)
18011                 {
18012 #ifdef NOT_USED
18013                         pg_log_warning("no referenced object %u %u",
18014                                                    refobjId.tableoid, refobjId.oid);
18015 #endif
18016                         continue;
18017                 }
18018
18019                 /*
18020                  * Ordinarily, table rowtypes have implicit dependencies on their
18021                  * tables.  However, for a composite type the implicit dependency goes
18022                  * the other way in pg_depend; which is the right thing for DROP but
18023                  * it doesn't produce the dependency ordering we need. So in that one
18024                  * case, we reverse the direction of the dependency.
18025                  */
18026                 if (deptype == 'i' &&
18027                         dobj->objType == DO_TABLE &&
18028                         refdobj->objType == DO_TYPE)
18029                         addObjectDependency(refdobj, dobj->dumpId);
18030                 else
18031                         /* normal case */
18032                         addObjectDependency(dobj, refdobj->dumpId);
18033         }
18034
18035         PQclear(res);
18036
18037         destroyPQExpBuffer(query);
18038 }
18039
18040
18041 /*
18042  * createBoundaryObjects - create dummy DumpableObjects to represent
18043  * dump section boundaries.
18044  */
18045 static DumpableObject *
18046 createBoundaryObjects(void)
18047 {
18048         DumpableObject *dobjs;
18049
18050         dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
18051
18052         dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
18053         dobjs[0].catId = nilCatalogId;
18054         AssignDumpId(dobjs + 0);
18055         dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
18056
18057         dobjs[1].objType = DO_POST_DATA_BOUNDARY;
18058         dobjs[1].catId = nilCatalogId;
18059         AssignDumpId(dobjs + 1);
18060         dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
18061
18062         return dobjs;
18063 }
18064
18065 /*
18066  * addBoundaryDependencies - add dependencies as needed to enforce the dump
18067  * section boundaries.
18068  */
18069 static void
18070 addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
18071                                                 DumpableObject *boundaryObjs)
18072 {
18073         DumpableObject *preDataBound = boundaryObjs + 0;
18074         DumpableObject *postDataBound = boundaryObjs + 1;
18075         int                     i;
18076
18077         for (i = 0; i < numObjs; i++)
18078         {
18079                 DumpableObject *dobj = dobjs[i];
18080
18081                 /*
18082                  * The classification of object types here must match the SECTION_xxx
18083                  * values assigned during subsequent ArchiveEntry calls!
18084                  */
18085                 switch (dobj->objType)
18086                 {
18087                         case DO_NAMESPACE:
18088                         case DO_EXTENSION:
18089                         case DO_TYPE:
18090                         case DO_SHELL_TYPE:
18091                         case DO_FUNC:
18092                         case DO_AGG:
18093                         case DO_OPERATOR:
18094                         case DO_ACCESS_METHOD:
18095                         case DO_OPCLASS:
18096                         case DO_OPFAMILY:
18097                         case DO_COLLATION:
18098                         case DO_CONVERSION:
18099                         case DO_TABLE:
18100                         case DO_ATTRDEF:
18101                         case DO_PROCLANG:
18102                         case DO_CAST:
18103                         case DO_DUMMY_TYPE:
18104                         case DO_TSPARSER:
18105                         case DO_TSDICT:
18106                         case DO_TSTEMPLATE:
18107                         case DO_TSCONFIG:
18108                         case DO_FDW:
18109                         case DO_FOREIGN_SERVER:
18110                         case DO_TRANSFORM:
18111                         case DO_BLOB:
18112                                 /* Pre-data objects: must come before the pre-data boundary */
18113                                 addObjectDependency(preDataBound, dobj->dumpId);
18114                                 break;
18115                         case DO_TABLE_DATA:
18116                         case DO_SEQUENCE_SET:
18117                         case DO_BLOB_DATA:
18118                                 /* Data objects: must come between the boundaries */
18119                                 addObjectDependency(dobj, preDataBound->dumpId);
18120                                 addObjectDependency(postDataBound, dobj->dumpId);
18121                                 break;
18122                         case DO_INDEX:
18123                         case DO_INDEX_ATTACH:
18124                         case DO_STATSEXT:
18125                         case DO_REFRESH_MATVIEW:
18126                         case DO_TRIGGER:
18127                         case DO_EVENT_TRIGGER:
18128                         case DO_DEFAULT_ACL:
18129                         case DO_POLICY:
18130                         case DO_PUBLICATION:
18131                         case DO_PUBLICATION_REL:
18132                         case DO_SUBSCRIPTION:
18133                                 /* Post-data objects: must come after the post-data boundary */
18134                                 addObjectDependency(dobj, postDataBound->dumpId);
18135                                 break;
18136                         case DO_RULE:
18137                                 /* Rules are post-data, but only if dumped separately */
18138                                 if (((RuleInfo *) dobj)->separate)
18139                                         addObjectDependency(dobj, postDataBound->dumpId);
18140                                 break;
18141                         case DO_CONSTRAINT:
18142                         case DO_FK_CONSTRAINT:
18143                                 /* Constraints are post-data, but only if dumped separately */
18144                                 if (((ConstraintInfo *) dobj)->separate)
18145                                         addObjectDependency(dobj, postDataBound->dumpId);
18146                                 break;
18147                         case DO_PRE_DATA_BOUNDARY:
18148                                 /* nothing to do */
18149                                 break;
18150                         case DO_POST_DATA_BOUNDARY:
18151                                 /* must come after the pre-data boundary */
18152                                 addObjectDependency(dobj, preDataBound->dumpId);
18153                                 break;
18154                 }
18155         }
18156 }
18157
18158
18159 /*
18160  * BuildArchiveDependencies - create dependency data for archive TOC entries
18161  *
18162  * The raw dependency data obtained by getDependencies() is not terribly
18163  * useful in an archive dump, because in many cases there are dependency
18164  * chains linking through objects that don't appear explicitly in the dump.
18165  * For example, a view will depend on its _RETURN rule while the _RETURN rule
18166  * will depend on other objects --- but the rule will not appear as a separate
18167  * object in the dump.  We need to adjust the view's dependencies to include
18168  * whatever the rule depends on that is included in the dump.
18169  *
18170  * Just to make things more complicated, there are also "special" dependencies
18171  * such as the dependency of a TABLE DATA item on its TABLE, which we must
18172  * not rearrange because pg_restore knows that TABLE DATA only depends on
18173  * its table.  In these cases we must leave the dependencies strictly as-is
18174  * even if they refer to not-to-be-dumped objects.
18175  *
18176  * To handle this, the convention is that "special" dependencies are created
18177  * during ArchiveEntry calls, and an archive TOC item that has any such
18178  * entries will not be touched here.  Otherwise, we recursively search the
18179  * DumpableObject data structures to build the correct dependencies for each
18180  * archive TOC item.
18181  */
18182 static void
18183 BuildArchiveDependencies(Archive *fout)
18184 {
18185         ArchiveHandle *AH = (ArchiveHandle *) fout;
18186         TocEntry   *te;
18187
18188         /* Scan all TOC entries in the archive */
18189         for (te = AH->toc->next; te != AH->toc; te = te->next)
18190         {
18191                 DumpableObject *dobj;
18192                 DumpId     *dependencies;
18193                 int                     nDeps;
18194                 int                     allocDeps;
18195
18196                 /* No need to process entries that will not be dumped */
18197                 if (te->reqs == 0)
18198                         continue;
18199                 /* Ignore entries that already have "special" dependencies */
18200                 if (te->nDeps > 0)
18201                         continue;
18202                 /* Otherwise, look up the item's original DumpableObject, if any */
18203                 dobj = findObjectByDumpId(te->dumpId);
18204                 if (dobj == NULL)
18205                         continue;
18206                 /* No work if it has no dependencies */
18207                 if (dobj->nDeps <= 0)
18208                         continue;
18209                 /* Set up work array */
18210                 allocDeps = 64;
18211                 dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
18212                 nDeps = 0;
18213                 /* Recursively find all dumpable dependencies */
18214                 findDumpableDependencies(AH, dobj,
18215                                                                  &dependencies, &nDeps, &allocDeps);
18216                 /* And save 'em ... */
18217                 if (nDeps > 0)
18218                 {
18219                         dependencies = (DumpId *) pg_realloc(dependencies,
18220                                                                                                  nDeps * sizeof(DumpId));
18221                         te->dependencies = dependencies;
18222                         te->nDeps = nDeps;
18223                 }
18224                 else
18225                         free(dependencies);
18226         }
18227 }
18228
18229 /* Recursive search subroutine for BuildArchiveDependencies */
18230 static void
18231 findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
18232                                                  DumpId **dependencies, int *nDeps, int *allocDeps)
18233 {
18234         int                     i;
18235
18236         /*
18237          * Ignore section boundary objects: if we search through them, we'll
18238          * report lots of bogus dependencies.
18239          */
18240         if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
18241                 dobj->objType == DO_POST_DATA_BOUNDARY)
18242                 return;
18243
18244         for (i = 0; i < dobj->nDeps; i++)
18245         {
18246                 DumpId          depid = dobj->dependencies[i];
18247
18248                 if (TocIDRequired(AH, depid) != 0)
18249                 {
18250                         /* Object will be dumped, so just reference it as a dependency */
18251                         if (*nDeps >= *allocDeps)
18252                         {
18253                                 *allocDeps *= 2;
18254                                 *dependencies = (DumpId *) pg_realloc(*dependencies,
18255                                                                                                           *allocDeps * sizeof(DumpId));
18256                         }
18257                         (*dependencies)[*nDeps] = depid;
18258                         (*nDeps)++;
18259                 }
18260                 else
18261                 {
18262                         /*
18263                          * Object will not be dumped, so recursively consider its deps. We
18264                          * rely on the assumption that sortDumpableObjects already broke
18265                          * any dependency loops, else we might recurse infinitely.
18266                          */
18267                         DumpableObject *otherdobj = findObjectByDumpId(depid);
18268
18269                         if (otherdobj)
18270                                 findDumpableDependencies(AH, otherdobj,
18271                                                                                  dependencies, nDeps, allocDeps);
18272                 }
18273         }
18274 }
18275
18276
18277 /*
18278  * getFormattedTypeName - retrieve a nicely-formatted type name for the
18279  * given type OID.
18280  *
18281  * This does not guarantee to schema-qualify the output, so it should not
18282  * be used to create the target object name for CREATE or ALTER commands.
18283  *
18284  * TODO: there might be some value in caching the results.
18285  */
18286 static char *
18287 getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
18288 {
18289         char       *result;
18290         PQExpBuffer query;
18291         PGresult   *res;
18292
18293         if (oid == 0)
18294         {
18295                 if ((opts & zeroAsOpaque) != 0)
18296                         return pg_strdup(g_opaque_type);
18297                 else if ((opts & zeroAsAny) != 0)
18298                         return pg_strdup("'any'");
18299                 else if ((opts & zeroAsStar) != 0)
18300                         return pg_strdup("*");
18301                 else if ((opts & zeroAsNone) != 0)
18302                         return pg_strdup("NONE");
18303         }
18304
18305         query = createPQExpBuffer();
18306         appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
18307                                           oid);
18308
18309         res = ExecuteSqlQueryForSingleRow(fout, query->data);
18310
18311         /* result of format_type is already quoted */
18312         result = pg_strdup(PQgetvalue(res, 0, 0));
18313
18314         PQclear(res);
18315         destroyPQExpBuffer(query);
18316
18317         return result;
18318 }
18319
18320 /*
18321  * Return a column list clause for the given relation.
18322  *
18323  * Special case: if there are no undropped columns in the relation, return
18324  * "", not an invalid "()" column list.
18325  */
18326 static const char *
18327 fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
18328 {
18329         int                     numatts = ti->numatts;
18330         char      **attnames = ti->attnames;
18331         bool       *attisdropped = ti->attisdropped;
18332         char       *attgenerated = ti->attgenerated;
18333         bool            needComma;
18334         int                     i;
18335
18336         appendPQExpBufferChar(buffer, '(');
18337         needComma = false;
18338         for (i = 0; i < numatts; i++)
18339         {
18340                 if (attisdropped[i])
18341                         continue;
18342                 if (attgenerated[i])
18343                         continue;
18344                 if (needComma)
18345                         appendPQExpBufferStr(buffer, ", ");
18346                 appendPQExpBufferStr(buffer, fmtId(attnames[i]));
18347                 needComma = true;
18348         }
18349
18350         if (!needComma)
18351                 return "";                              /* no undropped columns */
18352
18353         appendPQExpBufferChar(buffer, ')');
18354         return buffer->data;
18355 }
18356
18357 /*
18358  * Check if a reloptions array is nonempty.
18359  */
18360 static bool
18361 nonemptyReloptions(const char *reloptions)
18362 {
18363         /* Don't want to print it if it's just "{}" */
18364         return (reloptions != NULL && strlen(reloptions) > 2);
18365 }
18366
18367 /*
18368  * Format a reloptions array and append it to the given buffer.
18369  *
18370  * "prefix" is prepended to the option names; typically it's "" or "toast.".
18371  */
18372 static void
18373 appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
18374                                                 const char *prefix, Archive *fout)
18375 {
18376         bool            res;
18377
18378         res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
18379                                                                 fout->std_strings);
18380         if (!res)
18381                 pg_log_warning("could not parse reloptions array");
18382 }