]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_dump.c
Collations with nondeterministic comparison
[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 bool            g_verbose;                      /* User wants verbose narration of our
96                                                                  * activities. */
97 static bool dosync = true;              /* Issue fsync() to make dump durable on disk. */
98
99 /* subquery used to convert user ID (eg, datdba) to user name */
100 static const char *username_subquery;
101
102 /*
103  * For 8.0 and earlier servers, pulled from pg_database, for 8.1+ we use
104  * FirstNormalObjectId - 1.
105  */
106 static Oid      g_last_builtin_oid; /* value of the last builtin oid */
107
108 /* The specified names/patterns should to match at least one entity */
109 static int      strict_names = 0;
110
111 /*
112  * Object inclusion/exclusion lists
113  *
114  * The string lists record the patterns given by command-line switches,
115  * which we then convert to lists of OIDs of matching objects.
116  */
117 static SimpleStringList schema_include_patterns = {NULL, NULL};
118 static SimpleOidList schema_include_oids = {NULL, NULL};
119 static SimpleStringList schema_exclude_patterns = {NULL, NULL};
120 static SimpleOidList schema_exclude_oids = {NULL, NULL};
121
122 static SimpleStringList table_include_patterns = {NULL, NULL};
123 static SimpleOidList table_include_oids = {NULL, NULL};
124 static SimpleStringList table_exclude_patterns = {NULL, NULL};
125 static SimpleOidList table_exclude_oids = {NULL, NULL};
126 static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
127 static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
128
129
130 char            g_opaque_type[10];      /* name for the opaque type */
131
132 /* placeholders for the delimiters for comments */
133 char            g_comment_start[10];
134 char            g_comment_end[10];
135
136 static const CatalogId nilCatalogId = {0, 0};
137
138 /* override for standard extra_float_digits setting */
139 static bool have_extra_float_digits = false;
140 static int extra_float_digits;
141
142 /*
143  * The default number of rows per INSERT when
144  * --inserts is specified without --rows-per-insert
145  */
146 #define DUMP_DEFAULT_ROWS_PER_INSERT 1
147
148 /*
149  * Macro for producing quoted, schema-qualified name of a dumpable object.
150  */
151 #define fmtQualifiedDumpable(obj) \
152         fmtQualifiedId((obj)->dobj.namespace->dobj.name, \
153                                    (obj)->dobj.name)
154
155 static void help(const char *progname);
156 static void setup_connection(Archive *AH,
157                                  const char *dumpencoding, const char *dumpsnapshot,
158                                  char *use_role);
159 static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
160 static void expand_schema_name_patterns(Archive *fout,
161                                                         SimpleStringList *patterns,
162                                                         SimpleOidList *oids,
163                                                         bool strict_names);
164 static void expand_table_name_patterns(Archive *fout,
165                                                    SimpleStringList *patterns,
166                                                    SimpleOidList *oids,
167                                                    bool strict_names);
168 static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid);
169 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
170 static void refreshMatViewData(Archive *fout, TableDataInfo *tdinfo);
171 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
172 static void dumpComment(Archive *fout, const char *type, const char *name,
173                         const char *namespace, const char *owner,
174                         CatalogId catalogId, int subid, DumpId dumpId);
175 static int findComments(Archive *fout, Oid classoid, Oid objoid,
176                          CommentItem **items);
177 static int      collectComments(Archive *fout, CommentItem **items);
178 static void dumpSecLabel(Archive *fout, const char *type, const char *name,
179                          const char *namespace, const char *owner,
180                          CatalogId catalogId, int subid, DumpId dumpId);
181 static int findSecLabels(Archive *fout, Oid classoid, Oid objoid,
182                           SecLabelItem **items);
183 static int      collectSecLabels(Archive *fout, SecLabelItem **items);
184 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
185 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
186 static void dumpExtension(Archive *fout, ExtensionInfo *extinfo);
187 static void dumpType(Archive *fout, TypeInfo *tyinfo);
188 static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
189 static void dumpEnumType(Archive *fout, TypeInfo *tyinfo);
190 static void dumpRangeType(Archive *fout, TypeInfo *tyinfo);
191 static void dumpUndefinedType(Archive *fout, TypeInfo *tyinfo);
192 static void dumpDomain(Archive *fout, TypeInfo *tyinfo);
193 static void dumpCompositeType(Archive *fout, TypeInfo *tyinfo);
194 static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
195 static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
196 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
197 static void dumpFunc(Archive *fout, FuncInfo *finfo);
198 static void dumpCast(Archive *fout, CastInfo *cast);
199 static void dumpTransform(Archive *fout, TransformInfo *transform);
200 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
201 static void dumpAccessMethod(Archive *fout, AccessMethodInfo *oprinfo);
202 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
203 static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
204 static void dumpCollation(Archive *fout, CollInfo *collinfo);
205 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
206 static void dumpRule(Archive *fout, RuleInfo *rinfo);
207 static void dumpAgg(Archive *fout, AggInfo *agginfo);
208 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
209 static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
210 static void dumpTable(Archive *fout, TableInfo *tbinfo);
211 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
212 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
213 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
214 static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo);
215 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
216 static void dumpIndexAttach(Archive *fout, IndexAttachInfo *attachinfo);
217 static void dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo);
218 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
219 static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
220 static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
221 static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
222 static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
223 static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
224 static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
225 static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
226 static void dumpUserMappings(Archive *fout,
227                                  const char *servername, const char *namespace,
228                                  const char *owner, CatalogId catalogId, DumpId dumpId);
229 static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
230
231 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
232                 const char *type, const char *name, const char *subname,
233                 const char *nspname, const char *owner,
234                 const char *acls, const char *racls,
235                 const char *initacls, const char *initracls);
236
237 static void getDependencies(Archive *fout);
238 static void BuildArchiveDependencies(Archive *fout);
239 static void findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
240                                                  DumpId **dependencies, int *nDeps, int *allocDeps);
241
242 static DumpableObject *createBoundaryObjects(void);
243 static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
244                                                 DumpableObject *boundaryObjs);
245
246 static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
247 static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind);
248 static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo);
249 static void buildMatViewRefreshDependencies(Archive *fout);
250 static void getTableDataFKConstraints(void);
251 static char *format_function_arguments(FuncInfo *finfo, char *funcargs,
252                                                   bool is_agg);
253 static char *format_function_arguments_old(Archive *fout,
254                                                           FuncInfo *finfo, int nallargs,
255                                                           char **allargtypes,
256                                                           char **argmodes,
257                                                           char **argnames);
258 static char *format_function_signature(Archive *fout,
259                                                   FuncInfo *finfo, bool honor_quotes);
260 static char *convertRegProcReference(Archive *fout,
261                                                 const char *proc);
262 static char *getFormattedOperatorName(Archive *fout, const char *oproid);
263 static char *convertTSFunction(Archive *fout, Oid funcOid);
264 static Oid      findLastBuiltinOid_V71(Archive *fout);
265 static char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
266 static void getBlobs(Archive *fout);
267 static void dumpBlob(Archive *fout, BlobInfo *binfo);
268 static int      dumpBlobs(Archive *fout, void *arg);
269 static void dumpPolicy(Archive *fout, PolicyInfo *polinfo);
270 static void dumpPublication(Archive *fout, PublicationInfo *pubinfo);
271 static void dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo);
272 static void dumpSubscription(Archive *fout, SubscriptionInfo *subinfo);
273 static void dumpDatabase(Archive *AH);
274 static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
275                                    const char *dbname, Oid dboid);
276 static void dumpEncoding(Archive *AH);
277 static void dumpStdStrings(Archive *AH);
278 static void dumpSearchPath(Archive *AH);
279 static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
280                                                                                  PQExpBuffer upgrade_buffer,
281                                                                                  Oid pg_type_oid,
282                                                                                  bool force_array_type);
283 static bool binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
284                                                                                 PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
285 static void binary_upgrade_set_pg_class_oids(Archive *fout,
286                                                                  PQExpBuffer upgrade_buffer,
287                                                                  Oid pg_class_oid, bool is_index);
288 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
289                                                                 DumpableObject *dobj,
290                                                                 const char *objtype,
291                                                                 const char *objname,
292                                                                 const char *objnamespace);
293 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
294 static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
295 static bool nonemptyReloptions(const char *reloptions);
296 static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
297                                                 const char *prefix, Archive *fout);
298 static char *get_synchronized_snapshot(Archive *fout);
299 static void setupDumpWorker(Archive *AHX);
300 static TableInfo *getRootTableInfo(TableInfo *tbinfo);
301
302
303 int
304 main(int argc, char **argv)
305 {
306         int                     c;
307         const char *filename = NULL;
308         const char *format = "p";
309         TableInfo  *tblinfo;
310         int                     numTables;
311         DumpableObject **dobjs;
312         int                     numObjs;
313         DumpableObject *boundaryObjs;
314         int                     i;
315         int                     optindex;
316         char       *endptr;
317         RestoreOptions *ropt;
318         Archive    *fout;                       /* the script file */
319         const char *dumpencoding = NULL;
320         const char *dumpsnapshot = NULL;
321         char       *use_role = NULL;
322         long            rowsPerInsert;
323         int                     numWorkers = 1;
324         trivalue        prompt_password = TRI_DEFAULT;
325         int                     compressLevel = -1;
326         int                     plainText = 0;
327         ArchiveFormat archiveFormat = archUnknown;
328         ArchiveMode archiveMode;
329
330         static DumpOptions dopt;
331
332         static struct option long_options[] = {
333                 {"data-only", no_argument, NULL, 'a'},
334                 {"blobs", no_argument, NULL, 'b'},
335                 {"no-blobs", no_argument, NULL, 'B'},
336                 {"clean", no_argument, NULL, 'c'},
337                 {"create", no_argument, NULL, 'C'},
338                 {"dbname", required_argument, NULL, 'd'},
339                 {"file", required_argument, NULL, 'f'},
340                 {"format", required_argument, NULL, 'F'},
341                 {"host", required_argument, NULL, 'h'},
342                 {"jobs", 1, NULL, 'j'},
343                 {"no-reconnect", no_argument, NULL, 'R'},
344                 {"no-owner", no_argument, NULL, 'O'},
345                 {"port", required_argument, NULL, 'p'},
346                 {"schema", required_argument, NULL, 'n'},
347                 {"exclude-schema", required_argument, NULL, 'N'},
348                 {"schema-only", no_argument, NULL, 's'},
349                 {"superuser", required_argument, NULL, 'S'},
350                 {"table", required_argument, NULL, 't'},
351                 {"exclude-table", required_argument, NULL, 'T'},
352                 {"no-password", no_argument, NULL, 'w'},
353                 {"password", no_argument, NULL, 'W'},
354                 {"username", required_argument, NULL, 'U'},
355                 {"verbose", no_argument, NULL, 'v'},
356                 {"no-privileges", no_argument, NULL, 'x'},
357                 {"no-acl", no_argument, NULL, 'x'},
358                 {"compress", required_argument, NULL, 'Z'},
359                 {"encoding", required_argument, NULL, 'E'},
360                 {"help", no_argument, NULL, '?'},
361                 {"version", no_argument, NULL, 'V'},
362
363                 /*
364                  * the following options don't have an equivalent short option letter
365                  */
366                 {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
367                 {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
368                 {"column-inserts", no_argument, &dopt.column_inserts, 1},
369                 {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
370                 {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
371                 {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
372                 {"exclude-table-data", required_argument, NULL, 4},
373                 {"extra-float-digits", required_argument, NULL, 8},
374                 {"if-exists", no_argument, &dopt.if_exists, 1},
375                 {"inserts", no_argument, NULL, 9},
376                 {"lock-wait-timeout", required_argument, NULL, 2},
377                 {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
378                 {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
379                 {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
380                 {"role", required_argument, NULL, 3},
381                 {"section", required_argument, NULL, 5},
382                 {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
383                 {"snapshot", required_argument, NULL, 6},
384                 {"strict-names", no_argument, &strict_names, 1},
385                 {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
386                 {"no-comments", no_argument, &dopt.no_comments, 1},
387                 {"no-publications", no_argument, &dopt.no_publications, 1},
388                 {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
389                 {"no-synchronized-snapshots", no_argument, &dopt.no_synchronized_snapshots, 1},
390                 {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
391                 {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
392                 {"no-sync", no_argument, NULL, 7},
393                 {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
394                 {"rows-per-insert", required_argument, NULL, 10},
395
396                 {NULL, 0, NULL, 0}
397         };
398
399         set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
400
401         /*
402          * Initialize what we need for parallel execution, especially for thread
403          * support on Windows.
404          */
405         init_parallel_dump_utils();
406
407         g_verbose = false;
408
409         strcpy(g_comment_start, "-- ");
410         g_comment_end[0] = '\0';
411         strcpy(g_opaque_type, "opaque");
412
413         progname = get_progname(argv[0]);
414
415         if (argc > 1)
416         {
417                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
418                 {
419                         help(progname);
420                         exit_nicely(0);
421                 }
422                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
423                 {
424                         puts("pg_dump (PostgreSQL) " PG_VERSION);
425                         exit_nicely(0);
426                 }
427         }
428
429         InitDumpOptions(&dopt);
430
431         while ((c = getopt_long(argc, argv, "abBcCd:E:f:F:h:j:n:N:oOp:RsS:t:T:U:vwWxZ:",
432                                                         long_options, &optindex)) != -1)
433         {
434                 switch (c)
435                 {
436                         case 'a':                       /* Dump data only */
437                                 dopt.dataOnly = true;
438                                 break;
439
440                         case 'b':                       /* Dump blobs */
441                                 dopt.outputBlobs = true;
442                                 break;
443
444                         case 'B':                       /* Don't dump blobs */
445                                 dopt.dontOutputBlobs = true;
446                                 break;
447
448                         case 'c':                       /* clean (i.e., drop) schema prior to create */
449                                 dopt.outputClean = 1;
450                                 break;
451
452                         case 'C':                       /* Create DB */
453                                 dopt.outputCreateDB = 1;
454                                 break;
455
456                         case 'd':                       /* database name */
457                                 dopt.dbname = pg_strdup(optarg);
458                                 break;
459
460                         case 'E':                       /* Dump encoding */
461                                 dumpencoding = pg_strdup(optarg);
462                                 break;
463
464                         case 'f':
465                                 filename = pg_strdup(optarg);
466                                 break;
467
468                         case 'F':
469                                 format = pg_strdup(optarg);
470                                 break;
471
472                         case 'h':                       /* server host */
473                                 dopt.pghost = pg_strdup(optarg);
474                                 break;
475
476                         case 'j':                       /* number of dump jobs */
477                                 numWorkers = atoi(optarg);
478                                 break;
479
480                         case 'n':                       /* include schema(s) */
481                                 simple_string_list_append(&schema_include_patterns, optarg);
482                                 dopt.include_everything = false;
483                                 break;
484
485                         case 'N':                       /* exclude schema(s) */
486                                 simple_string_list_append(&schema_exclude_patterns, optarg);
487                                 break;
488
489                         case 'O':                       /* Don't reconnect to match owner */
490                                 dopt.outputNoOwner = 1;
491                                 break;
492
493                         case 'p':                       /* server port */
494                                 dopt.pgport = pg_strdup(optarg);
495                                 break;
496
497                         case 'R':
498                                 /* no-op, still accepted for backwards compatibility */
499                                 break;
500
501                         case 's':                       /* dump schema only */
502                                 dopt.schemaOnly = true;
503                                 break;
504
505                         case 'S':                       /* Username for superuser in plain text output */
506                                 dopt.outputSuperuser = pg_strdup(optarg);
507                                 break;
508
509                         case 't':                       /* include table(s) */
510                                 simple_string_list_append(&table_include_patterns, optarg);
511                                 dopt.include_everything = false;
512                                 break;
513
514                         case 'T':                       /* exclude table(s) */
515                                 simple_string_list_append(&table_exclude_patterns, optarg);
516                                 break;
517
518                         case 'U':
519                                 dopt.username = pg_strdup(optarg);
520                                 break;
521
522                         case 'v':                       /* verbose */
523                                 g_verbose = true;
524                                 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                                         write_msg(NULL, "compression level must be in range 0..9\n");
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                                         write_msg(NULL, "extra_float_digits must be in range -15..3\n");
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                                         write_msg(NULL, "rows-per-insert must be in range %d..%d\n",
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                 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
627                                 progname, 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                 write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
648                 exit_nicely(1);
649         }
650
651         if (dopt.dataOnly && dopt.outputClean)
652         {
653                 write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
654                 exit_nicely(1);
655         }
656
657         if (dopt.if_exists && !dopt.outputClean)
658                 exit_horribly(NULL, "option --if-exists requires option -c/--clean\n");
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                 exit_horribly(NULL, "option --on-conflict-do-nothing requires option --inserts, --rows-per-insert or --column-inserts\n");
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                 write_msg(NULL, "WARNING: requested compression not available in this "
688                                   "installation -- archive will be uncompressed\n");
689         compressLevel = 0;
690 #endif
691
692         /*
693          * If emitting an archive format, we always want to emit a DATABASE item,
694          * in case --create is specified at pg_restore time.
695          */
696         if (!plainText)
697                 dopt.outputCreateDB = 1;
698
699         /*
700          * On Windows we can only have at most MAXIMUM_WAIT_OBJECTS (= 64 usually)
701          * parallel jobs because that's the maximum limit for the
702          * WaitForMultipleObjects() call.
703          */
704         if (numWorkers <= 0
705 #ifdef WIN32
706                 || numWorkers > MAXIMUM_WAIT_OBJECTS
707 #endif
708                 )
709                 exit_horribly(NULL, "invalid number of parallel jobs\n");
710
711         /* Parallel backup only in the directory archive format so far */
712         if (archiveFormat != archDirectory && numWorkers > 1)
713                 exit_horribly(NULL, "parallel backup only supported by the directory format\n");
714
715         /* Open the output file */
716         fout = CreateArchive(filename, archiveFormat, compressLevel, dosync,
717                                                  archiveMode, setupDumpWorker);
718
719         /* Make dump options accessible right away */
720         SetArchiveOptions(fout, &dopt, NULL);
721
722         /* Register the cleanup hook */
723         on_exit_close_archive(fout);
724
725         /* Let the archiver know how noisy to be */
726         fout->verbose = g_verbose;
727
728         /*
729          * 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                 exit_horribly(NULL,
768                                           "Synchronized snapshots are not supported by this server version.\n"
769                                           "Run with --no-synchronized-snapshots instead if you do not need\n"
770                                           "synchronized snapshots.\n");
771
772         /* check the version when a snapshot is explicitly specified by user */
773         if (dumpsnapshot && fout->remoteVersion < 90200)
774                 exit_horribly(NULL,
775                                           "Exported snapshots are not supported by this server version.\n");
776
777         /*
778          * Find the last built-in OID, if needed (prior to 8.1)
779          *
780          * With 8.1 and above, we can just use FirstNormalObjectId - 1.
781          */
782         if (fout->remoteVersion < 80100)
783                 g_last_builtin_oid = findLastBuiltinOid_V71(fout);
784         else
785                 g_last_builtin_oid = FirstNormalObjectId - 1;
786
787         if (g_verbose)
788                 write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
789
790         /* Expand schema selection patterns into OID lists */
791         if (schema_include_patterns.head != NULL)
792         {
793                 expand_schema_name_patterns(fout, &schema_include_patterns,
794                                                                         &schema_include_oids,
795                                                                         strict_names);
796                 if (schema_include_oids.head == NULL)
797                         exit_horribly(NULL, "no matching schemas were found\n");
798         }
799         expand_schema_name_patterns(fout, &schema_exclude_patterns,
800                                                                 &schema_exclude_oids,
801                                                                 false);
802         /* non-matching exclusion patterns aren't an error */
803
804         /* Expand table selection patterns into OID lists */
805         if (table_include_patterns.head != NULL)
806         {
807                 expand_table_name_patterns(fout, &table_include_patterns,
808                                                                    &table_include_oids,
809                                                                    strict_names);
810                 if (table_include_oids.head == NULL)
811                         exit_horribly(NULL, "no matching tables were found\n");
812         }
813         expand_table_name_patterns(fout, &table_exclude_patterns,
814                                                            &table_exclude_oids,
815                                                            false);
816
817         expand_table_name_patterns(fout, &tabledata_exclude_patterns,
818                                                            &tabledata_exclude_oids,
819                                                            false);
820
821         /* non-matching exclusion patterns aren't an error */
822
823         /*
824          * Dumping blobs is the default for dumps where an inclusion switch is not
825          * used (an "include everything" dump).  -B can be used to exclude blobs
826          * from those dumps.  -b can be used to include blobs even when an
827          * inclusion switch is used.
828          *
829          * -s means "schema only" and blobs are data, not schema, so we never
830          * include blobs when -s is used.
831          */
832         if (dopt.include_everything && !dopt.schemaOnly && !dopt.dontOutputBlobs)
833                 dopt.outputBlobs = true;
834
835         /*
836          * Now scan the database and create DumpableObject structs for all the
837          * objects we intend to dump.
838          */
839         tblinfo = getSchemaData(fout, &numTables);
840
841         if (fout->remoteVersion < 80400)
842                 guessConstraintInheritance(tblinfo, numTables);
843
844         if (!dopt.schemaOnly)
845         {
846                 getTableData(&dopt, tblinfo, numTables, 0);
847                 buildMatViewRefreshDependencies(fout);
848                 if (dopt.dataOnly)
849                         getTableDataFKConstraints();
850         }
851
852         if (dopt.schemaOnly && dopt.sequence_data)
853                 getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
854
855         /*
856          * In binary-upgrade mode, we do not have to worry about the actual blob
857          * data or the associated metadata that resides in the pg_largeobject and
858          * pg_largeobject_metadata tables, respectively.
859          *
860          * However, we do need to collect blob information as there may be
861          * comments or other information on blobs that we do need to dump out.
862          */
863         if (dopt.outputBlobs || dopt.binary_upgrade)
864                 getBlobs(fout);
865
866         /*
867          * Collect dependency data to assist in ordering the objects.
868          */
869         getDependencies(fout);
870
871         /* Lastly, create dummy objects to represent the section boundaries */
872         boundaryObjs = createBoundaryObjects();
873
874         /* Get pointers to all the known DumpableObjects */
875         getDumpableObjects(&dobjs, &numObjs);
876
877         /*
878          * Add dummy dependencies to enforce the dump section ordering.
879          */
880         addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
881
882         /*
883          * Sort the objects into a safe dump order (no forward references).
884          *
885          * We rely on dependency information to help us determine a safe order, so
886          * the initial sort is mostly for cosmetic purposes: we sort by name to
887          * ensure that logically identical schemas will dump identically.
888          */
889         sortDumpableObjectsByTypeName(dobjs, numObjs);
890
891         sortDumpableObjects(dobjs, numObjs,
892                                                 boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
893
894         /*
895          * Create archive TOC entries for all the objects to be dumped, in a safe
896          * order.
897          */
898
899         /* First the special ENCODING, STDSTRINGS, and SEARCHPATH entries. */
900         dumpEncoding(fout);
901         dumpStdStrings(fout);
902         dumpSearchPath(fout);
903
904         /* The database items are always next, unless we don't want them at all */
905         if (dopt.outputCreateDB)
906                 dumpDatabase(fout);
907
908         /* Now the rearrangeable objects. */
909         for (i = 0; i < numObjs; i++)
910                 dumpDumpableObject(fout, dobjs[i]);
911
912         /*
913          * Set up options info to ensure we dump what we want.
914          */
915         ropt = NewRestoreOptions();
916         ropt->filename = filename;
917
918         /* if you change this list, see dumpOptionsFromRestoreOptions */
919         ropt->dropSchema = dopt.outputClean;
920         ropt->dataOnly = dopt.dataOnly;
921         ropt->schemaOnly = dopt.schemaOnly;
922         ropt->if_exists = dopt.if_exists;
923         ropt->column_inserts = dopt.column_inserts;
924         ropt->dumpSections = dopt.dumpSections;
925         ropt->aclsSkip = dopt.aclsSkip;
926         ropt->superuser = dopt.outputSuperuser;
927         ropt->createDB = dopt.outputCreateDB;
928         ropt->noOwner = dopt.outputNoOwner;
929         ropt->noTablespace = dopt.outputNoTablespaces;
930         ropt->disable_triggers = dopt.disable_triggers;
931         ropt->use_setsessauth = dopt.use_setsessauth;
932         ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
933         ropt->dump_inserts = dopt.dump_inserts;
934         ropt->no_comments = dopt.no_comments;
935         ropt->no_publications = dopt.no_publications;
936         ropt->no_security_labels = dopt.no_security_labels;
937         ropt->no_subscriptions = dopt.no_subscriptions;
938         ropt->lockWaitTimeout = dopt.lockWaitTimeout;
939         ropt->include_everything = dopt.include_everything;
940         ropt->enable_row_security = dopt.enable_row_security;
941         ropt->sequence_data = dopt.sequence_data;
942         ropt->binary_upgrade = dopt.binary_upgrade;
943
944         if (compressLevel == -1)
945                 ropt->compression = 0;
946         else
947                 ropt->compression = compressLevel;
948
949         ropt->suppressDumpWarnings = true;      /* We've already shown them */
950
951         SetArchiveOptions(fout, &dopt, ropt);
952
953         /* Mark which entries should be output */
954         ProcessArchiveRestoreOptions(fout);
955
956         /*
957          * The archive's TOC entries are now marked as to which ones will actually
958          * be output, so we can set up their dependency lists properly. This isn't
959          * necessary for plain-text output, though.
960          */
961         if (!plainText)
962                 BuildArchiveDependencies(fout);
963
964         /*
965          * And finally we can do the actual output.
966          *
967          * Note: for non-plain-text output formats, the output file is written
968          * inside CloseArchive().  This is, um, bizarre; but not worth changing
969          * right now.
970          */
971         if (plainText)
972                 RestoreArchive(fout);
973
974         CloseArchive(fout);
975
976         exit_nicely(0);
977 }
978
979
980 static void
981 help(const char *progname)
982 {
983         printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
984         printf(_("Usage:\n"));
985         printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
986
987         printf(_("\nGeneral options:\n"));
988         printf(_("  -f, --file=FILENAME          output file or directory name\n"));
989         printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
990                          "                               plain text (default))\n"));
991         printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
992         printf(_("  -v, --verbose                verbose mode\n"));
993         printf(_("  -V, --version                output version information, then exit\n"));
994         printf(_("  -Z, --compress=0-9           compression level for compressed formats\n"));
995         printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
996         printf(_("  --no-sync                    do not wait for changes to be written safely to disk\n"));
997         printf(_("  -?, --help                   show this help, then exit\n"));
998
999         printf(_("\nOptions controlling the output content:\n"));
1000         printf(_("  -a, --data-only              dump only the data, not the schema\n"));
1001         printf(_("  -b, --blobs                  include large objects in dump\n"));
1002         printf(_("  -B, --no-blobs               exclude large objects in dump\n"));
1003         printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
1004         printf(_("  -C, --create                 include commands to create database in dump\n"));
1005         printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
1006         printf(_("  -n, --schema=SCHEMA          dump the named schema(s) only\n"));
1007         printf(_("  -N, --exclude-schema=SCHEMA  do NOT dump the named schema(s)\n"));
1008         printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
1009                          "                               plain-text format\n"));
1010         printf(_("  -s, --schema-only            dump only the schema, no data\n"));
1011         printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
1012         printf(_("  -t, --table=TABLE            dump the named table(s) only\n"));
1013         printf(_("  -T, --exclude-table=TABLE    do NOT dump the named table(s)\n"));
1014         printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
1015         printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
1016         printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
1017         printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
1018         printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
1019         printf(_("  --enable-row-security        enable row security (dump only content user has\n"
1020                          "                               access to)\n"));
1021         printf(_("  --exclude-table-data=TABLE   do NOT dump data for the named table(s)\n"));
1022         printf(_("  --extra-float-digits=NUM     override default setting for extra_float_digits\n"));
1023         printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
1024         printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
1025         printf(_("  --load-via-partition-root    load partitions via the root table\n"));
1026         printf(_("  --no-comments                do not dump comments\n"));
1027         printf(_("  --no-publications            do not dump publications\n"));
1028         printf(_("  --no-security-labels         do not dump security label assignments\n"));
1029         printf(_("  --no-subscriptions           do not dump subscriptions\n"));
1030         printf(_("  --no-synchronized-snapshots  do not use synchronized snapshots in parallel jobs\n"));
1031         printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
1032         printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
1033         printf(_("  --on-conflict-do-nothing     add ON CONFLICT DO NOTHING to INSERT commands\n"));
1034         printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
1035         printf(_("  --rows-per-insert=NROWS      number of rows per INSERT; implies --inserts\n"));
1036         printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
1037         printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
1038         printf(_("  --snapshot=SNAPSHOT          use given snapshot for the dump\n"));
1039         printf(_("  --strict-names               require table and/or schema include patterns to\n"
1040                          "                               match at least one entity each\n"));
1041         printf(_("  --use-set-session-authorization\n"
1042                          "                               use SET SESSION AUTHORIZATION commands instead of\n"
1043                          "                               ALTER OWNER commands to set ownership\n"));
1044
1045         printf(_("\nConnection options:\n"));
1046         printf(_("  -d, --dbname=DBNAME      database to dump\n"));
1047         printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
1048         printf(_("  -p, --port=PORT          database server port number\n"));
1049         printf(_("  -U, --username=NAME      connect as specified database user\n"));
1050         printf(_("  -w, --no-password        never prompt for password\n"));
1051         printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
1052         printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
1053
1054         printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
1055                          "variable value is used.\n\n"));
1056         printf(_("Report bugs to <pgsql-bugs@lists.postgresql.org>.\n"));
1057 }
1058
1059 static void
1060 setup_connection(Archive *AH, const char *dumpencoding,
1061                                  const char *dumpsnapshot, char *use_role)
1062 {
1063         DumpOptions *dopt = AH->dopt;
1064         PGconn     *conn = GetConnection(AH);
1065         const char *std_strings;
1066
1067         PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
1068
1069         /*
1070          * Set the client encoding if requested.
1071          */
1072         if (dumpencoding)
1073         {
1074                 if (PQsetClientEncoding(conn, dumpencoding) < 0)
1075                         exit_horribly(NULL, "invalid client encoding \"%s\" specified\n",
1076                                                   dumpencoding);
1077         }
1078
1079         /*
1080          * Get the active encoding and the standard_conforming_strings setting, so
1081          * we know how to escape strings.
1082          */
1083         AH->encoding = PQclientEncoding(conn);
1084
1085         std_strings = PQparameterStatus(conn, "standard_conforming_strings");
1086         AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
1087
1088         /*
1089          * Set the role if requested.  In a parallel dump worker, we'll be passed
1090          * use_role == NULL, but AH->use_role is already set (if user specified it
1091          * originally) and we should use that.
1092          */
1093         if (!use_role && AH->use_role)
1094                 use_role = AH->use_role;
1095
1096         /* Set the role if requested */
1097         if (use_role && AH->remoteVersion >= 80100)
1098         {
1099                 PQExpBuffer query = createPQExpBuffer();
1100
1101                 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
1102                 ExecuteSqlStatement(AH, query->data);
1103                 destroyPQExpBuffer(query);
1104
1105                 /* save it for possible later use by parallel workers */
1106                 if (!AH->use_role)
1107                         AH->use_role = pg_strdup(use_role);
1108         }
1109
1110         /* Set the datestyle to ISO to ensure the dump's portability */
1111         ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
1112
1113         /* Likewise, avoid using sql_standard intervalstyle */
1114         if (AH->remoteVersion >= 80400)
1115                 ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
1116
1117         /*
1118          * Use an explicitly specified extra_float_digits if it has been
1119          * provided. Otherwise, set extra_float_digits so that we can dump float
1120          * data exactly (given correctly implemented float I/O code, anyway).
1121          */
1122         if (have_extra_float_digits)
1123         {
1124                 PQExpBuffer q = createPQExpBuffer();
1125                 appendPQExpBuffer(q, "SET extra_float_digits TO %d",
1126                                                   extra_float_digits);
1127                 ExecuteSqlStatement(AH, q->data);
1128                 destroyPQExpBuffer(q);
1129         }
1130         else if (AH->remoteVersion >= 90000)
1131                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
1132         else
1133                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 2");
1134
1135         /*
1136          * If synchronized scanning is supported, disable it, to prevent
1137          * unpredictable changes in row ordering across a dump and reload.
1138          */
1139         if (AH->remoteVersion >= 80300)
1140                 ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
1141
1142         /*
1143          * Disable timeouts if supported.
1144          */
1145         ExecuteSqlStatement(AH, "SET statement_timeout = 0");
1146         if (AH->remoteVersion >= 90300)
1147                 ExecuteSqlStatement(AH, "SET lock_timeout = 0");
1148         if (AH->remoteVersion >= 90600)
1149                 ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
1150
1151         /*
1152          * Quote all identifiers, if requested.
1153          */
1154         if (quote_all_identifiers && AH->remoteVersion >= 90100)
1155                 ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1156
1157         /*
1158          * Adjust row-security mode, if supported.
1159          */
1160         if (AH->remoteVersion >= 90500)
1161         {
1162                 if (dopt->enable_row_security)
1163                         ExecuteSqlStatement(AH, "SET row_security = on");
1164                 else
1165                         ExecuteSqlStatement(AH, "SET row_security = off");
1166         }
1167
1168         /*
1169          * Start transaction-snapshot mode transaction to dump consistent data.
1170          */
1171         ExecuteSqlStatement(AH, "BEGIN");
1172         if (AH->remoteVersion >= 90100)
1173         {
1174                 /*
1175                  * To support the combination of serializable_deferrable with the jobs
1176                  * option we use REPEATABLE READ for the worker connections that are
1177                  * passed a snapshot.  As long as the snapshot is acquired in a
1178                  * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
1179                  * REPEATABLE READ transaction provides the appropriate integrity
1180                  * guarantees.  This is a kluge, but safe for back-patching.
1181                  */
1182                 if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
1183                         ExecuteSqlStatement(AH,
1184                                                                 "SET TRANSACTION ISOLATION LEVEL "
1185                                                                 "SERIALIZABLE, READ ONLY, DEFERRABLE");
1186                 else
1187                         ExecuteSqlStatement(AH,
1188                                                                 "SET TRANSACTION ISOLATION LEVEL "
1189                                                                 "REPEATABLE READ, READ ONLY");
1190         }
1191         else
1192         {
1193                 ExecuteSqlStatement(AH,
1194                                                         "SET TRANSACTION ISOLATION LEVEL "
1195                                                         "SERIALIZABLE, READ ONLY");
1196         }
1197
1198         /*
1199          * If user specified a snapshot to use, select that.  In a parallel dump
1200          * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
1201          * is already set (if the server can handle it) and we should use that.
1202          */
1203         if (dumpsnapshot)
1204                 AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
1205
1206         if (AH->sync_snapshot_id)
1207         {
1208                 PQExpBuffer query = createPQExpBuffer();
1209
1210                 appendPQExpBuffer(query, "SET TRANSACTION SNAPSHOT ");
1211                 appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
1212                 ExecuteSqlStatement(AH, query->data);
1213                 destroyPQExpBuffer(query);
1214         }
1215         else if (AH->numWorkers > 1 &&
1216                          AH->remoteVersion >= 90200 &&
1217                          !dopt->no_synchronized_snapshots)
1218         {
1219                 if (AH->isStandby && AH->remoteVersion < 100000)
1220                         exit_horribly(NULL,
1221                                                   "Synchronized snapshots on standby servers are not supported by this server version.\n"
1222                                                   "Run with --no-synchronized-snapshots instead if you do not need\n"
1223                                                   "synchronized snapshots.\n");
1224
1225
1226                 AH->sync_snapshot_id = get_synchronized_snapshot(AH);
1227         }
1228 }
1229
1230 /* Set up connection for a parallel worker process */
1231 static void
1232 setupDumpWorker(Archive *AH)
1233 {
1234         /*
1235          * We want to re-select all the same values the master connection is
1236          * using.  We'll have inherited directly-usable values in
1237          * AH->sync_snapshot_id and AH->use_role, but we need to translate the
1238          * inherited encoding value back to a string to pass to setup_connection.
1239          */
1240         setup_connection(AH,
1241                                          pg_encoding_to_char(AH->encoding),
1242                                          NULL,
1243                                          NULL);
1244 }
1245
1246 static char *
1247 get_synchronized_snapshot(Archive *fout)
1248 {
1249         char       *query = "SELECT pg_catalog.pg_export_snapshot()";
1250         char       *result;
1251         PGresult   *res;
1252
1253         res = ExecuteSqlQueryForSingleRow(fout, query);
1254         result = pg_strdup(PQgetvalue(res, 0, 0));
1255         PQclear(res);
1256
1257         return result;
1258 }
1259
1260 static ArchiveFormat
1261 parseArchiveFormat(const char *format, ArchiveMode *mode)
1262 {
1263         ArchiveFormat archiveFormat;
1264
1265         *mode = archModeWrite;
1266
1267         if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1268         {
1269                 /* This is used by pg_dumpall, and is not documented */
1270                 archiveFormat = archNull;
1271                 *mode = archModeAppend;
1272         }
1273         else if (pg_strcasecmp(format, "c") == 0)
1274                 archiveFormat = archCustom;
1275         else if (pg_strcasecmp(format, "custom") == 0)
1276                 archiveFormat = archCustom;
1277         else if (pg_strcasecmp(format, "d") == 0)
1278                 archiveFormat = archDirectory;
1279         else if (pg_strcasecmp(format, "directory") == 0)
1280                 archiveFormat = archDirectory;
1281         else if (pg_strcasecmp(format, "p") == 0)
1282                 archiveFormat = archNull;
1283         else if (pg_strcasecmp(format, "plain") == 0)
1284                 archiveFormat = archNull;
1285         else if (pg_strcasecmp(format, "t") == 0)
1286                 archiveFormat = archTar;
1287         else if (pg_strcasecmp(format, "tar") == 0)
1288                 archiveFormat = archTar;
1289         else
1290                 exit_horribly(NULL, "invalid output format \"%s\" specified\n", format);
1291         return archiveFormat;
1292 }
1293
1294 /*
1295  * Find the OIDs of all schemas matching the given list of patterns,
1296  * and append them to the given OID list.
1297  */
1298 static void
1299 expand_schema_name_patterns(Archive *fout,
1300                                                         SimpleStringList *patterns,
1301                                                         SimpleOidList *oids,
1302                                                         bool strict_names)
1303 {
1304         PQExpBuffer query;
1305         PGresult   *res;
1306         SimpleStringListCell *cell;
1307         int                     i;
1308
1309         if (patterns->head == NULL)
1310                 return;                                 /* nothing to do */
1311
1312         query = createPQExpBuffer();
1313
1314         /*
1315          * The loop below runs multiple SELECTs might sometimes result in
1316          * duplicate entries in the OID list, but we don't care.
1317          */
1318
1319         for (cell = patterns->head; cell; cell = cell->next)
1320         {
1321                 appendPQExpBuffer(query,
1322                                                   "SELECT oid FROM pg_catalog.pg_namespace n\n");
1323                 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1324                                                           false, NULL, "n.nspname", NULL, NULL);
1325
1326                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1327                 if (strict_names && PQntuples(res) == 0)
1328                         exit_horribly(NULL, "no matching schemas were found for pattern \"%s\"\n", cell->val);
1329
1330                 for (i = 0; i < PQntuples(res); i++)
1331                 {
1332                         simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1333                 }
1334
1335                 PQclear(res);
1336                 resetPQExpBuffer(query);
1337         }
1338
1339         destroyPQExpBuffer(query);
1340 }
1341
1342 /*
1343  * Find the OIDs of all tables matching the given list of patterns,
1344  * and append them to the given OID list. See also expand_dbname_patterns()
1345  * in pg_dumpall.c
1346  */
1347 static void
1348 expand_table_name_patterns(Archive *fout,
1349                                                    SimpleStringList *patterns, SimpleOidList *oids,
1350                                                    bool strict_names)
1351 {
1352         PQExpBuffer query;
1353         PGresult   *res;
1354         SimpleStringListCell *cell;
1355         int                     i;
1356
1357         if (patterns->head == NULL)
1358                 return;                                 /* nothing to do */
1359
1360         query = createPQExpBuffer();
1361
1362         /*
1363          * this might sometimes result in duplicate entries in the OID list, but
1364          * we don't care.
1365          */
1366
1367         for (cell = patterns->head; cell; cell = cell->next)
1368         {
1369                 /*
1370                  * Query must remain ABSOLUTELY devoid of unqualified names.  This
1371                  * would be unnecessary given a pg_table_is_visible() variant taking a
1372                  * search_path argument.
1373                  */
1374                 appendPQExpBuffer(query,
1375                                                   "SELECT c.oid"
1376                                                   "\nFROM pg_catalog.pg_class c"
1377                                                   "\n     LEFT JOIN pg_catalog.pg_namespace n"
1378                                                   "\n     ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
1379                                                   "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
1380                                                   "\n    (array['%c', '%c', '%c', '%c', '%c', '%c'])\n",
1381                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1382                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
1383                                                   RELKIND_PARTITIONED_TABLE);
1384                 processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1385                                                           false, "n.nspname", "c.relname", NULL,
1386                                                           "pg_catalog.pg_table_is_visible(c.oid)");
1387
1388                 ExecuteSqlStatement(fout, "RESET search_path");
1389                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1390                 PQclear(ExecuteSqlQueryForSingleRow(fout,
1391                                                                                         ALWAYS_SECURE_SEARCH_PATH_SQL));
1392                 if (strict_names && PQntuples(res) == 0)
1393                         exit_horribly(NULL, "no matching tables were found for pattern \"%s\"\n", cell->val);
1394
1395                 for (i = 0; i < PQntuples(res); i++)
1396                 {
1397                         simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1398                 }
1399
1400                 PQclear(res);
1401                 resetPQExpBuffer(query);
1402         }
1403
1404         destroyPQExpBuffer(query);
1405 }
1406
1407 /*
1408  * checkExtensionMembership
1409  *              Determine whether object is an extension member, and if so,
1410  *              record an appropriate dependency and set the object's dump flag.
1411  *
1412  * It's important to call this for each object that could be an extension
1413  * member.  Generally, we integrate this with determining the object's
1414  * to-be-dumped-ness, since extension membership overrides other rules for that.
1415  *
1416  * Returns true if object is an extension member, else false.
1417  */
1418 static bool
1419 checkExtensionMembership(DumpableObject *dobj, Archive *fout)
1420 {
1421         ExtensionInfo *ext = findOwningExtension(dobj->catId);
1422
1423         if (ext == NULL)
1424                 return false;
1425
1426         dobj->ext_member = true;
1427
1428         /* Record dependency so that getDependencies needn't deal with that */
1429         addObjectDependency(dobj, ext->dobj.dumpId);
1430
1431         /*
1432          * In 9.6 and above, mark the member object to have any non-initial ACL,
1433          * policies, and security labels dumped.
1434          *
1435          * Note that any initial ACLs (see pg_init_privs) will be removed when we
1436          * extract the information about the object.  We don't provide support for
1437          * initial policies and security labels and it seems unlikely for those to
1438          * ever exist, but we may have to revisit this later.
1439          *
1440          * Prior to 9.6, we do not include any extension member components.
1441          *
1442          * In binary upgrades, we still dump all components of the members
1443          * individually, since the idea is to exactly reproduce the database
1444          * contents rather than replace the extension contents with something
1445          * different.
1446          */
1447         if (fout->dopt->binary_upgrade)
1448                 dobj->dump = ext->dobj.dump;
1449         else
1450         {
1451                 if (fout->remoteVersion < 90600)
1452                         dobj->dump = DUMP_COMPONENT_NONE;
1453                 else
1454                         dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL |
1455                                                                                                         DUMP_COMPONENT_SECLABEL |
1456                                                                                                         DUMP_COMPONENT_POLICY);
1457         }
1458
1459         return true;
1460 }
1461
1462 /*
1463  * selectDumpableNamespace: policy-setting subroutine
1464  *              Mark a namespace as to be dumped or not
1465  */
1466 static void
1467 selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
1468 {
1469         /*
1470          * If specific tables are being dumped, do not dump any complete
1471          * namespaces. If specific namespaces are being dumped, dump just those
1472          * namespaces. Otherwise, dump all non-system namespaces.
1473          */
1474         if (table_include_oids.head != NULL)
1475                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1476         else if (schema_include_oids.head != NULL)
1477                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
1478                         simple_oid_list_member(&schema_include_oids,
1479                                                                    nsinfo->dobj.catId.oid) ?
1480                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1481         else if (fout->remoteVersion >= 90600 &&
1482                          strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
1483         {
1484                 /*
1485                  * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
1486                  * they are interesting (and not the original ACLs which were set at
1487                  * initdb time, see pg_init_privs).
1488                  */
1489                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1490         }
1491         else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1492                          strcmp(nsinfo->dobj.name, "information_schema") == 0)
1493         {
1494                 /* Other system schemas don't get dumped */
1495                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1496         }
1497         else if (strcmp(nsinfo->dobj.name, "public") == 0)
1498         {
1499                 /*
1500                  * The public schema is a strange beast that sits in a sort of
1501                  * no-mans-land between being a system object and a user object.  We
1502                  * don't want to dump creation or comment commands for it, because
1503                  * that complicates matters for non-superuser use of pg_dump.  But we
1504                  * should dump any ACL changes that have occurred for it, and of
1505                  * course we should dump contained objects.
1506                  */
1507                 nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1508                 nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
1509         }
1510         else
1511                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
1512
1513         /*
1514          * In any case, a namespace can be excluded by an exclusion switch
1515          */
1516         if (nsinfo->dobj.dump_contains &&
1517                 simple_oid_list_member(&schema_exclude_oids,
1518                                                            nsinfo->dobj.catId.oid))
1519                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1520
1521         /*
1522          * If the schema belongs to an extension, allow extension membership to
1523          * override the dump decision for the schema itself.  However, this does
1524          * not change dump_contains, so this won't change what we do with objects
1525          * within the schema.  (If they belong to the extension, they'll get
1526          * suppressed by it, otherwise not.)
1527          */
1528         (void) checkExtensionMembership(&nsinfo->dobj, fout);
1529 }
1530
1531 /*
1532  * selectDumpableTable: policy-setting subroutine
1533  *              Mark a table as to be dumped or not
1534  */
1535 static void
1536 selectDumpableTable(TableInfo *tbinfo, Archive *fout)
1537 {
1538         if (checkExtensionMembership(&tbinfo->dobj, fout))
1539                 return;                                 /* extension membership overrides all else */
1540
1541         /*
1542          * If specific tables are being dumped, dump just those tables; else, dump
1543          * according to the parent namespace's dump flag.
1544          */
1545         if (table_include_oids.head != NULL)
1546                 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1547                                                                                                    tbinfo->dobj.catId.oid) ?
1548                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1549         else
1550                 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
1551
1552         /*
1553          * In any case, a table can be excluded by an exclusion switch
1554          */
1555         if (tbinfo->dobj.dump &&
1556                 simple_oid_list_member(&table_exclude_oids,
1557                                                            tbinfo->dobj.catId.oid))
1558                 tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
1559 }
1560
1561 /*
1562  * selectDumpableType: policy-setting subroutine
1563  *              Mark a type as to be dumped or not
1564  *
1565  * If it's a table's rowtype or an autogenerated array type, we also apply a
1566  * special type code to facilitate sorting into the desired order.  (We don't
1567  * want to consider those to be ordinary types because that would bring tables
1568  * up into the datatype part of the dump order.)  We still set the object's
1569  * dump flag; that's not going to cause the dummy type to be dumped, but we
1570  * need it so that casts involving such types will be dumped correctly -- see
1571  * dumpCast.  This means the flag should be set the same as for the underlying
1572  * object (the table or base type).
1573  */
1574 static void
1575 selectDumpableType(TypeInfo *tyinfo, Archive *fout)
1576 {
1577         /* skip complex types, except for standalone composite types */
1578         if (OidIsValid(tyinfo->typrelid) &&
1579                 tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1580         {
1581                 TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
1582
1583                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1584                 if (tytable != NULL)
1585                         tyinfo->dobj.dump = tytable->dobj.dump;
1586                 else
1587                         tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
1588                 return;
1589         }
1590
1591         /* skip auto-generated array types */
1592         if (tyinfo->isArray)
1593         {
1594                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1595
1596                 /*
1597                  * Fall through to set the dump flag; we assume that the subsequent
1598                  * rules will do the same thing as they would for the array's base
1599                  * type.  (We cannot reliably look up the base type here, since
1600                  * getTypes may not have processed it yet.)
1601                  */
1602         }
1603
1604         if (checkExtensionMembership(&tyinfo->dobj, fout))
1605                 return;                                 /* extension membership overrides all else */
1606
1607         /* Dump based on if the contents of the namespace are being dumped */
1608         tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
1609 }
1610
1611 /*
1612  * selectDumpableDefaultACL: policy-setting subroutine
1613  *              Mark a default ACL as to be dumped or not
1614  *
1615  * For per-schema default ACLs, dump if the schema is to be dumped.
1616  * Otherwise dump if we are dumping "everything".  Note that dataOnly
1617  * and aclsSkip are checked separately.
1618  */
1619 static void
1620 selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
1621 {
1622         /* Default ACLs can't be extension members */
1623
1624         if (dinfo->dobj.namespace)
1625                 /* default ACLs are considered part of the namespace */
1626                 dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
1627         else
1628                 dinfo->dobj.dump = dopt->include_everything ?
1629                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1630 }
1631
1632 /*
1633  * selectDumpableCast: policy-setting subroutine
1634  *              Mark a cast as to be dumped or not
1635  *
1636  * Casts do not belong to any particular namespace (since they haven't got
1637  * names), nor do they have identifiable owners.  To distinguish user-defined
1638  * casts from built-in ones, we must resort to checking whether the cast's
1639  * OID is in the range reserved for initdb.
1640  */
1641 static void
1642 selectDumpableCast(CastInfo *cast, Archive *fout)
1643 {
1644         if (checkExtensionMembership(&cast->dobj, fout))
1645                 return;                                 /* extension membership overrides all else */
1646
1647         /*
1648          * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
1649          * support ACLs currently.
1650          */
1651         if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1652                 cast->dobj.dump = DUMP_COMPONENT_NONE;
1653         else
1654                 cast->dobj.dump = fout->dopt->include_everything ?
1655                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1656 }
1657
1658 /*
1659  * selectDumpableProcLang: policy-setting subroutine
1660  *              Mark a procedural language as to be dumped or not
1661  *
1662  * Procedural languages do not belong to any particular namespace.  To
1663  * identify built-in languages, we must resort to checking whether the
1664  * language's OID is in the range reserved for initdb.
1665  */
1666 static void
1667 selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
1668 {
1669         if (checkExtensionMembership(&plang->dobj, fout))
1670                 return;                                 /* extension membership overrides all else */
1671
1672         /*
1673          * Only include procedural languages when we are dumping everything.
1674          *
1675          * For from-initdb procedural languages, only include ACLs, as we do for
1676          * the pg_catalog namespace.  We need this because procedural languages do
1677          * not live in any namespace.
1678          */
1679         if (!fout->dopt->include_everything)
1680                 plang->dobj.dump = DUMP_COMPONENT_NONE;
1681         else
1682         {
1683                 if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1684                         plang->dobj.dump = fout->remoteVersion < 90600 ?
1685                                 DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
1686                 else
1687                         plang->dobj.dump = DUMP_COMPONENT_ALL;
1688         }
1689 }
1690
1691 /*
1692  * selectDumpableAccessMethod: policy-setting subroutine
1693  *              Mark an access method as to be dumped or not
1694  *
1695  * Access methods do not belong to any particular namespace.  To identify
1696  * built-in access methods, we must resort to checking whether the
1697  * method's OID is in the range reserved for initdb.
1698  */
1699 static void
1700 selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
1701 {
1702         if (checkExtensionMembership(&method->dobj, fout))
1703                 return;                                 /* extension membership overrides all else */
1704
1705         /*
1706          * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
1707          * they do not support ACLs currently.
1708          */
1709         if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1710                 method->dobj.dump = DUMP_COMPONENT_NONE;
1711         else
1712                 method->dobj.dump = fout->dopt->include_everything ?
1713                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1714 }
1715
1716 /*
1717  * selectDumpableExtension: policy-setting subroutine
1718  *              Mark an extension as to be dumped or not
1719  *
1720  * Built-in extensions should be skipped except for checking ACLs, since we
1721  * assume those will already be installed in the target database.  We identify
1722  * such extensions by their having OIDs in the range reserved for initdb.
1723  * We dump all user-added extensions by default, or none of them if
1724  * include_everything is false (i.e., a --schema or --table switch was given).
1725  */
1726 static void
1727 selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
1728 {
1729         /*
1730          * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
1731          * change permissions on their member objects, if they wish to, and have
1732          * those changes preserved.
1733          */
1734         if (extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1735                 extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
1736         else
1737                 extinfo->dobj.dump = extinfo->dobj.dump_contains =
1738                         dopt->include_everything ? DUMP_COMPONENT_ALL :
1739                         DUMP_COMPONENT_NONE;
1740 }
1741
1742 /*
1743  * selectDumpablePublicationTable: policy-setting subroutine
1744  *              Mark a publication table as to be dumped or not
1745  *
1746  * Publication tables have schemas, but those are ignored in decision making,
1747  * because publications are only dumped when we are dumping everything.
1748  */
1749 static void
1750 selectDumpablePublicationTable(DumpableObject *dobj, Archive *fout)
1751 {
1752         if (checkExtensionMembership(dobj, fout))
1753                 return;                                 /* extension membership overrides all else */
1754
1755         dobj->dump = fout->dopt->include_everything ?
1756                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1757 }
1758
1759 /*
1760  * selectDumpableObject: policy-setting subroutine
1761  *              Mark a generic dumpable object as to be dumped or not
1762  *
1763  * Use this only for object types without a special-case routine above.
1764  */
1765 static void
1766 selectDumpableObject(DumpableObject *dobj, Archive *fout)
1767 {
1768         if (checkExtensionMembership(dobj, fout))
1769                 return;                                 /* extension membership overrides all else */
1770
1771         /*
1772          * Default policy is to dump if parent namespace is dumpable, or for
1773          * non-namespace-associated items, dump if we're dumping "everything".
1774          */
1775         if (dobj->namespace)
1776                 dobj->dump = dobj->namespace->dobj.dump_contains;
1777         else
1778                 dobj->dump = fout->dopt->include_everything ?
1779                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1780 }
1781
1782 /*
1783  *      Dump a table's contents for loading using the COPY command
1784  *      - this routine is called by the Archiver when it wants the table
1785  *        to be dumped.
1786  */
1787
1788 static int
1789 dumpTableData_copy(Archive *fout, void *dcontext)
1790 {
1791         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1792         TableInfo  *tbinfo = tdinfo->tdtable;
1793         const char *classname = tbinfo->dobj.name;
1794         PQExpBuffer q = createPQExpBuffer();
1795
1796         /*
1797          * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
1798          * which uses it already.
1799          */
1800         PQExpBuffer clistBuf = createPQExpBuffer();
1801         PGconn     *conn = GetConnection(fout);
1802         PGresult   *res;
1803         int                     ret;
1804         char       *copybuf;
1805         const char *column_list;
1806
1807         if (g_verbose)
1808                 write_msg(NULL, "dumping contents of table \"%s.%s\"\n",
1809                                   tbinfo->dobj.namespace->dobj.name, classname);
1810
1811         /*
1812          * Specify the column list explicitly so that we have no possibility of
1813          * retrieving data in the wrong column order.  (The default column
1814          * ordering of COPY will not be what we want in certain corner cases
1815          * involving ADD COLUMN and inheritance.)
1816          */
1817         column_list = fmtCopyColumnList(tbinfo, clistBuf);
1818
1819         if (tdinfo->filtercond)
1820         {
1821                 /* Note: this syntax is only supported in 8.2 and up */
1822                 appendPQExpBufferStr(q, "COPY (SELECT ");
1823                 /* klugery to get rid of parens in column list */
1824                 if (strlen(column_list) > 2)
1825                 {
1826                         appendPQExpBufferStr(q, column_list + 1);
1827                         q->data[q->len - 1] = ' ';
1828                 }
1829                 else
1830                         appendPQExpBufferStr(q, "* ");
1831                 appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
1832                                                   fmtQualifiedDumpable(tbinfo),
1833                                                   tdinfo->filtercond);
1834         }
1835         else
1836         {
1837                 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1838                                                   fmtQualifiedDumpable(tbinfo),
1839                                                   column_list);
1840         }
1841         res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
1842         PQclear(res);
1843         destroyPQExpBuffer(clistBuf);
1844
1845         for (;;)
1846         {
1847                 ret = PQgetCopyData(conn, &copybuf, 0);
1848
1849                 if (ret < 0)
1850                         break;                          /* done or error */
1851
1852                 if (copybuf)
1853                 {
1854                         WriteData(fout, copybuf, ret);
1855                         PQfreemem(copybuf);
1856                 }
1857
1858                 /* ----------
1859                  * THROTTLE:
1860                  *
1861                  * There was considerable discussion in late July, 2000 regarding
1862                  * slowing down pg_dump when backing up large tables. Users with both
1863                  * slow & fast (multi-processor) machines experienced performance
1864                  * degradation when doing a backup.
1865                  *
1866                  * Initial attempts based on sleeping for a number of ms for each ms
1867                  * of work were deemed too complex, then a simple 'sleep in each loop'
1868                  * implementation was suggested. The latter failed because the loop
1869                  * was too tight. Finally, the following was implemented:
1870                  *
1871                  * If throttle is non-zero, then
1872                  *              See how long since the last sleep.
1873                  *              Work out how long to sleep (based on ratio).
1874                  *              If sleep is more than 100ms, then
1875                  *                      sleep
1876                  *                      reset timer
1877                  *              EndIf
1878                  * EndIf
1879                  *
1880                  * where the throttle value was the number of ms to sleep per ms of
1881                  * work. The calculation was done in each loop.
1882                  *
1883                  * Most of the hard work is done in the backend, and this solution
1884                  * still did not work particularly well: on slow machines, the ratio
1885                  * was 50:1, and on medium paced machines, 1:1, and on fast
1886                  * multi-processor machines, it had little or no effect, for reasons
1887                  * that were unclear.
1888                  *
1889                  * Further discussion ensued, and the proposal was dropped.
1890                  *
1891                  * For those people who want this feature, it can be implemented using
1892                  * gettimeofday in each loop, calculating the time since last sleep,
1893                  * multiplying that by the sleep ratio, then if the result is more
1894                  * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1895                  * function to sleep for a subsecond period ie.
1896                  *
1897                  * select(0, NULL, NULL, NULL, &tvi);
1898                  *
1899                  * This will return after the interval specified in the structure tvi.
1900                  * Finally, call gettimeofday again to save the 'last sleep time'.
1901                  * ----------
1902                  */
1903         }
1904         archprintf(fout, "\\.\n\n\n");
1905
1906         if (ret == -2)
1907         {
1908                 /* copy data transfer failed */
1909                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
1910                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1911                 write_msg(NULL, "The command was: %s\n", q->data);
1912                 exit_nicely(1);
1913         }
1914
1915         /* Check command status and return to normal libpq state */
1916         res = PQgetResult(conn);
1917         if (PQresultStatus(res) != PGRES_COMMAND_OK)
1918         {
1919                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetResult() failed.\n", classname);
1920                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1921                 write_msg(NULL, "The command was: %s\n", q->data);
1922                 exit_nicely(1);
1923         }
1924         PQclear(res);
1925
1926         /* Do this to ensure we've pumped libpq back to idle state */
1927         if (PQgetResult(conn) != NULL)
1928                 write_msg(NULL, "WARNING: unexpected extra results during COPY of table \"%s\"\n",
1929                                   classname);
1930
1931         destroyPQExpBuffer(q);
1932         return 1;
1933 }
1934
1935 /*
1936  * Dump table data using INSERT commands.
1937  *
1938  * Caution: when we restore from an archive file direct to database, the
1939  * INSERT commands emitted by this function have to be parsed by
1940  * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
1941  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
1942  */
1943 static int
1944 dumpTableData_insert(Archive *fout, void *dcontext)
1945 {
1946         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1947         TableInfo  *tbinfo = tdinfo->tdtable;
1948         DumpOptions *dopt = fout->dopt;
1949         PQExpBuffer q = createPQExpBuffer();
1950         PQExpBuffer insertStmt = NULL;
1951         PGresult   *res;
1952         int                     nfields;
1953         int                     rows_per_statement = dopt->dump_inserts;
1954         int                     rows_this_statement = 0;
1955
1956         appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1957                                           "SELECT * FROM ONLY %s",
1958                                           fmtQualifiedDumpable(tbinfo));
1959         if (tdinfo->filtercond)
1960                 appendPQExpBuffer(q, " %s", tdinfo->filtercond);
1961
1962         ExecuteSqlStatement(fout, q->data);
1963
1964         while (1)
1965         {
1966                 res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
1967                                                           PGRES_TUPLES_OK);
1968                 nfields = PQnfields(res);
1969
1970                 /*
1971                  * First time through, we build as much of the INSERT statement as
1972                  * possible in "insertStmt", which we can then just print for each
1973                  * statement. If the table happens to have zero columns then this will
1974                  * be a complete statement, otherwise it will end in "VALUES" and be
1975                  * ready to have the row's column values printed.
1976                  */
1977                 if (insertStmt == NULL)
1978                 {
1979                         TableInfo  *targettab;
1980
1981                         insertStmt = createPQExpBuffer();
1982
1983                         /*
1984                          * When load-via-partition-root is set, get the root table name
1985                          * for the partition table, so that we can reload data through the
1986                          * root table.
1987                          */
1988                         if (dopt->load_via_partition_root && tbinfo->ispartition)
1989                                 targettab = getRootTableInfo(tbinfo);
1990                         else
1991                                 targettab = tbinfo;
1992
1993                         appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
1994                                                           fmtQualifiedDumpable(targettab));
1995
1996                         /* corner case for zero-column table */
1997                         if (nfields == 0)
1998                         {
1999                                 appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
2000                         }
2001                         else
2002                         {
2003                                 /* append the list of column names if required */
2004                                 if (dopt->column_inserts)
2005                                 {
2006                                         appendPQExpBufferChar(insertStmt, '(');
2007                                         for (int field = 0; field < nfields; field++)
2008                                         {
2009                                                 if (field > 0)
2010                                                         appendPQExpBufferStr(insertStmt, ", ");
2011                                                 appendPQExpBufferStr(insertStmt,
2012                                                                                          fmtId(PQfname(res, field)));
2013                                         }
2014                                         appendPQExpBufferStr(insertStmt, ") ");
2015                                 }
2016
2017                                 if (tbinfo->needs_override)
2018                                         appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
2019
2020                                 appendPQExpBufferStr(insertStmt, "VALUES");
2021                         }
2022                 }
2023
2024                 for (int tuple = 0; tuple < PQntuples(res); tuple++)
2025                 {
2026                         /* Write the INSERT if not in the middle of a multi-row INSERT. */
2027                         if (rows_this_statement == 0)
2028                                 archputs(insertStmt->data, fout);
2029
2030                         /*
2031                          * If it is zero-column table then we've aleady written the
2032                          * complete statement, which will mean we've disobeyed
2033                          * --rows-per-insert when it's set greater than 1.  We do support
2034                          * a way to make this multi-row with: SELECT UNION ALL SELECT
2035                          * UNION ALL ... but that's non-standard so we should avoid it
2036                          * given that using INSERTs is mostly only ever needed for
2037                          * cross-database exports.
2038                          */
2039                         if (nfields == 0)
2040                                 continue;
2041
2042                         /* Emit a row heading */
2043                         if (rows_per_statement == 1)
2044                                 archputs(" (", fout);
2045                         else if (rows_this_statement > 0)
2046                                 archputs(",\n\t(", fout);
2047                         else
2048                                 archputs("\n\t(", fout);
2049
2050                         for (int field = 0; field < nfields; field++)
2051                         {
2052                                 if (field > 0)
2053                                         archputs(", ", fout);
2054                                 if (PQgetisnull(res, tuple, field))
2055                                 {
2056                                         archputs("NULL", fout);
2057                                         continue;
2058                                 }
2059
2060                                 /* XXX This code is partially duplicated in ruleutils.c */
2061                                 switch (PQftype(res, field))
2062                                 {
2063                                         case INT2OID:
2064                                         case INT4OID:
2065                                         case INT8OID:
2066                                         case OIDOID:
2067                                         case FLOAT4OID:
2068                                         case FLOAT8OID:
2069                                         case NUMERICOID:
2070                                                 {
2071                                                         /*
2072                                                          * These types are printed without quotes unless
2073                                                          * they contain values that aren't accepted by the
2074                                                          * scanner unquoted (e.g., 'NaN').  Note that
2075                                                          * strtod() and friends might accept NaN, so we
2076                                                          * can't use that to test.
2077                                                          *
2078                                                          * In reality we only need to defend against
2079                                                          * infinity and NaN, so we need not get too crazy
2080                                                          * about pattern matching here.
2081                                                          */
2082                                                         const char *s = PQgetvalue(res, tuple, field);
2083
2084                                                         if (strspn(s, "0123456789 +-eE.") == strlen(s))
2085                                                                 archputs(s, fout);
2086                                                         else
2087                                                                 archprintf(fout, "'%s'", s);
2088                                                 }
2089                                                 break;
2090
2091                                         case BITOID:
2092                                         case VARBITOID:
2093                                                 archprintf(fout, "B'%s'",
2094                                                                    PQgetvalue(res, tuple, field));
2095                                                 break;
2096
2097                                         case BOOLOID:
2098                                                 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
2099                                                         archputs("true", fout);
2100                                                 else
2101                                                         archputs("false", fout);
2102                                                 break;
2103
2104                                         default:
2105                                                 /* All other types are printed as string literals. */
2106                                                 resetPQExpBuffer(q);
2107                                                 appendStringLiteralAH(q,
2108                                                                                           PQgetvalue(res, tuple, field),
2109                                                                                           fout);
2110                                                 archputs(q->data, fout);
2111                                                 break;
2112                                 }
2113                         }
2114
2115                         /* Terminate the row ... */
2116                         archputs(")", fout);
2117
2118                         /* ... and the statement, if the target no. of rows is reached */
2119                         if (++rows_this_statement >= rows_per_statement)
2120                         {
2121                                 if (dopt->do_nothing)
2122                                         archputs(" ON CONFLICT DO NOTHING;\n", fout);
2123                                 else
2124                                         archputs(";\n", fout);
2125                                 /* Reset the row counter */
2126                                 rows_this_statement = 0;
2127                         }
2128                 }
2129
2130                 if (PQntuples(res) <= 0)
2131                 {
2132                         PQclear(res);
2133                         break;
2134                 }
2135                 PQclear(res);
2136         }
2137
2138         /* Terminate any statements that didn't make the row count. */
2139         if (rows_this_statement > 0)
2140         {
2141                 if (dopt->do_nothing)
2142                         archputs(" ON CONFLICT DO NOTHING;\n", fout);
2143                 else
2144                         archputs(";\n", fout);
2145         }
2146
2147         archputs("\n\n", fout);
2148
2149         ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
2150
2151         destroyPQExpBuffer(q);
2152         if (insertStmt != NULL)
2153                 destroyPQExpBuffer(insertStmt);
2154
2155         return 1;
2156 }
2157
2158 /*
2159  * getRootTableInfo:
2160  *     get the root TableInfo for the given partition table.
2161  */
2162 static TableInfo *
2163 getRootTableInfo(TableInfo *tbinfo)
2164 {
2165         TableInfo  *parentTbinfo;
2166
2167         Assert(tbinfo->ispartition);
2168         Assert(tbinfo->numParents == 1);
2169
2170         parentTbinfo = tbinfo->parents[0];
2171         while (parentTbinfo->ispartition)
2172         {
2173                 Assert(parentTbinfo->numParents == 1);
2174                 parentTbinfo = parentTbinfo->parents[0];
2175         }
2176
2177         return parentTbinfo;
2178 }
2179
2180 /*
2181  * dumpTableData -
2182  *        dump the contents of a single table
2183  *
2184  * Actually, this just makes an ArchiveEntry for the table contents.
2185  */
2186 static void
2187 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
2188 {
2189         DumpOptions *dopt = fout->dopt;
2190         TableInfo  *tbinfo = tdinfo->tdtable;
2191         PQExpBuffer copyBuf = createPQExpBuffer();
2192         PQExpBuffer clistBuf = createPQExpBuffer();
2193         DataDumperPtr dumpFn;
2194         char       *copyStmt;
2195         const char *copyFrom;
2196
2197         if (!dopt->dump_inserts)
2198         {
2199                 /* Dump/restore using COPY */
2200                 dumpFn = dumpTableData_copy;
2201
2202                 /*
2203                  * When load-via-partition-root is set, get the root table name for
2204                  * the partition table, so that we can reload data through the root
2205                  * table.
2206                  */
2207                 if (dopt->load_via_partition_root && tbinfo->ispartition)
2208                 {
2209                         TableInfo  *parentTbinfo;
2210
2211                         parentTbinfo = getRootTableInfo(tbinfo);
2212                         copyFrom = fmtQualifiedDumpable(parentTbinfo);
2213                 }
2214                 else
2215                         copyFrom = fmtQualifiedDumpable(tbinfo);
2216
2217                 /* must use 2 steps here 'cause fmtId is nonreentrant */
2218                 appendPQExpBuffer(copyBuf, "COPY %s ",
2219                                                   copyFrom);
2220                 appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
2221                                                   fmtCopyColumnList(tbinfo, clistBuf));
2222                 copyStmt = copyBuf->data;
2223         }
2224         else
2225         {
2226                 /* Restore using INSERT */
2227                 dumpFn = dumpTableData_insert;
2228                 copyStmt = NULL;
2229         }
2230
2231         /*
2232          * Note: although the TableDataInfo is a full DumpableObject, we treat its
2233          * dependency on its table as "special" and pass it to ArchiveEntry now.
2234          * See comments for BuildArchiveDependencies.
2235          */
2236         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2237         {
2238                 TocEntry   *te;
2239
2240                 te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
2241                                                   ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
2242                                                                            .namespace = tbinfo->dobj.namespace->dobj.name,
2243                                                                            .owner = tbinfo->rolname,
2244                                                                            .description = "TABLE DATA",
2245                                                                            .section = SECTION_DATA,
2246                                                                            .createStmt = "",
2247                                                                            .dropStmt = "",
2248                                                                            .copyStmt = copyStmt,
2249                                                                            .deps = &(tbinfo->dobj.dumpId),
2250                                                                            .nDeps = 1,
2251                                                                            .dumpFn = dumpFn,
2252                                                                            .dumpArg = tdinfo));
2253
2254                 /*
2255                  * Set the TocEntry's dataLength in case we are doing a parallel dump
2256                  * and want to order dump jobs by table size.  We choose to measure
2257                  * dataLength in table pages during dump, so no scaling is needed.
2258                  * However, relpages is declared as "integer" in pg_class, and hence
2259                  * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
2260                  * Cast so that we get the right interpretation of table sizes
2261                  * exceeding INT_MAX pages.
2262                  */
2263                 te->dataLength = (BlockNumber) tbinfo->relpages;
2264         }
2265
2266         destroyPQExpBuffer(copyBuf);
2267         destroyPQExpBuffer(clistBuf);
2268 }
2269
2270 /*
2271  * refreshMatViewData -
2272  *        load or refresh the contents of a single materialized view
2273  *
2274  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
2275  * statement.
2276  */
2277 static void
2278 refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
2279 {
2280         TableInfo  *tbinfo = tdinfo->tdtable;
2281         PQExpBuffer q;
2282
2283         /* If the materialized view is not flagged as populated, skip this. */
2284         if (!tbinfo->relispopulated)
2285                 return;
2286
2287         q = createPQExpBuffer();
2288
2289         appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
2290                                           fmtQualifiedDumpable(tbinfo));
2291
2292         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2293                 ArchiveEntry(fout,
2294                                          tdinfo->dobj.catId,    /* catalog ID */
2295                                          tdinfo->dobj.dumpId,   /* dump ID */
2296                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
2297                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
2298                                                                   .owner = tbinfo->rolname,
2299                                                                   .description = "MATERIALIZED VIEW DATA",
2300                                                                   .section = SECTION_POST_DATA,
2301                                                                   .createStmt = q->data,
2302                                                                   .dropStmt = "",
2303                                                                   .deps = tdinfo->dobj.dependencies,
2304                                                                   .nDeps = tdinfo->dobj.nDeps));
2305
2306         destroyPQExpBuffer(q);
2307 }
2308
2309 /*
2310  * getTableData -
2311  *        set up dumpable objects representing the contents of tables
2312  */
2313 static void
2314 getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
2315 {
2316         int                     i;
2317
2318         for (i = 0; i < numTables; i++)
2319         {
2320                 if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
2321                         (!relkind || tblinfo[i].relkind == relkind))
2322                         makeTableDataInfo(dopt, &(tblinfo[i]));
2323         }
2324 }
2325
2326 /*
2327  * Make a dumpable object for the data of this specific table
2328  *
2329  * Note: we make a TableDataInfo if and only if we are going to dump the
2330  * table data; the "dump" flag in such objects isn't used.
2331  */
2332 static void
2333 makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
2334 {
2335         TableDataInfo *tdinfo;
2336
2337         /*
2338          * Nothing to do if we already decided to dump the table.  This will
2339          * happen for "config" tables.
2340          */
2341         if (tbinfo->dataObj != NULL)
2342                 return;
2343
2344         /* Skip VIEWs (no data to dump) */
2345         if (tbinfo->relkind == RELKIND_VIEW)
2346                 return;
2347         /* Skip FOREIGN TABLEs (no data to dump) */
2348         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2349                 return;
2350         /* Skip partitioned tables (data in partitions) */
2351         if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
2352                 return;
2353
2354         /* Don't dump data in unlogged tables, if so requested */
2355         if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
2356                 dopt->no_unlogged_table_data)
2357                 return;
2358
2359         /* Check that the data is not explicitly excluded */
2360         if (simple_oid_list_member(&tabledata_exclude_oids,
2361                                                            tbinfo->dobj.catId.oid))
2362                 return;
2363
2364         /* OK, let's dump it */
2365         tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
2366
2367         if (tbinfo->relkind == RELKIND_MATVIEW)
2368                 tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
2369         else if (tbinfo->relkind == RELKIND_SEQUENCE)
2370                 tdinfo->dobj.objType = DO_SEQUENCE_SET;
2371         else
2372                 tdinfo->dobj.objType = DO_TABLE_DATA;
2373
2374         /*
2375          * Note: use tableoid 0 so that this object won't be mistaken for
2376          * something that pg_depend entries apply to.
2377          */
2378         tdinfo->dobj.catId.tableoid = 0;
2379         tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
2380         AssignDumpId(&tdinfo->dobj);
2381         tdinfo->dobj.name = tbinfo->dobj.name;
2382         tdinfo->dobj.namespace = tbinfo->dobj.namespace;
2383         tdinfo->tdtable = tbinfo;
2384         tdinfo->filtercond = NULL;      /* might get set later */
2385         addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
2386
2387         tbinfo->dataObj = tdinfo;
2388 }
2389
2390 /*
2391  * The refresh for a materialized view must be dependent on the refresh for
2392  * any materialized view that this one is dependent on.
2393  *
2394  * This must be called after all the objects are created, but before they are
2395  * sorted.
2396  */
2397 static void
2398 buildMatViewRefreshDependencies(Archive *fout)
2399 {
2400         PQExpBuffer query;
2401         PGresult   *res;
2402         int                     ntups,
2403                                 i;
2404         int                     i_classid,
2405                                 i_objid,
2406                                 i_refobjid;
2407
2408         /* No Mat Views before 9.3. */
2409         if (fout->remoteVersion < 90300)
2410                 return;
2411
2412         query = createPQExpBuffer();
2413
2414         appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
2415                                                  "( "
2416                                                  "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
2417                                                  "FROM pg_depend d1 "
2418                                                  "JOIN pg_class c1 ON c1.oid = d1.objid "
2419                                                  "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
2420                                                  " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
2421                                                  "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
2422                                                  "AND d2.objid = r1.oid "
2423                                                  "AND d2.refobjid <> d1.objid "
2424                                                  "JOIN pg_class c2 ON c2.oid = d2.refobjid "
2425                                                  "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2426                                                  CppAsString2(RELKIND_VIEW) ") "
2427                                                  "WHERE d1.classid = 'pg_class'::regclass "
2428                                                  "UNION "
2429                                                  "SELECT w.objid, d3.refobjid, c3.relkind "
2430                                                  "FROM w "
2431                                                  "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
2432                                                  "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
2433                                                  "AND d3.objid = r3.oid "
2434                                                  "AND d3.refobjid <> w.refobjid "
2435                                                  "JOIN pg_class c3 ON c3.oid = d3.refobjid "
2436                                                  "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2437                                                  CppAsString2(RELKIND_VIEW) ") "
2438                                                  ") "
2439                                                  "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
2440                                                  "FROM w "
2441                                                  "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
2442
2443         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2444
2445         ntups = PQntuples(res);
2446
2447         i_classid = PQfnumber(res, "classid");
2448         i_objid = PQfnumber(res, "objid");
2449         i_refobjid = PQfnumber(res, "refobjid");
2450
2451         for (i = 0; i < ntups; i++)
2452         {
2453                 CatalogId       objId;
2454                 CatalogId       refobjId;
2455                 DumpableObject *dobj;
2456                 DumpableObject *refdobj;
2457                 TableInfo  *tbinfo;
2458                 TableInfo  *reftbinfo;
2459
2460                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
2461                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
2462                 refobjId.tableoid = objId.tableoid;
2463                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
2464
2465                 dobj = findObjectByCatalogId(objId);
2466                 if (dobj == NULL)
2467                         continue;
2468
2469                 Assert(dobj->objType == DO_TABLE);
2470                 tbinfo = (TableInfo *) dobj;
2471                 Assert(tbinfo->relkind == RELKIND_MATVIEW);
2472                 dobj = (DumpableObject *) tbinfo->dataObj;
2473                 if (dobj == NULL)
2474                         continue;
2475                 Assert(dobj->objType == DO_REFRESH_MATVIEW);
2476
2477                 refdobj = findObjectByCatalogId(refobjId);
2478                 if (refdobj == NULL)
2479                         continue;
2480
2481                 Assert(refdobj->objType == DO_TABLE);
2482                 reftbinfo = (TableInfo *) refdobj;
2483                 Assert(reftbinfo->relkind == RELKIND_MATVIEW);
2484                 refdobj = (DumpableObject *) reftbinfo->dataObj;
2485                 if (refdobj == NULL)
2486                         continue;
2487                 Assert(refdobj->objType == DO_REFRESH_MATVIEW);
2488
2489                 addObjectDependency(dobj, refdobj->dumpId);
2490
2491                 if (!reftbinfo->relispopulated)
2492                         tbinfo->relispopulated = false;
2493         }
2494
2495         PQclear(res);
2496
2497         destroyPQExpBuffer(query);
2498 }
2499
2500 /*
2501  * getTableDataFKConstraints -
2502  *        add dump-order dependencies reflecting foreign key constraints
2503  *
2504  * This code is executed only in a data-only dump --- in schema+data dumps
2505  * we handle foreign key issues by not creating the FK constraints until
2506  * after the data is loaded.  In a data-only dump, however, we want to
2507  * order the table data objects in such a way that a table's referenced
2508  * tables are restored first.  (In the presence of circular references or
2509  * self-references this may be impossible; we'll detect and complain about
2510  * that during the dependency sorting step.)
2511  */
2512 static void
2513 getTableDataFKConstraints(void)
2514 {
2515         DumpableObject **dobjs;
2516         int                     numObjs;
2517         int                     i;
2518
2519         /* Search through all the dumpable objects for FK constraints */
2520         getDumpableObjects(&dobjs, &numObjs);
2521         for (i = 0; i < numObjs; i++)
2522         {
2523                 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
2524                 {
2525                         ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
2526                         TableInfo  *ftable;
2527
2528                         /* Not interesting unless both tables are to be dumped */
2529                         if (cinfo->contable == NULL ||
2530                                 cinfo->contable->dataObj == NULL)
2531                                 continue;
2532                         ftable = findTableByOid(cinfo->confrelid);
2533                         if (ftable == NULL ||
2534                                 ftable->dataObj == NULL)
2535                                 continue;
2536
2537                         /*
2538                          * Okay, make referencing table's TABLE_DATA object depend on the
2539                          * referenced table's TABLE_DATA object.
2540                          */
2541                         addObjectDependency(&cinfo->contable->dataObj->dobj,
2542                                                                 ftable->dataObj->dobj.dumpId);
2543                 }
2544         }
2545         free(dobjs);
2546 }
2547
2548
2549 /*
2550  * guessConstraintInheritance:
2551  *      In pre-8.4 databases, we can't tell for certain which constraints
2552  *      are inherited.  We assume a CHECK constraint is inherited if its name
2553  *      matches the name of any constraint in the parent.  Originally this code
2554  *      tried to compare the expression texts, but that can fail for various
2555  *      reasons --- for example, if the parent and child tables are in different
2556  *      schemas, reverse-listing of function calls may produce different text
2557  *      (schema-qualified or not) depending on search path.
2558  *
2559  *      In 8.4 and up we can rely on the conislocal field to decide which
2560  *      constraints must be dumped; much safer.
2561  *
2562  *      This function assumes all conislocal flags were initialized to true.
2563  *      It clears the flag on anything that seems to be inherited.
2564  */
2565 static void
2566 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
2567 {
2568         int                     i,
2569                                 j,
2570                                 k;
2571
2572         for (i = 0; i < numTables; i++)
2573         {
2574                 TableInfo  *tbinfo = &(tblinfo[i]);
2575                 int                     numParents;
2576                 TableInfo **parents;
2577                 TableInfo  *parent;
2578
2579                 /* Sequences and views never have parents */
2580                 if (tbinfo->relkind == RELKIND_SEQUENCE ||
2581                         tbinfo->relkind == RELKIND_VIEW)
2582                         continue;
2583
2584                 /* Don't bother computing anything for non-target tables, either */
2585                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
2586                         continue;
2587
2588                 numParents = tbinfo->numParents;
2589                 parents = tbinfo->parents;
2590
2591                 if (numParents == 0)
2592                         continue;                       /* nothing to see here, move along */
2593
2594                 /* scan for inherited CHECK constraints */
2595                 for (j = 0; j < tbinfo->ncheck; j++)
2596                 {
2597                         ConstraintInfo *constr;
2598
2599                         constr = &(tbinfo->checkexprs[j]);
2600
2601                         for (k = 0; k < numParents; k++)
2602                         {
2603                                 int                     l;
2604
2605                                 parent = parents[k];
2606                                 for (l = 0; l < parent->ncheck; l++)
2607                                 {
2608                                         ConstraintInfo *pconstr = &(parent->checkexprs[l]);
2609
2610                                         if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
2611                                         {
2612                                                 constr->conislocal = false;
2613                                                 break;
2614                                         }
2615                                 }
2616                                 if (!constr->conislocal)
2617                                         break;
2618                         }
2619                 }
2620         }
2621 }
2622
2623
2624 /*
2625  * dumpDatabase:
2626  *      dump the database definition
2627  */
2628 static void
2629 dumpDatabase(Archive *fout)
2630 {
2631         DumpOptions *dopt = fout->dopt;
2632         PQExpBuffer dbQry = createPQExpBuffer();
2633         PQExpBuffer delQry = createPQExpBuffer();
2634         PQExpBuffer creaQry = createPQExpBuffer();
2635         PQExpBuffer labelq = createPQExpBuffer();
2636         PGconn     *conn = GetConnection(fout);
2637         PGresult   *res;
2638         int                     i_tableoid,
2639                                 i_oid,
2640                                 i_datname,
2641                                 i_dba,
2642                                 i_encoding,
2643                                 i_collate,
2644                                 i_ctype,
2645                                 i_frozenxid,
2646                                 i_minmxid,
2647                                 i_datacl,
2648                                 i_rdatacl,
2649                                 i_datistemplate,
2650                                 i_datconnlimit,
2651                                 i_tablespace;
2652         CatalogId       dbCatId;
2653         DumpId          dbDumpId;
2654         const char *datname,
2655                            *dba,
2656                            *encoding,
2657                            *collate,
2658                            *ctype,
2659                            *datacl,
2660                            *rdatacl,
2661                            *datistemplate,
2662                            *datconnlimit,
2663                            *tablespace;
2664         uint32          frozenxid,
2665                                 minmxid;
2666         char       *qdatname;
2667
2668         if (g_verbose)
2669                 write_msg(NULL, "saving database definition\n");
2670
2671         /* Fetch the database-level properties for this database */
2672         if (fout->remoteVersion >= 90600)
2673         {
2674                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2675                                                   "(%s datdba) AS dba, "
2676                                                   "pg_encoding_to_char(encoding) AS encoding, "
2677                                                   "datcollate, datctype, datfrozenxid, datminmxid, "
2678                                                   "(SELECT array_agg(acl ORDER BY acl::text COLLATE \"C\") FROM ( "
2679                                                   "  SELECT unnest(coalesce(datacl,acldefault('d',datdba))) AS acl "
2680                                                   "  EXCEPT SELECT unnest(acldefault('d',datdba))) as datacls)"
2681                                                   " AS datacl, "
2682                                                   "(SELECT array_agg(acl ORDER BY acl::text COLLATE \"C\") FROM ( "
2683                                                   "  SELECT unnest(acldefault('d',datdba)) AS acl "
2684                                                   "  EXCEPT SELECT unnest(coalesce(datacl,acldefault('d',datdba)))) as rdatacls)"
2685                                                   " AS rdatacl, "
2686                                                   "datistemplate, datconnlimit, "
2687                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2688                                                   "shobj_description(oid, 'pg_database') AS description "
2689
2690                                                   "FROM pg_database "
2691                                                   "WHERE datname = current_database()",
2692                                                   username_subquery);
2693         }
2694         else if (fout->remoteVersion >= 90300)
2695         {
2696                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2697                                                   "(%s datdba) AS dba, "
2698                                                   "pg_encoding_to_char(encoding) AS encoding, "
2699                                                   "datcollate, datctype, datfrozenxid, datminmxid, "
2700                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2701                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2702                                                   "shobj_description(oid, 'pg_database') AS description "
2703
2704                                                   "FROM pg_database "
2705                                                   "WHERE datname = current_database()",
2706                                                   username_subquery);
2707         }
2708         else if (fout->remoteVersion >= 80400)
2709         {
2710                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2711                                                   "(%s datdba) AS dba, "
2712                                                   "pg_encoding_to_char(encoding) AS encoding, "
2713                                                   "datcollate, datctype, datfrozenxid, 0 AS datminmxid, "
2714                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2715                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2716                                                   "shobj_description(oid, 'pg_database') AS description "
2717
2718                                                   "FROM pg_database "
2719                                                   "WHERE datname = current_database()",
2720                                                   username_subquery);
2721         }
2722         else if (fout->remoteVersion >= 80200)
2723         {
2724                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2725                                                   "(%s datdba) AS dba, "
2726                                                   "pg_encoding_to_char(encoding) AS encoding, "
2727                                                   "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2728                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2729                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2730                                                   "shobj_description(oid, 'pg_database') AS description "
2731
2732                                                   "FROM pg_database "
2733                                                   "WHERE datname = current_database()",
2734                                                   username_subquery);
2735         }
2736         else
2737         {
2738                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2739                                                   "(%s datdba) AS dba, "
2740                                                   "pg_encoding_to_char(encoding) AS encoding, "
2741                                                   "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2742                                                   "datacl, '' as rdatacl, datistemplate, "
2743                                                   "-1 as datconnlimit, "
2744                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
2745                                                   "FROM pg_database "
2746                                                   "WHERE datname = current_database()",
2747                                                   username_subquery);
2748         }
2749
2750         res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
2751
2752         i_tableoid = PQfnumber(res, "tableoid");
2753         i_oid = PQfnumber(res, "oid");
2754         i_datname = PQfnumber(res, "datname");
2755         i_dba = PQfnumber(res, "dba");
2756         i_encoding = PQfnumber(res, "encoding");
2757         i_collate = PQfnumber(res, "datcollate");
2758         i_ctype = PQfnumber(res, "datctype");
2759         i_frozenxid = PQfnumber(res, "datfrozenxid");
2760         i_minmxid = PQfnumber(res, "datminmxid");
2761         i_datacl = PQfnumber(res, "datacl");
2762         i_rdatacl = PQfnumber(res, "rdatacl");
2763         i_datistemplate = PQfnumber(res, "datistemplate");
2764         i_datconnlimit = PQfnumber(res, "datconnlimit");
2765         i_tablespace = PQfnumber(res, "tablespace");
2766
2767         dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
2768         dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
2769         datname = PQgetvalue(res, 0, i_datname);
2770         dba = PQgetvalue(res, 0, i_dba);
2771         encoding = PQgetvalue(res, 0, i_encoding);
2772         collate = PQgetvalue(res, 0, i_collate);
2773         ctype = PQgetvalue(res, 0, i_ctype);
2774         frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
2775         minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
2776         datacl = PQgetvalue(res, 0, i_datacl);
2777         rdatacl = PQgetvalue(res, 0, i_rdatacl);
2778         datistemplate = PQgetvalue(res, 0, i_datistemplate);
2779         datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
2780         tablespace = PQgetvalue(res, 0, i_tablespace);
2781
2782         qdatname = pg_strdup(fmtId(datname));
2783
2784         /*
2785          * Prepare the CREATE DATABASE command.  We must specify encoding, locale,
2786          * and tablespace since those can't be altered later.  Other DB properties
2787          * are left to the DATABASE PROPERTIES entry, so that they can be applied
2788          * after reconnecting to the target DB.
2789          */
2790         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
2791                                           qdatname);
2792         if (strlen(encoding) > 0)
2793         {
2794                 appendPQExpBufferStr(creaQry, " ENCODING = ");
2795                 appendStringLiteralAH(creaQry, encoding, fout);
2796         }
2797         if (strlen(collate) > 0)
2798         {
2799                 appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
2800                 appendStringLiteralAH(creaQry, collate, fout);
2801         }
2802         if (strlen(ctype) > 0)
2803         {
2804                 appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
2805                 appendStringLiteralAH(creaQry, ctype, fout);
2806         }
2807
2808         /*
2809          * Note: looking at dopt->outputNoTablespaces here is completely the wrong
2810          * thing; the decision whether to specify a tablespace should be left till
2811          * pg_restore, so that pg_restore --no-tablespaces applies.  Ideally we'd
2812          * label the DATABASE entry with the tablespace and let the normal
2813          * tablespace selection logic work ... but CREATE DATABASE doesn't pay
2814          * attention to default_tablespace, so that won't work.
2815          */
2816         if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
2817                 !dopt->outputNoTablespaces)
2818                 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
2819                                                   fmtId(tablespace));
2820         appendPQExpBufferStr(creaQry, ";\n");
2821
2822         appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
2823                                           qdatname);
2824
2825         dbDumpId = createDumpId();
2826
2827         ArchiveEntry(fout,
2828                                  dbCatId,               /* catalog ID */
2829                                  dbDumpId,              /* dump ID */
2830                                  ARCHIVE_OPTS(.tag = datname,
2831                                                           .owner = dba,
2832                                                           .description = "DATABASE",
2833                                                           .section = SECTION_PRE_DATA,
2834                                                           .createStmt = creaQry->data,
2835                                                           .dropStmt = delQry->data));
2836
2837         /* Compute correct tag for archive entry */
2838         appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
2839
2840         /* Dump DB comment if any */
2841         if (fout->remoteVersion >= 80200)
2842         {
2843                 /*
2844                  * 8.2 and up keep comments on shared objects in a shared table, so we
2845                  * cannot use the dumpComment() code used for other database objects.
2846                  * Be careful that the ArchiveEntry parameters match that function.
2847                  */
2848                 char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
2849
2850                 if (comment && *comment && !dopt->no_comments)
2851                 {
2852                         resetPQExpBuffer(dbQry);
2853
2854                         /*
2855                          * Generates warning when loaded into a differently-named
2856                          * database.
2857                          */
2858                         appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
2859                         appendStringLiteralAH(dbQry, comment, fout);
2860                         appendPQExpBufferStr(dbQry, ";\n");
2861
2862                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2863                                                  ARCHIVE_OPTS(.tag = labelq->data,
2864                                                                           .owner = dba,
2865                                                                           .description = "COMMENT",
2866                                                                           .section = SECTION_NONE,
2867                                                                           .createStmt = dbQry->data,
2868                                                                           .dropStmt = "",
2869                                                                           .deps = &dbDumpId,
2870                                                                           .nDeps = 1));
2871                 }
2872         }
2873         else
2874         {
2875                 dumpComment(fout, "DATABASE", qdatname, NULL, dba,
2876                                         dbCatId, 0, dbDumpId);
2877         }
2878
2879         /* Dump DB security label, if enabled */
2880         if (!dopt->no_security_labels && fout->remoteVersion >= 90200)
2881         {
2882                 PGresult   *shres;
2883                 PQExpBuffer seclabelQry;
2884
2885                 seclabelQry = createPQExpBuffer();
2886
2887                 buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
2888                 shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
2889                 resetPQExpBuffer(seclabelQry);
2890                 emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
2891                 if (seclabelQry->len > 0)
2892                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2893                                                  ARCHIVE_OPTS(.tag = labelq->data,
2894                                                                           .owner = dba,
2895                                                                           .description = "SECURITY LABEL",
2896                                                                           .section = SECTION_NONE,
2897                                                                           .createStmt = seclabelQry->data,
2898                                                                           .dropStmt = "",
2899                                                                           .deps = &dbDumpId,
2900                                                                           .nDeps = 1));
2901                 destroyPQExpBuffer(seclabelQry);
2902                 PQclear(shres);
2903         }
2904
2905         /*
2906          * Dump ACL if any.  Note that we do not support initial privileges
2907          * (pg_init_privs) on databases.
2908          */
2909         dumpACL(fout, dbCatId, dbDumpId, "DATABASE",
2910                         qdatname, NULL, NULL,
2911                         dba, datacl, rdatacl, "", "");
2912
2913         /*
2914          * Now construct a DATABASE PROPERTIES archive entry to restore any
2915          * non-default database-level properties.  (The reason this must be
2916          * separate is that we cannot put any additional commands into the TOC
2917          * entry that has CREATE DATABASE.  pg_restore would execute such a group
2918          * in an implicit transaction block, and the backend won't allow CREATE
2919          * DATABASE in that context.)
2920          */
2921         resetPQExpBuffer(creaQry);
2922         resetPQExpBuffer(delQry);
2923
2924         if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
2925                 appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
2926                                                   qdatname, datconnlimit);
2927
2928         if (strcmp(datistemplate, "t") == 0)
2929         {
2930                 appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
2931                                                   qdatname);
2932
2933                 /*
2934                  * The backend won't accept DROP DATABASE on a template database.  We
2935                  * can deal with that by removing the template marking before the DROP
2936                  * gets issued.  We'd prefer to use ALTER DATABASE IF EXISTS here, but
2937                  * since no such command is currently supported, fake it with a direct
2938                  * UPDATE on pg_database.
2939                  */
2940                 appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
2941                                                          "SET datistemplate = false WHERE datname = ");
2942                 appendStringLiteralAH(delQry, datname, fout);
2943                 appendPQExpBufferStr(delQry, ";\n");
2944         }
2945
2946         /* Add database-specific SET options */
2947         dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
2948
2949         /*
2950          * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
2951          * entry, too, for lack of a better place.
2952          */
2953         if (dopt->binary_upgrade)
2954         {
2955                 appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
2956                 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
2957                                                   "SET datfrozenxid = '%u', datminmxid = '%u'\n"
2958                                                   "WHERE datname = ",
2959                                                   frozenxid, minmxid);
2960                 appendStringLiteralAH(creaQry, datname, fout);
2961                 appendPQExpBufferStr(creaQry, ";\n");
2962         }
2963
2964         if (creaQry->len > 0)
2965                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
2966                                          ARCHIVE_OPTS(.tag = datname,
2967                                                                   .owner = dba,
2968                                                                   .description = "DATABASE PROPERTIES",
2969                                                                   .section = SECTION_PRE_DATA,
2970                                                                   .createStmt = creaQry->data,
2971                                                                   .dropStmt = delQry->data,
2972                                                                   .deps = &dbDumpId));
2973
2974         /*
2975          * pg_largeobject comes from the old system intact, so set its
2976          * relfrozenxids and relminmxids.
2977          */
2978         if (dopt->binary_upgrade)
2979         {
2980                 PGresult   *lo_res;
2981                 PQExpBuffer loFrozenQry = createPQExpBuffer();
2982                 PQExpBuffer loOutQry = createPQExpBuffer();
2983                 int                     i_relfrozenxid,
2984                                         i_relminmxid;
2985
2986                 /*
2987                  * pg_largeobject
2988                  */
2989                 if (fout->remoteVersion >= 90300)
2990                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
2991                                                           "FROM pg_catalog.pg_class\n"
2992                                                           "WHERE oid = %u;\n",
2993                                                           LargeObjectRelationId);
2994                 else
2995                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
2996                                                           "FROM pg_catalog.pg_class\n"
2997                                                           "WHERE oid = %u;\n",
2998                                                           LargeObjectRelationId);
2999
3000                 lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
3001
3002                 i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
3003                 i_relminmxid = PQfnumber(lo_res, "relminmxid");
3004
3005                 appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
3006                 appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
3007                                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
3008                                                   "WHERE oid = %u;\n",
3009                                                   atooid(PQgetvalue(lo_res, 0, i_relfrozenxid)),
3010                                                   atooid(PQgetvalue(lo_res, 0, i_relminmxid)),
3011                                                   LargeObjectRelationId);
3012                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
3013                                          ARCHIVE_OPTS(.tag = "pg_largeobject",
3014                                                                   .description = "pg_largeobject",
3015                                                                   .owner = "",
3016                                                                   .section = SECTION_PRE_DATA,
3017                                                                   .createStmt = loOutQry->data,
3018                                                                   .dropStmt = ""));
3019
3020                 PQclear(lo_res);
3021
3022                 destroyPQExpBuffer(loFrozenQry);
3023                 destroyPQExpBuffer(loOutQry);
3024         }
3025
3026         PQclear(res);
3027
3028         free(qdatname);
3029         destroyPQExpBuffer(dbQry);
3030         destroyPQExpBuffer(delQry);
3031         destroyPQExpBuffer(creaQry);
3032         destroyPQExpBuffer(labelq);
3033 }
3034
3035 /*
3036  * Collect any database-specific or role-and-database-specific SET options
3037  * for this database, and append them to outbuf.
3038  */
3039 static void
3040 dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
3041                                    const char *dbname, Oid dboid)
3042 {
3043         PGconn     *conn = GetConnection(AH);
3044         PQExpBuffer buf = createPQExpBuffer();
3045         PGresult   *res;
3046         int                     count = 1;
3047
3048         /*
3049          * First collect database-specific options.  Pre-8.4 server versions lack
3050          * unnest(), so we do this the hard way by querying once per subscript.
3051          */
3052         for (;;)
3053         {
3054                 if (AH->remoteVersion >= 90000)
3055                         printfPQExpBuffer(buf, "SELECT setconfig[%d] FROM pg_db_role_setting "
3056                                                           "WHERE setrole = 0 AND setdatabase = '%u'::oid",
3057                                                           count, dboid);
3058                 else
3059                         printfPQExpBuffer(buf, "SELECT datconfig[%d] FROM pg_database WHERE oid = '%u'::oid", count, dboid);
3060
3061                 res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3062
3063                 if (PQntuples(res) == 1 &&
3064                         !PQgetisnull(res, 0, 0))
3065                 {
3066                         makeAlterConfigCommand(conn, PQgetvalue(res, 0, 0),
3067                                                                    "DATABASE", dbname, NULL, NULL,
3068                                                                    outbuf);
3069                         PQclear(res);
3070                         count++;
3071                 }
3072                 else
3073                 {
3074                         PQclear(res);
3075                         break;
3076                 }
3077         }
3078
3079         /* Now look for role-and-database-specific options */
3080         if (AH->remoteVersion >= 90000)
3081         {
3082                 /* Here we can assume we have unnest() */
3083                 printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
3084                                                   "FROM pg_db_role_setting s, pg_roles r "
3085                                                   "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
3086                                                   dboid);
3087
3088                 res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3089
3090                 if (PQntuples(res) > 0)
3091                 {
3092                         int                     i;
3093
3094                         for (i = 0; i < PQntuples(res); i++)
3095                                 makeAlterConfigCommand(conn, PQgetvalue(res, i, 1),
3096                                                                            "ROLE", PQgetvalue(res, i, 0),
3097                                                                            "DATABASE", dbname,
3098                                                                            outbuf);
3099                 }
3100
3101                 PQclear(res);
3102         }
3103
3104         destroyPQExpBuffer(buf);
3105 }
3106
3107 /*
3108  * dumpEncoding: put the correct encoding into the archive
3109  */
3110 static void
3111 dumpEncoding(Archive *AH)
3112 {
3113         const char *encname = pg_encoding_to_char(AH->encoding);
3114         PQExpBuffer qry = createPQExpBuffer();
3115
3116         if (g_verbose)
3117                 write_msg(NULL, "saving encoding = %s\n", encname);
3118
3119         appendPQExpBufferStr(qry, "SET client_encoding = ");
3120         appendStringLiteralAH(qry, encname, AH);
3121         appendPQExpBufferStr(qry, ";\n");
3122
3123         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3124                                  ARCHIVE_OPTS(.tag = "ENCODING",
3125                                                           .description = "ENCODING",
3126                                                           .owner = "",
3127                                                           .section = SECTION_PRE_DATA,
3128                                                           .createStmt = qry->data,
3129                                                           .dropStmt = ""));
3130
3131         destroyPQExpBuffer(qry);
3132 }
3133
3134
3135 /*
3136  * dumpStdStrings: put the correct escape string behavior into the archive
3137  */
3138 static void
3139 dumpStdStrings(Archive *AH)
3140 {
3141         const char *stdstrings = AH->std_strings ? "on" : "off";
3142         PQExpBuffer qry = createPQExpBuffer();
3143
3144         if (g_verbose)
3145                 write_msg(NULL, "saving standard_conforming_strings = %s\n",
3146                                   stdstrings);
3147
3148         appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
3149                                           stdstrings);
3150
3151         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3152                                  ARCHIVE_OPTS(.tag = "STDSTRINGS",
3153                                                           .description = "STDSTRINGS",
3154                                                           .owner = "",
3155                                                           .section = SECTION_PRE_DATA,
3156                                                           .createStmt = qry->data,
3157                                                           .dropStmt = ""));
3158
3159         destroyPQExpBuffer(qry);
3160 }
3161
3162 /*
3163  * dumpSearchPath: record the active search_path in the archive
3164  */
3165 static void
3166 dumpSearchPath(Archive *AH)
3167 {
3168         PQExpBuffer qry = createPQExpBuffer();
3169         PQExpBuffer path = createPQExpBuffer();
3170         PGresult   *res;
3171         char      **schemanames = NULL;
3172         int                     nschemanames = 0;
3173         int                     i;
3174
3175         /*
3176          * We use the result of current_schemas(), not the search_path GUC,
3177          * because that might contain wildcards such as "$user", which won't
3178          * necessarily have the same value during restore.  Also, this way avoids
3179          * listing schemas that may appear in search_path but not actually exist,
3180          * which seems like a prudent exclusion.
3181          */
3182         res = ExecuteSqlQueryForSingleRow(AH,
3183                                                                           "SELECT pg_catalog.current_schemas(false)");
3184
3185         if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
3186                 exit_horribly(NULL, "could not parse result of current_schemas()\n");
3187
3188         /*
3189          * We use set_config(), not a simple "SET search_path" command, because
3190          * the latter has less-clean behavior if the search path is empty.  While
3191          * that's likely to get fixed at some point, it seems like a good idea to
3192          * be as backwards-compatible as possible in what we put into archives.
3193          */
3194         for (i = 0; i < nschemanames; i++)
3195         {
3196                 if (i > 0)
3197                         appendPQExpBufferStr(path, ", ");
3198                 appendPQExpBufferStr(path, fmtId(schemanames[i]));
3199         }
3200
3201         appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
3202         appendStringLiteralAH(qry, path->data, AH);
3203         appendPQExpBufferStr(qry, ", false);\n");
3204
3205         if (g_verbose)
3206                 write_msg(NULL, "saving search_path = %s\n", path->data);
3207
3208         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3209                                  ARCHIVE_OPTS(.tag = "SEARCHPATH",
3210                                                           .description = "SEARCHPATH",
3211                                                           .owner = "",
3212                                                           .section = SECTION_PRE_DATA,
3213                                                           .createStmt = qry->data,
3214                                                           .dropStmt = ""));
3215
3216         /* Also save it in AH->searchpath, in case we're doing plain text dump */
3217         AH->searchpath = pg_strdup(qry->data);
3218
3219         if (schemanames)
3220                 free(schemanames);
3221         PQclear(res);
3222         destroyPQExpBuffer(qry);
3223         destroyPQExpBuffer(path);
3224 }
3225
3226
3227 /*
3228  * getBlobs:
3229  *      Collect schema-level data about large objects
3230  */
3231 static void
3232 getBlobs(Archive *fout)
3233 {
3234         DumpOptions *dopt = fout->dopt;
3235         PQExpBuffer blobQry = createPQExpBuffer();
3236         BlobInfo   *binfo;
3237         DumpableObject *bdata;
3238         PGresult   *res;
3239         int                     ntups;
3240         int                     i;
3241         int                     i_oid;
3242         int                     i_lomowner;
3243         int                     i_lomacl;
3244         int                     i_rlomacl;
3245         int                     i_initlomacl;
3246         int                     i_initrlomacl;
3247
3248         /* Verbose message */
3249         if (g_verbose)
3250                 write_msg(NULL, "reading large objects\n");
3251
3252         /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
3253         if (fout->remoteVersion >= 90600)
3254         {
3255                 PQExpBuffer acl_subquery = createPQExpBuffer();
3256                 PQExpBuffer racl_subquery = createPQExpBuffer();
3257                 PQExpBuffer init_acl_subquery = createPQExpBuffer();
3258                 PQExpBuffer init_racl_subquery = createPQExpBuffer();
3259
3260                 buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
3261                                                 init_racl_subquery, "l.lomacl", "l.lomowner", "'L'",
3262                                                 dopt->binary_upgrade);
3263
3264                 appendPQExpBuffer(blobQry,
3265                                                   "SELECT l.oid, (%s l.lomowner) AS rolname, "
3266                                                   "%s AS lomacl, "
3267                                                   "%s AS rlomacl, "
3268                                                   "%s AS initlomacl, "
3269                                                   "%s AS initrlomacl "
3270                                                   "FROM pg_largeobject_metadata l "
3271                                                   "LEFT JOIN pg_init_privs pip ON "
3272                                                   "(l.oid = pip.objoid "
3273                                                   "AND pip.classoid = 'pg_largeobject'::regclass "
3274                                                   "AND pip.objsubid = 0) ",
3275                                                   username_subquery,
3276                                                   acl_subquery->data,
3277                                                   racl_subquery->data,
3278                                                   init_acl_subquery->data,
3279                                                   init_racl_subquery->data);
3280
3281                 destroyPQExpBuffer(acl_subquery);
3282                 destroyPQExpBuffer(racl_subquery);
3283                 destroyPQExpBuffer(init_acl_subquery);
3284                 destroyPQExpBuffer(init_racl_subquery);
3285         }
3286         else if (fout->remoteVersion >= 90000)
3287                 appendPQExpBuffer(blobQry,
3288                                                   "SELECT oid, (%s lomowner) AS rolname, lomacl, "
3289                                                   "NULL AS rlomacl, NULL AS initlomacl, "
3290                                                   "NULL AS initrlomacl "
3291                                                   " FROM pg_largeobject_metadata",
3292                                                   username_subquery);
3293         else
3294                 appendPQExpBufferStr(blobQry,
3295                                                          "SELECT DISTINCT loid AS oid, "
3296                                                          "NULL::name AS rolname, NULL::oid AS lomacl, "
3297                                                          "NULL::oid AS rlomacl, NULL::oid AS initlomacl, "
3298                                                          "NULL::oid AS initrlomacl "
3299                                                          " FROM pg_largeobject");
3300
3301         res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
3302
3303         i_oid = PQfnumber(res, "oid");
3304         i_lomowner = PQfnumber(res, "rolname");
3305         i_lomacl = PQfnumber(res, "lomacl");
3306         i_rlomacl = PQfnumber(res, "rlomacl");
3307         i_initlomacl = PQfnumber(res, "initlomacl");
3308         i_initrlomacl = PQfnumber(res, "initrlomacl");
3309
3310         ntups = PQntuples(res);
3311
3312         /*
3313          * Each large object has its own BLOB archive entry.
3314          */
3315         binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
3316
3317         for (i = 0; i < ntups; i++)
3318         {
3319                 binfo[i].dobj.objType = DO_BLOB;
3320                 binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
3321                 binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3322                 AssignDumpId(&binfo[i].dobj);
3323
3324                 binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oid));
3325                 binfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_lomowner));
3326                 binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, i_lomacl));
3327                 binfo[i].rblobacl = pg_strdup(PQgetvalue(res, i, i_rlomacl));
3328                 binfo[i].initblobacl = pg_strdup(PQgetvalue(res, i, i_initlomacl));
3329                 binfo[i].initrblobacl = pg_strdup(PQgetvalue(res, i, i_initrlomacl));
3330
3331                 if (PQgetisnull(res, i, i_lomacl) &&
3332                         PQgetisnull(res, i, i_rlomacl) &&
3333                         PQgetisnull(res, i, i_initlomacl) &&
3334                         PQgetisnull(res, i, i_initrlomacl))
3335                         binfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
3336
3337                 /*
3338                  * In binary-upgrade mode for blobs, we do *not* dump out the blob
3339                  * data, as it will be copied by pg_upgrade, which simply copies the
3340                  * pg_largeobject table. We *do* however dump out anything but the
3341                  * data, as pg_upgrade copies just pg_largeobject, but not
3342                  * pg_largeobject_metadata, after the dump is restored.
3343                  */
3344                 if (dopt->binary_upgrade)
3345                         binfo[i].dobj.dump &= ~DUMP_COMPONENT_DATA;
3346         }
3347
3348         /*
3349          * If we have any large objects, a "BLOBS" archive entry is needed. This
3350          * is just a placeholder for sorting; it carries no data now.
3351          */
3352         if (ntups > 0)
3353         {
3354                 bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
3355                 bdata->objType = DO_BLOB_DATA;
3356                 bdata->catId = nilCatalogId;
3357                 AssignDumpId(bdata);
3358                 bdata->name = pg_strdup("BLOBS");
3359         }
3360
3361         PQclear(res);
3362         destroyPQExpBuffer(blobQry);
3363 }
3364
3365 /*
3366  * dumpBlob
3367  *
3368  * dump the definition (metadata) of the given large object
3369  */
3370 static void
3371 dumpBlob(Archive *fout, BlobInfo *binfo)
3372 {
3373         PQExpBuffer cquery = createPQExpBuffer();
3374         PQExpBuffer dquery = createPQExpBuffer();
3375
3376         appendPQExpBuffer(cquery,
3377                                           "SELECT pg_catalog.lo_create('%s');\n",
3378                                           binfo->dobj.name);
3379
3380         appendPQExpBuffer(dquery,
3381                                           "SELECT pg_catalog.lo_unlink('%s');\n",
3382                                           binfo->dobj.name);
3383
3384         if (binfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
3385                 ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
3386                                          ARCHIVE_OPTS(.tag = binfo->dobj.name,
3387                                                                   .owner = binfo->rolname,
3388                                                                   .description = "BLOB",
3389                                                                   .section = SECTION_PRE_DATA,
3390                                                                   .createStmt = cquery->data,
3391                                                                   .dropStmt = dquery->data));
3392
3393         /* Dump comment if any */
3394         if (binfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3395                 dumpComment(fout, "LARGE OBJECT", binfo->dobj.name,
3396                                         NULL, binfo->rolname,
3397                                         binfo->dobj.catId, 0, binfo->dobj.dumpId);
3398
3399         /* Dump security label if any */
3400         if (binfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3401                 dumpSecLabel(fout, "LARGE OBJECT", binfo->dobj.name,
3402                                          NULL, binfo->rolname,
3403                                          binfo->dobj.catId, 0, binfo->dobj.dumpId);
3404
3405         /* Dump ACL if any */
3406         if (binfo->blobacl && (binfo->dobj.dump & DUMP_COMPONENT_ACL))
3407                 dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
3408                                 binfo->dobj.name, NULL,
3409                                 NULL, binfo->rolname, binfo->blobacl, binfo->rblobacl,
3410                                 binfo->initblobacl, binfo->initrblobacl);
3411
3412         destroyPQExpBuffer(cquery);
3413         destroyPQExpBuffer(dquery);
3414 }
3415
3416 /*
3417  * dumpBlobs:
3418  *      dump the data contents of all large objects
3419  */
3420 static int
3421 dumpBlobs(Archive *fout, void *arg)
3422 {
3423         const char *blobQry;
3424         const char *blobFetchQry;
3425         PGconn     *conn = GetConnection(fout);
3426         PGresult   *res;
3427         char            buf[LOBBUFSIZE];
3428         int                     ntups;
3429         int                     i;
3430         int                     cnt;
3431
3432         if (g_verbose)
3433                 write_msg(NULL, "saving large objects\n");
3434
3435         /*
3436          * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
3437          * the already-in-memory dumpable objects instead...
3438          */
3439         if (fout->remoteVersion >= 90000)
3440                 blobQry =
3441                         "DECLARE bloboid CURSOR FOR "
3442                         "SELECT oid FROM pg_largeobject_metadata ORDER BY 1";
3443         else
3444                 blobQry =
3445                         "DECLARE bloboid CURSOR FOR "
3446                         "SELECT DISTINCT loid FROM pg_largeobject ORDER BY 1";
3447
3448         ExecuteSqlStatement(fout, blobQry);
3449
3450         /* Command to fetch from cursor */
3451         blobFetchQry = "FETCH 1000 IN bloboid";
3452
3453         do
3454         {
3455                 /* Do a fetch */
3456                 res = ExecuteSqlQuery(fout, blobFetchQry, PGRES_TUPLES_OK);
3457
3458                 /* Process the tuples, if any */
3459                 ntups = PQntuples(res);
3460                 for (i = 0; i < ntups; i++)
3461                 {
3462                         Oid                     blobOid;
3463                         int                     loFd;
3464
3465                         blobOid = atooid(PQgetvalue(res, i, 0));
3466                         /* Open the BLOB */
3467                         loFd = lo_open(conn, blobOid, INV_READ);
3468                         if (loFd == -1)
3469                                 exit_horribly(NULL, "could not open large object %u: %s",
3470                                                           blobOid, PQerrorMessage(conn));
3471
3472                         StartBlob(fout, blobOid);
3473
3474                         /* Now read it in chunks, sending data to archive */
3475                         do
3476                         {
3477                                 cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
3478                                 if (cnt < 0)
3479                                         exit_horribly(NULL, "error reading large object %u: %s",
3480                                                                   blobOid, PQerrorMessage(conn));
3481
3482                                 WriteData(fout, buf, cnt);
3483                         } while (cnt > 0);
3484
3485                         lo_close(conn, loFd);
3486
3487                         EndBlob(fout, blobOid);
3488                 }
3489
3490                 PQclear(res);
3491         } while (ntups > 0);
3492
3493         return 1;
3494 }
3495
3496 /*
3497  * getPolicies
3498  *        get information about policies on a dumpable table.
3499  */
3500 void
3501 getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
3502 {
3503         PQExpBuffer query;
3504         PGresult   *res;
3505         PolicyInfo *polinfo;
3506         int                     i_oid;
3507         int                     i_tableoid;
3508         int                     i_polname;
3509         int                     i_polcmd;
3510         int                     i_polpermissive;
3511         int                     i_polroles;
3512         int                     i_polqual;
3513         int                     i_polwithcheck;
3514         int                     i,
3515                                 j,
3516                                 ntups;
3517
3518         if (fout->remoteVersion < 90500)
3519                 return;
3520
3521         query = createPQExpBuffer();
3522
3523         for (i = 0; i < numTables; i++)
3524         {
3525                 TableInfo  *tbinfo = &tblinfo[i];
3526
3527                 /* Ignore row security on tables not to be dumped */
3528                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
3529                         continue;
3530
3531                 if (g_verbose)
3532                         write_msg(NULL, "reading row security enabled for table \"%s.%s\"\n",
3533                                           tbinfo->dobj.namespace->dobj.name,
3534                                           tbinfo->dobj.name);
3535
3536                 /*
3537                  * Get row security enabled information for the table. We represent
3538                  * RLS being enabled on a table by creating a PolicyInfo object with
3539                  * null polname.
3540                  */
3541                 if (tbinfo->rowsec)
3542                 {
3543                         /*
3544                          * Note: use tableoid 0 so that this object won't be mistaken for
3545                          * something that pg_depend entries apply to.
3546                          */
3547                         polinfo = pg_malloc(sizeof(PolicyInfo));
3548                         polinfo->dobj.objType = DO_POLICY;
3549                         polinfo->dobj.catId.tableoid = 0;
3550                         polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
3551                         AssignDumpId(&polinfo->dobj);
3552                         polinfo->dobj.namespace = tbinfo->dobj.namespace;
3553                         polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
3554                         polinfo->poltable = tbinfo;
3555                         polinfo->polname = NULL;
3556                         polinfo->polcmd = '\0';
3557                         polinfo->polpermissive = 0;
3558                         polinfo->polroles = NULL;
3559                         polinfo->polqual = NULL;
3560                         polinfo->polwithcheck = NULL;
3561                 }
3562
3563                 if (g_verbose)
3564                         write_msg(NULL, "reading policies for table \"%s.%s\"\n",
3565                                           tbinfo->dobj.namespace->dobj.name,
3566                                           tbinfo->dobj.name);
3567
3568                 resetPQExpBuffer(query);
3569
3570                 /* Get the policies for the table. */
3571                 if (fout->remoteVersion >= 100000)
3572                         appendPQExpBuffer(query,
3573                                                           "SELECT oid, tableoid, pol.polname, pol.polcmd, pol.polpermissive, "
3574                                                           "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3575                                                           "   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, "
3576                                                           "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3577                                                           "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3578                                                           "FROM pg_catalog.pg_policy pol "
3579                                                           "WHERE polrelid = '%u'",
3580                                                           tbinfo->dobj.catId.oid);
3581                 else
3582                         appendPQExpBuffer(query,
3583                                                           "SELECT oid, tableoid, pol.polname, pol.polcmd, 't' as polpermissive, "
3584                                                           "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3585                                                           "   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, "
3586                                                           "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3587                                                           "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3588                                                           "FROM pg_catalog.pg_policy pol "
3589                                                           "WHERE polrelid = '%u'",
3590                                                           tbinfo->dobj.catId.oid);
3591                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3592
3593                 ntups = PQntuples(res);
3594
3595                 if (ntups == 0)
3596                 {
3597                         /*
3598                          * No explicit policies to handle (only the default-deny policy,
3599                          * which is handled as part of the table definition).  Clean up
3600                          * and return.
3601                          */
3602                         PQclear(res);
3603                         continue;
3604                 }
3605
3606                 i_oid = PQfnumber(res, "oid");
3607                 i_tableoid = PQfnumber(res, "tableoid");
3608                 i_polname = PQfnumber(res, "polname");
3609                 i_polcmd = PQfnumber(res, "polcmd");
3610                 i_polpermissive = PQfnumber(res, "polpermissive");
3611                 i_polroles = PQfnumber(res, "polroles");
3612                 i_polqual = PQfnumber(res, "polqual");
3613                 i_polwithcheck = PQfnumber(res, "polwithcheck");
3614
3615                 polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
3616
3617                 for (j = 0; j < ntups; j++)
3618                 {
3619                         polinfo[j].dobj.objType = DO_POLICY;
3620                         polinfo[j].dobj.catId.tableoid =
3621                                 atooid(PQgetvalue(res, j, i_tableoid));
3622                         polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3623                         AssignDumpId(&polinfo[j].dobj);
3624                         polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3625                         polinfo[j].poltable = tbinfo;
3626                         polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
3627                         polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
3628
3629                         polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
3630                         polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
3631
3632                         if (PQgetisnull(res, j, i_polroles))
3633                                 polinfo[j].polroles = NULL;
3634                         else
3635                                 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
3636
3637                         if (PQgetisnull(res, j, i_polqual))
3638                                 polinfo[j].polqual = NULL;
3639                         else
3640                                 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
3641
3642                         if (PQgetisnull(res, j, i_polwithcheck))
3643                                 polinfo[j].polwithcheck = NULL;
3644                         else
3645                                 polinfo[j].polwithcheck
3646                                         = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
3647                 }
3648                 PQclear(res);
3649         }
3650         destroyPQExpBuffer(query);
3651 }
3652
3653 /*
3654  * dumpPolicy
3655  *        dump the definition of the given policy
3656  */
3657 static void
3658 dumpPolicy(Archive *fout, PolicyInfo *polinfo)
3659 {
3660         DumpOptions *dopt = fout->dopt;
3661         TableInfo  *tbinfo = polinfo->poltable;
3662         PQExpBuffer query;
3663         PQExpBuffer delqry;
3664         const char *cmd;
3665         char       *tag;
3666
3667         if (dopt->dataOnly)
3668                 return;
3669
3670         /*
3671          * If polname is NULL, then this record is just indicating that ROW LEVEL
3672          * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
3673          * ROW LEVEL SECURITY.
3674          */
3675         if (polinfo->polname == NULL)
3676         {
3677                 query = createPQExpBuffer();
3678
3679                 appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
3680                                                   fmtQualifiedDumpable(tbinfo));
3681
3682                 /*
3683                  * We must emit the ROW SECURITY object's dependency on its table
3684                  * explicitly, because it will not match anything in pg_depend (unlike
3685                  * the case for other PolicyInfo objects).
3686                  */
3687                 if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3688                         ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3689                                                  ARCHIVE_OPTS(.tag = polinfo->dobj.name,
3690                                                                           .namespace = polinfo->dobj.namespace->dobj.name,
3691                                                                           .owner = tbinfo->rolname,
3692                                                                           .description = "ROW SECURITY",
3693                                                                           .section = SECTION_POST_DATA,
3694                                                                           .createStmt = query->data,
3695                                                                           .dropStmt = "",
3696                                                                           .deps = &(tbinfo->dobj.dumpId),
3697                                                                           .nDeps = 1));
3698
3699                 destroyPQExpBuffer(query);
3700                 return;
3701         }
3702
3703         if (polinfo->polcmd == '*')
3704                 cmd = "";
3705         else if (polinfo->polcmd == 'r')
3706                 cmd = " FOR SELECT";
3707         else if (polinfo->polcmd == 'a')
3708                 cmd = " FOR INSERT";
3709         else if (polinfo->polcmd == 'w')
3710                 cmd = " FOR UPDATE";
3711         else if (polinfo->polcmd == 'd')
3712                 cmd = " FOR DELETE";
3713         else
3714         {
3715                 write_msg(NULL, "unexpected policy command type: %c\n",
3716                                   polinfo->polcmd);
3717                 exit_nicely(1);
3718         }
3719
3720         query = createPQExpBuffer();
3721         delqry = createPQExpBuffer();
3722
3723         appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
3724
3725         appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
3726                                           !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
3727
3728         if (polinfo->polroles != NULL)
3729                 appendPQExpBuffer(query, " TO %s", polinfo->polroles);
3730
3731         if (polinfo->polqual != NULL)
3732                 appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
3733
3734         if (polinfo->polwithcheck != NULL)
3735                 appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
3736
3737         appendPQExpBuffer(query, ";\n");
3738
3739         appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
3740         appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
3741
3742         tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
3743
3744         if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3745                 ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3746                                          ARCHIVE_OPTS(.tag = tag,
3747                                                                   .namespace = polinfo->dobj.namespace->dobj.name,
3748                                                                   .owner = tbinfo->rolname,
3749                                                                   .description = "POLICY",
3750                                                                   .section = SECTION_POST_DATA,
3751                                                                   .createStmt = query->data,
3752                                                                   .dropStmt = delqry->data));
3753
3754         free(tag);
3755         destroyPQExpBuffer(query);
3756         destroyPQExpBuffer(delqry);
3757 }
3758
3759 /*
3760  * getPublications
3761  *        get information about publications
3762  */
3763 void
3764 getPublications(Archive *fout)
3765 {
3766         DumpOptions *dopt = fout->dopt;
3767         PQExpBuffer query;
3768         PGresult   *res;
3769         PublicationInfo *pubinfo;
3770         int                     i_tableoid;
3771         int                     i_oid;
3772         int                     i_pubname;
3773         int                     i_rolname;
3774         int                     i_puballtables;
3775         int                     i_pubinsert;
3776         int                     i_pubupdate;
3777         int                     i_pubdelete;
3778         int                     i_pubtruncate;
3779         int                     i,
3780                                 ntups;
3781
3782         if (dopt->no_publications || fout->remoteVersion < 100000)
3783                 return;
3784
3785         query = createPQExpBuffer();
3786
3787         resetPQExpBuffer(query);
3788
3789         /* Get the publications. */
3790         if (fout->remoteVersion >= 110000)
3791                 appendPQExpBuffer(query,
3792                                                   "SELECT p.tableoid, p.oid, p.pubname, "
3793                                                   "(%s p.pubowner) AS rolname, "
3794                                                   "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, p.pubtruncate "
3795                                                   "FROM pg_publication p",
3796                                                   username_subquery);
3797         else
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, false AS pubtruncate "
3802                                                   "FROM pg_publication p",
3803                                                   username_subquery);
3804
3805         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3806
3807         ntups = PQntuples(res);
3808
3809         i_tableoid = PQfnumber(res, "tableoid");
3810         i_oid = PQfnumber(res, "oid");
3811         i_pubname = PQfnumber(res, "pubname");
3812         i_rolname = PQfnumber(res, "rolname");
3813         i_puballtables = PQfnumber(res, "puballtables");
3814         i_pubinsert = PQfnumber(res, "pubinsert");
3815         i_pubupdate = PQfnumber(res, "pubupdate");
3816         i_pubdelete = PQfnumber(res, "pubdelete");
3817         i_pubtruncate = PQfnumber(res, "pubtruncate");
3818
3819         pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
3820
3821         for (i = 0; i < ntups; i++)
3822         {
3823                 pubinfo[i].dobj.objType = DO_PUBLICATION;
3824                 pubinfo[i].dobj.catId.tableoid =
3825                         atooid(PQgetvalue(res, i, i_tableoid));
3826                 pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3827                 AssignDumpId(&pubinfo[i].dobj);
3828                 pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
3829                 pubinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3830                 pubinfo[i].puballtables =
3831                         (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
3832                 pubinfo[i].pubinsert =
3833                         (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
3834                 pubinfo[i].pubupdate =
3835                         (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
3836                 pubinfo[i].pubdelete =
3837                         (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
3838                 pubinfo[i].pubtruncate =
3839                         (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
3840
3841                 if (strlen(pubinfo[i].rolname) == 0)
3842                         write_msg(NULL, "WARNING: owner of publication \"%s\" appears to be invalid\n",
3843                                           pubinfo[i].dobj.name);
3844
3845                 /* Decide whether we want to dump it */
3846                 selectDumpableObject(&(pubinfo[i].dobj), fout);
3847         }
3848         PQclear(res);
3849
3850         destroyPQExpBuffer(query);
3851 }
3852
3853 /*
3854  * dumpPublication
3855  *        dump the definition of the given publication
3856  */
3857 static void
3858 dumpPublication(Archive *fout, PublicationInfo *pubinfo)
3859 {
3860         PQExpBuffer delq;
3861         PQExpBuffer query;
3862         char       *qpubname;
3863         bool            first = true;
3864
3865         if (!(pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3866                 return;
3867
3868         delq = createPQExpBuffer();
3869         query = createPQExpBuffer();
3870
3871         qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
3872
3873         appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
3874                                           qpubname);
3875
3876         appendPQExpBuffer(query, "CREATE PUBLICATION %s",
3877                                           qpubname);
3878
3879         if (pubinfo->puballtables)
3880                 appendPQExpBufferStr(query, " FOR ALL TABLES");
3881
3882         appendPQExpBufferStr(query, " WITH (publish = '");
3883         if (pubinfo->pubinsert)
3884         {
3885                 appendPQExpBufferStr(query, "insert");
3886                 first = false;
3887         }
3888
3889         if (pubinfo->pubupdate)
3890         {
3891                 if (!first)
3892                         appendPQExpBufferStr(query, ", ");
3893
3894                 appendPQExpBufferStr(query, "update");
3895                 first = false;
3896         }
3897
3898         if (pubinfo->pubdelete)
3899         {
3900                 if (!first)
3901                         appendPQExpBufferStr(query, ", ");
3902
3903                 appendPQExpBufferStr(query, "delete");
3904                 first = false;
3905         }
3906
3907         if (pubinfo->pubtruncate)
3908         {
3909                 if (!first)
3910                         appendPQExpBufferStr(query, ", ");
3911
3912                 appendPQExpBufferStr(query, "truncate");
3913                 first = false;
3914         }
3915
3916         appendPQExpBufferStr(query, "');\n");
3917
3918         ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
3919                                  ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
3920                                                           .owner = pubinfo->rolname,
3921                                                           .description = "PUBLICATION",
3922                                                           .section = SECTION_POST_DATA,
3923                                                           .createStmt = query->data,
3924                                                           .dropStmt = delq->data));
3925
3926         if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3927                 dumpComment(fout, "PUBLICATION", qpubname,
3928                                         NULL, pubinfo->rolname,
3929                                         pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
3930
3931         if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3932                 dumpSecLabel(fout, "PUBLICATION", qpubname,
3933                                          NULL, pubinfo->rolname,
3934                                          pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
3935
3936         destroyPQExpBuffer(delq);
3937         destroyPQExpBuffer(query);
3938         free(qpubname);
3939 }
3940
3941 /*
3942  * getPublicationTables
3943  *        get information about publication membership for dumpable tables.
3944  */
3945 void
3946 getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
3947 {
3948         PQExpBuffer query;
3949         PGresult   *res;
3950         PublicationRelInfo *pubrinfo;
3951         DumpOptions *dopt = fout->dopt;
3952         int                     i_tableoid;
3953         int                     i_oid;
3954         int                     i_pubname;
3955         int                     i,
3956                                 j,
3957                                 ntups;
3958
3959         if (dopt->no_publications || fout->remoteVersion < 100000)
3960                 return;
3961
3962         query = createPQExpBuffer();
3963
3964         for (i = 0; i < numTables; i++)
3965         {
3966                 TableInfo  *tbinfo = &tblinfo[i];
3967
3968                 /* Only plain tables can be aded to publications. */
3969                 if (tbinfo->relkind != RELKIND_RELATION)
3970                         continue;
3971
3972                 /*
3973                  * Ignore publication membership of tables whose definitions are not
3974                  * to be dumped.
3975                  */
3976                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3977                         continue;
3978
3979                 if (g_verbose)
3980                         write_msg(NULL, "reading publication membership for table \"%s.%s\"\n",
3981                                           tbinfo->dobj.namespace->dobj.name,
3982                                           tbinfo->dobj.name);
3983
3984                 resetPQExpBuffer(query);
3985
3986                 /* Get the publication membership for the table. */
3987                 appendPQExpBuffer(query,
3988                                                   "SELECT pr.tableoid, pr.oid, p.pubname "
3989                                                   "FROM pg_publication_rel pr, pg_publication p "
3990                                                   "WHERE pr.prrelid = '%u'"
3991                                                   "  AND p.oid = pr.prpubid",
3992                                                   tbinfo->dobj.catId.oid);
3993                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3994
3995                 ntups = PQntuples(res);
3996
3997                 if (ntups == 0)
3998                 {
3999                         /*
4000                          * Table is not member of any publications. Clean up and return.
4001                          */
4002                         PQclear(res);
4003                         continue;
4004                 }
4005
4006                 i_tableoid = PQfnumber(res, "tableoid");
4007                 i_oid = PQfnumber(res, "oid");
4008                 i_pubname = PQfnumber(res, "pubname");
4009
4010                 pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
4011
4012                 for (j = 0; j < ntups; j++)
4013                 {
4014                         pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
4015                         pubrinfo[j].dobj.catId.tableoid =
4016                                 atooid(PQgetvalue(res, j, i_tableoid));
4017                         pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
4018                         AssignDumpId(&pubrinfo[j].dobj);
4019                         pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4020                         pubrinfo[j].dobj.name = tbinfo->dobj.name;
4021                         pubrinfo[j].pubname = pg_strdup(PQgetvalue(res, j, i_pubname));
4022                         pubrinfo[j].pubtable = tbinfo;
4023
4024                         /* Decide whether we want to dump it */
4025                         selectDumpablePublicationTable(&(pubrinfo[j].dobj), fout);
4026                 }
4027                 PQclear(res);
4028         }
4029         destroyPQExpBuffer(query);
4030 }
4031
4032 /*
4033  * dumpPublicationTable
4034  *        dump the definition of the given publication table mapping
4035  */
4036 static void
4037 dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo)
4038 {
4039         TableInfo  *tbinfo = pubrinfo->pubtable;
4040         PQExpBuffer query;
4041         char       *tag;
4042
4043         if (!(pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
4044                 return;
4045
4046         tag = psprintf("%s %s", pubrinfo->pubname, tbinfo->dobj.name);
4047
4048         query = createPQExpBuffer();
4049
4050         appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
4051                                           fmtId(pubrinfo->pubname));
4052         appendPQExpBuffer(query, " %s;\n",
4053                                           fmtQualifiedDumpable(tbinfo));
4054
4055         /*
4056          * There is no point in creating drop query as drop query as the drop is
4057          * done by table drop.
4058          */
4059         ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
4060                                  ARCHIVE_OPTS(.tag = tag,
4061                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
4062                                                           .description = "PUBLICATION TABLE",
4063                                                           .owner = "",
4064                                                           .section = SECTION_POST_DATA,
4065                                                           .createStmt = query->data,
4066                                                           .dropStmt = ""));
4067
4068         free(tag);
4069         destroyPQExpBuffer(query);
4070 }
4071
4072 /*
4073  * Is the currently connected user a superuser?
4074  */
4075 static bool
4076 is_superuser(Archive *fout)
4077 {
4078         ArchiveHandle *AH = (ArchiveHandle *) fout;
4079         const char *val;
4080
4081         val = PQparameterStatus(AH->connection, "is_superuser");
4082
4083         if (val && strcmp(val, "on") == 0)
4084                 return true;
4085
4086         return false;
4087 }
4088
4089 /*
4090  * getSubscriptions
4091  *        get information about subscriptions
4092  */
4093 void
4094 getSubscriptions(Archive *fout)
4095 {
4096         DumpOptions *dopt = fout->dopt;
4097         PQExpBuffer query;
4098         PGresult   *res;
4099         SubscriptionInfo *subinfo;
4100         int                     i_tableoid;
4101         int                     i_oid;
4102         int                     i_subname;
4103         int                     i_rolname;
4104         int                     i_subconninfo;
4105         int                     i_subslotname;
4106         int                     i_subsynccommit;
4107         int                     i_subpublications;
4108         int                     i,
4109                                 ntups;
4110
4111         if (dopt->no_subscriptions || fout->remoteVersion < 100000)
4112                 return;
4113
4114         if (!is_superuser(fout))
4115         {
4116                 int                     n;
4117
4118                 res = ExecuteSqlQuery(fout,
4119                                                           "SELECT count(*) FROM pg_subscription "
4120                                                           "WHERE subdbid = (SELECT oid FROM pg_database"
4121                                                           "                 WHERE datname = current_database())",
4122                                                           PGRES_TUPLES_OK);
4123                 n = atoi(PQgetvalue(res, 0, 0));
4124                 if (n > 0)
4125                         write_msg(NULL, "WARNING: subscriptions not dumped because current user is not a superuser\n");
4126                 PQclear(res);
4127                 return;
4128         }
4129
4130         query = createPQExpBuffer();
4131
4132         resetPQExpBuffer(query);
4133
4134         /* Get the subscriptions in current database. */
4135         appendPQExpBuffer(query,
4136                                           "SELECT s.tableoid, s.oid, s.subname,"
4137                                           "(%s s.subowner) AS rolname, "
4138                                           " s.subconninfo, s.subslotname, s.subsynccommit, "
4139                                           " s.subpublications "
4140                                           "FROM pg_subscription s "
4141                                           "WHERE s.subdbid = (SELECT oid FROM pg_database"
4142                                           "                   WHERE datname = current_database())",
4143                                           username_subquery);
4144         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4145
4146         ntups = PQntuples(res);
4147
4148         i_tableoid = PQfnumber(res, "tableoid");
4149         i_oid = PQfnumber(res, "oid");
4150         i_subname = PQfnumber(res, "subname");
4151         i_rolname = PQfnumber(res, "rolname");
4152         i_subconninfo = PQfnumber(res, "subconninfo");
4153         i_subslotname = PQfnumber(res, "subslotname");
4154         i_subsynccommit = PQfnumber(res, "subsynccommit");
4155         i_subpublications = PQfnumber(res, "subpublications");
4156
4157         subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
4158
4159         for (i = 0; i < ntups; i++)
4160         {
4161                 subinfo[i].dobj.objType = DO_SUBSCRIPTION;
4162                 subinfo[i].dobj.catId.tableoid =
4163                         atooid(PQgetvalue(res, i, i_tableoid));
4164                 subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4165                 AssignDumpId(&subinfo[i].dobj);
4166                 subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
4167                 subinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4168                 subinfo[i].subconninfo = pg_strdup(PQgetvalue(res, i, i_subconninfo));
4169                 if (PQgetisnull(res, i, i_subslotname))
4170                         subinfo[i].subslotname = NULL;
4171                 else
4172                         subinfo[i].subslotname = pg_strdup(PQgetvalue(res, i, i_subslotname));
4173                 subinfo[i].subsynccommit =
4174                         pg_strdup(PQgetvalue(res, i, i_subsynccommit));
4175                 subinfo[i].subpublications =
4176                         pg_strdup(PQgetvalue(res, i, i_subpublications));
4177
4178                 if (strlen(subinfo[i].rolname) == 0)
4179                         write_msg(NULL, "WARNING: owner of subscription \"%s\" appears to be invalid\n",
4180                                           subinfo[i].dobj.name);
4181
4182                 /* Decide whether we want to dump it */
4183                 selectDumpableObject(&(subinfo[i].dobj), fout);
4184         }
4185         PQclear(res);
4186
4187         destroyPQExpBuffer(query);
4188 }
4189
4190 /*
4191  * dumpSubscription
4192  *        dump the definition of the given subscription
4193  */
4194 static void
4195 dumpSubscription(Archive *fout, SubscriptionInfo *subinfo)
4196 {
4197         PQExpBuffer delq;
4198         PQExpBuffer query;
4199         PQExpBuffer publications;
4200         char       *qsubname;
4201         char      **pubnames = NULL;
4202         int                     npubnames = 0;
4203         int                     i;
4204
4205         if (!(subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
4206                 return;
4207
4208         delq = createPQExpBuffer();
4209         query = createPQExpBuffer();
4210
4211         qsubname = pg_strdup(fmtId(subinfo->dobj.name));
4212
4213         appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
4214                                           qsubname);
4215
4216         appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
4217                                           qsubname);
4218         appendStringLiteralAH(query, subinfo->subconninfo, fout);
4219
4220         /* Build list of quoted publications and append them to query. */
4221         if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
4222         {
4223                 write_msg(NULL,
4224                                   "WARNING: could not parse subpublications array\n");
4225                 if (pubnames)
4226                         free(pubnames);
4227                 pubnames = NULL;
4228                 npubnames = 0;
4229         }
4230
4231         publications = createPQExpBuffer();
4232         for (i = 0; i < npubnames; i++)
4233         {
4234                 if (i > 0)
4235                         appendPQExpBufferStr(publications, ", ");
4236
4237                 appendPQExpBufferStr(publications, fmtId(pubnames[i]));
4238         }
4239
4240         appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
4241         if (subinfo->subslotname)
4242                 appendStringLiteralAH(query, subinfo->subslotname, fout);
4243         else
4244                 appendPQExpBufferStr(query, "NONE");
4245
4246         if (strcmp(subinfo->subsynccommit, "off") != 0)
4247                 appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
4248
4249         appendPQExpBufferStr(query, ");\n");
4250
4251         ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
4252                                  ARCHIVE_OPTS(.tag = subinfo->dobj.name,
4253                                                           .owner = subinfo->rolname,
4254                                                           .description = "SUBSCRIPTION",
4255                                                           .section = SECTION_POST_DATA,
4256                                                           .createStmt = query->data,
4257                                                           .dropStmt = delq->data));
4258
4259         if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4260                 dumpComment(fout, "SUBSCRIPTION", qsubname,
4261                                         NULL, subinfo->rolname,
4262                                         subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
4263
4264         if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
4265                 dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
4266                                          NULL, subinfo->rolname,
4267                                          subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
4268
4269         destroyPQExpBuffer(publications);
4270         if (pubnames)
4271                 free(pubnames);
4272
4273         destroyPQExpBuffer(delq);
4274         destroyPQExpBuffer(query);
4275         free(qsubname);
4276 }
4277
4278 static void
4279 binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
4280                                                                                  PQExpBuffer upgrade_buffer,
4281                                                                                  Oid pg_type_oid,
4282                                                                                  bool force_array_type)
4283 {
4284         PQExpBuffer upgrade_query = createPQExpBuffer();
4285         PGresult   *res;
4286         Oid                     pg_type_array_oid;
4287
4288         appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
4289         appendPQExpBuffer(upgrade_buffer,
4290                                           "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4291                                           pg_type_oid);
4292
4293         /* we only support old >= 8.3 for binary upgrades */
4294         appendPQExpBuffer(upgrade_query,
4295                                           "SELECT typarray "
4296                                           "FROM pg_catalog.pg_type "
4297                                           "WHERE oid = '%u'::pg_catalog.oid;",
4298                                           pg_type_oid);
4299
4300         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4301
4302         pg_type_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
4303
4304         PQclear(res);
4305
4306         if (!OidIsValid(pg_type_array_oid) && force_array_type)
4307         {
4308                 /*
4309                  * If the old version didn't assign an array type, but the new version
4310                  * does, we must select an unused type OID to assign.  This currently
4311                  * only happens for domains, when upgrading pre-v11 to v11 and up.
4312                  *
4313                  * Note: local state here is kind of ugly, but we must have some,
4314                  * since we mustn't choose the same unused OID more than once.
4315                  */
4316                 static Oid      next_possible_free_oid = FirstNormalObjectId;
4317                 bool            is_dup;
4318
4319                 do
4320                 {
4321                         ++next_possible_free_oid;
4322                         printfPQExpBuffer(upgrade_query,
4323                                                           "SELECT EXISTS(SELECT 1 "
4324                                                           "FROM pg_catalog.pg_type "
4325                                                           "WHERE oid = '%u'::pg_catalog.oid);",
4326                                                           next_possible_free_oid);
4327                         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4328                         is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
4329                         PQclear(res);
4330                 } while (is_dup);
4331
4332                 pg_type_array_oid = next_possible_free_oid;
4333         }
4334
4335         if (OidIsValid(pg_type_array_oid))
4336         {
4337                 appendPQExpBufferStr(upgrade_buffer,
4338                                                          "\n-- For binary upgrade, must preserve pg_type array oid\n");
4339                 appendPQExpBuffer(upgrade_buffer,
4340                                                   "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4341                                                   pg_type_array_oid);
4342         }
4343
4344         destroyPQExpBuffer(upgrade_query);
4345 }
4346
4347 static bool
4348 binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
4349                                                                                 PQExpBuffer upgrade_buffer,
4350                                                                                 Oid pg_rel_oid)
4351 {
4352         PQExpBuffer upgrade_query = createPQExpBuffer();
4353         PGresult   *upgrade_res;
4354         Oid                     pg_type_oid;
4355         bool            toast_set = false;
4356
4357         /*
4358          * We only support old >= 8.3 for binary upgrades.
4359          *
4360          * We purposefully ignore toast OIDs for partitioned tables; the reason is
4361          * that versions 10 and 11 have them, but 12 does not, so emitting them
4362          * causes the upgrade to fail.
4363          */
4364         appendPQExpBuffer(upgrade_query,
4365                                           "SELECT c.reltype AS crel, t.reltype AS trel "
4366                                           "FROM pg_catalog.pg_class c "
4367                                           "LEFT JOIN pg_catalog.pg_class t ON "
4368                                           "  (c.reltoastrelid = t.oid AND c.relkind <> '%c') "
4369                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
4370                                           RELKIND_PARTITIONED_TABLE, pg_rel_oid);
4371
4372         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4373
4374         pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
4375
4376         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
4377                                                                                          pg_type_oid, false);
4378
4379         if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
4380         {
4381                 /* Toast tables do not have pg_type array rows */
4382                 Oid                     pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
4383                                                                                                                   PQfnumber(upgrade_res, "trel")));
4384
4385                 appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
4386                 appendPQExpBuffer(upgrade_buffer,
4387                                                   "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4388                                                   pg_type_toast_oid);
4389
4390                 toast_set = true;
4391         }
4392
4393         PQclear(upgrade_res);
4394         destroyPQExpBuffer(upgrade_query);
4395
4396         return toast_set;
4397 }
4398
4399 static void
4400 binary_upgrade_set_pg_class_oids(Archive *fout,
4401                                                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid,
4402                                                                  bool is_index)
4403 {
4404         PQExpBuffer upgrade_query = createPQExpBuffer();
4405         PGresult   *upgrade_res;
4406         Oid                     pg_class_reltoastrelid;
4407         Oid                     pg_index_indexrelid;
4408
4409         appendPQExpBuffer(upgrade_query,
4410                                           "SELECT c.reltoastrelid, i.indexrelid "
4411                                           "FROM pg_catalog.pg_class c LEFT JOIN "
4412                                           "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
4413                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
4414                                           pg_class_oid);
4415
4416         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4417
4418         pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
4419         pg_index_indexrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "indexrelid")));
4420
4421         appendPQExpBufferStr(upgrade_buffer,
4422                                                  "\n-- For binary upgrade, must preserve pg_class oids\n");
4423
4424         if (!is_index)
4425         {
4426                 appendPQExpBuffer(upgrade_buffer,
4427                                                   "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
4428                                                   pg_class_oid);
4429                 /* only tables have toast tables, not indexes */
4430                 if (OidIsValid(pg_class_reltoastrelid))
4431                 {
4432                         /*
4433                          * One complexity is that the table definition might not require
4434                          * the creation of a TOAST table, and the TOAST table might have
4435                          * been created long after table creation, when the table was
4436                          * loaded with wide data.  By setting the TOAST oid we force
4437                          * creation of the TOAST heap and TOAST index by the backend so we
4438                          * can cleanly copy the files during binary upgrade.
4439                          */
4440
4441                         appendPQExpBuffer(upgrade_buffer,
4442                                                           "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
4443                                                           pg_class_reltoastrelid);
4444
4445                         /* every toast table has an index */
4446                         appendPQExpBuffer(upgrade_buffer,
4447                                                           "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
4448                                                           pg_index_indexrelid);
4449                 }
4450         }
4451         else
4452                 appendPQExpBuffer(upgrade_buffer,
4453                                                   "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
4454                                                   pg_class_oid);
4455
4456         appendPQExpBufferChar(upgrade_buffer, '\n');
4457
4458         PQclear(upgrade_res);
4459         destroyPQExpBuffer(upgrade_query);
4460 }
4461
4462 /*
4463  * If the DumpableObject is a member of an extension, add a suitable
4464  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
4465  *
4466  * For somewhat historical reasons, objname should already be quoted,
4467  * but not objnamespace (if any).
4468  */
4469 static void
4470 binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
4471                                                                 DumpableObject *dobj,
4472                                                                 const char *objtype,
4473                                                                 const char *objname,
4474                                                                 const char *objnamespace)
4475 {
4476         DumpableObject *extobj = NULL;
4477         int                     i;
4478
4479         if (!dobj->ext_member)
4480                 return;
4481
4482         /*
4483          * Find the parent extension.  We could avoid this search if we wanted to
4484          * add a link field to DumpableObject, but the space costs of that would
4485          * be considerable.  We assume that member objects could only have a
4486          * direct dependency on their own extension, not any others.
4487          */
4488         for (i = 0; i < dobj->nDeps; i++)
4489         {
4490                 extobj = findObjectByDumpId(dobj->dependencies[i]);
4491                 if (extobj && extobj->objType == DO_EXTENSION)
4492                         break;
4493                 extobj = NULL;
4494         }
4495         if (extobj == NULL)
4496                 exit_horribly(NULL, "could not find parent extension for %s %s\n",
4497                                           objtype, objname);
4498
4499         appendPQExpBufferStr(upgrade_buffer,
4500                                                  "\n-- For binary upgrade, handle extension membership the hard way\n");
4501         appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
4502                                           fmtId(extobj->name),
4503                                           objtype);
4504         if (objnamespace && *objnamespace)
4505                 appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
4506         appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
4507 }
4508
4509 /*
4510  * getNamespaces:
4511  *        read all namespaces in the system catalogs and return them in the
4512  * NamespaceInfo* structure
4513  *
4514  *      numNamespaces is set to the number of namespaces read in
4515  */
4516 NamespaceInfo *
4517 getNamespaces(Archive *fout, int *numNamespaces)
4518 {
4519         DumpOptions *dopt = fout->dopt;
4520         PGresult   *res;
4521         int                     ntups;
4522         int                     i;
4523         PQExpBuffer query;
4524         NamespaceInfo *nsinfo;
4525         int                     i_tableoid;
4526         int                     i_oid;
4527         int                     i_nspname;
4528         int                     i_rolname;
4529         int                     i_nspacl;
4530         int                     i_rnspacl;
4531         int                     i_initnspacl;
4532         int                     i_initrnspacl;
4533
4534         query = createPQExpBuffer();
4535
4536         /*
4537          * we fetch all namespaces including system ones, so that every object we
4538          * read in can be linked to a containing namespace.
4539          */
4540         if (fout->remoteVersion >= 90600)
4541         {
4542                 PQExpBuffer acl_subquery = createPQExpBuffer();
4543                 PQExpBuffer racl_subquery = createPQExpBuffer();
4544                 PQExpBuffer init_acl_subquery = createPQExpBuffer();
4545                 PQExpBuffer init_racl_subquery = createPQExpBuffer();
4546
4547                 buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
4548                                                 init_racl_subquery, "n.nspacl", "n.nspowner", "'n'",
4549                                                 dopt->binary_upgrade);
4550
4551                 appendPQExpBuffer(query, "SELECT n.tableoid, n.oid, n.nspname, "
4552                                                   "(%s nspowner) AS rolname, "
4553                                                   "%s as nspacl, "
4554                                                   "%s as rnspacl, "
4555                                                   "%s as initnspacl, "
4556                                                   "%s as initrnspacl "
4557                                                   "FROM pg_namespace n "
4558                                                   "LEFT JOIN pg_init_privs pip "
4559                                                   "ON (n.oid = pip.objoid "
4560                                                   "AND pip.classoid = 'pg_namespace'::regclass "
4561                                                   "AND pip.objsubid = 0",
4562                                                   username_subquery,
4563                                                   acl_subquery->data,
4564                                                   racl_subquery->data,
4565                                                   init_acl_subquery->data,
4566                                                   init_racl_subquery->data);
4567
4568                 appendPQExpBuffer(query, ") ");
4569
4570                 destroyPQExpBuffer(acl_subquery);
4571                 destroyPQExpBuffer(racl_subquery);
4572                 destroyPQExpBuffer(init_acl_subquery);
4573                 destroyPQExpBuffer(init_racl_subquery);
4574         }
4575         else
4576                 appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
4577                                                   "(%s nspowner) AS rolname, "
4578                                                   "nspacl, NULL as rnspacl, "
4579                                                   "NULL AS initnspacl, NULL as initrnspacl "
4580                                                   "FROM pg_namespace",
4581                                                   username_subquery);
4582
4583         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4584
4585         ntups = PQntuples(res);
4586
4587         nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
4588
4589         i_tableoid = PQfnumber(res, "tableoid");
4590         i_oid = PQfnumber(res, "oid");
4591         i_nspname = PQfnumber(res, "nspname");
4592         i_rolname = PQfnumber(res, "rolname");
4593         i_nspacl = PQfnumber(res, "nspacl");
4594         i_rnspacl = PQfnumber(res, "rnspacl");
4595         i_initnspacl = PQfnumber(res, "initnspacl");
4596         i_initrnspacl = PQfnumber(res, "initrnspacl");
4597
4598         for (i = 0; i < ntups; i++)
4599         {
4600                 nsinfo[i].dobj.objType = DO_NAMESPACE;
4601                 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4602                 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4603                 AssignDumpId(&nsinfo[i].dobj);
4604                 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
4605                 nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4606                 nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
4607                 nsinfo[i].rnspacl = pg_strdup(PQgetvalue(res, i, i_rnspacl));
4608                 nsinfo[i].initnspacl = pg_strdup(PQgetvalue(res, i, i_initnspacl));
4609                 nsinfo[i].initrnspacl = pg_strdup(PQgetvalue(res, i, i_initrnspacl));
4610
4611                 /* Decide whether to dump this namespace */
4612                 selectDumpableNamespace(&nsinfo[i], fout);
4613
4614                 /*
4615                  * Do not try to dump ACL if the ACL is empty or the default.
4616                  *
4617                  * This is useful because, for some schemas/objects, the only
4618                  * component we are going to try and dump is the ACL and if we can
4619                  * remove that then 'dump' goes to zero/false and we don't consider
4620                  * this object for dumping at all later on.
4621                  */
4622                 if (PQgetisnull(res, i, i_nspacl) && PQgetisnull(res, i, i_rnspacl) &&
4623                         PQgetisnull(res, i, i_initnspacl) &&
4624                         PQgetisnull(res, i, i_initrnspacl))
4625                         nsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4626
4627                 if (strlen(nsinfo[i].rolname) == 0)
4628                         write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
4629                                           nsinfo[i].dobj.name);
4630         }
4631
4632         PQclear(res);
4633         destroyPQExpBuffer(query);
4634
4635         *numNamespaces = ntups;
4636
4637         return nsinfo;
4638 }
4639
4640 /*
4641  * findNamespace:
4642  *              given a namespace OID, look up the info read by getNamespaces
4643  */
4644 static NamespaceInfo *
4645 findNamespace(Archive *fout, Oid nsoid)
4646 {
4647         NamespaceInfo *nsinfo;
4648
4649         nsinfo = findNamespaceByOid(nsoid);
4650         if (nsinfo == NULL)
4651                 exit_horribly(NULL, "schema with OID %u does not exist\n", nsoid);
4652         return nsinfo;
4653 }
4654
4655 /*
4656  * getExtensions:
4657  *        read all extensions in the system catalogs and return them in the
4658  * ExtensionInfo* structure
4659  *
4660  *      numExtensions is set to the number of extensions read in
4661  */
4662 ExtensionInfo *
4663 getExtensions(Archive *fout, int *numExtensions)
4664 {
4665         DumpOptions *dopt = fout->dopt;
4666         PGresult   *res;
4667         int                     ntups;
4668         int                     i;
4669         PQExpBuffer query;
4670         ExtensionInfo *extinfo;
4671         int                     i_tableoid;
4672         int                     i_oid;
4673         int                     i_extname;
4674         int                     i_nspname;
4675         int                     i_extrelocatable;
4676         int                     i_extversion;
4677         int                     i_extconfig;
4678         int                     i_extcondition;
4679
4680         /*
4681          * Before 9.1, there are no extensions.
4682          */
4683         if (fout->remoteVersion < 90100)
4684         {
4685                 *numExtensions = 0;
4686                 return NULL;
4687         }
4688
4689         query = createPQExpBuffer();
4690
4691         appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
4692                                                  "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
4693                                                  "FROM pg_extension x "
4694                                                  "JOIN pg_namespace n ON n.oid = x.extnamespace");
4695
4696         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4697
4698         ntups = PQntuples(res);
4699
4700         extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
4701
4702         i_tableoid = PQfnumber(res, "tableoid");
4703         i_oid = PQfnumber(res, "oid");
4704         i_extname = PQfnumber(res, "extname");
4705         i_nspname = PQfnumber(res, "nspname");
4706         i_extrelocatable = PQfnumber(res, "extrelocatable");
4707         i_extversion = PQfnumber(res, "extversion");
4708         i_extconfig = PQfnumber(res, "extconfig");
4709         i_extcondition = PQfnumber(res, "extcondition");
4710
4711         for (i = 0; i < ntups; i++)
4712         {
4713                 extinfo[i].dobj.objType = DO_EXTENSION;
4714                 extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4715                 extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4716                 AssignDumpId(&extinfo[i].dobj);
4717                 extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
4718                 extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
4719                 extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
4720                 extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
4721                 extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
4722                 extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
4723
4724                 /* Decide whether we want to dump it */
4725                 selectDumpableExtension(&(extinfo[i]), dopt);
4726         }
4727
4728         PQclear(res);
4729         destroyPQExpBuffer(query);
4730
4731         *numExtensions = ntups;
4732
4733         return extinfo;
4734 }
4735
4736 /*
4737  * getTypes:
4738  *        read all types in the system catalogs and return them in the
4739  * TypeInfo* structure
4740  *
4741  *      numTypes is set to the number of types read in
4742  *
4743  * NB: this must run after getFuncs() because we assume we can do
4744  * findFuncByOid().
4745  */
4746 TypeInfo *
4747 getTypes(Archive *fout, int *numTypes)
4748 {
4749         DumpOptions *dopt = fout->dopt;
4750         PGresult   *res;
4751         int                     ntups;
4752         int                     i;
4753         PQExpBuffer query = createPQExpBuffer();
4754         TypeInfo   *tyinfo;
4755         ShellTypeInfo *stinfo;
4756         int                     i_tableoid;
4757         int                     i_oid;
4758         int                     i_typname;
4759         int                     i_typnamespace;
4760         int                     i_typacl;
4761         int                     i_rtypacl;
4762         int                     i_inittypacl;
4763         int                     i_initrtypacl;
4764         int                     i_rolname;
4765         int                     i_typelem;
4766         int                     i_typrelid;
4767         int                     i_typrelkind;
4768         int                     i_typtype;
4769         int                     i_typisdefined;
4770         int                     i_isarray;
4771
4772         /*
4773          * we include even the built-in types because those may be used as array
4774          * elements by user-defined types
4775          *
4776          * we filter out the built-in types when we dump out the types
4777          *
4778          * same approach for undefined (shell) types and array types
4779          *
4780          * Note: as of 8.3 we can reliably detect whether a type is an
4781          * auto-generated array type by checking the element type's typarray.
4782          * (Before that the test is capable of generating false positives.) We
4783          * still check for name beginning with '_', though, so as to avoid the
4784          * cost of the subselect probe for all standard types.  This would have to
4785          * be revisited if the backend ever allows renaming of array types.
4786          */
4787
4788         if (fout->remoteVersion >= 90600)
4789         {
4790                 PQExpBuffer acl_subquery = createPQExpBuffer();
4791                 PQExpBuffer racl_subquery = createPQExpBuffer();
4792                 PQExpBuffer initacl_subquery = createPQExpBuffer();
4793                 PQExpBuffer initracl_subquery = createPQExpBuffer();
4794
4795                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
4796                                                 initracl_subquery, "t.typacl", "t.typowner", "'T'",
4797                                                 dopt->binary_upgrade);
4798
4799                 appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, t.typname, "
4800                                                   "t.typnamespace, "
4801                                                   "%s AS typacl, "
4802                                                   "%s AS rtypacl, "
4803                                                   "%s AS inittypacl, "
4804                                                   "%s AS initrtypacl, "
4805                                                   "(%s t.typowner) AS rolname, "
4806                                                   "t.typelem, t.typrelid, "
4807                                                   "CASE WHEN t.typrelid = 0 THEN ' '::\"char\" "
4808                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = t.typrelid) END AS typrelkind, "
4809                                                   "t.typtype, t.typisdefined, "
4810                                                   "t.typname[0] = '_' AND t.typelem != 0 AND "
4811                                                   "(SELECT typarray FROM pg_type te WHERE oid = t.typelem) = t.oid AS isarray "
4812                                                   "FROM pg_type t "
4813                                                   "LEFT JOIN pg_init_privs pip ON "
4814                                                   "(t.oid = pip.objoid "
4815                                                   "AND pip.classoid = 'pg_type'::regclass "
4816                                                   "AND pip.objsubid = 0) ",
4817                                                   acl_subquery->data,
4818                                                   racl_subquery->data,
4819                                                   initacl_subquery->data,
4820                                                   initracl_subquery->data,
4821                                                   username_subquery);
4822
4823                 destroyPQExpBuffer(acl_subquery);
4824                 destroyPQExpBuffer(racl_subquery);
4825                 destroyPQExpBuffer(initacl_subquery);
4826                 destroyPQExpBuffer(initracl_subquery);
4827         }
4828         else if (fout->remoteVersion >= 90200)
4829         {
4830                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4831                                                   "typnamespace, typacl, NULL as rtypacl, "
4832                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4833                                                   "(%s typowner) AS rolname, "
4834                                                   "typelem, typrelid, "
4835                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4836                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4837                                                   "typtype, typisdefined, "
4838                                                   "typname[0] = '_' AND typelem != 0 AND "
4839                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4840                                                   "FROM pg_type",
4841                                                   username_subquery);
4842         }
4843         else if (fout->remoteVersion >= 80300)
4844         {
4845                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4846                                                   "typnamespace, NULL AS typacl, NULL as rtypacl, "
4847                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4848                                                   "(%s typowner) AS rolname, "
4849                                                   "typelem, typrelid, "
4850                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4851                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4852                                                   "typtype, typisdefined, "
4853                                                   "typname[0] = '_' AND typelem != 0 AND "
4854                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4855                                                   "FROM pg_type",
4856                                                   username_subquery);
4857         }
4858         else
4859         {
4860                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4861                                                   "typnamespace, NULL AS typacl, NULL as rtypacl, "
4862                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4863                                                   "(%s typowner) AS rolname, "
4864                                                   "typelem, typrelid, "
4865                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4866                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4867                                                   "typtype, typisdefined, "
4868                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
4869                                                   "FROM pg_type",
4870                                                   username_subquery);
4871         }
4872
4873         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4874
4875         ntups = PQntuples(res);
4876
4877         tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
4878
4879         i_tableoid = PQfnumber(res, "tableoid");
4880         i_oid = PQfnumber(res, "oid");
4881         i_typname = PQfnumber(res, "typname");
4882         i_typnamespace = PQfnumber(res, "typnamespace");
4883         i_typacl = PQfnumber(res, "typacl");
4884         i_rtypacl = PQfnumber(res, "rtypacl");
4885         i_inittypacl = PQfnumber(res, "inittypacl");
4886         i_initrtypacl = PQfnumber(res, "initrtypacl");
4887         i_rolname = PQfnumber(res, "rolname");
4888         i_typelem = PQfnumber(res, "typelem");
4889         i_typrelid = PQfnumber(res, "typrelid");
4890         i_typrelkind = PQfnumber(res, "typrelkind");
4891         i_typtype = PQfnumber(res, "typtype");
4892         i_typisdefined = PQfnumber(res, "typisdefined");
4893         i_isarray = PQfnumber(res, "isarray");
4894
4895         for (i = 0; i < ntups; i++)
4896         {
4897                 tyinfo[i].dobj.objType = DO_TYPE;
4898                 tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4899                 tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4900                 AssignDumpId(&tyinfo[i].dobj);
4901                 tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
4902                 tyinfo[i].dobj.namespace =
4903                         findNamespace(fout,
4904                                                   atooid(PQgetvalue(res, i, i_typnamespace)));
4905                 tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4906                 tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
4907                 tyinfo[i].rtypacl = pg_strdup(PQgetvalue(res, i, i_rtypacl));
4908                 tyinfo[i].inittypacl = pg_strdup(PQgetvalue(res, i, i_inittypacl));
4909                 tyinfo[i].initrtypacl = pg_strdup(PQgetvalue(res, i, i_initrtypacl));
4910                 tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
4911                 tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
4912                 tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
4913                 tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
4914                 tyinfo[i].shellType = NULL;
4915
4916                 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
4917                         tyinfo[i].isDefined = true;
4918                 else
4919                         tyinfo[i].isDefined = false;
4920
4921                 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
4922                         tyinfo[i].isArray = true;
4923                 else
4924                         tyinfo[i].isArray = false;
4925
4926                 /* Decide whether we want to dump it */
4927                 selectDumpableType(&tyinfo[i], fout);
4928
4929                 /* Do not try to dump ACL if no ACL exists. */
4930                 if (PQgetisnull(res, i, i_typacl) && PQgetisnull(res, i, i_rtypacl) &&
4931                         PQgetisnull(res, i, i_inittypacl) &&
4932                         PQgetisnull(res, i, i_initrtypacl))
4933                         tyinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4934
4935                 /*
4936                  * If it's a domain, fetch info about its constraints, if any
4937                  */
4938                 tyinfo[i].nDomChecks = 0;
4939                 tyinfo[i].domChecks = NULL;
4940                 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4941                         tyinfo[i].typtype == TYPTYPE_DOMAIN)
4942                         getDomainConstraints(fout, &(tyinfo[i]));
4943
4944                 /*
4945                  * If it's a base type, make a DumpableObject representing a shell
4946                  * definition of the type.  We will need to dump that ahead of the I/O
4947                  * functions for the type.  Similarly, range types need a shell
4948                  * definition in case they have a canonicalize function.
4949                  *
4950                  * Note: the shell type doesn't have a catId.  You might think it
4951                  * should copy the base type's catId, but then it might capture the
4952                  * pg_depend entries for the type, which we don't want.
4953                  */
4954                 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4955                         (tyinfo[i].typtype == TYPTYPE_BASE ||
4956                          tyinfo[i].typtype == TYPTYPE_RANGE))
4957                 {
4958                         stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
4959                         stinfo->dobj.objType = DO_SHELL_TYPE;
4960                         stinfo->dobj.catId = nilCatalogId;
4961                         AssignDumpId(&stinfo->dobj);
4962                         stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
4963                         stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
4964                         stinfo->baseType = &(tyinfo[i]);
4965                         tyinfo[i].shellType = stinfo;
4966
4967                         /*
4968                          * Initially mark the shell type as not to be dumped.  We'll only
4969                          * dump it if the I/O or canonicalize functions need to be dumped;
4970                          * this is taken care of while sorting dependencies.
4971                          */
4972                         stinfo->dobj.dump = DUMP_COMPONENT_NONE;
4973                 }
4974
4975                 if (strlen(tyinfo[i].rolname) == 0)
4976                         write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
4977                                           tyinfo[i].dobj.name);
4978         }
4979
4980         *numTypes = ntups;
4981
4982         PQclear(res);
4983
4984         destroyPQExpBuffer(query);
4985
4986         return tyinfo;
4987 }
4988
4989 /*
4990  * getOperators:
4991  *        read all operators in the system catalogs and return them in the
4992  * OprInfo* structure
4993  *
4994  *      numOprs is set to the number of operators read in
4995  */
4996 OprInfo *
4997 getOperators(Archive *fout, int *numOprs)
4998 {
4999         PGresult   *res;
5000         int                     ntups;
5001         int                     i;
5002         PQExpBuffer query = createPQExpBuffer();
5003         OprInfo    *oprinfo;
5004         int                     i_tableoid;
5005         int                     i_oid;
5006         int                     i_oprname;
5007         int                     i_oprnamespace;
5008         int                     i_rolname;
5009         int                     i_oprkind;
5010         int                     i_oprcode;
5011
5012         /*
5013          * find all operators, including builtin operators; we filter out
5014          * system-defined operators at dump-out time.
5015          */
5016
5017         appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
5018                                           "oprnamespace, "
5019                                           "(%s oprowner) AS rolname, "
5020                                           "oprkind, "
5021                                           "oprcode::oid AS oprcode "
5022                                           "FROM pg_operator",
5023                                           username_subquery);
5024
5025         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5026
5027         ntups = PQntuples(res);
5028         *numOprs = ntups;
5029
5030         oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
5031
5032         i_tableoid = PQfnumber(res, "tableoid");
5033         i_oid = PQfnumber(res, "oid");
5034         i_oprname = PQfnumber(res, "oprname");
5035         i_oprnamespace = PQfnumber(res, "oprnamespace");
5036         i_rolname = PQfnumber(res, "rolname");
5037         i_oprkind = PQfnumber(res, "oprkind");
5038         i_oprcode = PQfnumber(res, "oprcode");
5039
5040         for (i = 0; i < ntups; i++)
5041         {
5042                 oprinfo[i].dobj.objType = DO_OPERATOR;
5043                 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5044                 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5045                 AssignDumpId(&oprinfo[i].dobj);
5046                 oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
5047                 oprinfo[i].dobj.namespace =
5048                         findNamespace(fout,
5049                                                   atooid(PQgetvalue(res, i, i_oprnamespace)));
5050                 oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5051                 oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
5052                 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
5053
5054                 /* Decide whether we want to dump it */
5055                 selectDumpableObject(&(oprinfo[i].dobj), fout);
5056
5057                 /* Operators do not currently have ACLs. */
5058                 oprinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5059
5060                 if (strlen(oprinfo[i].rolname) == 0)
5061                         write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
5062                                           oprinfo[i].dobj.name);
5063         }
5064
5065         PQclear(res);
5066
5067         destroyPQExpBuffer(query);
5068
5069         return oprinfo;
5070 }
5071
5072 /*
5073  * getCollations:
5074  *        read all collations in the system catalogs and return them in the
5075  * CollInfo* structure
5076  *
5077  *      numCollations is set to the number of collations read in
5078  */
5079 CollInfo *
5080 getCollations(Archive *fout, int *numCollations)
5081 {
5082         PGresult   *res;
5083         int                     ntups;
5084         int                     i;
5085         PQExpBuffer query;
5086         CollInfo   *collinfo;
5087         int                     i_tableoid;
5088         int                     i_oid;
5089         int                     i_collname;
5090         int                     i_collnamespace;
5091         int                     i_rolname;
5092
5093         /* Collations didn't exist pre-9.1 */
5094         if (fout->remoteVersion < 90100)
5095         {
5096                 *numCollations = 0;
5097                 return NULL;
5098         }
5099
5100         query = createPQExpBuffer();
5101
5102         /*
5103          * find all collations, including builtin collations; we filter out
5104          * system-defined collations at dump-out time.
5105          */
5106
5107         appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
5108                                           "collnamespace, "
5109                                           "(%s collowner) AS rolname "
5110                                           "FROM pg_collation",
5111                                           username_subquery);
5112
5113         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5114
5115         ntups = PQntuples(res);
5116         *numCollations = ntups;
5117
5118         collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
5119
5120         i_tableoid = PQfnumber(res, "tableoid");
5121         i_oid = PQfnumber(res, "oid");
5122         i_collname = PQfnumber(res, "collname");
5123         i_collnamespace = PQfnumber(res, "collnamespace");
5124         i_rolname = PQfnumber(res, "rolname");
5125
5126         for (i = 0; i < ntups; i++)
5127         {
5128                 collinfo[i].dobj.objType = DO_COLLATION;
5129                 collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5130                 collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5131                 AssignDumpId(&collinfo[i].dobj);
5132                 collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
5133                 collinfo[i].dobj.namespace =
5134                         findNamespace(fout,
5135                                                   atooid(PQgetvalue(res, i, i_collnamespace)));
5136                 collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5137
5138                 /* Decide whether we want to dump it */
5139                 selectDumpableObject(&(collinfo[i].dobj), fout);
5140
5141                 /* Collations do not currently have ACLs. */
5142                 collinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5143         }
5144
5145         PQclear(res);
5146
5147         destroyPQExpBuffer(query);
5148
5149         return collinfo;
5150 }
5151
5152 /*
5153  * getConversions:
5154  *        read all conversions in the system catalogs and return them in the
5155  * ConvInfo* structure
5156  *
5157  *      numConversions is set to the number of conversions read in
5158  */
5159 ConvInfo *
5160 getConversions(Archive *fout, int *numConversions)
5161 {
5162         PGresult   *res;
5163         int                     ntups;
5164         int                     i;
5165         PQExpBuffer query;
5166         ConvInfo   *convinfo;
5167         int                     i_tableoid;
5168         int                     i_oid;
5169         int                     i_conname;
5170         int                     i_connamespace;
5171         int                     i_rolname;
5172
5173         query = createPQExpBuffer();
5174
5175         /*
5176          * find all conversions, including builtin conversions; we filter out
5177          * system-defined conversions at dump-out time.
5178          */
5179
5180         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5181                                           "connamespace, "
5182                                           "(%s conowner) AS rolname "
5183                                           "FROM pg_conversion",
5184                                           username_subquery);
5185
5186         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5187
5188         ntups = PQntuples(res);
5189         *numConversions = ntups;
5190
5191         convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
5192
5193         i_tableoid = PQfnumber(res, "tableoid");
5194         i_oid = PQfnumber(res, "oid");
5195         i_conname = PQfnumber(res, "conname");
5196         i_connamespace = PQfnumber(res, "connamespace");
5197         i_rolname = PQfnumber(res, "rolname");
5198
5199         for (i = 0; i < ntups; i++)
5200         {
5201                 convinfo[i].dobj.objType = DO_CONVERSION;
5202                 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5203                 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5204                 AssignDumpId(&convinfo[i].dobj);
5205                 convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
5206                 convinfo[i].dobj.namespace =
5207                         findNamespace(fout,
5208                                                   atooid(PQgetvalue(res, i, i_connamespace)));
5209                 convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5210
5211                 /* Decide whether we want to dump it */
5212                 selectDumpableObject(&(convinfo[i].dobj), fout);
5213
5214                 /* Conversions do not currently have ACLs. */
5215                 convinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5216         }
5217
5218         PQclear(res);
5219
5220         destroyPQExpBuffer(query);
5221
5222         return convinfo;
5223 }
5224
5225 /*
5226  * getAccessMethods:
5227  *        read all user-defined access methods in the system catalogs and return
5228  *        them in the AccessMethodInfo* structure
5229  *
5230  *      numAccessMethods is set to the number of access methods read in
5231  */
5232 AccessMethodInfo *
5233 getAccessMethods(Archive *fout, int *numAccessMethods)
5234 {
5235         PGresult   *res;
5236         int                     ntups;
5237         int                     i;
5238         PQExpBuffer query;
5239         AccessMethodInfo *aminfo;
5240         int                     i_tableoid;
5241         int                     i_oid;
5242         int                     i_amname;
5243         int                     i_amhandler;
5244         int                     i_amtype;
5245
5246         /* Before 9.6, there are no user-defined access methods */
5247         if (fout->remoteVersion < 90600)
5248         {
5249                 *numAccessMethods = 0;
5250                 return NULL;
5251         }
5252
5253         query = createPQExpBuffer();
5254
5255         /* Select all access methods from pg_am table */
5256         appendPQExpBuffer(query, "SELECT tableoid, oid, amname, amtype, "
5257                                           "amhandler::pg_catalog.regproc AS amhandler "
5258                                           "FROM pg_am");
5259
5260         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5261
5262         ntups = PQntuples(res);
5263         *numAccessMethods = ntups;
5264
5265         aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
5266
5267         i_tableoid = PQfnumber(res, "tableoid");
5268         i_oid = PQfnumber(res, "oid");
5269         i_amname = PQfnumber(res, "amname");
5270         i_amhandler = PQfnumber(res, "amhandler");
5271         i_amtype = PQfnumber(res, "amtype");
5272
5273         for (i = 0; i < ntups; i++)
5274         {
5275                 aminfo[i].dobj.objType = DO_ACCESS_METHOD;
5276                 aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5277                 aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5278                 AssignDumpId(&aminfo[i].dobj);
5279                 aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
5280                 aminfo[i].dobj.namespace = NULL;
5281                 aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
5282                 aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
5283
5284                 /* Decide whether we want to dump it */
5285                 selectDumpableAccessMethod(&(aminfo[i]), fout);
5286
5287                 /* Access methods do not currently have ACLs. */
5288                 aminfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5289         }
5290
5291         PQclear(res);
5292
5293         destroyPQExpBuffer(query);
5294
5295         return aminfo;
5296 }
5297
5298
5299 /*
5300  * getOpclasses:
5301  *        read all opclasses in the system catalogs and return them in the
5302  * OpclassInfo* structure
5303  *
5304  *      numOpclasses is set to the number of opclasses read in
5305  */
5306 OpclassInfo *
5307 getOpclasses(Archive *fout, int *numOpclasses)
5308 {
5309         PGresult   *res;
5310         int                     ntups;
5311         int                     i;
5312         PQExpBuffer query = createPQExpBuffer();
5313         OpclassInfo *opcinfo;
5314         int                     i_tableoid;
5315         int                     i_oid;
5316         int                     i_opcname;
5317         int                     i_opcnamespace;
5318         int                     i_rolname;
5319
5320         /*
5321          * find all opclasses, including builtin opclasses; we filter out
5322          * system-defined opclasses at dump-out time.
5323          */
5324
5325         appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
5326                                           "opcnamespace, "
5327                                           "(%s opcowner) AS rolname "
5328                                           "FROM pg_opclass",
5329                                           username_subquery);
5330
5331         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5332
5333         ntups = PQntuples(res);
5334         *numOpclasses = ntups;
5335
5336         opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
5337
5338         i_tableoid = PQfnumber(res, "tableoid");
5339         i_oid = PQfnumber(res, "oid");
5340         i_opcname = PQfnumber(res, "opcname");
5341         i_opcnamespace = PQfnumber(res, "opcnamespace");
5342         i_rolname = PQfnumber(res, "rolname");
5343
5344         for (i = 0; i < ntups; i++)
5345         {
5346                 opcinfo[i].dobj.objType = DO_OPCLASS;
5347                 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5348                 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5349                 AssignDumpId(&opcinfo[i].dobj);
5350                 opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
5351                 opcinfo[i].dobj.namespace =
5352                         findNamespace(fout,
5353                                                   atooid(PQgetvalue(res, i, i_opcnamespace)));
5354                 opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5355
5356                 /* Decide whether we want to dump it */
5357                 selectDumpableObject(&(opcinfo[i].dobj), fout);
5358
5359                 /* Op Classes do not currently have ACLs. */
5360                 opcinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5361
5362                 if (strlen(opcinfo[i].rolname) == 0)
5363                         write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
5364                                           opcinfo[i].dobj.name);
5365         }
5366
5367         PQclear(res);
5368
5369         destroyPQExpBuffer(query);
5370
5371         return opcinfo;
5372 }
5373
5374 /*
5375  * getOpfamilies:
5376  *        read all opfamilies in the system catalogs and return them in the
5377  * OpfamilyInfo* structure
5378  *
5379  *      numOpfamilies is set to the number of opfamilies read in
5380  */
5381 OpfamilyInfo *
5382 getOpfamilies(Archive *fout, int *numOpfamilies)
5383 {
5384         PGresult   *res;
5385         int                     ntups;
5386         int                     i;
5387         PQExpBuffer query;
5388         OpfamilyInfo *opfinfo;
5389         int                     i_tableoid;
5390         int                     i_oid;
5391         int                     i_opfname;
5392         int                     i_opfnamespace;
5393         int                     i_rolname;
5394
5395         /* Before 8.3, there is no separate concept of opfamilies */
5396         if (fout->remoteVersion < 80300)
5397         {
5398                 *numOpfamilies = 0;
5399                 return NULL;
5400         }
5401
5402         query = createPQExpBuffer();
5403
5404         /*
5405          * find all opfamilies, including builtin opfamilies; we filter out
5406          * system-defined opfamilies at dump-out time.
5407          */
5408
5409         appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
5410                                           "opfnamespace, "
5411                                           "(%s opfowner) AS rolname "
5412                                           "FROM pg_opfamily",
5413                                           username_subquery);
5414
5415         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5416
5417         ntups = PQntuples(res);
5418         *numOpfamilies = ntups;
5419
5420         opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
5421
5422         i_tableoid = PQfnumber(res, "tableoid");
5423         i_oid = PQfnumber(res, "oid");
5424         i_opfname = PQfnumber(res, "opfname");
5425         i_opfnamespace = PQfnumber(res, "opfnamespace");
5426         i_rolname = PQfnumber(res, "rolname");
5427
5428         for (i = 0; i < ntups; i++)
5429         {
5430                 opfinfo[i].dobj.objType = DO_OPFAMILY;
5431                 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5432                 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5433                 AssignDumpId(&opfinfo[i].dobj);
5434                 opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
5435                 opfinfo[i].dobj.namespace =
5436                         findNamespace(fout,
5437                                                   atooid(PQgetvalue(res, i, i_opfnamespace)));
5438                 opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5439
5440                 /* Decide whether we want to dump it */
5441                 selectDumpableObject(&(opfinfo[i].dobj), fout);
5442
5443                 /* Extensions do not currently have ACLs. */
5444                 opfinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5445
5446                 if (strlen(opfinfo[i].rolname) == 0)
5447                         write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
5448                                           opfinfo[i].dobj.name);
5449         }
5450
5451         PQclear(res);
5452
5453         destroyPQExpBuffer(query);
5454
5455         return opfinfo;
5456 }
5457
5458 /*
5459  * getAggregates:
5460  *        read all the user-defined aggregates in the system catalogs and
5461  * return them in the AggInfo* structure
5462  *
5463  * numAggs is set to the number of aggregates read in
5464  */
5465 AggInfo *
5466 getAggregates(Archive *fout, int *numAggs)
5467 {
5468         DumpOptions *dopt = fout->dopt;
5469         PGresult   *res;
5470         int                     ntups;
5471         int                     i;
5472         PQExpBuffer query = createPQExpBuffer();
5473         AggInfo    *agginfo;
5474         int                     i_tableoid;
5475         int                     i_oid;
5476         int                     i_aggname;
5477         int                     i_aggnamespace;
5478         int                     i_pronargs;
5479         int                     i_proargtypes;
5480         int                     i_rolname;
5481         int                     i_aggacl;
5482         int                     i_raggacl;
5483         int                     i_initaggacl;
5484         int                     i_initraggacl;
5485
5486         /*
5487          * Find all interesting aggregates.  See comment in getFuncs() for the
5488          * rationale behind the filtering logic.
5489          */
5490         if (fout->remoteVersion >= 90600)
5491         {
5492                 PQExpBuffer acl_subquery = createPQExpBuffer();
5493                 PQExpBuffer racl_subquery = createPQExpBuffer();
5494                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5495                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5496                 const char *agg_check;
5497
5498                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5499                                                 initracl_subquery, "p.proacl", "p.proowner", "'f'",
5500                                                 dopt->binary_upgrade);
5501
5502                 agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
5503                                          : "p.proisagg");
5504
5505                 appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
5506                                                   "p.proname AS aggname, "
5507                                                   "p.pronamespace AS aggnamespace, "
5508                                                   "p.pronargs, p.proargtypes, "
5509                                                   "(%s p.proowner) AS rolname, "
5510                                                   "%s AS aggacl, "
5511                                                   "%s AS raggacl, "
5512                                                   "%s AS initaggacl, "
5513                                                   "%s AS initraggacl "
5514                                                   "FROM pg_proc p "
5515                                                   "LEFT JOIN pg_init_privs pip ON "
5516                                                   "(p.oid = pip.objoid "
5517                                                   "AND pip.classoid = 'pg_proc'::regclass "
5518                                                   "AND pip.objsubid = 0) "
5519                                                   "WHERE %s AND ("
5520                                                   "p.pronamespace != "
5521                                                   "(SELECT oid FROM pg_namespace "
5522                                                   "WHERE nspname = 'pg_catalog') OR "
5523                                                   "p.proacl IS DISTINCT FROM pip.initprivs",
5524                                                   username_subquery,
5525                                                   acl_subquery->data,
5526                                                   racl_subquery->data,
5527                                                   initacl_subquery->data,
5528                                                   initracl_subquery->data,
5529                                                   agg_check);
5530                 if (dopt->binary_upgrade)
5531                         appendPQExpBufferStr(query,
5532                                                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5533                                                                  "classid = 'pg_proc'::regclass AND "
5534                                                                  "objid = p.oid AND "
5535                                                                  "refclassid = 'pg_extension'::regclass AND "
5536                                                                  "deptype = 'e')");
5537                 appendPQExpBufferChar(query, ')');
5538
5539                 destroyPQExpBuffer(acl_subquery);
5540                 destroyPQExpBuffer(racl_subquery);
5541                 destroyPQExpBuffer(initacl_subquery);
5542                 destroyPQExpBuffer(initracl_subquery);
5543         }
5544         else if (fout->remoteVersion >= 80200)
5545         {
5546                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
5547                                                   "pronamespace AS aggnamespace, "
5548                                                   "pronargs, proargtypes, "
5549                                                   "(%s proowner) AS rolname, "
5550                                                   "proacl AS aggacl, "
5551                                                   "NULL AS raggacl, "
5552                                                   "NULL AS initaggacl, NULL AS initraggacl "
5553                                                   "FROM pg_proc p "
5554                                                   "WHERE proisagg AND ("
5555                                                   "pronamespace != "
5556                                                   "(SELECT oid FROM pg_namespace "
5557                                                   "WHERE nspname = 'pg_catalog')",
5558                                                   username_subquery);
5559                 if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
5560                         appendPQExpBufferStr(query,
5561                                                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5562                                                                  "classid = 'pg_proc'::regclass AND "
5563                                                                  "objid = p.oid AND "
5564                                                                  "refclassid = 'pg_extension'::regclass AND "
5565                                                                  "deptype = 'e')");
5566                 appendPQExpBufferChar(query, ')');
5567         }
5568         else
5569         {
5570                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
5571                                                   "pronamespace AS aggnamespace, "
5572                                                   "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
5573                                                   "proargtypes, "
5574                                                   "(%s proowner) AS rolname, "
5575                                                   "proacl AS aggacl, "
5576                                                   "NULL AS raggacl, "
5577                                                   "NULL AS initaggacl, NULL AS initraggacl "
5578                                                   "FROM pg_proc "
5579                                                   "WHERE proisagg "
5580                                                   "AND pronamespace != "
5581                                                   "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
5582                                                   username_subquery);
5583         }
5584
5585         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5586
5587         ntups = PQntuples(res);
5588         *numAggs = ntups;
5589
5590         agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
5591
5592         i_tableoid = PQfnumber(res, "tableoid");
5593         i_oid = PQfnumber(res, "oid");
5594         i_aggname = PQfnumber(res, "aggname");
5595         i_aggnamespace = PQfnumber(res, "aggnamespace");
5596         i_pronargs = PQfnumber(res, "pronargs");
5597         i_proargtypes = PQfnumber(res, "proargtypes");
5598         i_rolname = PQfnumber(res, "rolname");
5599         i_aggacl = PQfnumber(res, "aggacl");
5600         i_raggacl = PQfnumber(res, "raggacl");
5601         i_initaggacl = PQfnumber(res, "initaggacl");
5602         i_initraggacl = PQfnumber(res, "initraggacl");
5603
5604         for (i = 0; i < ntups; i++)
5605         {
5606                 agginfo[i].aggfn.dobj.objType = DO_AGG;
5607                 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5608                 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5609                 AssignDumpId(&agginfo[i].aggfn.dobj);
5610                 agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
5611                 agginfo[i].aggfn.dobj.namespace =
5612                         findNamespace(fout,
5613                                                   atooid(PQgetvalue(res, i, i_aggnamespace)));
5614                 agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5615                 if (strlen(agginfo[i].aggfn.rolname) == 0)
5616                         write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
5617                                           agginfo[i].aggfn.dobj.name);
5618                 agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
5619                 agginfo[i].aggfn.prorettype = InvalidOid;       /* not saved */
5620                 agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
5621                 agginfo[i].aggfn.rproacl = pg_strdup(PQgetvalue(res, i, i_raggacl));
5622                 agginfo[i].aggfn.initproacl = pg_strdup(PQgetvalue(res, i, i_initaggacl));
5623                 agginfo[i].aggfn.initrproacl = pg_strdup(PQgetvalue(res, i, i_initraggacl));
5624                 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
5625                 if (agginfo[i].aggfn.nargs == 0)
5626                         agginfo[i].aggfn.argtypes = NULL;
5627                 else
5628                 {
5629                         agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
5630                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
5631                                                   agginfo[i].aggfn.argtypes,
5632                                                   agginfo[i].aggfn.nargs);
5633                 }
5634
5635                 /* Decide whether we want to dump it */
5636                 selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
5637
5638                 /* Do not try to dump ACL if no ACL exists. */
5639                 if (PQgetisnull(res, i, i_aggacl) && PQgetisnull(res, i, i_raggacl) &&
5640                         PQgetisnull(res, i, i_initaggacl) &&
5641                         PQgetisnull(res, i, i_initraggacl))
5642                         agginfo[i].aggfn.dobj.dump &= ~DUMP_COMPONENT_ACL;
5643         }
5644
5645         PQclear(res);
5646
5647         destroyPQExpBuffer(query);
5648
5649         return agginfo;
5650 }
5651
5652 /*
5653  * getFuncs:
5654  *        read all the user-defined functions in the system catalogs and
5655  * return them in the FuncInfo* structure
5656  *
5657  * numFuncs is set to the number of functions read in
5658  */
5659 FuncInfo *
5660 getFuncs(Archive *fout, int *numFuncs)
5661 {
5662         DumpOptions *dopt = fout->dopt;
5663         PGresult   *res;
5664         int                     ntups;
5665         int                     i;
5666         PQExpBuffer query = createPQExpBuffer();
5667         FuncInfo   *finfo;
5668         int                     i_tableoid;
5669         int                     i_oid;
5670         int                     i_proname;
5671         int                     i_pronamespace;
5672         int                     i_rolname;
5673         int                     i_prolang;
5674         int                     i_pronargs;
5675         int                     i_proargtypes;
5676         int                     i_prorettype;
5677         int                     i_proacl;
5678         int                     i_rproacl;
5679         int                     i_initproacl;
5680         int                     i_initrproacl;
5681
5682         /*
5683          * Find all interesting functions.  This is a bit complicated:
5684          *
5685          * 1. Always exclude aggregates; those are handled elsewhere.
5686          *
5687          * 2. Always exclude functions that are internally dependent on something
5688          * else, since presumably those will be created as a result of creating
5689          * the something else.  This currently acts only to suppress constructor
5690          * functions for range types (so we only need it in 9.2 and up).  Note
5691          * this is OK only because the constructors don't have any dependencies
5692          * the range type doesn't have; otherwise we might not get creation
5693          * ordering correct.
5694          *
5695          * 3. Otherwise, we normally exclude functions in pg_catalog.  However, if
5696          * they're members of extensions and we are in binary-upgrade mode then
5697          * include them, since we want to dump extension members individually in
5698          * that mode.  Also, if they are used by casts or transforms then we need
5699          * to gather the information about them, though they won't be dumped if
5700          * they are built-in.  Also, in 9.6 and up, include functions in
5701          * pg_catalog if they have an ACL different from what's shown in
5702          * pg_init_privs.
5703          */
5704         if (fout->remoteVersion >= 90600)
5705         {
5706                 PQExpBuffer acl_subquery = createPQExpBuffer();
5707                 PQExpBuffer racl_subquery = createPQExpBuffer();
5708                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5709                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5710                 const char *not_agg_check;
5711
5712                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5713                                                 initracl_subquery, "p.proacl", "p.proowner", "'f'",
5714                                                 dopt->binary_upgrade);
5715
5716                 not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
5717                                                  : "NOT p.proisagg");
5718
5719                 appendPQExpBuffer(query,
5720                                                   "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
5721                                                   "p.pronargs, p.proargtypes, p.prorettype, "
5722                                                   "%s AS proacl, "
5723                                                   "%s AS rproacl, "
5724                                                   "%s AS initproacl, "
5725                                                   "%s AS initrproacl, "
5726                                                   "p.pronamespace, "
5727                                                   "(%s p.proowner) AS rolname "
5728                                                   "FROM pg_proc p "
5729                                                   "LEFT JOIN pg_init_privs pip ON "
5730                                                   "(p.oid = pip.objoid "
5731                                                   "AND pip.classoid = 'pg_proc'::regclass "
5732                                                   "AND pip.objsubid = 0) "
5733                                                   "WHERE %s"
5734                                                   "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
5735                                                   "WHERE classid = 'pg_proc'::regclass AND "
5736                                                   "objid = p.oid AND deptype = 'i')"
5737                                                   "\n  AND ("
5738                                                   "\n  pronamespace != "
5739                                                   "(SELECT oid FROM pg_namespace "
5740                                                   "WHERE nspname = 'pg_catalog')"
5741                                                   "\n  OR EXISTS (SELECT 1 FROM pg_cast"
5742                                                   "\n  WHERE pg_cast.oid > %u "
5743                                                   "\n  AND p.oid = pg_cast.castfunc)"
5744                                                   "\n  OR EXISTS (SELECT 1 FROM pg_transform"
5745                                                   "\n  WHERE pg_transform.oid > %u AND "
5746                                                   "\n  (p.oid = pg_transform.trffromsql"
5747                                                   "\n  OR p.oid = pg_transform.trftosql))",
5748                                                   acl_subquery->data,
5749                                                   racl_subquery->data,
5750                                                   initacl_subquery->data,
5751                                                   initracl_subquery->data,
5752                                                   username_subquery,
5753                                                   not_agg_check,
5754                                                   g_last_builtin_oid,
5755                                                   g_last_builtin_oid);
5756                 if (dopt->binary_upgrade)
5757                         appendPQExpBufferStr(query,
5758                                                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5759                                                                  "classid = 'pg_proc'::regclass AND "
5760                                                                  "objid = p.oid AND "
5761                                                                  "refclassid = 'pg_extension'::regclass AND "
5762                                                                  "deptype = 'e')");
5763                 appendPQExpBufferStr(query,
5764                                                          "\n  OR p.proacl IS DISTINCT FROM pip.initprivs");
5765                 appendPQExpBufferChar(query, ')');
5766
5767                 destroyPQExpBuffer(acl_subquery);
5768                 destroyPQExpBuffer(racl_subquery);
5769                 destroyPQExpBuffer(initacl_subquery);
5770                 destroyPQExpBuffer(initracl_subquery);
5771         }
5772         else
5773         {
5774                 appendPQExpBuffer(query,
5775                                                   "SELECT tableoid, oid, proname, prolang, "
5776                                                   "pronargs, proargtypes, prorettype, proacl, "
5777                                                   "NULL as rproacl, "
5778                                                   "NULL as initproacl, NULL AS initrproacl, "
5779                                                   "pronamespace, "
5780                                                   "(%s proowner) AS rolname "
5781                                                   "FROM pg_proc p "
5782                                                   "WHERE NOT proisagg",
5783                                                   username_subquery);
5784                 if (fout->remoteVersion >= 90200)
5785                         appendPQExpBufferStr(query,
5786                                                                  "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
5787                                                                  "WHERE classid = 'pg_proc'::regclass AND "
5788                                                                  "objid = p.oid AND deptype = 'i')");
5789                 appendPQExpBuffer(query,
5790                                                   "\n  AND ("
5791                                                   "\n  pronamespace != "
5792                                                   "(SELECT oid FROM pg_namespace "
5793                                                   "WHERE nspname = 'pg_catalog')"
5794                                                   "\n  OR EXISTS (SELECT 1 FROM pg_cast"
5795                                                   "\n  WHERE pg_cast.oid > '%u'::oid"
5796                                                   "\n  AND p.oid = pg_cast.castfunc)",
5797                                                   g_last_builtin_oid);
5798
5799                 if (fout->remoteVersion >= 90500)
5800                         appendPQExpBuffer(query,
5801                                                           "\n  OR EXISTS (SELECT 1 FROM pg_transform"
5802                                                           "\n  WHERE pg_transform.oid > '%u'::oid"
5803                                                           "\n  AND (p.oid = pg_transform.trffromsql"
5804                                                           "\n  OR p.oid = pg_transform.trftosql))",
5805                                                           g_last_builtin_oid);
5806
5807                 if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
5808                         appendPQExpBufferStr(query,
5809                                                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5810                                                                  "classid = 'pg_proc'::regclass AND "
5811                                                                  "objid = p.oid AND "
5812                                                                  "refclassid = 'pg_extension'::regclass AND "
5813                                                                  "deptype = 'e')");
5814                 appendPQExpBufferChar(query, ')');
5815         }
5816
5817         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5818
5819         ntups = PQntuples(res);
5820
5821         *numFuncs = ntups;
5822
5823         finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
5824
5825         i_tableoid = PQfnumber(res, "tableoid");
5826         i_oid = PQfnumber(res, "oid");
5827         i_proname = PQfnumber(res, "proname");
5828         i_pronamespace = PQfnumber(res, "pronamespace");
5829         i_rolname = PQfnumber(res, "rolname");
5830         i_prolang = PQfnumber(res, "prolang");
5831         i_pronargs = PQfnumber(res, "pronargs");
5832         i_proargtypes = PQfnumber(res, "proargtypes");
5833         i_prorettype = PQfnumber(res, "prorettype");
5834         i_proacl = PQfnumber(res, "proacl");
5835         i_rproacl = PQfnumber(res, "rproacl");
5836         i_initproacl = PQfnumber(res, "initproacl");
5837         i_initrproacl = PQfnumber(res, "initrproacl");
5838
5839         for (i = 0; i < ntups; i++)
5840         {
5841                 finfo[i].dobj.objType = DO_FUNC;
5842                 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5843                 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5844                 AssignDumpId(&finfo[i].dobj);
5845                 finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
5846                 finfo[i].dobj.namespace =
5847                         findNamespace(fout,
5848                                                   atooid(PQgetvalue(res, i, i_pronamespace)));
5849                 finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5850                 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
5851                 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
5852                 finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
5853                 finfo[i].rproacl = pg_strdup(PQgetvalue(res, i, i_rproacl));
5854                 finfo[i].initproacl = pg_strdup(PQgetvalue(res, i, i_initproacl));
5855                 finfo[i].initrproacl = pg_strdup(PQgetvalue(res, i, i_initrproacl));
5856                 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
5857                 if (finfo[i].nargs == 0)
5858                         finfo[i].argtypes = NULL;
5859                 else
5860                 {
5861                         finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
5862                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
5863                                                   finfo[i].argtypes, finfo[i].nargs);
5864                 }
5865
5866                 /* Decide whether we want to dump it */
5867                 selectDumpableObject(&(finfo[i].dobj), fout);
5868
5869                 /* Do not try to dump ACL if no ACL exists. */
5870                 if (PQgetisnull(res, i, i_proacl) && PQgetisnull(res, i, i_rproacl) &&
5871                         PQgetisnull(res, i, i_initproacl) &&
5872                         PQgetisnull(res, i, i_initrproacl))
5873                         finfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5874
5875                 if (strlen(finfo[i].rolname) == 0)
5876                         write_msg(NULL,
5877                                           "WARNING: owner of function \"%s\" appears to be invalid\n",
5878                                           finfo[i].dobj.name);
5879         }
5880
5881         PQclear(res);
5882
5883         destroyPQExpBuffer(query);
5884
5885         return finfo;
5886 }
5887
5888 /*
5889  * getTables
5890  *        read all the tables (no indexes)
5891  * in the system catalogs return them in the TableInfo* structure
5892  *
5893  * numTables is set to the number of tables read in
5894  */
5895 TableInfo *
5896 getTables(Archive *fout, int *numTables)
5897 {
5898         DumpOptions *dopt = fout->dopt;
5899         PGresult   *res;
5900         int                     ntups;
5901         int                     i;
5902         PQExpBuffer query = createPQExpBuffer();
5903         TableInfo  *tblinfo;
5904         int                     i_reltableoid;
5905         int                     i_reloid;
5906         int                     i_relname;
5907         int                     i_relnamespace;
5908         int                     i_relkind;
5909         int                     i_relacl;
5910         int                     i_rrelacl;
5911         int                     i_initrelacl;
5912         int                     i_initrrelacl;
5913         int                     i_rolname;
5914         int                     i_relchecks;
5915         int                     i_relhastriggers;
5916         int                     i_relhasindex;
5917         int                     i_relhasrules;
5918         int                     i_relrowsec;
5919         int                     i_relforcerowsec;
5920         int                     i_relhasoids;
5921         int                     i_relfrozenxid;
5922         int                     i_relminmxid;
5923         int                     i_toastoid;
5924         int                     i_toastfrozenxid;
5925         int                     i_toastminmxid;
5926         int                     i_relpersistence;
5927         int                     i_relispopulated;
5928         int                     i_relreplident;
5929         int                     i_owning_tab;
5930         int                     i_owning_col;
5931         int                     i_reltablespace;
5932         int                     i_reloptions;
5933         int                     i_checkoption;
5934         int                     i_toastreloptions;
5935         int                     i_reloftype;
5936         int                     i_relpages;
5937         int                     i_is_identity_sequence;
5938         int                     i_changed_acl;
5939         int                     i_partkeydef;
5940         int                     i_ispartition;
5941         int                     i_partbound;
5942         int                     i_amname;
5943
5944         /*
5945          * Find all the tables and table-like objects.
5946          *
5947          * We include system catalogs, so that we can work if a user table is
5948          * defined to inherit from a system catalog (pretty weird, but...)
5949          *
5950          * We ignore relations that are not ordinary tables, sequences, views,
5951          * materialized views, composite types, or foreign tables.
5952          *
5953          * Composite-type table entries won't be dumped as such, but we have to
5954          * make a DumpableObject for them so that we can track dependencies of the
5955          * composite type (pg_depend entries for columns of the composite type
5956          * link to the pg_class entry not the pg_type entry).
5957          *
5958          * Note: in this phase we should collect only a minimal amount of
5959          * information about each table, basically just enough to decide if it is
5960          * interesting. We must fetch all tables in this phase because otherwise
5961          * we cannot correctly identify inherited columns, owned sequences, etc.
5962          *
5963          * We purposefully ignore toast OIDs for partitioned tables; the reason is
5964          * that versions 10 and 11 have them, but 12 does not, so emitting them
5965          * causes the upgrade to fail.
5966          */
5967
5968         if (fout->remoteVersion >= 90600)
5969         {
5970                 char       *partkeydef = "NULL";
5971                 char       *ispartition = "false";
5972                 char       *partbound = "NULL";
5973                 char       *relhasoids = "c.relhasoids";
5974
5975                 PQExpBuffer acl_subquery = createPQExpBuffer();
5976                 PQExpBuffer racl_subquery = createPQExpBuffer();
5977                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5978                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5979
5980                 PQExpBuffer attacl_subquery = createPQExpBuffer();
5981                 PQExpBuffer attracl_subquery = createPQExpBuffer();
5982                 PQExpBuffer attinitacl_subquery = createPQExpBuffer();
5983                 PQExpBuffer attinitracl_subquery = createPQExpBuffer();
5984
5985                 /*
5986                  * Collect the information about any partitioned tables, which were
5987                  * added in PG10.
5988                  */
5989
5990                 if (fout->remoteVersion >= 100000)
5991                 {
5992                         partkeydef = "pg_get_partkeydef(c.oid)";
5993                         ispartition = "c.relispartition";
5994                         partbound = "pg_get_expr(c.relpartbound, c.oid)";
5995                 }
5996
5997                 /* In PG12 upwards WITH OIDS does not exist anymore. */
5998                 if (fout->remoteVersion >= 120000)
5999                         relhasoids = "'f'::bool";
6000
6001                 /*
6002                  * Left join to pick up dependency info linking sequences to their
6003                  * owning column, if any (note this dependency is AUTO as of 8.2)
6004                  *
6005                  * Left join to detect if any privileges are still as-set-at-init, in
6006                  * which case we won't dump out ACL commands for those.
6007                  */
6008
6009                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
6010                                                 initracl_subquery, "c.relacl", "c.relowner",
6011                                                 "CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
6012                                                 " THEN 's' ELSE 'r' END::\"char\"",
6013                                                 dopt->binary_upgrade);
6014
6015                 buildACLQueries(attacl_subquery, attracl_subquery, attinitacl_subquery,
6016                                                 attinitracl_subquery, "at.attacl", "c.relowner", "'c'",
6017                                                 dopt->binary_upgrade);
6018
6019                 appendPQExpBuffer(query,
6020                                                   "SELECT c.tableoid, c.oid, c.relname, "
6021                                                   "%s AS relacl, %s as rrelacl, "
6022                                                   "%s AS initrelacl, %s as initrrelacl, "
6023                                                   "c.relkind, c.relnamespace, "
6024                                                   "(%s c.relowner) AS rolname, "
6025                                                   "c.relchecks, c.relhastriggers, "
6026                                                   "c.relhasindex, c.relhasrules, %s AS relhasoids, "
6027                                                   "c.relrowsecurity, c.relforcerowsecurity, "
6028                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6029                                                   "tc.relfrozenxid AS tfrozenxid, "
6030                                                   "tc.relminmxid AS tminmxid, "
6031                                                   "c.relpersistence, c.relispopulated, "
6032                                                   "c.relreplident, c.relpages, am.amname, "
6033                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6034                                                   "d.refobjid AS owning_tab, "
6035                                                   "d.refobjsubid AS owning_col, "
6036                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6037                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6038                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6039                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6040                                                   "tc.reloptions AS toast_reloptions, "
6041                                                   "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, "
6042                                                   "EXISTS (SELECT 1 FROM pg_attribute at LEFT JOIN pg_init_privs pip ON "
6043                                                   "(c.oid = pip.objoid "
6044                                                   "AND pip.classoid = 'pg_class'::regclass "
6045                                                   "AND pip.objsubid = at.attnum)"
6046                                                   "WHERE at.attrelid = c.oid AND ("
6047                                                   "%s IS NOT NULL "
6048                                                   "OR %s IS NOT NULL "
6049                                                   "OR %s IS NOT NULL "
6050                                                   "OR %s IS NOT NULL"
6051                                                   "))"
6052                                                   "AS changed_acl, "
6053                                                   "%s AS partkeydef, "
6054                                                   "%s AS ispartition, "
6055                                                   "%s AS partbound "
6056                                                   "FROM pg_class c "
6057                                                   "LEFT JOIN pg_depend d ON "
6058                                                   "(c.relkind = '%c' AND "
6059                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6060                                                   "d.objsubid = 0 AND "
6061                                                   "d.refclassid = c.tableoid AND d.deptype IN ('a', 'i')) "
6062                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid AND c.relkind <> '%c') "
6063                                                   "LEFT JOIN pg_am am ON (c.relam = am.oid) "
6064                                                   "LEFT JOIN pg_init_privs pip ON "
6065                                                   "(c.oid = pip.objoid "
6066                                                   "AND pip.classoid = 'pg_class'::regclass "
6067                                                   "AND pip.objsubid = 0) "
6068                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c', '%c') "
6069                                                   "ORDER BY c.oid",
6070                                                   acl_subquery->data,
6071                                                   racl_subquery->data,
6072                                                   initacl_subquery->data,
6073                                                   initracl_subquery->data,
6074                                                   username_subquery,
6075                                                   relhasoids,
6076                                                   RELKIND_SEQUENCE,
6077                                                   attacl_subquery->data,
6078                                                   attracl_subquery->data,
6079                                                   attinitacl_subquery->data,
6080                                                   attinitracl_subquery->data,
6081                                                   partkeydef,
6082                                                   ispartition,
6083                                                   partbound,
6084                                                   RELKIND_SEQUENCE,
6085                                                   RELKIND_PARTITIONED_TABLE,
6086                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6087                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6088                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
6089                                                   RELKIND_PARTITIONED_TABLE);
6090
6091                 destroyPQExpBuffer(acl_subquery);
6092                 destroyPQExpBuffer(racl_subquery);
6093                 destroyPQExpBuffer(initacl_subquery);
6094                 destroyPQExpBuffer(initracl_subquery);
6095
6096                 destroyPQExpBuffer(attacl_subquery);
6097                 destroyPQExpBuffer(attracl_subquery);
6098                 destroyPQExpBuffer(attinitacl_subquery);
6099                 destroyPQExpBuffer(attinitracl_subquery);
6100         }
6101         else if (fout->remoteVersion >= 90500)
6102         {
6103                 /*
6104                  * Left join to pick up dependency info linking sequences to their
6105                  * owning column, if any (note this dependency is AUTO as of 8.2)
6106                  */
6107                 appendPQExpBuffer(query,
6108                                                   "SELECT c.tableoid, c.oid, c.relname, "
6109                                                   "c.relacl, NULL as rrelacl, "
6110                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6111                                                   "c.relkind, "
6112                                                   "c.relnamespace, "
6113                                                   "(%s c.relowner) AS rolname, "
6114                                                   "c.relchecks, c.relhastriggers, "
6115                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6116                                                   "c.relrowsecurity, c.relforcerowsecurity, "
6117                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6118                                                   "tc.relfrozenxid AS tfrozenxid, "
6119                                                   "tc.relminmxid AS tminmxid, "
6120                                                   "c.relpersistence, c.relispopulated, "
6121                                                   "c.relreplident, c.relpages, "
6122                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6123                                                   "d.refobjid AS owning_tab, "
6124                                                   "d.refobjsubid AS owning_col, "
6125                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6126                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6127                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6128                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6129                                                   "tc.reloptions AS toast_reloptions, "
6130                                                   "NULL AS changed_acl, "
6131                                                   "NULL AS partkeydef, "
6132                                                   "false AS ispartition, "
6133                                                   "NULL AS partbound "
6134                                                   "FROM pg_class c "
6135                                                   "LEFT JOIN pg_depend d ON "
6136                                                   "(c.relkind = '%c' AND "
6137                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6138                                                   "d.objsubid = 0 AND "
6139                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6140                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6141                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6142                                                   "ORDER BY c.oid",
6143                                                   username_subquery,
6144                                                   RELKIND_SEQUENCE,
6145                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6146                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6147                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6148         }
6149         else if (fout->remoteVersion >= 90400)
6150         {
6151                 /*
6152                  * Left join to pick up dependency info linking sequences to their
6153                  * owning column, if any (note this dependency is AUTO as of 8.2)
6154                  */
6155                 appendPQExpBuffer(query,
6156                                                   "SELECT c.tableoid, c.oid, c.relname, "
6157                                                   "c.relacl, NULL as rrelacl, "
6158                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6159                                                   "c.relkind, "
6160                                                   "c.relnamespace, "
6161                                                   "(%s c.relowner) AS rolname, "
6162                                                   "c.relchecks, c.relhastriggers, "
6163                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6164                                                   "'f'::bool AS relrowsecurity, "
6165                                                   "'f'::bool AS relforcerowsecurity, "
6166                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6167                                                   "tc.relfrozenxid AS tfrozenxid, "
6168                                                   "tc.relminmxid AS tminmxid, "
6169                                                   "c.relpersistence, c.relispopulated, "
6170                                                   "c.relreplident, c.relpages, "
6171                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6172                                                   "d.refobjid AS owning_tab, "
6173                                                   "d.refobjsubid AS owning_col, "
6174                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6175                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6176                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6177                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6178                                                   "tc.reloptions AS toast_reloptions, "
6179                                                   "NULL AS changed_acl, "
6180                                                   "NULL AS partkeydef, "
6181                                                   "false AS ispartition, "
6182                                                   "NULL AS partbound "
6183                                                   "FROM pg_class c "
6184                                                   "LEFT JOIN pg_depend d ON "
6185                                                   "(c.relkind = '%c' AND "
6186                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6187                                                   "d.objsubid = 0 AND "
6188                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6189                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6190                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6191                                                   "ORDER BY c.oid",
6192                                                   username_subquery,
6193                                                   RELKIND_SEQUENCE,
6194                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6195                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6196                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6197         }
6198         else if (fout->remoteVersion >= 90300)
6199         {
6200                 /*
6201                  * Left join to pick up dependency info linking sequences to their
6202                  * owning column, if any (note this dependency is AUTO as of 8.2)
6203                  */
6204                 appendPQExpBuffer(query,
6205                                                   "SELECT c.tableoid, c.oid, c.relname, "
6206                                                   "c.relacl, NULL as rrelacl, "
6207                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6208                                                   "c.relkind, "
6209                                                   "c.relnamespace, "
6210                                                   "(%s c.relowner) AS rolname, "
6211                                                   "c.relchecks, c.relhastriggers, "
6212                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6213                                                   "'f'::bool AS relrowsecurity, "
6214                                                   "'f'::bool AS relforcerowsecurity, "
6215                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6216                                                   "tc.relfrozenxid AS tfrozenxid, "
6217                                                   "tc.relminmxid AS tminmxid, "
6218                                                   "c.relpersistence, c.relispopulated, "
6219                                                   "'d' AS relreplident, c.relpages, "
6220                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6221                                                   "d.refobjid AS owning_tab, "
6222                                                   "d.refobjsubid AS owning_col, "
6223                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6224                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6225                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6226                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6227                                                   "tc.reloptions AS toast_reloptions, "
6228                                                   "NULL AS changed_acl, "
6229                                                   "NULL AS partkeydef, "
6230                                                   "false AS ispartition, "
6231                                                   "NULL AS partbound "
6232                                                   "FROM pg_class c "
6233                                                   "LEFT JOIN pg_depend d ON "
6234                                                   "(c.relkind = '%c' AND "
6235                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6236                                                   "d.objsubid = 0 AND "
6237                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6238                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6239                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6240                                                   "ORDER BY c.oid",
6241                                                   username_subquery,
6242                                                   RELKIND_SEQUENCE,
6243                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6244                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6245                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6246         }
6247         else if (fout->remoteVersion >= 90100)
6248         {
6249                 /*
6250                  * Left join to pick up dependency info linking sequences to their
6251                  * owning column, if any (note this dependency is AUTO as of 8.2)
6252                  */
6253                 appendPQExpBuffer(query,
6254                                                   "SELECT c.tableoid, c.oid, c.relname, "
6255                                                   "c.relacl, NULL as rrelacl, "
6256                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6257                                                   "c.relkind, "
6258                                                   "c.relnamespace, "
6259                                                   "(%s c.relowner) AS rolname, "
6260                                                   "c.relchecks, c.relhastriggers, "
6261                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6262                                                   "'f'::bool AS relrowsecurity, "
6263                                                   "'f'::bool AS relforcerowsecurity, "
6264                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6265                                                   "tc.relfrozenxid AS tfrozenxid, "
6266                                                   "0 AS tminmxid, "
6267                                                   "c.relpersistence, 't' as relispopulated, "
6268                                                   "'d' AS relreplident, c.relpages, "
6269                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6270                                                   "d.refobjid AS owning_tab, "
6271                                                   "d.refobjsubid AS owning_col, "
6272                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6273                                                   "c.reloptions AS reloptions, "
6274                                                   "tc.reloptions AS toast_reloptions, "
6275                                                   "NULL AS changed_acl, "
6276                                                   "NULL AS partkeydef, "
6277                                                   "false AS ispartition, "
6278                                                   "NULL AS partbound "
6279                                                   "FROM pg_class c "
6280                                                   "LEFT JOIN pg_depend d ON "
6281                                                   "(c.relkind = '%c' AND "
6282                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6283                                                   "d.objsubid = 0 AND "
6284                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6285                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6286                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6287                                                   "ORDER BY c.oid",
6288                                                   username_subquery,
6289                                                   RELKIND_SEQUENCE,
6290                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6291                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6292                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6293         }
6294         else if (fout->remoteVersion >= 90000)
6295         {
6296                 /*
6297                  * Left join to pick up dependency info linking sequences to their
6298                  * owning column, if any (note this dependency is AUTO as of 8.2)
6299                  */
6300                 appendPQExpBuffer(query,
6301                                                   "SELECT c.tableoid, c.oid, c.relname, "
6302                                                   "c.relacl, NULL as rrelacl, "
6303                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6304                                                   "c.relkind, "
6305                                                   "c.relnamespace, "
6306                                                   "(%s c.relowner) AS rolname, "
6307                                                   "c.relchecks, c.relhastriggers, "
6308                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6309                                                   "'f'::bool AS relrowsecurity, "
6310                                                   "'f'::bool AS relforcerowsecurity, "
6311                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6312                                                   "tc.relfrozenxid AS tfrozenxid, "
6313                                                   "0 AS tminmxid, "
6314                                                   "'p' AS relpersistence, 't' as relispopulated, "
6315                                                   "'d' AS relreplident, c.relpages, "
6316                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6317                                                   "d.refobjid AS owning_tab, "
6318                                                   "d.refobjsubid AS owning_col, "
6319                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6320                                                   "c.reloptions AS reloptions, "
6321                                                   "tc.reloptions AS toast_reloptions, "
6322                                                   "NULL AS changed_acl, "
6323                                                   "NULL AS partkeydef, "
6324                                                   "false AS ispartition, "
6325                                                   "NULL AS partbound "
6326                                                   "FROM pg_class c "
6327                                                   "LEFT JOIN pg_depend d ON "
6328                                                   "(c.relkind = '%c' AND "
6329                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6330                                                   "d.objsubid = 0 AND "
6331                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6332                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6333                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6334                                                   "ORDER BY c.oid",
6335                                                   username_subquery,
6336                                                   RELKIND_SEQUENCE,
6337                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6338                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6339         }
6340         else if (fout->remoteVersion >= 80400)
6341         {
6342                 /*
6343                  * Left join to pick up dependency info linking sequences to their
6344                  * owning column, if any (note this dependency is AUTO as of 8.2)
6345                  */
6346                 appendPQExpBuffer(query,
6347                                                   "SELECT c.tableoid, c.oid, c.relname, "
6348                                                   "c.relacl, NULL as rrelacl, "
6349                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6350                                                   "c.relkind, "
6351                                                   "c.relnamespace, "
6352                                                   "(%s c.relowner) AS rolname, "
6353                                                   "c.relchecks, c.relhastriggers, "
6354                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6355                                                   "'f'::bool AS relrowsecurity, "
6356                                                   "'f'::bool AS relforcerowsecurity, "
6357                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6358                                                   "tc.relfrozenxid AS tfrozenxid, "
6359                                                   "0 AS tminmxid, "
6360                                                   "'p' AS relpersistence, 't' as relispopulated, "
6361                                                   "'d' AS relreplident, c.relpages, "
6362                                                   "NULL AS reloftype, "
6363                                                   "d.refobjid AS owning_tab, "
6364                                                   "d.refobjsubid AS owning_col, "
6365                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6366                                                   "c.reloptions AS reloptions, "
6367                                                   "tc.reloptions AS toast_reloptions, "
6368                                                   "NULL AS changed_acl, "
6369                                                   "NULL AS partkeydef, "
6370                                                   "false AS ispartition, "
6371                                                   "NULL AS partbound "
6372                                                   "FROM pg_class c "
6373                                                   "LEFT JOIN pg_depend d ON "
6374                                                   "(c.relkind = '%c' AND "
6375                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6376                                                   "d.objsubid = 0 AND "
6377                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6378                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6379                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6380                                                   "ORDER BY c.oid",
6381                                                   username_subquery,
6382                                                   RELKIND_SEQUENCE,
6383                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6384                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6385         }
6386         else if (fout->remoteVersion >= 80200)
6387         {
6388                 /*
6389                  * Left join to pick up dependency info linking sequences to their
6390                  * owning column, if any (note this dependency is AUTO as of 8.2)
6391                  */
6392                 appendPQExpBuffer(query,
6393                                                   "SELECT c.tableoid, c.oid, c.relname, "
6394                                                   "c.relacl, NULL as rrelacl, "
6395                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6396                                                   "c.relkind, "
6397                                                   "c.relnamespace, "
6398                                                   "(%s c.relowner) AS rolname, "
6399                                                   "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
6400                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6401                                                   "'f'::bool AS relrowsecurity, "
6402                                                   "'f'::bool AS relforcerowsecurity, "
6403                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6404                                                   "tc.relfrozenxid AS tfrozenxid, "
6405                                                   "0 AS tminmxid, "
6406                                                   "'p' AS relpersistence, 't' as relispopulated, "
6407                                                   "'d' AS relreplident, c.relpages, "
6408                                                   "NULL AS reloftype, "
6409                                                   "d.refobjid AS owning_tab, "
6410                                                   "d.refobjsubid AS owning_col, "
6411                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6412                                                   "c.reloptions AS reloptions, "
6413                                                   "NULL AS toast_reloptions, "
6414                                                   "NULL AS changed_acl, "
6415                                                   "NULL AS partkeydef, "
6416                                                   "false AS ispartition, "
6417                                                   "NULL AS partbound "
6418                                                   "FROM pg_class c "
6419                                                   "LEFT JOIN pg_depend d ON "
6420                                                   "(c.relkind = '%c' AND "
6421                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6422                                                   "d.objsubid = 0 AND "
6423                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6424                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6425                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6426                                                   "ORDER BY c.oid",
6427                                                   username_subquery,
6428                                                   RELKIND_SEQUENCE,
6429                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6430                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6431         }
6432         else
6433         {
6434                 /*
6435                  * Left join to pick up dependency info linking sequences to their
6436                  * owning column, if any
6437                  */
6438                 appendPQExpBuffer(query,
6439                                                   "SELECT c.tableoid, c.oid, relname, "
6440                                                   "relacl, NULL as rrelacl, "
6441                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6442                                                   "relkind, relnamespace, "
6443                                                   "(%s relowner) AS rolname, "
6444                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
6445                                                   "relhasindex, relhasrules, relhasoids, "
6446                                                   "'f'::bool AS relrowsecurity, "
6447                                                   "'f'::bool AS relforcerowsecurity, "
6448                                                   "0 AS relfrozenxid, 0 AS relminmxid,"
6449                                                   "0 AS toid, "
6450                                                   "0 AS tfrozenxid, 0 AS tminmxid,"
6451                                                   "'p' AS relpersistence, 't' as relispopulated, "
6452                                                   "'d' AS relreplident, relpages, "
6453                                                   "NULL AS reloftype, "
6454                                                   "d.refobjid AS owning_tab, "
6455                                                   "d.refobjsubid AS owning_col, "
6456                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6457                                                   "NULL AS reloptions, "
6458                                                   "NULL AS toast_reloptions, "
6459                                                   "NULL AS changed_acl, "
6460                                                   "NULL AS partkeydef, "
6461                                                   "false AS ispartition, "
6462                                                   "NULL AS partbound "
6463                                                   "FROM pg_class c "
6464                                                   "LEFT JOIN pg_depend d ON "
6465                                                   "(c.relkind = '%c' AND "
6466                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6467                                                   "d.objsubid = 0 AND "
6468                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
6469                                                   "WHERE relkind in ('%c', '%c', '%c', '%c') "
6470                                                   "ORDER BY c.oid",
6471                                                   username_subquery,
6472                                                   RELKIND_SEQUENCE,
6473                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6474                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6475         }
6476
6477         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6478
6479         ntups = PQntuples(res);
6480
6481         *numTables = ntups;
6482
6483         /*
6484          * Extract data from result and lock dumpable tables.  We do the locking
6485          * before anything else, to minimize the window wherein a table could
6486          * disappear under us.
6487          *
6488          * Note that we have to save info about all tables here, even when dumping
6489          * only one, because we don't yet know which tables might be inheritance
6490          * ancestors of the target table.
6491          */
6492         tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
6493
6494         i_reltableoid = PQfnumber(res, "tableoid");
6495         i_reloid = PQfnumber(res, "oid");
6496         i_relname = PQfnumber(res, "relname");
6497         i_relnamespace = PQfnumber(res, "relnamespace");
6498         i_relacl = PQfnumber(res, "relacl");
6499         i_rrelacl = PQfnumber(res, "rrelacl");
6500         i_initrelacl = PQfnumber(res, "initrelacl");
6501         i_initrrelacl = PQfnumber(res, "initrrelacl");
6502         i_relkind = PQfnumber(res, "relkind");
6503         i_rolname = PQfnumber(res, "rolname");
6504         i_relchecks = PQfnumber(res, "relchecks");
6505         i_relhastriggers = PQfnumber(res, "relhastriggers");
6506         i_relhasindex = PQfnumber(res, "relhasindex");
6507         i_relhasrules = PQfnumber(res, "relhasrules");
6508         i_relrowsec = PQfnumber(res, "relrowsecurity");
6509         i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
6510         i_relhasoids = PQfnumber(res, "relhasoids");
6511         i_relfrozenxid = PQfnumber(res, "relfrozenxid");
6512         i_relminmxid = PQfnumber(res, "relminmxid");
6513         i_toastoid = PQfnumber(res, "toid");
6514         i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
6515         i_toastminmxid = PQfnumber(res, "tminmxid");
6516         i_relpersistence = PQfnumber(res, "relpersistence");
6517         i_relispopulated = PQfnumber(res, "relispopulated");
6518         i_relreplident = PQfnumber(res, "relreplident");
6519         i_relpages = PQfnumber(res, "relpages");
6520         i_owning_tab = PQfnumber(res, "owning_tab");
6521         i_owning_col = PQfnumber(res, "owning_col");
6522         i_reltablespace = PQfnumber(res, "reltablespace");
6523         i_reloptions = PQfnumber(res, "reloptions");
6524         i_checkoption = PQfnumber(res, "checkoption");
6525         i_toastreloptions = PQfnumber(res, "toast_reloptions");
6526         i_reloftype = PQfnumber(res, "reloftype");
6527         i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
6528         i_changed_acl = PQfnumber(res, "changed_acl");
6529         i_partkeydef = PQfnumber(res, "partkeydef");
6530         i_ispartition = PQfnumber(res, "ispartition");
6531         i_partbound = PQfnumber(res, "partbound");
6532         i_amname = PQfnumber(res, "amname");
6533
6534         if (dopt->lockWaitTimeout)
6535         {
6536                 /*
6537                  * Arrange to fail instead of waiting forever for a table lock.
6538                  *
6539                  * NB: this coding assumes that the only queries issued within the
6540                  * following loop are LOCK TABLEs; else the timeout may be undesirably
6541                  * applied to other things too.
6542                  */
6543                 resetPQExpBuffer(query);
6544                 appendPQExpBufferStr(query, "SET statement_timeout = ");
6545                 appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
6546                 ExecuteSqlStatement(fout, query->data);
6547         }
6548
6549         for (i = 0; i < ntups; i++)
6550         {
6551                 tblinfo[i].dobj.objType = DO_TABLE;
6552                 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
6553                 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
6554                 AssignDumpId(&tblinfo[i].dobj);
6555                 tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
6556                 tblinfo[i].dobj.namespace =
6557                         findNamespace(fout,
6558                                                   atooid(PQgetvalue(res, i, i_relnamespace)));
6559                 tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6560                 tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
6561                 tblinfo[i].rrelacl = pg_strdup(PQgetvalue(res, i, i_rrelacl));
6562                 tblinfo[i].initrelacl = pg_strdup(PQgetvalue(res, i, i_initrelacl));
6563                 tblinfo[i].initrrelacl = pg_strdup(PQgetvalue(res, i, i_initrrelacl));
6564                 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
6565                 tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
6566                 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
6567                 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
6568                 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
6569                 tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
6570                 tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
6571                 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
6572                 tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
6573                 tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
6574                 tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
6575                 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
6576                 tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
6577                 tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
6578                 tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
6579                 tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
6580                 if (PQgetisnull(res, i, i_reloftype))
6581                         tblinfo[i].reloftype = NULL;
6582                 else
6583                         tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
6584                 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
6585                 if (PQgetisnull(res, i, i_owning_tab))
6586                 {
6587                         tblinfo[i].owning_tab = InvalidOid;
6588                         tblinfo[i].owning_col = 0;
6589                 }
6590                 else
6591                 {
6592                         tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
6593                         tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
6594                 }
6595                 tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
6596                 tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
6597                 if (i_checkoption == -1 || PQgetisnull(res, i, i_checkoption))
6598                         tblinfo[i].checkoption = NULL;
6599                 else
6600                         tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
6601                 tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
6602                 if (PQgetisnull(res, i, i_amname))
6603                         tblinfo[i].amname = NULL;
6604                 else
6605                         tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
6606
6607                 /* other fields were zeroed above */
6608
6609                 /*
6610                  * Decide whether we want to dump this table.
6611                  */
6612                 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
6613                         tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
6614                 else
6615                         selectDumpableTable(&tblinfo[i], fout);
6616
6617                 /*
6618                  * If the table-level and all column-level ACLs for this table are
6619                  * unchanged, then we don't need to worry about including the ACLs for
6620                  * this table.  If any column-level ACLs have been changed, the
6621                  * 'changed_acl' column from the query will indicate that.
6622                  *
6623                  * This can result in a significant performance improvement in cases
6624                  * where we are only looking to dump out the ACL (eg: pg_catalog).
6625                  */
6626                 if (PQgetisnull(res, i, i_relacl) && PQgetisnull(res, i, i_rrelacl) &&
6627                         PQgetisnull(res, i, i_initrelacl) &&
6628                         PQgetisnull(res, i, i_initrrelacl) &&
6629                         strcmp(PQgetvalue(res, i, i_changed_acl), "f") == 0)
6630                         tblinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
6631
6632                 tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
6633                 tblinfo[i].dummy_view = false;  /* might get set during sort */
6634                 tblinfo[i].postponed_def = false;       /* might get set during sort */
6635
6636                 tblinfo[i].is_identity_sequence = (i_is_identity_sequence >= 0 &&
6637                                                                                    strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
6638
6639                 /* Partition key string or NULL */
6640                 tblinfo[i].partkeydef = pg_strdup(PQgetvalue(res, i, i_partkeydef));
6641                 tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
6642                 tblinfo[i].partbound = pg_strdup(PQgetvalue(res, i, i_partbound));
6643
6644                 /*
6645                  * Read-lock target tables to make sure they aren't DROPPED or altered
6646                  * in schema before we get around to dumping them.
6647                  *
6648                  * Note that we don't explicitly lock parents of the target tables; we
6649                  * assume our lock on the child is enough to prevent schema
6650                  * alterations to parent tables.
6651                  *
6652                  * NOTE: it'd be kinda nice to lock other relations too, not only
6653                  * plain or partitioned tables, but the backend doesn't presently
6654                  * allow that.
6655                  *
6656                  * We only need to lock the table for certain components; see
6657                  * pg_dump.h
6658                  */
6659                 if (tblinfo[i].dobj.dump &&
6660                         (tblinfo[i].relkind == RELKIND_RELATION ||
6661                          tblinfo->relkind == RELKIND_PARTITIONED_TABLE) &&
6662                         (tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK))
6663                 {
6664                         resetPQExpBuffer(query);
6665                         appendPQExpBuffer(query,
6666                                                           "LOCK TABLE %s IN ACCESS SHARE MODE",
6667                                                           fmtQualifiedDumpable(&tblinfo[i]));
6668                         ExecuteSqlStatement(fout, query->data);
6669                 }
6670
6671                 /* Emit notice if join for owner failed */
6672                 if (strlen(tblinfo[i].rolname) == 0)
6673                         write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
6674                                           tblinfo[i].dobj.name);
6675         }
6676
6677         if (dopt->lockWaitTimeout)
6678         {
6679                 ExecuteSqlStatement(fout, "SET statement_timeout = 0");
6680         }
6681
6682         PQclear(res);
6683
6684         destroyPQExpBuffer(query);
6685
6686         return tblinfo;
6687 }
6688
6689 /*
6690  * getOwnedSeqs
6691  *        identify owned sequences and mark them as dumpable if owning table is
6692  *
6693  * We used to do this in getTables(), but it's better to do it after the
6694  * index used by findTableByOid() has been set up.
6695  */
6696 void
6697 getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
6698 {
6699         int                     i;
6700
6701         /*
6702          * Force sequences that are "owned" by table columns to be dumped whenever
6703          * their owning table is being dumped.
6704          */
6705         for (i = 0; i < numTables; i++)
6706         {
6707                 TableInfo  *seqinfo = &tblinfo[i];
6708                 TableInfo  *owning_tab;
6709
6710                 if (!OidIsValid(seqinfo->owning_tab))
6711                         continue;                       /* not an owned sequence */
6712
6713                 owning_tab = findTableByOid(seqinfo->owning_tab);
6714                 if (owning_tab == NULL)
6715                         exit_horribly(NULL, "failed sanity check, parent table with OID %u of sequence with OID %u not found\n",
6716                                                   seqinfo->owning_tab, seqinfo->dobj.catId.oid);
6717
6718                 /*
6719                  * Only dump identity sequences if we're going to dump the table that
6720                  * it belongs to.
6721                  */
6722                 if (owning_tab->dobj.dump == DUMP_COMPONENT_NONE &&
6723                         seqinfo->is_identity_sequence)
6724                 {
6725                         seqinfo->dobj.dump = DUMP_COMPONENT_NONE;
6726                         continue;
6727                 }
6728
6729                 /*
6730                  * Otherwise we need to dump the components that are being dumped for
6731                  * the table and any components which the sequence is explicitly
6732                  * marked with.
6733                  *
6734                  * We can't simply use the set of components which are being dumped
6735                  * for the table as the table might be in an extension (and only the
6736                  * non-extension components, eg: ACLs if changed, security labels, and
6737                  * policies, are being dumped) while the sequence is not (and
6738                  * therefore the definition and other components should also be
6739                  * dumped).
6740                  *
6741                  * If the sequence is part of the extension then it should be properly
6742                  * marked by checkExtensionMembership() and this will be a no-op as
6743                  * the table will be equivalently marked.
6744                  */
6745                 seqinfo->dobj.dump = seqinfo->dobj.dump | owning_tab->dobj.dump;
6746
6747                 if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
6748                         seqinfo->interesting = true;
6749         }
6750 }
6751
6752 /*
6753  * getInherits
6754  *        read all the inheritance information
6755  * from the system catalogs return them in the InhInfo* structure
6756  *
6757  * numInherits is set to the number of pairs read in
6758  */
6759 InhInfo *
6760 getInherits(Archive *fout, int *numInherits)
6761 {
6762         PGresult   *res;
6763         int                     ntups;
6764         int                     i;
6765         PQExpBuffer query = createPQExpBuffer();
6766         InhInfo    *inhinfo;
6767
6768         int                     i_inhrelid;
6769         int                     i_inhparent;
6770
6771         /*
6772          * Find all the inheritance information, excluding implicit inheritance
6773          * via partitioning.  We handle that case using getPartitions(), because
6774          * we want more information about partitions than just the parent-child
6775          * relationship.
6776          */
6777         appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
6778
6779         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6780
6781         ntups = PQntuples(res);
6782
6783         *numInherits = ntups;
6784
6785         inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
6786
6787         i_inhrelid = PQfnumber(res, "inhrelid");
6788         i_inhparent = PQfnumber(res, "inhparent");
6789
6790         for (i = 0; i < ntups; i++)
6791         {
6792                 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
6793                 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
6794         }
6795
6796         PQclear(res);
6797
6798         destroyPQExpBuffer(query);
6799
6800         return inhinfo;
6801 }
6802
6803 /*
6804  * getIndexes
6805  *        get information about every index on a dumpable table
6806  *
6807  * Note: index data is not returned directly to the caller, but it
6808  * does get entered into the DumpableObject tables.
6809  */
6810 void
6811 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
6812 {
6813         int                     i,
6814                                 j;
6815         PQExpBuffer query = createPQExpBuffer();
6816         PGresult   *res;
6817         IndxInfo   *indxinfo;
6818         ConstraintInfo *constrinfo;
6819         int                     i_tableoid,
6820                                 i_oid,
6821                                 i_indexname,
6822                                 i_parentidx,
6823                                 i_indexdef,
6824                                 i_indnkeyatts,
6825                                 i_indnatts,
6826                                 i_indkey,
6827                                 i_indisclustered,
6828                                 i_indisreplident,
6829                                 i_contype,
6830                                 i_conname,
6831                                 i_condeferrable,
6832                                 i_condeferred,
6833                                 i_contableoid,
6834                                 i_conoid,
6835                                 i_condef,
6836                                 i_tablespace,
6837                                 i_indreloptions,
6838                                 i_indstatcols,
6839                                 i_indstatvals;
6840         int                     ntups;
6841
6842         for (i = 0; i < numTables; i++)
6843         {
6844                 TableInfo  *tbinfo = &tblinfo[i];
6845
6846                 if (!tbinfo->hasindex)
6847                         continue;
6848
6849                 /*
6850                  * Ignore indexes of tables whose definitions are not to be dumped.
6851                  *
6852                  * We also need indexes on partitioned tables which have partitions to
6853                  * be dumped, in order to dump the indexes on the partitions.
6854                  */
6855                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION) &&
6856                         !tbinfo->interesting)
6857                         continue;
6858
6859                 if (g_verbose)
6860                         write_msg(NULL, "reading indexes for table \"%s.%s\"\n",
6861                                           tbinfo->dobj.namespace->dobj.name,
6862                                           tbinfo->dobj.name);
6863
6864                 /*
6865                  * The point of the messy-looking outer join is to find a constraint
6866                  * that is related by an internal dependency link to the index. If we
6867                  * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
6868                  * assume an index won't have more than one internal dependency.
6869                  *
6870                  * As of 9.0 we don't need to look at pg_depend but can check for a
6871                  * match to pg_constraint.conindid.  The check on conrelid is
6872                  * redundant but useful because that column is indexed while conindid
6873                  * is not.
6874                  */
6875                 resetPQExpBuffer(query);
6876                 if (fout->remoteVersion >= 110000)
6877                 {
6878                         appendPQExpBuffer(query,
6879                                                           "SELECT t.tableoid, t.oid, "
6880                                                           "t.relname AS indexname, "
6881                                                           "inh.inhparent AS parentidx, "
6882                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6883                                                           "i.indnkeyatts AS indnkeyatts, "
6884                                                           "i.indnatts AS indnatts, "
6885                                                           "i.indkey, i.indisclustered, "
6886                                                           "i.indisreplident, "
6887                                                           "c.contype, c.conname, "
6888                                                           "c.condeferrable, c.condeferred, "
6889                                                           "c.tableoid AS contableoid, "
6890                                                           "c.oid AS conoid, "
6891                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6892                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6893                                                           "t.reloptions AS indreloptions, "
6894                                                           "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
6895                                                           "  FROM pg_catalog.pg_attribute "
6896                                                           "  WHERE attrelid = i.indexrelid AND "
6897                                                           "    attstattarget >= 0) AS indstatcols,"
6898                                                           "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
6899                                                           "  FROM pg_catalog.pg_attribute "
6900                                                           "  WHERE attrelid = i.indexrelid AND "
6901                                                           "    attstattarget >= 0) AS indstatvals "
6902                                                           "FROM pg_catalog.pg_index i "
6903                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6904                                                           "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
6905                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6906                                                           "ON (i.indrelid = c.conrelid AND "
6907                                                           "i.indexrelid = c.conindid AND "
6908                                                           "c.contype IN ('p','u','x')) "
6909                                                           "LEFT JOIN pg_catalog.pg_inherits inh "
6910                                                           "ON (inh.inhrelid = indexrelid) "
6911                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6912                                                           "AND (i.indisvalid OR t2.relkind = 'p') "
6913                                                           "AND i.indisready "
6914                                                           "ORDER BY indexname",
6915                                                           tbinfo->dobj.catId.oid);
6916                 }
6917                 else if (fout->remoteVersion >= 90400)
6918                 {
6919                         /*
6920                          * the test on indisready is necessary in 9.2, and harmless in
6921                          * earlier/later versions
6922                          */
6923                         appendPQExpBuffer(query,
6924                                                           "SELECT t.tableoid, t.oid, "
6925                                                           "t.relname AS indexname, "
6926                                                           "0 AS parentidx, "
6927                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6928                                                           "i.indnatts AS indnkeyatts, "
6929                                                           "i.indnatts AS indnatts, "
6930                                                           "i.indkey, i.indisclustered, "
6931                                                           "i.indisreplident, "
6932                                                           "c.contype, c.conname, "
6933                                                           "c.condeferrable, c.condeferred, "
6934                                                           "c.tableoid AS contableoid, "
6935                                                           "c.oid AS conoid, "
6936                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6937                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6938                                                           "t.reloptions AS indreloptions, "
6939                                                           "'' AS indstatcols, "
6940                                                           "'' AS indstatvals "
6941                                                           "FROM pg_catalog.pg_index i "
6942                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6943                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6944                                                           "ON (i.indrelid = c.conrelid AND "
6945                                                           "i.indexrelid = c.conindid AND "
6946                                                           "c.contype IN ('p','u','x')) "
6947                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6948                                                           "AND i.indisvalid AND i.indisready "
6949                                                           "ORDER BY indexname",
6950                                                           tbinfo->dobj.catId.oid);
6951                 }
6952                 else if (fout->remoteVersion >= 90000)
6953                 {
6954                         /*
6955                          * the test on indisready is necessary in 9.2, and harmless in
6956                          * earlier/later versions
6957                          */
6958                         appendPQExpBuffer(query,
6959                                                           "SELECT t.tableoid, t.oid, "
6960                                                           "t.relname AS indexname, "
6961                                                           "0 AS parentidx, "
6962                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6963                                                           "i.indnatts AS indnkeyatts, "
6964                                                           "i.indnatts AS indnatts, "
6965                                                           "i.indkey, i.indisclustered, "
6966                                                           "false AS indisreplident, "
6967                                                           "c.contype, c.conname, "
6968                                                           "c.condeferrable, c.condeferred, "
6969                                                           "c.tableoid AS contableoid, "
6970                                                           "c.oid AS conoid, "
6971                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6972                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6973                                                           "t.reloptions AS indreloptions, "
6974                                                           "'' AS indstatcols, "
6975                                                           "'' AS indstatvals "
6976                                                           "FROM pg_catalog.pg_index i "
6977                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6978                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6979                                                           "ON (i.indrelid = c.conrelid AND "
6980                                                           "i.indexrelid = c.conindid AND "
6981                                                           "c.contype IN ('p','u','x')) "
6982                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6983                                                           "AND i.indisvalid AND i.indisready "
6984                                                           "ORDER BY indexname",
6985                                                           tbinfo->dobj.catId.oid);
6986                 }
6987                 else if (fout->remoteVersion >= 80200)
6988                 {
6989                         appendPQExpBuffer(query,
6990                                                           "SELECT t.tableoid, t.oid, "
6991                                                           "t.relname AS indexname, "
6992                                                           "0 AS parentidx, "
6993                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6994                                                           "i.indnatts AS indnkeyatts, "
6995                                                           "i.indnatts AS indnatts, "
6996                                                           "i.indkey, i.indisclustered, "
6997                                                           "false AS indisreplident, "
6998                                                           "c.contype, c.conname, "
6999                                                           "c.condeferrable, c.condeferred, "
7000                                                           "c.tableoid AS contableoid, "
7001                                                           "c.oid AS conoid, "
7002                                                           "null AS condef, "
7003                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
7004                                                           "t.reloptions AS indreloptions, "
7005                                                           "'' AS indstatcols, "
7006                                                           "'' AS indstatvals "
7007                                                           "FROM pg_catalog.pg_index i "
7008                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
7009                                                           "LEFT JOIN pg_catalog.pg_depend d "
7010                                                           "ON (d.classid = t.tableoid "
7011                                                           "AND d.objid = t.oid "
7012                                                           "AND d.deptype = 'i') "
7013                                                           "LEFT JOIN pg_catalog.pg_constraint c "
7014                                                           "ON (d.refclassid = c.tableoid "
7015                                                           "AND d.refobjid = c.oid) "
7016                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
7017                                                           "AND i.indisvalid "
7018                                                           "ORDER BY indexname",
7019                                                           tbinfo->dobj.catId.oid);
7020                 }
7021                 else
7022                 {
7023                         appendPQExpBuffer(query,
7024                                                           "SELECT t.tableoid, t.oid, "
7025                                                           "t.relname AS indexname, "
7026                                                           "0 AS parentidx, "
7027                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
7028                                                           "t.relnatts AS indnkeyatts, "
7029                                                           "t.relnatts AS indnatts, "
7030                                                           "i.indkey, i.indisclustered, "
7031                                                           "false AS indisreplident, "
7032                                                           "c.contype, c.conname, "
7033                                                           "c.condeferrable, c.condeferred, "
7034                                                           "c.tableoid AS contableoid, "
7035                                                           "c.oid AS conoid, "
7036                                                           "null AS condef, "
7037                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
7038                                                           "null AS indreloptions, "
7039                                                           "'' AS indstatcols, "
7040                                                           "'' AS indstatvals "
7041                                                           "FROM pg_catalog.pg_index i "
7042                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
7043                                                           "LEFT JOIN pg_catalog.pg_depend d "
7044                                                           "ON (d.classid = t.tableoid "
7045                                                           "AND d.objid = t.oid "
7046                                                           "AND d.deptype = 'i') "
7047                                                           "LEFT JOIN pg_catalog.pg_constraint c "
7048                                                           "ON (d.refclassid = c.tableoid "
7049                                                           "AND d.refobjid = c.oid) "
7050                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
7051                                                           "ORDER BY indexname",
7052                                                           tbinfo->dobj.catId.oid);
7053                 }
7054
7055                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7056
7057                 ntups = PQntuples(res);
7058
7059                 i_tableoid = PQfnumber(res, "tableoid");
7060                 i_oid = PQfnumber(res, "oid");
7061                 i_indexname = PQfnumber(res, "indexname");
7062                 i_parentidx = PQfnumber(res, "parentidx");
7063                 i_indexdef = PQfnumber(res, "indexdef");
7064                 i_indnkeyatts = PQfnumber(res, "indnkeyatts");
7065                 i_indnatts = PQfnumber(res, "indnatts");
7066                 i_indkey = PQfnumber(res, "indkey");
7067                 i_indisclustered = PQfnumber(res, "indisclustered");
7068                 i_indisreplident = PQfnumber(res, "indisreplident");
7069                 i_contype = PQfnumber(res, "contype");
7070                 i_conname = PQfnumber(res, "conname");
7071                 i_condeferrable = PQfnumber(res, "condeferrable");
7072                 i_condeferred = PQfnumber(res, "condeferred");
7073                 i_contableoid = PQfnumber(res, "contableoid");
7074                 i_conoid = PQfnumber(res, "conoid");
7075                 i_condef = PQfnumber(res, "condef");
7076                 i_tablespace = PQfnumber(res, "tablespace");
7077                 i_indreloptions = PQfnumber(res, "indreloptions");
7078                 i_indstatcols = PQfnumber(res, "indstatcols");
7079                 i_indstatvals = PQfnumber(res, "indstatvals");
7080
7081                 tbinfo->indexes = indxinfo =
7082                         (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
7083                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7084                 tbinfo->numIndexes = ntups;
7085
7086                 for (j = 0; j < ntups; j++)
7087                 {
7088                         char            contype;
7089
7090                         indxinfo[j].dobj.objType = DO_INDEX;
7091                         indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
7092                         indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7093                         AssignDumpId(&indxinfo[j].dobj);
7094                         indxinfo[j].dobj.dump = tbinfo->dobj.dump;
7095                         indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
7096                         indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7097                         indxinfo[j].indextable = tbinfo;
7098                         indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
7099                         indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
7100                         indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
7101                         indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
7102                         indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
7103                         indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
7104                         indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
7105                         indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
7106                         parseOidArray(PQgetvalue(res, j, i_indkey),
7107                                                   indxinfo[j].indkeys, indxinfo[j].indnattrs);
7108                         indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
7109                         indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
7110                         indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
7111                         contype = *(PQgetvalue(res, j, i_contype));
7112
7113                         if (contype == 'p' || contype == 'u' || contype == 'x')
7114                         {
7115                                 /*
7116                                  * If we found a constraint matching the index, create an
7117                                  * entry for it.
7118                                  */
7119                                 constrinfo[j].dobj.objType = DO_CONSTRAINT;
7120                                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7121                                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7122                                 AssignDumpId(&constrinfo[j].dobj);
7123                                 constrinfo[j].dobj.dump = tbinfo->dobj.dump;
7124                                 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7125                                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7126                                 constrinfo[j].contable = tbinfo;
7127                                 constrinfo[j].condomain = NULL;
7128                                 constrinfo[j].contype = contype;
7129                                 if (contype == 'x')
7130                                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
7131                                 else
7132                                         constrinfo[j].condef = NULL;
7133                                 constrinfo[j].confrelid = InvalidOid;
7134                                 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
7135                                 constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
7136                                 constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
7137                                 constrinfo[j].conislocal = true;
7138                                 constrinfo[j].separate = true;
7139
7140                                 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
7141                         }
7142                         else
7143                         {
7144                                 /* Plain secondary index */
7145                                 indxinfo[j].indexconstraint = 0;
7146                         }
7147                 }
7148
7149                 PQclear(res);
7150         }
7151
7152         destroyPQExpBuffer(query);
7153 }
7154
7155 /*
7156  * getExtendedStatistics
7157  *        get information about extended-statistics objects.
7158  *
7159  * Note: extended statistics data is not returned directly to the caller, but
7160  * it does get entered into the DumpableObject tables.
7161  */
7162 void
7163 getExtendedStatistics(Archive *fout)
7164 {
7165         PQExpBuffer query;
7166         PGresult   *res;
7167         StatsExtInfo *statsextinfo;
7168         int                     ntups;
7169         int                     i_tableoid;
7170         int                     i_oid;
7171         int                     i_stxname;
7172         int                     i_stxnamespace;
7173         int                     i_rolname;
7174         int                     i;
7175
7176         /* Extended statistics were new in v10 */
7177         if (fout->remoteVersion < 100000)
7178                 return;
7179
7180         query = createPQExpBuffer();
7181
7182         appendPQExpBuffer(query, "SELECT tableoid, oid, stxname, "
7183                                           "stxnamespace, (%s stxowner) AS rolname "
7184                                           "FROM pg_catalog.pg_statistic_ext",
7185                                           username_subquery);
7186
7187         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7188
7189         ntups = PQntuples(res);
7190
7191         i_tableoid = PQfnumber(res, "tableoid");
7192         i_oid = PQfnumber(res, "oid");
7193         i_stxname = PQfnumber(res, "stxname");
7194         i_stxnamespace = PQfnumber(res, "stxnamespace");
7195         i_rolname = PQfnumber(res, "rolname");
7196
7197         statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
7198
7199         for (i = 0; i < ntups; i++)
7200         {
7201                 statsextinfo[i].dobj.objType = DO_STATSEXT;
7202                 statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7203                 statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7204                 AssignDumpId(&statsextinfo[i].dobj);
7205                 statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
7206                 statsextinfo[i].dobj.namespace =
7207                         findNamespace(fout,
7208                                                   atooid(PQgetvalue(res, i, i_stxnamespace)));
7209                 statsextinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7210
7211                 /* Decide whether we want to dump it */
7212                 selectDumpableObject(&(statsextinfo[i].dobj), fout);
7213
7214                 /* Stats objects do not currently have ACLs. */
7215                 statsextinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7216         }
7217
7218         PQclear(res);
7219         destroyPQExpBuffer(query);
7220 }
7221
7222 /*
7223  * getConstraints
7224  *
7225  * Get info about constraints on dumpable tables.
7226  *
7227  * Currently handles foreign keys only.
7228  * Unique and primary key constraints are handled with indexes,
7229  * while check constraints are processed in getTableAttrs().
7230  */
7231 void
7232 getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
7233 {
7234         int                     i,
7235                                 j;
7236         ConstraintInfo *constrinfo;
7237         PQExpBuffer query;
7238         PGresult   *res;
7239         int                     i_contableoid,
7240                                 i_conoid,
7241                                 i_conname,
7242                                 i_confrelid,
7243                                 i_condef;
7244         int                     ntups;
7245
7246         query = createPQExpBuffer();
7247
7248         for (i = 0; i < numTables; i++)
7249         {
7250                 TableInfo  *tbinfo = &tblinfo[i];
7251
7252                 /*
7253                  * For partitioned tables, foreign keys have no triggers so they must
7254                  * be included anyway in case some foreign keys are defined.
7255                  */
7256                 if ((!tbinfo->hastriggers &&
7257                          tbinfo->relkind != RELKIND_PARTITIONED_TABLE) ||
7258                         !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7259                         continue;
7260
7261                 if (g_verbose)
7262                         write_msg(NULL, "reading foreign key constraints for table \"%s.%s\"\n",
7263                                           tbinfo->dobj.namespace->dobj.name,
7264                                           tbinfo->dobj.name);
7265
7266                 resetPQExpBuffer(query);
7267                 if (fout->remoteVersion >= 110000)
7268                         appendPQExpBuffer(query,
7269                                                           "SELECT tableoid, oid, conname, confrelid, "
7270                                                           "pg_catalog.pg_get_constraintdef(oid) AS condef "
7271                                                           "FROM pg_catalog.pg_constraint "
7272                                                           "WHERE conrelid = '%u'::pg_catalog.oid "
7273                                                           "AND conparentid = 0 "
7274                                                           "AND contype = 'f'",
7275                                                           tbinfo->dobj.catId.oid);
7276                 else
7277                         appendPQExpBuffer(query,
7278                                                           "SELECT tableoid, oid, conname, confrelid, "
7279                                                           "pg_catalog.pg_get_constraintdef(oid) AS condef "
7280                                                           "FROM pg_catalog.pg_constraint "
7281                                                           "WHERE conrelid = '%u'::pg_catalog.oid "
7282                                                           "AND contype = 'f'",
7283                                                           tbinfo->dobj.catId.oid);
7284                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7285
7286                 ntups = PQntuples(res);
7287
7288                 i_contableoid = PQfnumber(res, "tableoid");
7289                 i_conoid = PQfnumber(res, "oid");
7290                 i_conname = PQfnumber(res, "conname");
7291                 i_confrelid = PQfnumber(res, "confrelid");
7292                 i_condef = PQfnumber(res, "condef");
7293
7294                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7295
7296                 for (j = 0; j < ntups; j++)
7297                 {
7298                         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
7299                         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7300                         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7301                         AssignDumpId(&constrinfo[j].dobj);
7302                         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7303                         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7304                         constrinfo[j].contable = tbinfo;
7305                         constrinfo[j].condomain = NULL;
7306                         constrinfo[j].contype = 'f';
7307                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
7308                         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
7309                         constrinfo[j].conindex = 0;
7310                         constrinfo[j].condeferrable = false;
7311                         constrinfo[j].condeferred = false;
7312                         constrinfo[j].conislocal = true;
7313                         constrinfo[j].separate = true;
7314                 }
7315
7316                 PQclear(res);
7317         }
7318
7319         destroyPQExpBuffer(query);
7320 }
7321
7322 /*
7323  * getDomainConstraints
7324  *
7325  * Get info about constraints on a domain.
7326  */
7327 static void
7328 getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
7329 {
7330         int                     i;
7331         ConstraintInfo *constrinfo;
7332         PQExpBuffer query;
7333         PGresult   *res;
7334         int                     i_tableoid,
7335                                 i_oid,
7336                                 i_conname,
7337                                 i_consrc;
7338         int                     ntups;
7339
7340         query = createPQExpBuffer();
7341
7342         if (fout->remoteVersion >= 90100)
7343                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
7344                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7345                                                   "convalidated "
7346                                                   "FROM pg_catalog.pg_constraint "
7347                                                   "WHERE contypid = '%u'::pg_catalog.oid "
7348                                                   "ORDER BY conname",
7349                                                   tyinfo->dobj.catId.oid);
7350
7351         else
7352                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
7353                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7354                                                   "true as convalidated "
7355                                                   "FROM pg_catalog.pg_constraint "
7356                                                   "WHERE contypid = '%u'::pg_catalog.oid "
7357                                                   "ORDER BY conname",
7358                                                   tyinfo->dobj.catId.oid);
7359
7360         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7361
7362         ntups = PQntuples(res);
7363
7364         i_tableoid = PQfnumber(res, "tableoid");
7365         i_oid = PQfnumber(res, "oid");
7366         i_conname = PQfnumber(res, "conname");
7367         i_consrc = PQfnumber(res, "consrc");
7368
7369         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7370
7371         tyinfo->nDomChecks = ntups;
7372         tyinfo->domChecks = constrinfo;
7373
7374         for (i = 0; i < ntups; i++)
7375         {
7376                 bool            validated = PQgetvalue(res, i, 4)[0] == 't';
7377
7378                 constrinfo[i].dobj.objType = DO_CONSTRAINT;
7379                 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7380                 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7381                 AssignDumpId(&constrinfo[i].dobj);
7382                 constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
7383                 constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
7384                 constrinfo[i].contable = NULL;
7385                 constrinfo[i].condomain = tyinfo;
7386                 constrinfo[i].contype = 'c';
7387                 constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
7388                 constrinfo[i].confrelid = InvalidOid;
7389                 constrinfo[i].conindex = 0;
7390                 constrinfo[i].condeferrable = false;
7391                 constrinfo[i].condeferred = false;
7392                 constrinfo[i].conislocal = true;
7393
7394                 constrinfo[i].separate = !validated;
7395
7396                 /*
7397                  * Make the domain depend on the constraint, ensuring it won't be
7398                  * output till any constraint dependencies are OK.  If the constraint
7399                  * has not been validated, it's going to be dumped after the domain
7400                  * anyway, so this doesn't matter.
7401                  */
7402                 if (validated)
7403                         addObjectDependency(&tyinfo->dobj,
7404                                                                 constrinfo[i].dobj.dumpId);
7405         }
7406
7407         PQclear(res);
7408
7409         destroyPQExpBuffer(query);
7410 }
7411
7412 /*
7413  * getRules
7414  *        get basic information about every rule in the system
7415  *
7416  * numRules is set to the number of rules read in
7417  */
7418 RuleInfo *
7419 getRules(Archive *fout, int *numRules)
7420 {
7421         PGresult   *res;
7422         int                     ntups;
7423         int                     i;
7424         PQExpBuffer query = createPQExpBuffer();
7425         RuleInfo   *ruleinfo;
7426         int                     i_tableoid;
7427         int                     i_oid;
7428         int                     i_rulename;
7429         int                     i_ruletable;
7430         int                     i_ev_type;
7431         int                     i_is_instead;
7432         int                     i_ev_enabled;
7433
7434         if (fout->remoteVersion >= 80300)
7435         {
7436                 appendPQExpBufferStr(query, "SELECT "
7437                                                          "tableoid, oid, rulename, "
7438                                                          "ev_class AS ruletable, ev_type, is_instead, "
7439                                                          "ev_enabled "
7440                                                          "FROM pg_rewrite "
7441                                                          "ORDER BY oid");
7442         }
7443         else
7444         {
7445                 appendPQExpBufferStr(query, "SELECT "
7446                                                          "tableoid, oid, rulename, "
7447                                                          "ev_class AS ruletable, ev_type, is_instead, "
7448                                                          "'O'::char AS ev_enabled "
7449                                                          "FROM pg_rewrite "
7450                                                          "ORDER BY oid");
7451         }
7452
7453         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7454
7455         ntups = PQntuples(res);
7456
7457         *numRules = ntups;
7458
7459         ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
7460
7461         i_tableoid = PQfnumber(res, "tableoid");
7462         i_oid = PQfnumber(res, "oid");
7463         i_rulename = PQfnumber(res, "rulename");
7464         i_ruletable = PQfnumber(res, "ruletable");
7465         i_ev_type = PQfnumber(res, "ev_type");
7466         i_is_instead = PQfnumber(res, "is_instead");
7467         i_ev_enabled = PQfnumber(res, "ev_enabled");
7468
7469         for (i = 0; i < ntups; i++)
7470         {
7471                 Oid                     ruletableoid;
7472
7473                 ruleinfo[i].dobj.objType = DO_RULE;
7474                 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7475                 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7476                 AssignDumpId(&ruleinfo[i].dobj);
7477                 ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
7478                 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
7479                 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
7480                 if (ruleinfo[i].ruletable == NULL)
7481                         exit_horribly(NULL, "failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found\n",
7482                                                   ruletableoid, ruleinfo[i].dobj.catId.oid);
7483                 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
7484                 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
7485                 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
7486                 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
7487                 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
7488                 if (ruleinfo[i].ruletable)
7489                 {
7490                         /*
7491                          * If the table is a view or materialized view, force its ON
7492                          * SELECT rule to be sorted before the view itself --- this
7493                          * ensures that any dependencies for the rule affect the table's
7494                          * positioning. Other rules are forced to appear after their
7495                          * table.
7496                          */
7497                         if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
7498                                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
7499                                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
7500                         {
7501                                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
7502                                                                         ruleinfo[i].dobj.dumpId);
7503                                 /* We'll merge the rule into CREATE VIEW, if possible */
7504                                 ruleinfo[i].separate = false;
7505                         }
7506                         else
7507                         {
7508                                 addObjectDependency(&ruleinfo[i].dobj,
7509                                                                         ruleinfo[i].ruletable->dobj.dumpId);
7510                                 ruleinfo[i].separate = true;
7511                         }
7512                 }
7513                 else
7514                         ruleinfo[i].separate = true;
7515         }
7516
7517         PQclear(res);
7518
7519         destroyPQExpBuffer(query);
7520
7521         return ruleinfo;
7522 }
7523
7524 /*
7525  * getTriggers
7526  *        get information about every trigger on a dumpable table
7527  *
7528  * Note: trigger data is not returned directly to the caller, but it
7529  * does get entered into the DumpableObject tables.
7530  */
7531 void
7532 getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
7533 {
7534         int                     i,
7535                                 j;
7536         PQExpBuffer query = createPQExpBuffer();
7537         PGresult   *res;
7538         TriggerInfo *tginfo;
7539         int                     i_tableoid,
7540                                 i_oid,
7541                                 i_tgname,
7542                                 i_tgfname,
7543                                 i_tgtype,
7544                                 i_tgnargs,
7545                                 i_tgargs,
7546                                 i_tgisconstraint,
7547                                 i_tgconstrname,
7548                                 i_tgconstrrelid,
7549                                 i_tgconstrrelname,
7550                                 i_tgenabled,
7551                                 i_tgdeferrable,
7552                                 i_tginitdeferred,
7553                                 i_tgdef;
7554         int                     ntups;
7555
7556         for (i = 0; i < numTables; i++)
7557         {
7558                 TableInfo  *tbinfo = &tblinfo[i];
7559
7560                 if (!tbinfo->hastriggers ||
7561                         !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7562                         continue;
7563
7564                 if (g_verbose)
7565                         write_msg(NULL, "reading triggers for table \"%s.%s\"\n",
7566                                           tbinfo->dobj.namespace->dobj.name,
7567                                           tbinfo->dobj.name);
7568
7569                 resetPQExpBuffer(query);
7570                 if (fout->remoteVersion >= 90000)
7571                 {
7572                         /*
7573                          * NB: think not to use pretty=true in pg_get_triggerdef.  It
7574                          * could result in non-forward-compatible dumps of WHEN clauses
7575                          * due to under-parenthesization.
7576                          */
7577                         appendPQExpBuffer(query,
7578                                                           "SELECT tgname, "
7579                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7580                                                           "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
7581                                                           "tgenabled, tableoid, oid "
7582                                                           "FROM pg_catalog.pg_trigger t "
7583                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7584                                                           "AND NOT tgisinternal",
7585                                                           tbinfo->dobj.catId.oid);
7586                 }
7587                 else if (fout->remoteVersion >= 80300)
7588                 {
7589                         /*
7590                          * We ignore triggers that are tied to a foreign-key constraint
7591                          */
7592                         appendPQExpBuffer(query,
7593                                                           "SELECT tgname, "
7594                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7595                                                           "tgtype, tgnargs, tgargs, tgenabled, "
7596                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
7597                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
7598                                                           "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
7599                                                           "FROM pg_catalog.pg_trigger t "
7600                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7601                                                           "AND tgconstraint = 0",
7602                                                           tbinfo->dobj.catId.oid);
7603                 }
7604                 else
7605                 {
7606                         /*
7607                          * We ignore triggers that are tied to a foreign-key constraint,
7608                          * but in these versions we have to grovel through pg_constraint
7609                          * to find out
7610                          */
7611                         appendPQExpBuffer(query,
7612                                                           "SELECT tgname, "
7613                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7614                                                           "tgtype, tgnargs, tgargs, tgenabled, "
7615                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
7616                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
7617                                                           "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
7618                                                           "FROM pg_catalog.pg_trigger t "
7619                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7620                                                           "AND (NOT tgisconstraint "
7621                                                           " OR NOT EXISTS"
7622                                                           "  (SELECT 1 FROM pg_catalog.pg_depend d "
7623                                                           "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
7624                                                           "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
7625                                                           tbinfo->dobj.catId.oid);
7626                 }
7627
7628                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7629
7630                 ntups = PQntuples(res);
7631
7632                 i_tableoid = PQfnumber(res, "tableoid");
7633                 i_oid = PQfnumber(res, "oid");
7634                 i_tgname = PQfnumber(res, "tgname");
7635                 i_tgfname = PQfnumber(res, "tgfname");
7636                 i_tgtype = PQfnumber(res, "tgtype");
7637                 i_tgnargs = PQfnumber(res, "tgnargs");
7638                 i_tgargs = PQfnumber(res, "tgargs");
7639                 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
7640                 i_tgconstrname = PQfnumber(res, "tgconstrname");
7641                 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
7642                 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
7643                 i_tgenabled = PQfnumber(res, "tgenabled");
7644                 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
7645                 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
7646                 i_tgdef = PQfnumber(res, "tgdef");
7647
7648                 tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
7649
7650                 tbinfo->numTriggers = ntups;
7651                 tbinfo->triggers = tginfo;
7652
7653                 for (j = 0; j < ntups; j++)
7654                 {
7655                         tginfo[j].dobj.objType = DO_TRIGGER;
7656                         tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
7657                         tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7658                         AssignDumpId(&tginfo[j].dobj);
7659                         tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
7660                         tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
7661                         tginfo[j].tgtable = tbinfo;
7662                         tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
7663                         if (i_tgdef >= 0)
7664                         {
7665                                 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
7666
7667                                 /* remaining fields are not valid if we have tgdef */
7668                                 tginfo[j].tgfname = NULL;
7669                                 tginfo[j].tgtype = 0;
7670                                 tginfo[j].tgnargs = 0;
7671                                 tginfo[j].tgargs = NULL;
7672                                 tginfo[j].tgisconstraint = false;
7673                                 tginfo[j].tgdeferrable = false;
7674                                 tginfo[j].tginitdeferred = false;
7675                                 tginfo[j].tgconstrname = NULL;
7676                                 tginfo[j].tgconstrrelid = InvalidOid;
7677                                 tginfo[j].tgconstrrelname = NULL;
7678                         }
7679                         else
7680                         {
7681                                 tginfo[j].tgdef = NULL;
7682
7683                                 tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
7684                                 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
7685                                 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
7686                                 tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
7687                                 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
7688                                 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
7689                                 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
7690
7691                                 if (tginfo[j].tgisconstraint)
7692                                 {
7693                                         tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
7694                                         tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
7695                                         if (OidIsValid(tginfo[j].tgconstrrelid))
7696                                         {
7697                                                 if (PQgetisnull(res, j, i_tgconstrrelname))
7698                                                         exit_horribly(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
7699                                                                                   tginfo[j].dobj.name,
7700                                                                                   tbinfo->dobj.name,
7701                                                                                   tginfo[j].tgconstrrelid);
7702                                                 tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
7703                                         }
7704                                         else
7705                                                 tginfo[j].tgconstrrelname = NULL;
7706                                 }
7707                                 else
7708                                 {
7709                                         tginfo[j].tgconstrname = NULL;
7710                                         tginfo[j].tgconstrrelid = InvalidOid;
7711                                         tginfo[j].tgconstrrelname = NULL;
7712                                 }
7713                         }
7714                 }
7715
7716                 PQclear(res);
7717         }
7718
7719         destroyPQExpBuffer(query);
7720 }
7721
7722 /*
7723  * getEventTriggers
7724  *        get information about event triggers
7725  */
7726 EventTriggerInfo *
7727 getEventTriggers(Archive *fout, int *numEventTriggers)
7728 {
7729         int                     i;
7730         PQExpBuffer query;
7731         PGresult   *res;
7732         EventTriggerInfo *evtinfo;
7733         int                     i_tableoid,
7734                                 i_oid,
7735                                 i_evtname,
7736                                 i_evtevent,
7737                                 i_evtowner,
7738                                 i_evttags,
7739                                 i_evtfname,
7740                                 i_evtenabled;
7741         int                     ntups;
7742
7743         /* Before 9.3, there are no event triggers */
7744         if (fout->remoteVersion < 90300)
7745         {
7746                 *numEventTriggers = 0;
7747                 return NULL;
7748         }
7749
7750         query = createPQExpBuffer();
7751
7752         appendPQExpBuffer(query,
7753                                           "SELECT e.tableoid, e.oid, evtname, evtenabled, "
7754                                           "evtevent, (%s evtowner) AS evtowner, "
7755                                           "array_to_string(array("
7756                                           "select quote_literal(x) "
7757                                           " from unnest(evttags) as t(x)), ', ') as evttags, "
7758                                           "e.evtfoid::regproc as evtfname "
7759                                           "FROM pg_event_trigger e "
7760                                           "ORDER BY e.oid",
7761                                           username_subquery);
7762
7763         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7764
7765         ntups = PQntuples(res);
7766
7767         *numEventTriggers = ntups;
7768
7769         evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
7770
7771         i_tableoid = PQfnumber(res, "tableoid");
7772         i_oid = PQfnumber(res, "oid");
7773         i_evtname = PQfnumber(res, "evtname");
7774         i_evtevent = PQfnumber(res, "evtevent");
7775         i_evtowner = PQfnumber(res, "evtowner");
7776         i_evttags = PQfnumber(res, "evttags");
7777         i_evtfname = PQfnumber(res, "evtfname");
7778         i_evtenabled = PQfnumber(res, "evtenabled");
7779
7780         for (i = 0; i < ntups; i++)
7781         {
7782                 evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
7783                 evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7784                 evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7785                 AssignDumpId(&evtinfo[i].dobj);
7786                 evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
7787                 evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
7788                 evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
7789                 evtinfo[i].evtowner = pg_strdup(PQgetvalue(res, i, i_evtowner));
7790                 evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
7791                 evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
7792                 evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
7793
7794                 /* Decide whether we want to dump it */
7795                 selectDumpableObject(&(evtinfo[i].dobj), fout);
7796
7797                 /* Event Triggers do not currently have ACLs. */
7798                 evtinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7799         }
7800
7801         PQclear(res);
7802
7803         destroyPQExpBuffer(query);
7804
7805         return evtinfo;
7806 }
7807
7808 /*
7809  * getProcLangs
7810  *        get basic information about every procedural language in the system
7811  *
7812  * numProcLangs is set to the number of langs read in
7813  *
7814  * NB: this must run after getFuncs() because we assume we can do
7815  * findFuncByOid().
7816  */
7817 ProcLangInfo *
7818 getProcLangs(Archive *fout, int *numProcLangs)
7819 {
7820         DumpOptions *dopt = fout->dopt;
7821         PGresult   *res;
7822         int                     ntups;
7823         int                     i;
7824         PQExpBuffer query = createPQExpBuffer();
7825         ProcLangInfo *planginfo;
7826         int                     i_tableoid;
7827         int                     i_oid;
7828         int                     i_lanname;
7829         int                     i_lanpltrusted;
7830         int                     i_lanplcallfoid;
7831         int                     i_laninline;
7832         int                     i_lanvalidator;
7833         int                     i_lanacl;
7834         int                     i_rlanacl;
7835         int                     i_initlanacl;
7836         int                     i_initrlanacl;
7837         int                     i_lanowner;
7838
7839         if (fout->remoteVersion >= 90600)
7840         {
7841                 PQExpBuffer acl_subquery = createPQExpBuffer();
7842                 PQExpBuffer racl_subquery = createPQExpBuffer();
7843                 PQExpBuffer initacl_subquery = createPQExpBuffer();
7844                 PQExpBuffer initracl_subquery = createPQExpBuffer();
7845
7846                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
7847                                                 initracl_subquery, "l.lanacl", "l.lanowner", "'l'",
7848                                                 dopt->binary_upgrade);
7849
7850                 /* pg_language has a laninline column */
7851                 appendPQExpBuffer(query, "SELECT l.tableoid, l.oid, "
7852                                                   "l.lanname, l.lanpltrusted, l.lanplcallfoid, "
7853                                                   "l.laninline, l.lanvalidator, "
7854                                                   "%s AS lanacl, "
7855                                                   "%s AS rlanacl, "
7856                                                   "%s AS initlanacl, "
7857                                                   "%s AS initrlanacl, "
7858                                                   "(%s l.lanowner) AS lanowner "
7859                                                   "FROM pg_language l "
7860                                                   "LEFT JOIN pg_init_privs pip ON "
7861                                                   "(l.oid = pip.objoid "
7862                                                   "AND pip.classoid = 'pg_language'::regclass "
7863                                                   "AND pip.objsubid = 0) "
7864                                                   "WHERE l.lanispl "
7865                                                   "ORDER BY l.oid",
7866                                                   acl_subquery->data,
7867                                                   racl_subquery->data,
7868                                                   initacl_subquery->data,
7869                                                   initracl_subquery->data,
7870                                                   username_subquery);
7871
7872                 destroyPQExpBuffer(acl_subquery);
7873                 destroyPQExpBuffer(racl_subquery);
7874                 destroyPQExpBuffer(initacl_subquery);
7875                 destroyPQExpBuffer(initracl_subquery);
7876         }
7877         else if (fout->remoteVersion >= 90000)
7878         {
7879                 /* pg_language has a laninline column */
7880                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7881                                                   "lanname, lanpltrusted, lanplcallfoid, "
7882                                                   "laninline, lanvalidator, lanacl, NULL AS rlanacl, "
7883                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7884                                                   "(%s lanowner) AS lanowner "
7885                                                   "FROM pg_language "
7886                                                   "WHERE lanispl "
7887                                                   "ORDER BY oid",
7888                                                   username_subquery);
7889         }
7890         else if (fout->remoteVersion >= 80300)
7891         {
7892                 /* pg_language has a lanowner column */
7893                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7894                                                   "lanname, lanpltrusted, lanplcallfoid, "
7895                                                   "0 AS laninline, lanvalidator, lanacl, "
7896                                                   "NULL AS rlanacl, "
7897                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7898                                                   "(%s lanowner) AS lanowner "
7899                                                   "FROM pg_language "
7900                                                   "WHERE lanispl "
7901                                                   "ORDER BY oid",
7902                                                   username_subquery);
7903         }
7904         else if (fout->remoteVersion >= 80100)
7905         {
7906                 /* Languages are owned by the bootstrap superuser, OID 10 */
7907                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7908                                                   "lanname, lanpltrusted, lanplcallfoid, "
7909                                                   "0 AS laninline, lanvalidator, lanacl, "
7910                                                   "NULL AS rlanacl, "
7911                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7912                                                   "(%s '10') AS lanowner "
7913                                                   "FROM pg_language "
7914                                                   "WHERE lanispl "
7915                                                   "ORDER BY oid",
7916                                                   username_subquery);
7917         }
7918         else
7919         {
7920                 /* Languages are owned by the bootstrap superuser, sysid 1 */
7921                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7922                                                   "lanname, lanpltrusted, lanplcallfoid, "
7923                                                   "0 AS laninline, lanvalidator, lanacl, "
7924                                                   "NULL AS rlanacl, "
7925                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7926                                                   "(%s '1') AS lanowner "
7927                                                   "FROM pg_language "
7928                                                   "WHERE lanispl "
7929                                                   "ORDER BY oid",
7930                                                   username_subquery);
7931         }
7932
7933         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7934
7935         ntups = PQntuples(res);
7936
7937         *numProcLangs = ntups;
7938
7939         planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
7940
7941         i_tableoid = PQfnumber(res, "tableoid");
7942         i_oid = PQfnumber(res, "oid");
7943         i_lanname = PQfnumber(res, "lanname");
7944         i_lanpltrusted = PQfnumber(res, "lanpltrusted");
7945         i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
7946         i_laninline = PQfnumber(res, "laninline");
7947         i_lanvalidator = PQfnumber(res, "lanvalidator");
7948         i_lanacl = PQfnumber(res, "lanacl");
7949         i_rlanacl = PQfnumber(res, "rlanacl");
7950         i_initlanacl = PQfnumber(res, "initlanacl");
7951         i_initrlanacl = PQfnumber(res, "initrlanacl");
7952         i_lanowner = PQfnumber(res, "lanowner");
7953
7954         for (i = 0; i < ntups; i++)
7955         {
7956                 planginfo[i].dobj.objType = DO_PROCLANG;
7957                 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7958                 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7959                 AssignDumpId(&planginfo[i].dobj);
7960
7961                 planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
7962                 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
7963                 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
7964                 planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
7965                 planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
7966                 planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
7967                 planginfo[i].rlanacl = pg_strdup(PQgetvalue(res, i, i_rlanacl));
7968                 planginfo[i].initlanacl = pg_strdup(PQgetvalue(res, i, i_initlanacl));
7969                 planginfo[i].initrlanacl = pg_strdup(PQgetvalue(res, i, i_initrlanacl));
7970                 planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
7971
7972                 /* Decide whether we want to dump it */
7973                 selectDumpableProcLang(&(planginfo[i]), fout);
7974
7975                 /* Do not try to dump ACL if no ACL exists. */
7976                 if (PQgetisnull(res, i, i_lanacl) && PQgetisnull(res, i, i_rlanacl) &&
7977                         PQgetisnull(res, i, i_initlanacl) &&
7978                         PQgetisnull(res, i, i_initrlanacl))
7979                         planginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7980         }
7981
7982         PQclear(res);
7983
7984         destroyPQExpBuffer(query);
7985
7986         return planginfo;
7987 }
7988
7989 /*
7990  * getCasts
7991  *        get basic information about every cast in the system
7992  *
7993  * numCasts is set to the number of casts read in
7994  */
7995 CastInfo *
7996 getCasts(Archive *fout, int *numCasts)
7997 {
7998         PGresult   *res;
7999         int                     ntups;
8000         int                     i;
8001         PQExpBuffer query = createPQExpBuffer();
8002         CastInfo   *castinfo;
8003         int                     i_tableoid;
8004         int                     i_oid;
8005         int                     i_castsource;
8006         int                     i_casttarget;
8007         int                     i_castfunc;
8008         int                     i_castcontext;
8009         int                     i_castmethod;
8010
8011         if (fout->remoteVersion >= 80400)
8012         {
8013                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8014                                                          "castsource, casttarget, castfunc, castcontext, "
8015                                                          "castmethod "
8016                                                          "FROM pg_cast ORDER BY 3,4");
8017         }
8018         else
8019         {
8020                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8021                                                          "castsource, casttarget, castfunc, castcontext, "
8022                                                          "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
8023                                                          "FROM pg_cast ORDER BY 3,4");
8024         }
8025
8026         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8027
8028         ntups = PQntuples(res);
8029
8030         *numCasts = ntups;
8031
8032         castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
8033
8034         i_tableoid = PQfnumber(res, "tableoid");
8035         i_oid = PQfnumber(res, "oid");
8036         i_castsource = PQfnumber(res, "castsource");
8037         i_casttarget = PQfnumber(res, "casttarget");
8038         i_castfunc = PQfnumber(res, "castfunc");
8039         i_castcontext = PQfnumber(res, "castcontext");
8040         i_castmethod = PQfnumber(res, "castmethod");
8041
8042         for (i = 0; i < ntups; i++)
8043         {
8044                 PQExpBufferData namebuf;
8045                 TypeInfo   *sTypeInfo;
8046                 TypeInfo   *tTypeInfo;
8047
8048                 castinfo[i].dobj.objType = DO_CAST;
8049                 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8050                 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8051                 AssignDumpId(&castinfo[i].dobj);
8052                 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
8053                 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
8054                 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
8055                 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
8056                 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
8057
8058                 /*
8059                  * Try to name cast as concatenation of typnames.  This is only used
8060                  * for purposes of sorting.  If we fail to find either type, the name
8061                  * will be an empty string.
8062                  */
8063                 initPQExpBuffer(&namebuf);
8064                 sTypeInfo = findTypeByOid(castinfo[i].castsource);
8065                 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
8066                 if (sTypeInfo && tTypeInfo)
8067                         appendPQExpBuffer(&namebuf, "%s %s",
8068                                                           sTypeInfo->dobj.name, tTypeInfo->dobj.name);
8069                 castinfo[i].dobj.name = namebuf.data;
8070
8071                 /* Decide whether we want to dump it */
8072                 selectDumpableCast(&(castinfo[i]), fout);
8073
8074                 /* Casts do not currently have ACLs. */
8075                 castinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8076         }
8077
8078         PQclear(res);
8079
8080         destroyPQExpBuffer(query);
8081
8082         return castinfo;
8083 }
8084
8085 static char *
8086 get_language_name(Archive *fout, Oid langid)
8087 {
8088         PQExpBuffer query;
8089         PGresult   *res;
8090         char       *lanname;
8091
8092         query = createPQExpBuffer();
8093         appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
8094         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8095         lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
8096         destroyPQExpBuffer(query);
8097         PQclear(res);
8098
8099         return lanname;
8100 }
8101
8102 /*
8103  * getTransforms
8104  *        get basic information about every transform in the system
8105  *
8106  * numTransforms is set to the number of transforms read in
8107  */
8108 TransformInfo *
8109 getTransforms(Archive *fout, int *numTransforms)
8110 {
8111         PGresult   *res;
8112         int                     ntups;
8113         int                     i;
8114         PQExpBuffer query;
8115         TransformInfo *transforminfo;
8116         int                     i_tableoid;
8117         int                     i_oid;
8118         int                     i_trftype;
8119         int                     i_trflang;
8120         int                     i_trffromsql;
8121         int                     i_trftosql;
8122
8123         /* Transforms didn't exist pre-9.5 */
8124         if (fout->remoteVersion < 90500)
8125         {
8126                 *numTransforms = 0;
8127                 return NULL;
8128         }
8129
8130         query = createPQExpBuffer();
8131
8132         appendPQExpBuffer(query, "SELECT tableoid, oid, "
8133                                           "trftype, trflang, trffromsql::oid, trftosql::oid "
8134                                           "FROM pg_transform "
8135                                           "ORDER BY 3,4");
8136
8137         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8138
8139         ntups = PQntuples(res);
8140
8141         *numTransforms = ntups;
8142
8143         transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
8144
8145         i_tableoid = PQfnumber(res, "tableoid");
8146         i_oid = PQfnumber(res, "oid");
8147         i_trftype = PQfnumber(res, "trftype");
8148         i_trflang = PQfnumber(res, "trflang");
8149         i_trffromsql = PQfnumber(res, "trffromsql");
8150         i_trftosql = PQfnumber(res, "trftosql");
8151
8152         for (i = 0; i < ntups; i++)
8153         {
8154                 PQExpBufferData namebuf;
8155                 TypeInfo   *typeInfo;
8156                 char       *lanname;
8157
8158                 transforminfo[i].dobj.objType = DO_TRANSFORM;
8159                 transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8160                 transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8161                 AssignDumpId(&transforminfo[i].dobj);
8162                 transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
8163                 transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
8164                 transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
8165                 transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
8166
8167                 /*
8168                  * Try to name transform as concatenation of type and language name.
8169                  * This is only used for purposes of sorting.  If we fail to find
8170                  * either, the name will be an empty string.
8171                  */
8172                 initPQExpBuffer(&namebuf);
8173                 typeInfo = findTypeByOid(transforminfo[i].trftype);
8174                 lanname = get_language_name(fout, transforminfo[i].trflang);
8175                 if (typeInfo && lanname)
8176                         appendPQExpBuffer(&namebuf, "%s %s",
8177                                                           typeInfo->dobj.name, lanname);
8178                 transforminfo[i].dobj.name = namebuf.data;
8179                 free(lanname);
8180
8181                 /* Decide whether we want to dump it */
8182                 selectDumpableObject(&(transforminfo[i].dobj), fout);
8183         }
8184
8185         PQclear(res);
8186
8187         destroyPQExpBuffer(query);
8188
8189         return transforminfo;
8190 }
8191
8192 /*
8193  * getTableAttrs -
8194  *        for each interesting table, read info about its attributes
8195  *        (names, types, default values, CHECK constraints, etc)
8196  *
8197  * This is implemented in a very inefficient way right now, looping
8198  * through the tblinfo and doing a join per table to find the attrs and their
8199  * types.  However, because we want type names and so forth to be named
8200  * relative to the schema of each table, we couldn't do it in just one
8201  * query.  (Maybe one query per schema?)
8202  *
8203  *      modifies tblinfo
8204  */
8205 void
8206 getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
8207 {
8208         DumpOptions *dopt = fout->dopt;
8209         int                     i,
8210                                 j;
8211         PQExpBuffer q = createPQExpBuffer();
8212         int                     i_attnum;
8213         int                     i_attname;
8214         int                     i_atttypname;
8215         int                     i_atttypmod;
8216         int                     i_attstattarget;
8217         int                     i_attstorage;
8218         int                     i_typstorage;
8219         int                     i_attnotnull;
8220         int                     i_atthasdef;
8221         int                     i_attidentity;
8222         int                     i_attisdropped;
8223         int                     i_attlen;
8224         int                     i_attalign;
8225         int                     i_attislocal;
8226         int                     i_attoptions;
8227         int                     i_attcollation;
8228         int                     i_attfdwoptions;
8229         int                     i_attmissingval;
8230         PGresult   *res;
8231         int                     ntups;
8232         bool            hasdefaults;
8233
8234         for (i = 0; i < numTables; i++)
8235         {
8236                 TableInfo  *tbinfo = &tblinfo[i];
8237
8238                 /* Don't bother to collect info for sequences */
8239                 if (tbinfo->relkind == RELKIND_SEQUENCE)
8240                         continue;
8241
8242                 /* Don't bother with uninteresting tables, either */
8243                 if (!tbinfo->interesting)
8244                         continue;
8245
8246                 /* find all the user attributes and their types */
8247
8248                 /*
8249                  * we must read the attribute names in attribute number order! because
8250                  * we will use the attnum to index into the attnames array later.
8251                  */
8252                 if (g_verbose)
8253                         write_msg(NULL, "finding the columns and types of table \"%s.%s\"\n",
8254                                           tbinfo->dobj.namespace->dobj.name,
8255                                           tbinfo->dobj.name);
8256
8257                 resetPQExpBuffer(q);
8258
8259                 appendPQExpBuffer(q,
8260                                                   "SELECT\n"
8261                                                   "a.attnum,\n"
8262                                                   "a.attname,\n"
8263                                                   "a.atttypmod,\n"
8264                                                   "a.attstattarget,\n"
8265                                                   "a.attstorage,\n"
8266                                                   "t.typstorage,\n"
8267                                                   "a.attnotnull,\n"
8268                                                   "a.atthasdef,\n"
8269                                                   "a.attisdropped,\n"
8270                                                   "a.attlen,\n"
8271                                                   "a.attalign,\n"
8272                                                   "a.attislocal,\n"
8273                                                   "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n");
8274
8275                 if (fout->remoteVersion >= 110000)
8276                         appendPQExpBuffer(q,
8277                                                           "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
8278                                                           "THEN a.attmissingval ELSE null END AS attmissingval,\n");
8279                 else
8280                         appendPQExpBuffer(q,
8281                                                           "NULL AS attmissingval,\n");
8282
8283                 if (fout->remoteVersion >= 100000)
8284                         appendPQExpBuffer(q,
8285                                                           "a.attidentity,\n");
8286                 else
8287                         appendPQExpBuffer(q,
8288                                                           "'' AS attidentity,\n");
8289
8290                 if (fout->remoteVersion >= 90200)
8291                         appendPQExpBuffer(q,
8292                                                           "pg_catalog.array_to_string(ARRAY("
8293                                                           "SELECT pg_catalog.quote_ident(option_name) || "
8294                                                           "' ' || pg_catalog.quote_literal(option_value) "
8295                                                           "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
8296                                                           "ORDER BY option_name"
8297                                                           "), E',\n    ') AS attfdwoptions,\n");
8298                 else
8299                         appendPQExpBuffer(q,
8300                                                           "'' AS attfdwoptions,\n");
8301
8302                 if (fout->remoteVersion >= 90100)
8303                 {
8304                         /*
8305                          * Since we only want to dump COLLATE clauses for attributes whose
8306                          * collation is different from their type's default, we use a CASE
8307                          * here to suppress uninteresting attcollations cheaply.
8308                          */
8309                         appendPQExpBuffer(q,
8310                                                           "CASE WHEN a.attcollation <> t.typcollation "
8311                                                           "THEN a.attcollation ELSE 0 END AS attcollation,\n");
8312                 }
8313                 else
8314                         appendPQExpBuffer(q,
8315                                                           "0 AS attcollation,\n");
8316
8317                 if (fout->remoteVersion >= 90000)
8318                         appendPQExpBuffer(q,
8319                                                           "array_to_string(a.attoptions, ', ') AS attoptions\n");
8320                 else
8321                         appendPQExpBuffer(q,
8322                                                           "'' AS attoptions\n");
8323
8324                 /* need left join here to not fail on dropped columns ... */
8325                 appendPQExpBuffer(q,
8326                                                   "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
8327                                                   "ON a.atttypid = t.oid\n"
8328                                                   "WHERE a.attrelid = '%u'::pg_catalog.oid "
8329                                                   "AND a.attnum > 0::pg_catalog.int2\n"
8330                                                   "ORDER BY a.attnum",
8331                                                   tbinfo->dobj.catId.oid);
8332
8333                 res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8334
8335                 ntups = PQntuples(res);
8336
8337                 i_attnum = PQfnumber(res, "attnum");
8338                 i_attname = PQfnumber(res, "attname");
8339                 i_atttypname = PQfnumber(res, "atttypname");
8340                 i_atttypmod = PQfnumber(res, "atttypmod");
8341                 i_attstattarget = PQfnumber(res, "attstattarget");
8342                 i_attstorage = PQfnumber(res, "attstorage");
8343                 i_typstorage = PQfnumber(res, "typstorage");
8344                 i_attnotnull = PQfnumber(res, "attnotnull");
8345                 i_atthasdef = PQfnumber(res, "atthasdef");
8346                 i_attidentity = PQfnumber(res, "attidentity");
8347                 i_attisdropped = PQfnumber(res, "attisdropped");
8348                 i_attlen = PQfnumber(res, "attlen");
8349                 i_attalign = PQfnumber(res, "attalign");
8350                 i_attislocal = PQfnumber(res, "attislocal");
8351                 i_attoptions = PQfnumber(res, "attoptions");
8352                 i_attcollation = PQfnumber(res, "attcollation");
8353                 i_attfdwoptions = PQfnumber(res, "attfdwoptions");
8354                 i_attmissingval = PQfnumber(res, "attmissingval");
8355
8356                 tbinfo->numatts = ntups;
8357                 tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
8358                 tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
8359                 tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
8360                 tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
8361                 tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
8362                 tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
8363                 tbinfo->attidentity = (char *) pg_malloc(ntups * sizeof(char));
8364                 tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
8365                 tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
8366                 tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
8367                 tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
8368                 tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
8369                 tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
8370                 tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
8371                 tbinfo->attmissingval = (char **) pg_malloc(ntups * sizeof(char *));
8372                 tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
8373                 tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
8374                 tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
8375                 hasdefaults = false;
8376
8377                 for (j = 0; j < ntups; j++)
8378                 {
8379                         if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
8380                                 exit_horribly(NULL,
8381                                                           "invalid column numbering in table \"%s\"\n",
8382                                                           tbinfo->dobj.name);
8383                         tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
8384                         tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
8385                         tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
8386                         tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
8387                         tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
8388                         tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
8389                         tbinfo->attidentity[j] = *(PQgetvalue(res, j, i_attidentity));
8390                         tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
8391                         tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
8392                         tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
8393                         tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
8394                         tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
8395                         tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
8396                         tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
8397                         tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
8398                         tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
8399                         tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, j, i_attmissingval));
8400                         tbinfo->attrdefs[j] = NULL; /* fix below */
8401                         if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
8402                                 hasdefaults = true;
8403                         /* these flags will be set in flagInhAttrs() */
8404                         tbinfo->inhNotNull[j] = false;
8405                 }
8406
8407                 PQclear(res);
8408
8409                 /*
8410                  * Get info about column defaults
8411                  */
8412                 if (hasdefaults)
8413                 {
8414                         AttrDefInfo *attrdefs;
8415                         int                     numDefaults;
8416
8417                         if (g_verbose)
8418                                 write_msg(NULL, "finding default expressions of table \"%s.%s\"\n",
8419                                                   tbinfo->dobj.namespace->dobj.name,
8420                                                   tbinfo->dobj.name);
8421
8422                         printfPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
8423                                                           "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
8424                                                           "FROM pg_catalog.pg_attrdef "
8425                                                           "WHERE adrelid = '%u'::pg_catalog.oid",
8426                                                           tbinfo->dobj.catId.oid);
8427
8428                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8429
8430                         numDefaults = PQntuples(res);
8431                         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
8432
8433                         for (j = 0; j < numDefaults; j++)
8434                         {
8435                                 int                     adnum;
8436
8437                                 adnum = atoi(PQgetvalue(res, j, 2));
8438
8439                                 if (adnum <= 0 || adnum > ntups)
8440                                         exit_horribly(NULL,
8441                                                                   "invalid adnum value %d for table \"%s\"\n",
8442                                                                   adnum, tbinfo->dobj.name);
8443
8444                                 /*
8445                                  * dropped columns shouldn't have defaults, but just in case,
8446                                  * ignore 'em
8447                                  */
8448                                 if (tbinfo->attisdropped[adnum - 1])
8449                                         continue;
8450
8451                                 attrdefs[j].dobj.objType = DO_ATTRDEF;
8452                                 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
8453                                 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
8454                                 AssignDumpId(&attrdefs[j].dobj);
8455                                 attrdefs[j].adtable = tbinfo;
8456                                 attrdefs[j].adnum = adnum;
8457                                 attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
8458
8459                                 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
8460                                 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
8461
8462                                 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
8463
8464                                 /*
8465                                  * Defaults on a VIEW must always be dumped as separate ALTER
8466                                  * TABLE commands.  Defaults on regular tables are dumped as
8467                                  * part of the CREATE TABLE if possible, which it won't be if
8468                                  * the column is not going to be emitted explicitly.
8469                                  */
8470                                 if (tbinfo->relkind == RELKIND_VIEW)
8471                                 {
8472                                         attrdefs[j].separate = true;
8473                                 }
8474                                 else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
8475                                 {
8476                                         /* column will be suppressed, print default separately */
8477                                         attrdefs[j].separate = true;
8478                                 }
8479                                 else
8480                                 {
8481                                         attrdefs[j].separate = false;
8482
8483                                         /*
8484                                          * Mark the default as needing to appear before the table,
8485                                          * so that any dependencies it has must be emitted before
8486                                          * the CREATE TABLE.  If this is not possible, we'll
8487                                          * change to "separate" mode while sorting dependencies.
8488                                          */
8489                                         addObjectDependency(&tbinfo->dobj,
8490                                                                                 attrdefs[j].dobj.dumpId);
8491                                 }
8492
8493                                 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
8494                         }
8495                         PQclear(res);
8496                 }
8497
8498                 /*
8499                  * Get info about table CHECK constraints
8500                  */
8501                 if (tbinfo->ncheck > 0)
8502                 {
8503                         ConstraintInfo *constrs;
8504                         int                     numConstrs;
8505
8506                         if (g_verbose)
8507                                 write_msg(NULL, "finding check constraints for table \"%s.%s\"\n",
8508                                                   tbinfo->dobj.namespace->dobj.name,
8509                                                   tbinfo->dobj.name);
8510
8511                         resetPQExpBuffer(q);
8512                         if (fout->remoteVersion >= 90200)
8513                         {
8514                                 /*
8515                                  * convalidated is new in 9.2 (actually, it is there in 9.1,
8516                                  * but it wasn't ever false for check constraints until 9.2).
8517                                  */
8518                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8519                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8520                                                                   "conislocal, convalidated "
8521                                                                   "FROM pg_catalog.pg_constraint "
8522                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8523                                                                   "   AND contype = 'c' "
8524                                                                   "ORDER BY conname",
8525                                                                   tbinfo->dobj.catId.oid);
8526                         }
8527                         else if (fout->remoteVersion >= 80400)
8528                         {
8529                                 /* conislocal is new in 8.4 */
8530                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8531                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8532                                                                   "conislocal, true AS convalidated "
8533                                                                   "FROM pg_catalog.pg_constraint "
8534                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8535                                                                   "   AND contype = 'c' "
8536                                                                   "ORDER BY conname",
8537                                                                   tbinfo->dobj.catId.oid);
8538                         }
8539                         else
8540                         {
8541                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8542                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8543                                                                   "true AS 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
8551                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8552
8553                         numConstrs = PQntuples(res);
8554                         if (numConstrs != tbinfo->ncheck)
8555                         {
8556                                 write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
8557                                                                                  "expected %d check constraints on table \"%s\" but found %d\n",
8558                                                                                  tbinfo->ncheck),
8559                                                   tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
8560                                 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
8561                                 exit_nicely(1);
8562                         }
8563
8564                         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
8565                         tbinfo->checkexprs = constrs;
8566
8567                         for (j = 0; j < numConstrs; j++)
8568                         {
8569                                 bool            validated = PQgetvalue(res, j, 5)[0] == 't';
8570
8571                                 constrs[j].dobj.objType = DO_CONSTRAINT;
8572                                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
8573                                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
8574                                 AssignDumpId(&constrs[j].dobj);
8575                                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
8576                                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
8577                                 constrs[j].contable = tbinfo;
8578                                 constrs[j].condomain = NULL;
8579                                 constrs[j].contype = 'c';
8580                                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
8581                                 constrs[j].confrelid = InvalidOid;
8582                                 constrs[j].conindex = 0;
8583                                 constrs[j].condeferrable = false;
8584                                 constrs[j].condeferred = false;
8585                                 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
8586
8587                                 /*
8588                                  * An unvalidated constraint needs to be dumped separately, so
8589                                  * that potentially-violating existing data is loaded before
8590                                  * the constraint.
8591                                  */
8592                                 constrs[j].separate = !validated;
8593
8594                                 constrs[j].dobj.dump = tbinfo->dobj.dump;
8595
8596                                 /*
8597                                  * Mark the constraint as needing to appear before the table
8598                                  * --- this is so that any other dependencies of the
8599                                  * constraint will be emitted before we try to create the
8600                                  * table.  If the constraint is to be dumped separately, it
8601                                  * will be dumped after data is loaded anyway, so don't do it.
8602                                  * (There's an automatic dependency in the opposite direction
8603                                  * anyway, so don't need to add one manually here.)
8604                                  */
8605                                 if (!constrs[j].separate)
8606                                         addObjectDependency(&tbinfo->dobj,
8607                                                                                 constrs[j].dobj.dumpId);
8608
8609                                 /*
8610                                  * If the constraint is inherited, this will be detected later
8611                                  * (in pre-8.4 databases).  We also detect later if the
8612                                  * constraint must be split out from the table definition.
8613                                  */
8614                         }
8615                         PQclear(res);
8616                 }
8617         }
8618
8619         destroyPQExpBuffer(q);
8620 }
8621
8622 /*
8623  * Test whether a column should be printed as part of table's CREATE TABLE.
8624  * Column number is zero-based.
8625  *
8626  * Normally this is always true, but it's false for dropped columns, as well
8627  * as those that were inherited without any local definition.  (If we print
8628  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
8629  * However, in binary_upgrade mode, we must print all such columns anyway and
8630  * fix the attislocal/attisdropped state later, so as to keep control of the
8631  * physical column order.
8632  *
8633  * This function exists because there are scattered nonobvious places that
8634  * must be kept in sync with this decision.
8635  */
8636 bool
8637 shouldPrintColumn(DumpOptions *dopt, TableInfo *tbinfo, int colno)
8638 {
8639         if (dopt->binary_upgrade)
8640                 return true;
8641         return (tbinfo->attislocal[colno] && !tbinfo->attisdropped[colno]);
8642 }
8643
8644
8645 /*
8646  * getTSParsers:
8647  *        read all text search parsers in the system catalogs and return them
8648  *        in the TSParserInfo* structure
8649  *
8650  *      numTSParsers is set to the number of parsers read in
8651  */
8652 TSParserInfo *
8653 getTSParsers(Archive *fout, int *numTSParsers)
8654 {
8655         PGresult   *res;
8656         int                     ntups;
8657         int                     i;
8658         PQExpBuffer query;
8659         TSParserInfo *prsinfo;
8660         int                     i_tableoid;
8661         int                     i_oid;
8662         int                     i_prsname;
8663         int                     i_prsnamespace;
8664         int                     i_prsstart;
8665         int                     i_prstoken;
8666         int                     i_prsend;
8667         int                     i_prsheadline;
8668         int                     i_prslextype;
8669
8670         /* Before 8.3, there is no built-in text search support */
8671         if (fout->remoteVersion < 80300)
8672         {
8673                 *numTSParsers = 0;
8674                 return NULL;
8675         }
8676
8677         query = createPQExpBuffer();
8678
8679         /*
8680          * find all text search objects, including builtin ones; we filter out
8681          * system-defined objects at dump-out time.
8682          */
8683
8684         appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
8685                                                  "prsstart::oid, prstoken::oid, "
8686                                                  "prsend::oid, prsheadline::oid, prslextype::oid "
8687                                                  "FROM pg_ts_parser");
8688
8689         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8690
8691         ntups = PQntuples(res);
8692         *numTSParsers = ntups;
8693
8694         prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
8695
8696         i_tableoid = PQfnumber(res, "tableoid");
8697         i_oid = PQfnumber(res, "oid");
8698         i_prsname = PQfnumber(res, "prsname");
8699         i_prsnamespace = PQfnumber(res, "prsnamespace");
8700         i_prsstart = PQfnumber(res, "prsstart");
8701         i_prstoken = PQfnumber(res, "prstoken");
8702         i_prsend = PQfnumber(res, "prsend");
8703         i_prsheadline = PQfnumber(res, "prsheadline");
8704         i_prslextype = PQfnumber(res, "prslextype");
8705
8706         for (i = 0; i < ntups; i++)
8707         {
8708                 prsinfo[i].dobj.objType = DO_TSPARSER;
8709                 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8710                 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8711                 AssignDumpId(&prsinfo[i].dobj);
8712                 prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
8713                 prsinfo[i].dobj.namespace =
8714                         findNamespace(fout,
8715                                                   atooid(PQgetvalue(res, i, i_prsnamespace)));
8716                 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
8717                 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
8718                 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
8719                 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
8720                 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
8721
8722                 /* Decide whether we want to dump it */
8723                 selectDumpableObject(&(prsinfo[i].dobj), fout);
8724
8725                 /* Text Search Parsers do not currently have ACLs. */
8726                 prsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8727         }
8728
8729         PQclear(res);
8730
8731         destroyPQExpBuffer(query);
8732
8733         return prsinfo;
8734 }
8735
8736 /*
8737  * getTSDictionaries:
8738  *        read all text search dictionaries in the system catalogs and return them
8739  *        in the TSDictInfo* structure
8740  *
8741  *      numTSDicts is set to the number of dictionaries read in
8742  */
8743 TSDictInfo *
8744 getTSDictionaries(Archive *fout, int *numTSDicts)
8745 {
8746         PGresult   *res;
8747         int                     ntups;
8748         int                     i;
8749         PQExpBuffer query;
8750         TSDictInfo *dictinfo;
8751         int                     i_tableoid;
8752         int                     i_oid;
8753         int                     i_dictname;
8754         int                     i_dictnamespace;
8755         int                     i_rolname;
8756         int                     i_dicttemplate;
8757         int                     i_dictinitoption;
8758
8759         /* Before 8.3, there is no built-in text search support */
8760         if (fout->remoteVersion < 80300)
8761         {
8762                 *numTSDicts = 0;
8763                 return NULL;
8764         }
8765
8766         query = createPQExpBuffer();
8767
8768         appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
8769                                           "dictnamespace, (%s dictowner) AS rolname, "
8770                                           "dicttemplate, dictinitoption "
8771                                           "FROM pg_ts_dict",
8772                                           username_subquery);
8773
8774         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8775
8776         ntups = PQntuples(res);
8777         *numTSDicts = ntups;
8778
8779         dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
8780
8781         i_tableoid = PQfnumber(res, "tableoid");
8782         i_oid = PQfnumber(res, "oid");
8783         i_dictname = PQfnumber(res, "dictname");
8784         i_dictnamespace = PQfnumber(res, "dictnamespace");
8785         i_rolname = PQfnumber(res, "rolname");
8786         i_dictinitoption = PQfnumber(res, "dictinitoption");
8787         i_dicttemplate = PQfnumber(res, "dicttemplate");
8788
8789         for (i = 0; i < ntups; i++)
8790         {
8791                 dictinfo[i].dobj.objType = DO_TSDICT;
8792                 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8793                 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8794                 AssignDumpId(&dictinfo[i].dobj);
8795                 dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
8796                 dictinfo[i].dobj.namespace =
8797                         findNamespace(fout,
8798                                                   atooid(PQgetvalue(res, i, i_dictnamespace)));
8799                 dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8800                 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
8801                 if (PQgetisnull(res, i, i_dictinitoption))
8802                         dictinfo[i].dictinitoption = NULL;
8803                 else
8804                         dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
8805
8806                 /* Decide whether we want to dump it */
8807                 selectDumpableObject(&(dictinfo[i].dobj), fout);
8808
8809                 /* Text Search Dictionaries do not currently have ACLs. */
8810                 dictinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8811         }
8812
8813         PQclear(res);
8814
8815         destroyPQExpBuffer(query);
8816
8817         return dictinfo;
8818 }
8819
8820 /*
8821  * getTSTemplates:
8822  *        read all text search templates in the system catalogs and return them
8823  *        in the TSTemplateInfo* structure
8824  *
8825  *      numTSTemplates is set to the number of templates read in
8826  */
8827 TSTemplateInfo *
8828 getTSTemplates(Archive *fout, int *numTSTemplates)
8829 {
8830         PGresult   *res;
8831         int                     ntups;
8832         int                     i;
8833         PQExpBuffer query;
8834         TSTemplateInfo *tmplinfo;
8835         int                     i_tableoid;
8836         int                     i_oid;
8837         int                     i_tmplname;
8838         int                     i_tmplnamespace;
8839         int                     i_tmplinit;
8840         int                     i_tmpllexize;
8841
8842         /* Before 8.3, there is no built-in text search support */
8843         if (fout->remoteVersion < 80300)
8844         {
8845                 *numTSTemplates = 0;
8846                 return NULL;
8847         }
8848
8849         query = createPQExpBuffer();
8850
8851         appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
8852                                                  "tmplnamespace, tmplinit::oid, tmpllexize::oid "
8853                                                  "FROM pg_ts_template");
8854
8855         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8856
8857         ntups = PQntuples(res);
8858         *numTSTemplates = ntups;
8859
8860         tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
8861
8862         i_tableoid = PQfnumber(res, "tableoid");
8863         i_oid = PQfnumber(res, "oid");
8864         i_tmplname = PQfnumber(res, "tmplname");
8865         i_tmplnamespace = PQfnumber(res, "tmplnamespace");
8866         i_tmplinit = PQfnumber(res, "tmplinit");
8867         i_tmpllexize = PQfnumber(res, "tmpllexize");
8868
8869         for (i = 0; i < ntups; i++)
8870         {
8871                 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
8872                 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8873                 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8874                 AssignDumpId(&tmplinfo[i].dobj);
8875                 tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
8876                 tmplinfo[i].dobj.namespace =
8877                         findNamespace(fout,
8878                                                   atooid(PQgetvalue(res, i, i_tmplnamespace)));
8879                 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
8880                 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
8881
8882                 /* Decide whether we want to dump it */
8883                 selectDumpableObject(&(tmplinfo[i].dobj), fout);
8884
8885                 /* Text Search Templates do not currently have ACLs. */
8886                 tmplinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8887         }
8888
8889         PQclear(res);
8890
8891         destroyPQExpBuffer(query);
8892
8893         return tmplinfo;
8894 }
8895
8896 /*
8897  * getTSConfigurations:
8898  *        read all text search configurations in the system catalogs and return
8899  *        them in the TSConfigInfo* structure
8900  *
8901  *      numTSConfigs is set to the number of configurations read in
8902  */
8903 TSConfigInfo *
8904 getTSConfigurations(Archive *fout, int *numTSConfigs)
8905 {
8906         PGresult   *res;
8907         int                     ntups;
8908         int                     i;
8909         PQExpBuffer query;
8910         TSConfigInfo *cfginfo;
8911         int                     i_tableoid;
8912         int                     i_oid;
8913         int                     i_cfgname;
8914         int                     i_cfgnamespace;
8915         int                     i_rolname;
8916         int                     i_cfgparser;
8917
8918         /* Before 8.3, there is no built-in text search support */
8919         if (fout->remoteVersion < 80300)
8920         {
8921                 *numTSConfigs = 0;
8922                 return NULL;
8923         }
8924
8925         query = createPQExpBuffer();
8926
8927         appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
8928                                           "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
8929                                           "FROM pg_ts_config",
8930                                           username_subquery);
8931
8932         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8933
8934         ntups = PQntuples(res);
8935         *numTSConfigs = ntups;
8936
8937         cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
8938
8939         i_tableoid = PQfnumber(res, "tableoid");
8940         i_oid = PQfnumber(res, "oid");
8941         i_cfgname = PQfnumber(res, "cfgname");
8942         i_cfgnamespace = PQfnumber(res, "cfgnamespace");
8943         i_rolname = PQfnumber(res, "rolname");
8944         i_cfgparser = PQfnumber(res, "cfgparser");
8945
8946         for (i = 0; i < ntups; i++)
8947         {
8948                 cfginfo[i].dobj.objType = DO_TSCONFIG;
8949                 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8950                 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8951                 AssignDumpId(&cfginfo[i].dobj);
8952                 cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
8953                 cfginfo[i].dobj.namespace =
8954                         findNamespace(fout,
8955                                                   atooid(PQgetvalue(res, i, i_cfgnamespace)));
8956                 cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8957                 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
8958
8959                 /* Decide whether we want to dump it */
8960                 selectDumpableObject(&(cfginfo[i].dobj), fout);
8961
8962                 /* Text Search Configurations do not currently have ACLs. */
8963                 cfginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8964         }
8965
8966         PQclear(res);
8967
8968         destroyPQExpBuffer(query);
8969
8970         return cfginfo;
8971 }
8972
8973 /*
8974  * getForeignDataWrappers:
8975  *        read all foreign-data wrappers in the system catalogs and return
8976  *        them in the FdwInfo* structure
8977  *
8978  *      numForeignDataWrappers is set to the number of fdws read in
8979  */
8980 FdwInfo *
8981 getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
8982 {
8983         DumpOptions *dopt = fout->dopt;
8984         PGresult   *res;
8985         int                     ntups;
8986         int                     i;
8987         PQExpBuffer query;
8988         FdwInfo    *fdwinfo;
8989         int                     i_tableoid;
8990         int                     i_oid;
8991         int                     i_fdwname;
8992         int                     i_rolname;
8993         int                     i_fdwhandler;
8994         int                     i_fdwvalidator;
8995         int                     i_fdwacl;
8996         int                     i_rfdwacl;
8997         int                     i_initfdwacl;
8998         int                     i_initrfdwacl;
8999         int                     i_fdwoptions;
9000
9001         /* Before 8.4, there are no foreign-data wrappers */
9002         if (fout->remoteVersion < 80400)
9003         {
9004                 *numForeignDataWrappers = 0;
9005                 return NULL;
9006         }
9007
9008         query = createPQExpBuffer();
9009
9010         if (fout->remoteVersion >= 90600)
9011         {
9012                 PQExpBuffer acl_subquery = createPQExpBuffer();
9013                 PQExpBuffer racl_subquery = createPQExpBuffer();
9014                 PQExpBuffer initacl_subquery = createPQExpBuffer();
9015                 PQExpBuffer initracl_subquery = createPQExpBuffer();
9016
9017                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9018                                                 initracl_subquery, "f.fdwacl", "f.fdwowner", "'F'",
9019                                                 dopt->binary_upgrade);
9020
9021                 appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.fdwname, "
9022                                                   "(%s f.fdwowner) AS rolname, "
9023                                                   "f.fdwhandler::pg_catalog.regproc, "
9024                                                   "f.fdwvalidator::pg_catalog.regproc, "
9025                                                   "%s AS fdwacl, "
9026                                                   "%s AS rfdwacl, "
9027                                                   "%s AS initfdwacl, "
9028                                                   "%s AS initrfdwacl, "
9029                                                   "array_to_string(ARRAY("
9030                                                   "SELECT quote_ident(option_name) || ' ' || "
9031                                                   "quote_literal(option_value) "
9032                                                   "FROM pg_options_to_table(f.fdwoptions) "
9033                                                   "ORDER BY option_name"
9034                                                   "), E',\n    ') AS fdwoptions "
9035                                                   "FROM pg_foreign_data_wrapper f "
9036                                                   "LEFT JOIN pg_init_privs pip ON "
9037                                                   "(f.oid = pip.objoid "
9038                                                   "AND pip.classoid = 'pg_foreign_data_wrapper'::regclass "
9039                                                   "AND pip.objsubid = 0) ",
9040                                                   username_subquery,
9041                                                   acl_subquery->data,
9042                                                   racl_subquery->data,
9043                                                   initacl_subquery->data,
9044                                                   initracl_subquery->data);
9045
9046                 destroyPQExpBuffer(acl_subquery);
9047                 destroyPQExpBuffer(racl_subquery);
9048                 destroyPQExpBuffer(initacl_subquery);
9049                 destroyPQExpBuffer(initracl_subquery);
9050         }
9051         else if (fout->remoteVersion >= 90100)
9052         {
9053                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
9054                                                   "(%s fdwowner) AS rolname, "
9055                                                   "fdwhandler::pg_catalog.regproc, "
9056                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
9057                                                   "NULL as rfdwacl, "
9058                                                   "NULL as initfdwacl, NULL AS initrfdwacl, "
9059                                                   "array_to_string(ARRAY("
9060                                                   "SELECT quote_ident(option_name) || ' ' || "
9061                                                   "quote_literal(option_value) "
9062                                                   "FROM pg_options_to_table(fdwoptions) "
9063                                                   "ORDER BY option_name"
9064                                                   "), E',\n    ') AS fdwoptions "
9065                                                   "FROM pg_foreign_data_wrapper",
9066                                                   username_subquery);
9067         }
9068         else
9069         {
9070                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
9071                                                   "(%s fdwowner) AS rolname, "
9072                                                   "'-' AS fdwhandler, "
9073                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
9074                                                   "NULL as rfdwacl, "
9075                                                   "NULL as initfdwacl, NULL AS initrfdwacl, "
9076                                                   "array_to_string(ARRAY("
9077                                                   "SELECT quote_ident(option_name) || ' ' || "
9078                                                   "quote_literal(option_value) "
9079                                                   "FROM pg_options_to_table(fdwoptions) "
9080                                                   "ORDER BY option_name"
9081                                                   "), E',\n    ') AS fdwoptions "
9082                                                   "FROM pg_foreign_data_wrapper",
9083                                                   username_subquery);
9084         }
9085
9086         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9087
9088         ntups = PQntuples(res);
9089         *numForeignDataWrappers = ntups;
9090
9091         fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
9092
9093         i_tableoid = PQfnumber(res, "tableoid");
9094         i_oid = PQfnumber(res, "oid");
9095         i_fdwname = PQfnumber(res, "fdwname");
9096         i_rolname = PQfnumber(res, "rolname");
9097         i_fdwhandler = PQfnumber(res, "fdwhandler");
9098         i_fdwvalidator = PQfnumber(res, "fdwvalidator");
9099         i_fdwacl = PQfnumber(res, "fdwacl");
9100         i_rfdwacl = PQfnumber(res, "rfdwacl");
9101         i_initfdwacl = PQfnumber(res, "initfdwacl");
9102         i_initrfdwacl = PQfnumber(res, "initrfdwacl");
9103         i_fdwoptions = PQfnumber(res, "fdwoptions");
9104
9105         for (i = 0; i < ntups; i++)
9106         {
9107                 fdwinfo[i].dobj.objType = DO_FDW;
9108                 fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9109                 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9110                 AssignDumpId(&fdwinfo[i].dobj);
9111                 fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
9112                 fdwinfo[i].dobj.namespace = NULL;
9113                 fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
9114                 fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
9115                 fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
9116                 fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
9117                 fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
9118                 fdwinfo[i].rfdwacl = pg_strdup(PQgetvalue(res, i, i_rfdwacl));
9119                 fdwinfo[i].initfdwacl = pg_strdup(PQgetvalue(res, i, i_initfdwacl));
9120                 fdwinfo[i].initrfdwacl = pg_strdup(PQgetvalue(res, i, i_initrfdwacl));
9121
9122                 /* Decide whether we want to dump it */
9123                 selectDumpableObject(&(fdwinfo[i].dobj), fout);
9124
9125                 /* Do not try to dump ACL if no ACL exists. */
9126                 if (PQgetisnull(res, i, i_fdwacl) && PQgetisnull(res, i, i_rfdwacl) &&
9127                         PQgetisnull(res, i, i_initfdwacl) &&
9128                         PQgetisnull(res, i, i_initrfdwacl))
9129                         fdwinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
9130         }
9131
9132         PQclear(res);
9133
9134         destroyPQExpBuffer(query);
9135
9136         return fdwinfo;
9137 }
9138
9139 /*
9140  * getForeignServers:
9141  *        read all foreign servers in the system catalogs and return
9142  *        them in the ForeignServerInfo * structure
9143  *
9144  *      numForeignServers is set to the number of servers read in
9145  */
9146 ForeignServerInfo *
9147 getForeignServers(Archive *fout, int *numForeignServers)
9148 {
9149         DumpOptions *dopt = fout->dopt;
9150         PGresult   *res;
9151         int                     ntups;
9152         int                     i;
9153         PQExpBuffer query;
9154         ForeignServerInfo *srvinfo;
9155         int                     i_tableoid;
9156         int                     i_oid;
9157         int                     i_srvname;
9158         int                     i_rolname;
9159         int                     i_srvfdw;
9160         int                     i_srvtype;
9161         int                     i_srvversion;
9162         int                     i_srvacl;
9163         int                     i_rsrvacl;
9164         int                     i_initsrvacl;
9165         int                     i_initrsrvacl;
9166         int                     i_srvoptions;
9167
9168         /* Before 8.4, there are no foreign servers */
9169         if (fout->remoteVersion < 80400)
9170         {
9171                 *numForeignServers = 0;
9172                 return NULL;
9173         }
9174
9175         query = createPQExpBuffer();
9176
9177         if (fout->remoteVersion >= 90600)
9178         {
9179                 PQExpBuffer acl_subquery = createPQExpBuffer();
9180                 PQExpBuffer racl_subquery = createPQExpBuffer();
9181                 PQExpBuffer initacl_subquery = createPQExpBuffer();
9182                 PQExpBuffer initracl_subquery = createPQExpBuffer();
9183
9184                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9185                                                 initracl_subquery, "f.srvacl", "f.srvowner", "'S'",
9186                                                 dopt->binary_upgrade);
9187
9188                 appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.srvname, "
9189                                                   "(%s f.srvowner) AS rolname, "
9190                                                   "f.srvfdw, f.srvtype, f.srvversion, "
9191                                                   "%s AS srvacl, "
9192                                                   "%s AS rsrvacl, "
9193                                                   "%s AS initsrvacl, "
9194                                                   "%s AS initrsrvacl, "
9195                                                   "array_to_string(ARRAY("
9196                                                   "SELECT quote_ident(option_name) || ' ' || "
9197                                                   "quote_literal(option_value) "
9198                                                   "FROM pg_options_to_table(f.srvoptions) "
9199                                                   "ORDER BY option_name"
9200                                                   "), E',\n    ') AS srvoptions "
9201                                                   "FROM pg_foreign_server f "
9202                                                   "LEFT JOIN pg_init_privs pip "
9203                                                   "ON (f.oid = pip.objoid "
9204                                                   "AND pip.classoid = 'pg_foreign_server'::regclass "
9205                                                   "AND pip.objsubid = 0) ",
9206                                                   username_subquery,
9207                                                   acl_subquery->data,
9208                                                   racl_subquery->data,
9209                                                   initacl_subquery->data,
9210                                                   initracl_subquery->data);
9211
9212                 destroyPQExpBuffer(acl_subquery);
9213                 destroyPQExpBuffer(racl_subquery);
9214                 destroyPQExpBuffer(initacl_subquery);
9215                 destroyPQExpBuffer(initracl_subquery);
9216         }
9217         else
9218         {
9219                 appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
9220                                                   "(%s srvowner) AS rolname, "
9221                                                   "srvfdw, srvtype, srvversion, srvacl, "
9222                                                   "NULL AS rsrvacl, "
9223                                                   "NULL AS initsrvacl, NULL AS initrsrvacl, "
9224                                                   "array_to_string(ARRAY("
9225                                                   "SELECT quote_ident(option_name) || ' ' || "
9226                                                   "quote_literal(option_value) "
9227                                                   "FROM pg_options_to_table(srvoptions) "
9228                                                   "ORDER BY option_name"
9229                                                   "), E',\n    ') AS srvoptions "
9230                                                   "FROM pg_foreign_server",
9231                                                   username_subquery);
9232         }
9233
9234         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9235
9236         ntups = PQntuples(res);
9237         *numForeignServers = ntups;
9238
9239         srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
9240
9241         i_tableoid = PQfnumber(res, "tableoid");
9242         i_oid = PQfnumber(res, "oid");
9243         i_srvname = PQfnumber(res, "srvname");
9244         i_rolname = PQfnumber(res, "rolname");
9245         i_srvfdw = PQfnumber(res, "srvfdw");
9246         i_srvtype = PQfnumber(res, "srvtype");
9247         i_srvversion = PQfnumber(res, "srvversion");
9248         i_srvacl = PQfnumber(res, "srvacl");
9249         i_rsrvacl = PQfnumber(res, "rsrvacl");
9250         i_initsrvacl = PQfnumber(res, "initsrvacl");
9251         i_initrsrvacl = PQfnumber(res, "initrsrvacl");
9252         i_srvoptions = PQfnumber(res, "srvoptions");
9253
9254         for (i = 0; i < ntups; i++)
9255         {
9256                 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
9257                 srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9258                 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9259                 AssignDumpId(&srvinfo[i].dobj);
9260                 srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
9261                 srvinfo[i].dobj.namespace = NULL;
9262                 srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
9263                 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
9264                 srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
9265                 srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
9266                 srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
9267                 srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
9268                 srvinfo[i].rsrvacl = pg_strdup(PQgetvalue(res, i, i_rsrvacl));
9269                 srvinfo[i].initsrvacl = pg_strdup(PQgetvalue(res, i, i_initsrvacl));
9270                 srvinfo[i].initrsrvacl = pg_strdup(PQgetvalue(res, i, i_initrsrvacl));
9271
9272                 /* Decide whether we want to dump it */
9273                 selectDumpableObject(&(srvinfo[i].dobj), fout);
9274
9275                 /* Do not try to dump ACL if no ACL exists. */
9276                 if (PQgetisnull(res, i, i_srvacl) && PQgetisnull(res, i, i_rsrvacl) &&
9277                         PQgetisnull(res, i, i_initsrvacl) &&
9278                         PQgetisnull(res, i, i_initrsrvacl))
9279                         srvinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
9280         }
9281
9282         PQclear(res);
9283
9284         destroyPQExpBuffer(query);
9285
9286         return srvinfo;
9287 }
9288
9289 /*
9290  * getDefaultACLs:
9291  *        read all default ACL information in the system catalogs and return
9292  *        them in the DefaultACLInfo structure
9293  *
9294  *      numDefaultACLs is set to the number of ACLs read in
9295  */
9296 DefaultACLInfo *
9297 getDefaultACLs(Archive *fout, int *numDefaultACLs)
9298 {
9299         DumpOptions *dopt = fout->dopt;
9300         DefaultACLInfo *daclinfo;
9301         PQExpBuffer query;
9302         PGresult   *res;
9303         int                     i_oid;
9304         int                     i_tableoid;
9305         int                     i_defaclrole;
9306         int                     i_defaclnamespace;
9307         int                     i_defaclobjtype;
9308         int                     i_defaclacl;
9309         int                     i_rdefaclacl;
9310         int                     i_initdefaclacl;
9311         int                     i_initrdefaclacl;
9312         int                     i,
9313                                 ntups;
9314
9315         if (fout->remoteVersion < 90000)
9316         {
9317                 *numDefaultACLs = 0;
9318                 return NULL;
9319         }
9320
9321         query = createPQExpBuffer();
9322
9323         if (fout->remoteVersion >= 90600)
9324         {
9325                 PQExpBuffer acl_subquery = createPQExpBuffer();
9326                 PQExpBuffer racl_subquery = createPQExpBuffer();
9327                 PQExpBuffer initacl_subquery = createPQExpBuffer();
9328                 PQExpBuffer initracl_subquery = createPQExpBuffer();
9329
9330                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9331                                                 initracl_subquery, "defaclacl", "defaclrole",
9332                                                 "CASE WHEN defaclobjtype = 'S' THEN 's' ELSE defaclobjtype END::\"char\"",
9333                                                 dopt->binary_upgrade);
9334
9335                 appendPQExpBuffer(query, "SELECT d.oid, d.tableoid, "
9336                                                   "(%s d.defaclrole) AS defaclrole, "
9337                                                   "d.defaclnamespace, "
9338                                                   "d.defaclobjtype, "
9339                                                   "%s AS defaclacl, "
9340                                                   "%s AS rdefaclacl, "
9341                                                   "%s AS initdefaclacl, "
9342                                                   "%s AS initrdefaclacl "
9343                                                   "FROM pg_default_acl d "
9344                                                   "LEFT JOIN pg_init_privs pip ON "
9345                                                   "(d.oid = pip.objoid "
9346                                                   "AND pip.classoid = 'pg_default_acl'::regclass "
9347                                                   "AND pip.objsubid = 0) ",
9348                                                   username_subquery,
9349                                                   acl_subquery->data,
9350                                                   racl_subquery->data,
9351                                                   initacl_subquery->data,
9352                                                   initracl_subquery->data);
9353         }
9354         else
9355         {
9356                 appendPQExpBuffer(query, "SELECT oid, tableoid, "
9357                                                   "(%s defaclrole) AS defaclrole, "
9358                                                   "defaclnamespace, "
9359                                                   "defaclobjtype, "
9360                                                   "defaclacl, "
9361                                                   "NULL AS rdefaclacl, "
9362                                                   "NULL AS initdefaclacl, "
9363                                                   "NULL AS initrdefaclacl "
9364                                                   "FROM pg_default_acl",
9365                                                   username_subquery);
9366         }
9367
9368         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9369
9370         ntups = PQntuples(res);
9371         *numDefaultACLs = ntups;
9372
9373         daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
9374
9375         i_oid = PQfnumber(res, "oid");
9376         i_tableoid = PQfnumber(res, "tableoid");
9377         i_defaclrole = PQfnumber(res, "defaclrole");
9378         i_defaclnamespace = PQfnumber(res, "defaclnamespace");
9379         i_defaclobjtype = PQfnumber(res, "defaclobjtype");
9380         i_defaclacl = PQfnumber(res, "defaclacl");
9381         i_rdefaclacl = PQfnumber(res, "rdefaclacl");
9382         i_initdefaclacl = PQfnumber(res, "initdefaclacl");
9383         i_initrdefaclacl = PQfnumber(res, "initrdefaclacl");
9384
9385         for (i = 0; i < ntups; i++)
9386         {
9387                 Oid                     nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
9388
9389                 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
9390                 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9391                 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9392                 AssignDumpId(&daclinfo[i].dobj);
9393                 /* cheesy ... is it worth coming up with a better object name? */
9394                 daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
9395
9396                 if (nspid != InvalidOid)
9397                         daclinfo[i].dobj.namespace = findNamespace(fout, nspid);
9398                 else
9399                         daclinfo[i].dobj.namespace = NULL;
9400
9401                 daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
9402                 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
9403                 daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
9404                 daclinfo[i].rdefaclacl = pg_strdup(PQgetvalue(res, i, i_rdefaclacl));
9405                 daclinfo[i].initdefaclacl = pg_strdup(PQgetvalue(res, i, i_initdefaclacl));
9406                 daclinfo[i].initrdefaclacl = pg_strdup(PQgetvalue(res, i, i_initrdefaclacl));
9407
9408                 /* Decide whether we want to dump it */
9409                 selectDumpableDefaultACL(&(daclinfo[i]), dopt);
9410         }
9411
9412         PQclear(res);
9413
9414         destroyPQExpBuffer(query);
9415
9416         return daclinfo;
9417 }
9418
9419 /*
9420  * dumpComment --
9421  *
9422  * This routine is used to dump any comments associated with the
9423  * object handed to this routine. The routine takes the object type
9424  * and object name (ready to print, except for schema decoration), plus
9425  * the namespace and owner of the object (for labeling the ArchiveEntry),
9426  * plus catalog ID and subid which are the lookup key for pg_description,
9427  * plus the dump ID for the object (for setting a dependency).
9428  * If a matching pg_description entry is found, it is dumped.
9429  *
9430  * Note: in some cases, such as comments for triggers and rules, the "type"
9431  * string really looks like, e.g., "TRIGGER name ON".  This is a bit of a hack
9432  * but it doesn't seem worth complicating the API for all callers to make
9433  * it cleaner.
9434  *
9435  * Note: although this routine takes a dumpId for dependency purposes,
9436  * that purpose is just to mark the dependency in the emitted dump file
9437  * for possible future use by pg_restore.  We do NOT use it for determining
9438  * ordering of the comment in the dump file, because this routine is called
9439  * after dependency sorting occurs.  This routine should be called just after
9440  * calling ArchiveEntry() for the specified object.
9441  */
9442 static void
9443 dumpComment(Archive *fout, const char *type, const char *name,
9444                         const char *namespace, const char *owner,
9445                         CatalogId catalogId, int subid, DumpId dumpId)
9446 {
9447         DumpOptions *dopt = fout->dopt;
9448         CommentItem *comments;
9449         int                     ncomments;
9450
9451         /* do nothing, if --no-comments is supplied */
9452         if (dopt->no_comments)
9453                 return;
9454
9455         /* Comments are schema not data ... except blob comments are data */
9456         if (strcmp(type, "LARGE OBJECT") != 0)
9457         {
9458                 if (dopt->dataOnly)
9459                         return;
9460         }
9461         else
9462         {
9463                 /* We do dump blob comments in binary-upgrade mode */
9464                 if (dopt->schemaOnly && !dopt->binary_upgrade)
9465                         return;
9466         }
9467
9468         /* Search for comments associated with catalogId, using table */
9469         ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
9470                                                          &comments);
9471
9472         /* Is there one matching the subid? */
9473         while (ncomments > 0)
9474         {
9475                 if (comments->objsubid == subid)
9476                         break;
9477                 comments++;
9478                 ncomments--;
9479         }
9480
9481         /* If a comment exists, build COMMENT ON statement */
9482         if (ncomments > 0)
9483         {
9484                 PQExpBuffer query = createPQExpBuffer();
9485                 PQExpBuffer tag = createPQExpBuffer();
9486
9487                 appendPQExpBuffer(query, "COMMENT ON %s ", type);
9488                 if (namespace && *namespace)
9489                         appendPQExpBuffer(query, "%s.", fmtId(namespace));
9490                 appendPQExpBuffer(query, "%s IS ", name);
9491                 appendStringLiteralAH(query, comments->descr, fout);
9492                 appendPQExpBufferStr(query, ";\n");
9493
9494                 appendPQExpBuffer(tag, "%s %s", type, name);
9495
9496                 /*
9497                  * We mark comments as SECTION_NONE because they really belong in the
9498                  * same section as their parent, whether that is pre-data or
9499                  * post-data.
9500                  */
9501                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
9502                                          ARCHIVE_OPTS(.tag = tag->data,
9503                                                                   .namespace = namespace,
9504                                                                   .owner = owner,
9505                                                                   .description = "COMMENT",
9506                                                                   .section = SECTION_NONE,
9507                                                                   .createStmt = query->data,
9508                                                                   .dropStmt = "",
9509                                                                   .deps = &dumpId,
9510                                                                   .nDeps = 1));
9511
9512                 destroyPQExpBuffer(query);
9513                 destroyPQExpBuffer(tag);
9514         }
9515 }
9516
9517 /*
9518  * dumpTableComment --
9519  *
9520  * As above, but dump comments for both the specified table (or view)
9521  * and its columns.
9522  */
9523 static void
9524 dumpTableComment(Archive *fout, TableInfo *tbinfo,
9525                                  const char *reltypename)
9526 {
9527         DumpOptions *dopt = fout->dopt;
9528         CommentItem *comments;
9529         int                     ncomments;
9530         PQExpBuffer query;
9531         PQExpBuffer tag;
9532
9533         /* do nothing, if --no-comments is supplied */
9534         if (dopt->no_comments)
9535                 return;
9536
9537         /* Comments are SCHEMA not data */
9538         if (dopt->dataOnly)
9539                 return;
9540
9541         /* Search for comments associated with relation, using table */
9542         ncomments = findComments(fout,
9543                                                          tbinfo->dobj.catId.tableoid,
9544                                                          tbinfo->dobj.catId.oid,
9545                                                          &comments);
9546
9547         /* If comments exist, build COMMENT ON statements */
9548         if (ncomments <= 0)
9549                 return;
9550
9551         query = createPQExpBuffer();
9552         tag = createPQExpBuffer();
9553
9554         while (ncomments > 0)
9555         {
9556                 const char *descr = comments->descr;
9557                 int                     objsubid = comments->objsubid;
9558
9559                 if (objsubid == 0)
9560                 {
9561                         resetPQExpBuffer(tag);
9562                         appendPQExpBuffer(tag, "%s %s", reltypename,
9563                                                           fmtId(tbinfo->dobj.name));
9564
9565                         resetPQExpBuffer(query);
9566                         appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
9567                                                           fmtQualifiedDumpable(tbinfo));
9568                         appendStringLiteralAH(query, descr, fout);
9569                         appendPQExpBufferStr(query, ";\n");
9570
9571                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
9572                                                  ARCHIVE_OPTS(.tag = tag->data,
9573                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
9574                                                                           .owner = tbinfo->rolname,
9575                                                                           .description = "COMMENT",
9576                                                                           .section = SECTION_NONE,
9577                                                                           .createStmt = query->data,
9578                                                                           .dropStmt = "",
9579                                                                           .deps = &(tbinfo->dobj.dumpId),
9580                                                                           .nDeps = 1));
9581                 }
9582                 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
9583                 {
9584                         resetPQExpBuffer(tag);
9585                         appendPQExpBuffer(tag, "COLUMN %s.",
9586                                                           fmtId(tbinfo->dobj.name));
9587                         appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
9588
9589                         resetPQExpBuffer(query);
9590                         appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
9591                                                           fmtQualifiedDumpable(tbinfo));
9592                         appendPQExpBuffer(query, "%s IS ",
9593                                                           fmtId(tbinfo->attnames[objsubid - 1]));
9594                         appendStringLiteralAH(query, descr, fout);
9595                         appendPQExpBufferStr(query, ";\n");
9596
9597                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
9598                                                  ARCHIVE_OPTS(.tag = tag->data,
9599                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
9600                                                                           .owner = tbinfo->rolname,
9601                                                                           .description = "COMMENT",
9602                                                                           .section = SECTION_NONE,
9603                                                                           .createStmt = query->data,
9604                                                                           .dropStmt = "",
9605                                                                           .deps = &(tbinfo->dobj.dumpId),
9606                                                                           .nDeps = 1));
9607                 }
9608
9609                 comments++;
9610                 ncomments--;
9611         }
9612
9613         destroyPQExpBuffer(query);
9614         destroyPQExpBuffer(tag);
9615 }
9616
9617 /*
9618  * findComments --
9619  *
9620  * Find the comment(s), if any, associated with the given object.  All the
9621  * objsubid values associated with the given classoid/objoid are found with
9622  * one search.
9623  */
9624 static int
9625 findComments(Archive *fout, Oid classoid, Oid objoid,
9626                          CommentItem **items)
9627 {
9628         /* static storage for table of comments */
9629         static CommentItem *comments = NULL;
9630         static int      ncomments = -1;
9631
9632         CommentItem *middle = NULL;
9633         CommentItem *low;
9634         CommentItem *high;
9635         int                     nmatch;
9636
9637         /* Get comments if we didn't already */
9638         if (ncomments < 0)
9639                 ncomments = collectComments(fout, &comments);
9640
9641         /*
9642          * Do binary search to find some item matching the object.
9643          */
9644         low = &comments[0];
9645         high = &comments[ncomments - 1];
9646         while (low <= high)
9647         {
9648                 middle = low + (high - low) / 2;
9649
9650                 if (classoid < middle->classoid)
9651                         high = middle - 1;
9652                 else if (classoid > middle->classoid)
9653                         low = middle + 1;
9654                 else if (objoid < middle->objoid)
9655                         high = middle - 1;
9656                 else if (objoid > middle->objoid)
9657                         low = middle + 1;
9658                 else
9659                         break;                          /* found a match */
9660         }
9661
9662         if (low > high)                         /* no matches */
9663         {
9664                 *items = NULL;
9665                 return 0;
9666         }
9667
9668         /*
9669          * Now determine how many items match the object.  The search loop
9670          * invariant still holds: only items between low and high inclusive could
9671          * match.
9672          */
9673         nmatch = 1;
9674         while (middle > low)
9675         {
9676                 if (classoid != middle[-1].classoid ||
9677                         objoid != middle[-1].objoid)
9678                         break;
9679                 middle--;
9680                 nmatch++;
9681         }
9682
9683         *items = middle;
9684
9685         middle += nmatch;
9686         while (middle <= high)
9687         {
9688                 if (classoid != middle->classoid ||
9689                         objoid != middle->objoid)
9690                         break;
9691                 middle++;
9692                 nmatch++;
9693         }
9694
9695         return nmatch;
9696 }
9697
9698 /*
9699  * collectComments --
9700  *
9701  * Construct a table of all comments available for database objects.
9702  * We used to do per-object queries for the comments, but it's much faster
9703  * to pull them all over at once, and on most databases the memory cost
9704  * isn't high.
9705  *
9706  * The table is sorted by classoid/objid/objsubid for speed in lookup.
9707  */
9708 static int
9709 collectComments(Archive *fout, CommentItem **items)
9710 {
9711         PGresult   *res;
9712         PQExpBuffer query;
9713         int                     i_description;
9714         int                     i_classoid;
9715         int                     i_objoid;
9716         int                     i_objsubid;
9717         int                     ntups;
9718         int                     i;
9719         CommentItem *comments;
9720
9721         query = createPQExpBuffer();
9722
9723         appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
9724                                                  "FROM pg_catalog.pg_description "
9725                                                  "ORDER BY classoid, objoid, objsubid");
9726
9727         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9728
9729         /* Construct lookup table containing OIDs in numeric form */
9730
9731         i_description = PQfnumber(res, "description");
9732         i_classoid = PQfnumber(res, "classoid");
9733         i_objoid = PQfnumber(res, "objoid");
9734         i_objsubid = PQfnumber(res, "objsubid");
9735
9736         ntups = PQntuples(res);
9737
9738         comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
9739
9740         for (i = 0; i < ntups; i++)
9741         {
9742                 comments[i].descr = PQgetvalue(res, i, i_description);
9743                 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
9744                 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
9745                 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
9746         }
9747
9748         /* Do NOT free the PGresult since we are keeping pointers into it */
9749         destroyPQExpBuffer(query);
9750
9751         *items = comments;
9752         return ntups;
9753 }
9754
9755 /*
9756  * dumpDumpableObject
9757  *
9758  * This routine and its subsidiaries are responsible for creating
9759  * ArchiveEntries (TOC objects) for each object to be dumped.
9760  */
9761 static void
9762 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
9763 {
9764         switch (dobj->objType)
9765         {
9766                 case DO_NAMESPACE:
9767                         dumpNamespace(fout, (NamespaceInfo *) dobj);
9768                         break;
9769                 case DO_EXTENSION:
9770                         dumpExtension(fout, (ExtensionInfo *) dobj);
9771                         break;
9772                 case DO_TYPE:
9773                         dumpType(fout, (TypeInfo *) dobj);
9774                         break;
9775                 case DO_SHELL_TYPE:
9776                         dumpShellType(fout, (ShellTypeInfo *) dobj);
9777                         break;
9778                 case DO_FUNC:
9779                         dumpFunc(fout, (FuncInfo *) dobj);
9780                         break;
9781                 case DO_AGG:
9782                         dumpAgg(fout, (AggInfo *) dobj);
9783                         break;
9784                 case DO_OPERATOR:
9785                         dumpOpr(fout, (OprInfo *) dobj);
9786                         break;
9787                 case DO_ACCESS_METHOD:
9788                         dumpAccessMethod(fout, (AccessMethodInfo *) dobj);
9789                         break;
9790                 case DO_OPCLASS:
9791                         dumpOpclass(fout, (OpclassInfo *) dobj);
9792                         break;
9793                 case DO_OPFAMILY:
9794                         dumpOpfamily(fout, (OpfamilyInfo *) dobj);
9795                         break;
9796                 case DO_COLLATION:
9797                         dumpCollation(fout, (CollInfo *) dobj);
9798                         break;
9799                 case DO_CONVERSION:
9800                         dumpConversion(fout, (ConvInfo *) dobj);
9801                         break;
9802                 case DO_TABLE:
9803                         dumpTable(fout, (TableInfo *) dobj);
9804                         break;
9805                 case DO_ATTRDEF:
9806                         dumpAttrDef(fout, (AttrDefInfo *) dobj);
9807                         break;
9808                 case DO_INDEX:
9809                         dumpIndex(fout, (IndxInfo *) dobj);
9810                         break;
9811                 case DO_INDEX_ATTACH:
9812                         dumpIndexAttach(fout, (IndexAttachInfo *) dobj);
9813                         break;
9814                 case DO_STATSEXT:
9815                         dumpStatisticsExt(fout, (StatsExtInfo *) dobj);
9816                         break;
9817                 case DO_REFRESH_MATVIEW:
9818                         refreshMatViewData(fout, (TableDataInfo *) dobj);
9819                         break;
9820                 case DO_RULE:
9821                         dumpRule(fout, (RuleInfo *) dobj);
9822                         break;
9823                 case DO_TRIGGER:
9824                         dumpTrigger(fout, (TriggerInfo *) dobj);
9825                         break;
9826                 case DO_EVENT_TRIGGER:
9827                         dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
9828                         break;
9829                 case DO_CONSTRAINT:
9830                         dumpConstraint(fout, (ConstraintInfo *) dobj);
9831                         break;
9832                 case DO_FK_CONSTRAINT:
9833                         dumpConstraint(fout, (ConstraintInfo *) dobj);
9834                         break;
9835                 case DO_PROCLANG:
9836                         dumpProcLang(fout, (ProcLangInfo *) dobj);
9837                         break;
9838                 case DO_CAST:
9839                         dumpCast(fout, (CastInfo *) dobj);
9840                         break;
9841                 case DO_TRANSFORM:
9842                         dumpTransform(fout, (TransformInfo *) dobj);
9843                         break;
9844                 case DO_SEQUENCE_SET:
9845                         dumpSequenceData(fout, (TableDataInfo *) dobj);
9846                         break;
9847                 case DO_TABLE_DATA:
9848                         dumpTableData(fout, (TableDataInfo *) dobj);
9849                         break;
9850                 case DO_DUMMY_TYPE:
9851                         /* table rowtypes and array types are never dumped separately */
9852                         break;
9853                 case DO_TSPARSER:
9854                         dumpTSParser(fout, (TSParserInfo *) dobj);
9855                         break;
9856                 case DO_TSDICT:
9857                         dumpTSDictionary(fout, (TSDictInfo *) dobj);
9858                         break;
9859                 case DO_TSTEMPLATE:
9860                         dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
9861                         break;
9862                 case DO_TSCONFIG:
9863                         dumpTSConfig(fout, (TSConfigInfo *) dobj);
9864                         break;
9865                 case DO_FDW:
9866                         dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
9867                         break;
9868                 case DO_FOREIGN_SERVER:
9869                         dumpForeignServer(fout, (ForeignServerInfo *) dobj);
9870                         break;
9871                 case DO_DEFAULT_ACL:
9872                         dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
9873                         break;
9874                 case DO_BLOB:
9875                         dumpBlob(fout, (BlobInfo *) dobj);
9876                         break;
9877                 case DO_BLOB_DATA:
9878                         if (dobj->dump & DUMP_COMPONENT_DATA)
9879                         {
9880                                 TocEntry   *te;
9881
9882                                 te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
9883                                                                   ARCHIVE_OPTS(.tag = dobj->name,
9884                                                                                            .description = "BLOBS",
9885                                                                                            .owner = "",
9886                                                                                            .section = SECTION_DATA,
9887                                                                                            .dumpFn = dumpBlobs,
9888                                                                                            .createStmt = "",
9889                                                                                            .dropStmt = ""));
9890
9891                                 /*
9892                                  * Set the TocEntry's dataLength in case we are doing a
9893                                  * parallel dump and want to order dump jobs by table size.
9894                                  * (We need some size estimate for every TocEntry with a
9895                                  * DataDumper function.)  We don't currently have any cheap
9896                                  * way to estimate the size of blobs, but it doesn't matter;
9897                                  * let's just set the size to a large value so parallel dumps
9898                                  * will launch this job first.  If there's lots of blobs, we
9899                                  * win, and if there aren't, we don't lose much.  (If you want
9900                                  * to improve on this, really what you should be thinking
9901                                  * about is allowing blob dumping to be parallelized, not just
9902                                  * getting a smarter estimate for the single TOC entry.)
9903                                  */
9904                                 te->dataLength = MaxBlockNumber;
9905                         }
9906                         break;
9907                 case DO_POLICY:
9908                         dumpPolicy(fout, (PolicyInfo *) dobj);
9909                         break;
9910                 case DO_PUBLICATION:
9911                         dumpPublication(fout, (PublicationInfo *) dobj);
9912                         break;
9913                 case DO_PUBLICATION_REL:
9914                         dumpPublicationTable(fout, (PublicationRelInfo *) dobj);
9915                         break;
9916                 case DO_SUBSCRIPTION:
9917                         dumpSubscription(fout, (SubscriptionInfo *) dobj);
9918                         break;
9919                 case DO_PRE_DATA_BOUNDARY:
9920                 case DO_POST_DATA_BOUNDARY:
9921                         /* never dumped, nothing to do */
9922                         break;
9923         }
9924 }
9925
9926 /*
9927  * dumpNamespace
9928  *        writes out to fout the queries to recreate a user-defined namespace
9929  */
9930 static void
9931 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
9932 {
9933         DumpOptions *dopt = fout->dopt;
9934         PQExpBuffer q;
9935         PQExpBuffer delq;
9936         char       *qnspname;
9937
9938         /* Skip if not to be dumped */
9939         if (!nspinfo->dobj.dump || dopt->dataOnly)
9940                 return;
9941
9942         q = createPQExpBuffer();
9943         delq = createPQExpBuffer();
9944
9945         qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
9946
9947         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
9948
9949         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
9950
9951         if (dopt->binary_upgrade)
9952                 binary_upgrade_extension_member(q, &nspinfo->dobj,
9953                                                                                 "SCHEMA", qnspname, NULL);
9954
9955         if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
9956                 ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
9957                                          ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
9958                                                                   .owner = nspinfo->rolname,
9959                                                                   .description = "SCHEMA",
9960                                                                   .section = SECTION_PRE_DATA,
9961                                                                   .createStmt = q->data,
9962                                                                   .dropStmt = delq->data));
9963
9964         /* Dump Schema Comments and Security Labels */
9965         if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
9966                 dumpComment(fout, "SCHEMA", qnspname,
9967                                         NULL, nspinfo->rolname,
9968                                         nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
9969
9970         if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
9971                 dumpSecLabel(fout, "SCHEMA", qnspname,
9972                                          NULL, nspinfo->rolname,
9973                                          nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
9974
9975         if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
9976                 dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
9977                                 qnspname, NULL, NULL,
9978                                 nspinfo->rolname, nspinfo->nspacl, nspinfo->rnspacl,
9979                                 nspinfo->initnspacl, nspinfo->initrnspacl);
9980
9981         free(qnspname);
9982
9983         destroyPQExpBuffer(q);
9984         destroyPQExpBuffer(delq);
9985 }
9986
9987 /*
9988  * dumpExtension
9989  *        writes out to fout the queries to recreate an extension
9990  */
9991 static void
9992 dumpExtension(Archive *fout, ExtensionInfo *extinfo)
9993 {
9994         DumpOptions *dopt = fout->dopt;
9995         PQExpBuffer q;
9996         PQExpBuffer delq;
9997         char       *qextname;
9998
9999         /* Skip if not to be dumped */
10000         if (!extinfo->dobj.dump || dopt->dataOnly)
10001                 return;
10002
10003         q = createPQExpBuffer();
10004         delq = createPQExpBuffer();
10005
10006         qextname = pg_strdup(fmtId(extinfo->dobj.name));
10007
10008         appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
10009
10010         if (!dopt->binary_upgrade)
10011         {
10012                 /*
10013                  * In a regular dump, we simply create the extension, intentionally
10014                  * not specifying a version, so that the destination installation's
10015                  * default version is used.
10016                  *
10017                  * Use of IF NOT EXISTS here is unlike our behavior for other object
10018                  * types; but there are various scenarios in which it's convenient to
10019                  * manually create the desired extension before restoring, so we
10020                  * prefer to allow it to exist already.
10021                  */
10022                 appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
10023                                                   qextname, fmtId(extinfo->namespace));
10024         }
10025         else
10026         {
10027                 /*
10028                  * In binary-upgrade mode, it's critical to reproduce the state of the
10029                  * database exactly, so our procedure is to create an empty extension,
10030                  * restore all the contained objects normally, and add them to the
10031                  * extension one by one.  This function performs just the first of
10032                  * those steps.  binary_upgrade_extension_member() takes care of
10033                  * adding member objects as they're created.
10034                  */
10035                 int                     i;
10036                 int                     n;
10037
10038                 appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
10039
10040                 /*
10041                  * We unconditionally create the extension, so we must drop it if it
10042                  * exists.  This could happen if the user deleted 'plpgsql' and then
10043                  * readded it, causing its oid to be greater than g_last_builtin_oid.
10044                  */
10045                 appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
10046
10047                 appendPQExpBufferStr(q,
10048                                                          "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
10049                 appendStringLiteralAH(q, extinfo->dobj.name, fout);
10050                 appendPQExpBufferStr(q, ", ");
10051                 appendStringLiteralAH(q, extinfo->namespace, fout);
10052                 appendPQExpBufferStr(q, ", ");
10053                 appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
10054                 appendStringLiteralAH(q, extinfo->extversion, fout);
10055                 appendPQExpBufferStr(q, ", ");
10056
10057                 /*
10058                  * Note that we're pushing extconfig (an OID array) back into
10059                  * pg_extension exactly as-is.  This is OK because pg_class OIDs are
10060                  * preserved in binary upgrade.
10061                  */
10062                 if (strlen(extinfo->extconfig) > 2)
10063                         appendStringLiteralAH(q, extinfo->extconfig, fout);
10064                 else
10065                         appendPQExpBufferStr(q, "NULL");
10066                 appendPQExpBufferStr(q, ", ");
10067                 if (strlen(extinfo->extcondition) > 2)
10068                         appendStringLiteralAH(q, extinfo->extcondition, fout);
10069                 else
10070                         appendPQExpBufferStr(q, "NULL");
10071                 appendPQExpBufferStr(q, ", ");
10072                 appendPQExpBufferStr(q, "ARRAY[");
10073                 n = 0;
10074                 for (i = 0; i < extinfo->dobj.nDeps; i++)
10075                 {
10076                         DumpableObject *extobj;
10077
10078                         extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
10079                         if (extobj && extobj->objType == DO_EXTENSION)
10080                         {
10081                                 if (n++ > 0)
10082                                         appendPQExpBufferChar(q, ',');
10083                                 appendStringLiteralAH(q, extobj->name, fout);
10084                         }
10085                 }
10086                 appendPQExpBufferStr(q, "]::pg_catalog.text[]");
10087                 appendPQExpBufferStr(q, ");\n");
10088         }
10089
10090         if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10091                 ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
10092                                          ARCHIVE_OPTS(.tag = extinfo->dobj.name,
10093                                                                   .description = "EXTENSION",
10094                                                                   .owner = "",
10095                                                                   .section = SECTION_PRE_DATA,
10096                                                                   .createStmt = q->data,
10097                                                                   .dropStmt = delq->data));
10098
10099         /* Dump Extension Comments and Security Labels */
10100         if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10101                 dumpComment(fout, "EXTENSION", qextname,
10102                                         NULL, "",
10103                                         extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
10104
10105         if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10106                 dumpSecLabel(fout, "EXTENSION", qextname,
10107                                          NULL, "",
10108                                          extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
10109
10110         free(qextname);
10111
10112         destroyPQExpBuffer(q);
10113         destroyPQExpBuffer(delq);
10114 }
10115
10116 /*
10117  * dumpType
10118  *        writes out to fout the queries to recreate a user-defined type
10119  */
10120 static void
10121 dumpType(Archive *fout, TypeInfo *tyinfo)
10122 {
10123         DumpOptions *dopt = fout->dopt;
10124
10125         /* Skip if not to be dumped */
10126         if (!tyinfo->dobj.dump || dopt->dataOnly)
10127                 return;
10128
10129         /* Dump out in proper style */
10130         if (tyinfo->typtype == TYPTYPE_BASE)
10131                 dumpBaseType(fout, tyinfo);
10132         else if (tyinfo->typtype == TYPTYPE_DOMAIN)
10133                 dumpDomain(fout, tyinfo);
10134         else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
10135                 dumpCompositeType(fout, tyinfo);
10136         else if (tyinfo->typtype == TYPTYPE_ENUM)
10137                 dumpEnumType(fout, tyinfo);
10138         else if (tyinfo->typtype == TYPTYPE_RANGE)
10139                 dumpRangeType(fout, tyinfo);
10140         else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
10141                 dumpUndefinedType(fout, tyinfo);
10142         else
10143                 write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
10144                                   tyinfo->dobj.name);
10145 }
10146
10147 /*
10148  * dumpEnumType
10149  *        writes out to fout the queries to recreate a user-defined enum type
10150  */
10151 static void
10152 dumpEnumType(Archive *fout, TypeInfo *tyinfo)
10153 {
10154         DumpOptions *dopt = fout->dopt;
10155         PQExpBuffer q = createPQExpBuffer();
10156         PQExpBuffer delq = createPQExpBuffer();
10157         PQExpBuffer query = createPQExpBuffer();
10158         PGresult   *res;
10159         int                     num,
10160                                 i;
10161         Oid                     enum_oid;
10162         char       *qtypname;
10163         char       *qualtypname;
10164         char       *label;
10165
10166         if (fout->remoteVersion >= 90100)
10167                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
10168                                                   "FROM pg_catalog.pg_enum "
10169                                                   "WHERE enumtypid = '%u'"
10170                                                   "ORDER BY enumsortorder",
10171                                                   tyinfo->dobj.catId.oid);
10172         else
10173                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
10174                                                   "FROM pg_catalog.pg_enum "
10175                                                   "WHERE enumtypid = '%u'"
10176                                                   "ORDER BY oid",
10177                                                   tyinfo->dobj.catId.oid);
10178
10179         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10180
10181         num = PQntuples(res);
10182
10183         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10184         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10185
10186         /*
10187          * CASCADE shouldn't be required here as for normal types since the I/O
10188          * functions are generic and do not get dropped.
10189          */
10190         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10191
10192         if (dopt->binary_upgrade)
10193                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10194                                                                                                  tyinfo->dobj.catId.oid,
10195                                                                                                  false);
10196
10197         appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
10198                                           qualtypname);
10199
10200         if (!dopt->binary_upgrade)
10201         {
10202                 /* Labels with server-assigned oids */
10203                 for (i = 0; i < num; i++)
10204                 {
10205                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
10206                         if (i > 0)
10207                                 appendPQExpBufferChar(q, ',');
10208                         appendPQExpBufferStr(q, "\n    ");
10209                         appendStringLiteralAH(q, label, fout);
10210                 }
10211         }
10212
10213         appendPQExpBufferStr(q, "\n);\n");
10214
10215         if (dopt->binary_upgrade)
10216         {
10217                 /* Labels with dump-assigned (preserved) oids */
10218                 for (i = 0; i < num; i++)
10219                 {
10220                         enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
10221                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
10222
10223                         if (i == 0)
10224                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
10225                         appendPQExpBuffer(q,
10226                                                           "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
10227                                                           enum_oid);
10228                         appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
10229                         appendStringLiteralAH(q, label, fout);
10230                         appendPQExpBufferStr(q, ";\n\n");
10231                 }
10232         }
10233
10234         if (dopt->binary_upgrade)
10235                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10236                                                                                 "TYPE", qtypname,
10237                                                                                 tyinfo->dobj.namespace->dobj.name);
10238
10239         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10240                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10241                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10242                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10243                                                                   .owner = tyinfo->rolname,
10244                                                                   .description = "TYPE",
10245                                                                   .section = SECTION_PRE_DATA,
10246                                                                   .createStmt = q->data,
10247                                                                   .dropStmt = delq->data));
10248
10249         /* Dump Type Comments and Security Labels */
10250         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10251                 dumpComment(fout, "TYPE", qtypname,
10252                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10253                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10254
10255         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10256                 dumpSecLabel(fout, "TYPE", qtypname,
10257                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10258                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10259
10260         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10261                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10262                                 qtypname, NULL,
10263                                 tyinfo->dobj.namespace->dobj.name,
10264                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10265                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10266
10267         PQclear(res);
10268         destroyPQExpBuffer(q);
10269         destroyPQExpBuffer(delq);
10270         destroyPQExpBuffer(query);
10271         free(qtypname);
10272         free(qualtypname);
10273 }
10274
10275 /*
10276  * dumpRangeType
10277  *        writes out to fout the queries to recreate a user-defined range type
10278  */
10279 static void
10280 dumpRangeType(Archive *fout, TypeInfo *tyinfo)
10281 {
10282         DumpOptions *dopt = fout->dopt;
10283         PQExpBuffer q = createPQExpBuffer();
10284         PQExpBuffer delq = createPQExpBuffer();
10285         PQExpBuffer query = createPQExpBuffer();
10286         PGresult   *res;
10287         Oid                     collationOid;
10288         char       *qtypname;
10289         char       *qualtypname;
10290         char       *procname;
10291
10292         appendPQExpBuffer(query,
10293                                           "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
10294                                           "opc.opcname AS opcname, "
10295                                           "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
10296                                           "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
10297                                           "opc.opcdefault, "
10298                                           "CASE WHEN rngcollation = st.typcollation THEN 0 "
10299                                           "     ELSE rngcollation END AS collation, "
10300                                           "rngcanonical, rngsubdiff "
10301                                           "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
10302                                           "     pg_catalog.pg_opclass opc "
10303                                           "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
10304                                           "rngtypid = '%u'",
10305                                           tyinfo->dobj.catId.oid);
10306
10307         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10308
10309         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10310         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10311
10312         /*
10313          * CASCADE shouldn't be required here as for normal types since the I/O
10314          * functions are generic and do not get dropped.
10315          */
10316         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10317
10318         if (dopt->binary_upgrade)
10319                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10320                                                                                                  tyinfo->dobj.catId.oid,
10321                                                                                                  false);
10322
10323         appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
10324                                           qualtypname);
10325
10326         appendPQExpBuffer(q, "\n    subtype = %s",
10327                                           PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
10328
10329         /* print subtype_opclass only if not default for subtype */
10330         if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
10331         {
10332                 char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
10333                 char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
10334
10335                 appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
10336                                                   fmtId(nspname));
10337                 appendPQExpBufferStr(q, fmtId(opcname));
10338         }
10339
10340         collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
10341         if (OidIsValid(collationOid))
10342         {
10343                 CollInfo   *coll = findCollationByOid(collationOid);
10344
10345                 if (coll)
10346                         appendPQExpBuffer(q, ",\n    collation = %s",
10347                                                           fmtQualifiedDumpable(coll));
10348         }
10349
10350         procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
10351         if (strcmp(procname, "-") != 0)
10352                 appendPQExpBuffer(q, ",\n    canonical = %s", procname);
10353
10354         procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
10355         if (strcmp(procname, "-") != 0)
10356                 appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
10357
10358         appendPQExpBufferStr(q, "\n);\n");
10359
10360         if (dopt->binary_upgrade)
10361                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10362                                                                                 "TYPE", qtypname,
10363                                                                                 tyinfo->dobj.namespace->dobj.name);
10364
10365         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10366                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10367                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10368                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10369                                                                   .owner = tyinfo->rolname,
10370                                                                   .description = "TYPE",
10371                                                                   .section = SECTION_PRE_DATA,
10372                                                                   .createStmt = q->data,
10373                                                                   .dropStmt = delq->data));
10374
10375         /* Dump Type Comments and Security Labels */
10376         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10377                 dumpComment(fout, "TYPE", qtypname,
10378                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10379                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10380
10381         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10382                 dumpSecLabel(fout, "TYPE", qtypname,
10383                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10384                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10385
10386         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10387                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10388                                 qtypname, NULL,
10389                                 tyinfo->dobj.namespace->dobj.name,
10390                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10391                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10392
10393         PQclear(res);
10394         destroyPQExpBuffer(q);
10395         destroyPQExpBuffer(delq);
10396         destroyPQExpBuffer(query);
10397         free(qtypname);
10398         free(qualtypname);
10399 }
10400
10401 /*
10402  * dumpUndefinedType
10403  *        writes out to fout the queries to recreate a !typisdefined type
10404  *
10405  * This is a shell type, but we use different terminology to distinguish
10406  * this case from where we have to emit a shell type definition to break
10407  * circular dependencies.  An undefined type shouldn't ever have anything
10408  * depending on it.
10409  */
10410 static void
10411 dumpUndefinedType(Archive *fout, TypeInfo *tyinfo)
10412 {
10413         DumpOptions *dopt = fout->dopt;
10414         PQExpBuffer q = createPQExpBuffer();
10415         PQExpBuffer delq = createPQExpBuffer();
10416         char       *qtypname;
10417         char       *qualtypname;
10418
10419         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10420         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10421
10422         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10423
10424         if (dopt->binary_upgrade)
10425                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10426                                                                                                  tyinfo->dobj.catId.oid,
10427                                                                                                  false);
10428
10429         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
10430                                           qualtypname);
10431
10432         if (dopt->binary_upgrade)
10433                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10434                                                                                 "TYPE", qtypname,
10435                                                                                 tyinfo->dobj.namespace->dobj.name);
10436
10437         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10438                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10439                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10440                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10441                                                                   .owner = tyinfo->rolname,
10442                                                                   .description = "TYPE",
10443                                                                   .section = SECTION_PRE_DATA,
10444                                                                   .createStmt = q->data,
10445                                                                   .dropStmt = delq->data));
10446
10447         /* Dump Type Comments and Security Labels */
10448         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10449                 dumpComment(fout, "TYPE", qtypname,
10450                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10451                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10452
10453         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10454                 dumpSecLabel(fout, "TYPE", qtypname,
10455                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10456                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10457
10458         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10459                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10460                                 qtypname, NULL,
10461                                 tyinfo->dobj.namespace->dobj.name,
10462                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10463                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10464
10465         destroyPQExpBuffer(q);
10466         destroyPQExpBuffer(delq);
10467         free(qtypname);
10468         free(qualtypname);
10469 }
10470
10471 /*
10472  * dumpBaseType
10473  *        writes out to fout the queries to recreate a user-defined base type
10474  */
10475 static void
10476 dumpBaseType(Archive *fout, TypeInfo *tyinfo)
10477 {
10478         DumpOptions *dopt = fout->dopt;
10479         PQExpBuffer q = createPQExpBuffer();
10480         PQExpBuffer delq = createPQExpBuffer();
10481         PQExpBuffer query = createPQExpBuffer();
10482         PGresult   *res;
10483         char       *qtypname;
10484         char       *qualtypname;
10485         char       *typlen;
10486         char       *typinput;
10487         char       *typoutput;
10488         char       *typreceive;
10489         char       *typsend;
10490         char       *typmodin;
10491         char       *typmodout;
10492         char       *typanalyze;
10493         Oid                     typreceiveoid;
10494         Oid                     typsendoid;
10495         Oid                     typmodinoid;
10496         Oid                     typmodoutoid;
10497         Oid                     typanalyzeoid;
10498         char       *typcategory;
10499         char       *typispreferred;
10500         char       *typdelim;
10501         char       *typbyval;
10502         char       *typalign;
10503         char       *typstorage;
10504         char       *typcollatable;
10505         char       *typdefault;
10506         bool            typdefault_is_literal = false;
10507
10508         /* Fetch type-specific details */
10509         if (fout->remoteVersion >= 90100)
10510         {
10511                 appendPQExpBuffer(query, "SELECT typlen, "
10512                                                   "typinput, typoutput, typreceive, typsend, "
10513                                                   "typmodin, typmodout, typanalyze, "
10514                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10515                                                   "typsend::pg_catalog.oid AS typsendoid, "
10516                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10517                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10518                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10519                                                   "typcategory, typispreferred, "
10520                                                   "typdelim, typbyval, typalign, typstorage, "
10521                                                   "(typcollation <> 0) AS typcollatable, "
10522                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
10523                                                   "FROM pg_catalog.pg_type "
10524                                                   "WHERE oid = '%u'::pg_catalog.oid",
10525                                                   tyinfo->dobj.catId.oid);
10526         }
10527         else if (fout->remoteVersion >= 80400)
10528         {
10529                 appendPQExpBuffer(query, "SELECT typlen, "
10530                                                   "typinput, typoutput, typreceive, typsend, "
10531                                                   "typmodin, typmodout, typanalyze, "
10532                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10533                                                   "typsend::pg_catalog.oid AS typsendoid, "
10534                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10535                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10536                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10537                                                   "typcategory, typispreferred, "
10538                                                   "typdelim, typbyval, typalign, typstorage, "
10539                                                   "false AS typcollatable, "
10540                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
10541                                                   "FROM pg_catalog.pg_type "
10542                                                   "WHERE oid = '%u'::pg_catalog.oid",
10543                                                   tyinfo->dobj.catId.oid);
10544         }
10545         else if (fout->remoteVersion >= 80300)
10546         {
10547                 /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
10548                 appendPQExpBuffer(query, "SELECT typlen, "
10549                                                   "typinput, typoutput, typreceive, typsend, "
10550                                                   "typmodin, typmodout, typanalyze, "
10551                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10552                                                   "typsend::pg_catalog.oid AS typsendoid, "
10553                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10554                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10555                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10556                                                   "'U' AS typcategory, false AS typispreferred, "
10557                                                   "typdelim, typbyval, typalign, typstorage, "
10558                                                   "false AS typcollatable, "
10559                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10560                                                   "FROM pg_catalog.pg_type "
10561                                                   "WHERE oid = '%u'::pg_catalog.oid",
10562                                                   tyinfo->dobj.catId.oid);
10563         }
10564         else
10565         {
10566                 appendPQExpBuffer(query, "SELECT typlen, "
10567                                                   "typinput, typoutput, typreceive, typsend, "
10568                                                   "'-' AS typmodin, '-' AS typmodout, "
10569                                                   "typanalyze, "
10570                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10571                                                   "typsend::pg_catalog.oid AS typsendoid, "
10572                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
10573                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10574                                                   "'U' AS typcategory, false AS typispreferred, "
10575                                                   "typdelim, typbyval, typalign, typstorage, "
10576                                                   "false AS typcollatable, "
10577                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10578                                                   "FROM pg_catalog.pg_type "
10579                                                   "WHERE oid = '%u'::pg_catalog.oid",
10580                                                   tyinfo->dobj.catId.oid);
10581         }
10582
10583         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10584
10585         typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
10586         typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
10587         typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
10588         typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
10589         typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
10590         typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
10591         typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
10592         typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
10593         typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
10594         typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
10595         typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
10596         typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
10597         typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
10598         typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
10599         typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
10600         typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
10601         typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
10602         typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
10603         typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
10604         typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
10605         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
10606                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
10607         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
10608         {
10609                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
10610                 typdefault_is_literal = true;   /* it needs quotes */
10611         }
10612         else
10613                 typdefault = NULL;
10614
10615         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10616         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10617
10618         /*
10619          * The reason we include CASCADE is that the circular dependency between
10620          * the type and its I/O functions makes it impossible to drop the type any
10621          * other way.
10622          */
10623         appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
10624
10625         /*
10626          * We might already have a shell type, but setting pg_type_oid is
10627          * harmless, and in any case we'd better set the array type OID.
10628          */
10629         if (dopt->binary_upgrade)
10630                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10631                                                                                                  tyinfo->dobj.catId.oid,
10632                                                                                                  false);
10633
10634         appendPQExpBuffer(q,
10635                                           "CREATE TYPE %s (\n"
10636                                           "    INTERNALLENGTH = %s",
10637                                           qualtypname,
10638                                           (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
10639
10640         /* regproc result is sufficiently quoted already */
10641         appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
10642         appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
10643         if (OidIsValid(typreceiveoid))
10644                 appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
10645         if (OidIsValid(typsendoid))
10646                 appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
10647         if (OidIsValid(typmodinoid))
10648                 appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
10649         if (OidIsValid(typmodoutoid))
10650                 appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
10651         if (OidIsValid(typanalyzeoid))
10652                 appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
10653
10654         if (strcmp(typcollatable, "t") == 0)
10655                 appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
10656
10657         if (typdefault != NULL)
10658         {
10659                 appendPQExpBufferStr(q, ",\n    DEFAULT = ");
10660                 if (typdefault_is_literal)
10661                         appendStringLiteralAH(q, typdefault, fout);
10662                 else
10663                         appendPQExpBufferStr(q, typdefault);
10664         }
10665
10666         if (OidIsValid(tyinfo->typelem))
10667         {
10668                 char       *elemType;
10669
10670                 elemType = getFormattedTypeName(fout, tyinfo->typelem, zeroAsOpaque);
10671                 appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
10672                 free(elemType);
10673         }
10674
10675         if (strcmp(typcategory, "U") != 0)
10676         {
10677                 appendPQExpBufferStr(q, ",\n    CATEGORY = ");
10678                 appendStringLiteralAH(q, typcategory, fout);
10679         }
10680
10681         if (strcmp(typispreferred, "t") == 0)
10682                 appendPQExpBufferStr(q, ",\n    PREFERRED = true");
10683
10684         if (typdelim && strcmp(typdelim, ",") != 0)
10685         {
10686                 appendPQExpBufferStr(q, ",\n    DELIMITER = ");
10687                 appendStringLiteralAH(q, typdelim, fout);
10688         }
10689
10690         if (strcmp(typalign, "c") == 0)
10691                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
10692         else if (strcmp(typalign, "s") == 0)
10693                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
10694         else if (strcmp(typalign, "i") == 0)
10695                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
10696         else if (strcmp(typalign, "d") == 0)
10697                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
10698
10699         if (strcmp(typstorage, "p") == 0)
10700                 appendPQExpBufferStr(q, ",\n    STORAGE = plain");
10701         else if (strcmp(typstorage, "e") == 0)
10702                 appendPQExpBufferStr(q, ",\n    STORAGE = external");
10703         else if (strcmp(typstorage, "x") == 0)
10704                 appendPQExpBufferStr(q, ",\n    STORAGE = extended");
10705         else if (strcmp(typstorage, "m") == 0)
10706                 appendPQExpBufferStr(q, ",\n    STORAGE = main");
10707
10708         if (strcmp(typbyval, "t") == 0)
10709                 appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
10710
10711         appendPQExpBufferStr(q, "\n);\n");
10712
10713         if (dopt->binary_upgrade)
10714                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10715                                                                                 "TYPE", qtypname,
10716                                                                                 tyinfo->dobj.namespace->dobj.name);
10717
10718         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10719                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10720                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10721                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10722                                                                   .owner = tyinfo->rolname,
10723                                                                   .description = "TYPE",
10724                                                                   .section = SECTION_PRE_DATA,
10725                                                                   .createStmt = q->data,
10726                                                                   .dropStmt = delq->data));
10727
10728         /* Dump Type Comments and Security Labels */
10729         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10730                 dumpComment(fout, "TYPE", qtypname,
10731                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10732                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10733
10734         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10735                 dumpSecLabel(fout, "TYPE", qtypname,
10736                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10737                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10738
10739         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10740                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10741                                 qtypname, NULL,
10742                                 tyinfo->dobj.namespace->dobj.name,
10743                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10744                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10745
10746         PQclear(res);
10747         destroyPQExpBuffer(q);
10748         destroyPQExpBuffer(delq);
10749         destroyPQExpBuffer(query);
10750         free(qtypname);
10751         free(qualtypname);
10752 }
10753
10754 /*
10755  * dumpDomain
10756  *        writes out to fout the queries to recreate a user-defined domain
10757  */
10758 static void
10759 dumpDomain(Archive *fout, TypeInfo *tyinfo)
10760 {
10761         DumpOptions *dopt = fout->dopt;
10762         PQExpBuffer q = createPQExpBuffer();
10763         PQExpBuffer delq = createPQExpBuffer();
10764         PQExpBuffer query = createPQExpBuffer();
10765         PGresult   *res;
10766         int                     i;
10767         char       *qtypname;
10768         char       *qualtypname;
10769         char       *typnotnull;
10770         char       *typdefn;
10771         char       *typdefault;
10772         Oid                     typcollation;
10773         bool            typdefault_is_literal = false;
10774
10775         /* Fetch domain specific details */
10776         if (fout->remoteVersion >= 90100)
10777         {
10778                 /* typcollation is new in 9.1 */
10779                 appendPQExpBuffer(query, "SELECT t.typnotnull, "
10780                                                   "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
10781                                                   "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
10782                                                   "t.typdefault, "
10783                                                   "CASE WHEN t.typcollation <> u.typcollation "
10784                                                   "THEN t.typcollation ELSE 0 END AS typcollation "
10785                                                   "FROM pg_catalog.pg_type t "
10786                                                   "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
10787                                                   "WHERE t.oid = '%u'::pg_catalog.oid",
10788                                                   tyinfo->dobj.catId.oid);
10789         }
10790         else
10791         {
10792                 appendPQExpBuffer(query, "SELECT typnotnull, "
10793                                                   "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
10794                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
10795                                                   "typdefault, 0 AS typcollation "
10796                                                   "FROM pg_catalog.pg_type "
10797                                                   "WHERE oid = '%u'::pg_catalog.oid",
10798                                                   tyinfo->dobj.catId.oid);
10799         }
10800
10801         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10802
10803         typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
10804         typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
10805         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
10806                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
10807         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
10808         {
10809                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
10810                 typdefault_is_literal = true;   /* it needs quotes */
10811         }
10812         else
10813                 typdefault = NULL;
10814         typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
10815
10816         if (dopt->binary_upgrade)
10817                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10818                                                                                                  tyinfo->dobj.catId.oid,
10819                                                                                                  true); /* force array type */
10820
10821         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10822         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10823
10824         appendPQExpBuffer(q,
10825                                           "CREATE DOMAIN %s AS %s",
10826                                           qualtypname,
10827                                           typdefn);
10828
10829         /* Print collation only if different from base type's collation */
10830         if (OidIsValid(typcollation))
10831         {
10832                 CollInfo   *coll;
10833
10834                 coll = findCollationByOid(typcollation);
10835                 if (coll)
10836                         appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
10837         }
10838
10839         if (typnotnull[0] == 't')
10840                 appendPQExpBufferStr(q, " NOT NULL");
10841
10842         if (typdefault != NULL)
10843         {
10844                 appendPQExpBufferStr(q, " DEFAULT ");
10845                 if (typdefault_is_literal)
10846                         appendStringLiteralAH(q, typdefault, fout);
10847                 else
10848                         appendPQExpBufferStr(q, typdefault);
10849         }
10850
10851         PQclear(res);
10852
10853         /*
10854          * Add any CHECK constraints for the domain
10855          */
10856         for (i = 0; i < tyinfo->nDomChecks; i++)
10857         {
10858                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
10859
10860                 if (!domcheck->separate)
10861                         appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
10862                                                           fmtId(domcheck->dobj.name), domcheck->condef);
10863         }
10864
10865         appendPQExpBufferStr(q, ";\n");
10866
10867         appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
10868
10869         if (dopt->binary_upgrade)
10870                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10871                                                                                 "DOMAIN", qtypname,
10872                                                                                 tyinfo->dobj.namespace->dobj.name);
10873
10874         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10875                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10876                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10877                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10878                                                                   .owner = tyinfo->rolname,
10879                                                                   .description = "DOMAIN",
10880                                                                   .section = SECTION_PRE_DATA,
10881                                                                   .createStmt = q->data,
10882                                                                   .dropStmt = delq->data));
10883
10884         /* Dump Domain Comments and Security Labels */
10885         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10886                 dumpComment(fout, "DOMAIN", qtypname,
10887                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10888                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10889
10890         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10891                 dumpSecLabel(fout, "DOMAIN", qtypname,
10892                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10893                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10894
10895         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10896                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10897                                 qtypname, NULL,
10898                                 tyinfo->dobj.namespace->dobj.name,
10899                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10900                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10901
10902         /* Dump any per-constraint comments */
10903         for (i = 0; i < tyinfo->nDomChecks; i++)
10904         {
10905                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
10906                 PQExpBuffer conprefix = createPQExpBuffer();
10907
10908                 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
10909                                                   fmtId(domcheck->dobj.name));
10910
10911                 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10912                         dumpComment(fout, conprefix->data, qtypname,
10913                                                 tyinfo->dobj.namespace->dobj.name,
10914                                                 tyinfo->rolname,
10915                                                 domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
10916
10917                 destroyPQExpBuffer(conprefix);
10918         }
10919
10920         destroyPQExpBuffer(q);
10921         destroyPQExpBuffer(delq);
10922         destroyPQExpBuffer(query);
10923         free(qtypname);
10924         free(qualtypname);
10925 }
10926
10927 /*
10928  * dumpCompositeType
10929  *        writes out to fout the queries to recreate a user-defined stand-alone
10930  *        composite type
10931  */
10932 static void
10933 dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
10934 {
10935         DumpOptions *dopt = fout->dopt;
10936         PQExpBuffer q = createPQExpBuffer();
10937         PQExpBuffer dropped = createPQExpBuffer();
10938         PQExpBuffer delq = createPQExpBuffer();
10939         PQExpBuffer query = createPQExpBuffer();
10940         PGresult   *res;
10941         char       *qtypname;
10942         char       *qualtypname;
10943         int                     ntups;
10944         int                     i_attname;
10945         int                     i_atttypdefn;
10946         int                     i_attlen;
10947         int                     i_attalign;
10948         int                     i_attisdropped;
10949         int                     i_attcollation;
10950         int                     i;
10951         int                     actual_atts;
10952
10953         /* Fetch type specific details */
10954         if (fout->remoteVersion >= 90100)
10955         {
10956                 /*
10957                  * attcollation is new in 9.1.  Since we only want to dump COLLATE
10958                  * clauses for attributes whose collation is different from their
10959                  * type's default, we use a CASE here to suppress uninteresting
10960                  * attcollations cheaply.  atttypid will be 0 for dropped columns;
10961                  * collation does not matter for those.
10962                  */
10963                 appendPQExpBuffer(query, "SELECT a.attname, "
10964                                                   "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
10965                                                   "a.attlen, a.attalign, a.attisdropped, "
10966                                                   "CASE WHEN a.attcollation <> at.typcollation "
10967                                                   "THEN a.attcollation ELSE 0 END AS attcollation "
10968                                                   "FROM pg_catalog.pg_type ct "
10969                                                   "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
10970                                                   "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
10971                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
10972                                                   "ORDER BY a.attnum ",
10973                                                   tyinfo->dobj.catId.oid);
10974         }
10975         else
10976         {
10977                 /*
10978                  * Since ALTER TYPE could not drop columns until 9.1, attisdropped
10979                  * should always be false.
10980                  */
10981                 appendPQExpBuffer(query, "SELECT a.attname, "
10982                                                   "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
10983                                                   "a.attlen, a.attalign, a.attisdropped, "
10984                                                   "0 AS attcollation "
10985                                                   "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
10986                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
10987                                                   "AND a.attrelid = ct.typrelid "
10988                                                   "ORDER BY a.attnum ",
10989                                                   tyinfo->dobj.catId.oid);
10990         }
10991
10992         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10993
10994         ntups = PQntuples(res);
10995
10996         i_attname = PQfnumber(res, "attname");
10997         i_atttypdefn = PQfnumber(res, "atttypdefn");
10998         i_attlen = PQfnumber(res, "attlen");
10999         i_attalign = PQfnumber(res, "attalign");
11000         i_attisdropped = PQfnumber(res, "attisdropped");
11001         i_attcollation = PQfnumber(res, "attcollation");
11002
11003         if (dopt->binary_upgrade)
11004         {
11005                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
11006                                                                                                  tyinfo->dobj.catId.oid,
11007                                                                                                  false);
11008                 binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid, false);
11009         }
11010
11011         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
11012         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
11013
11014         appendPQExpBuffer(q, "CREATE TYPE %s AS (",
11015                                           qualtypname);
11016
11017         actual_atts = 0;
11018         for (i = 0; i < ntups; i++)
11019         {
11020                 char       *attname;
11021                 char       *atttypdefn;
11022                 char       *attlen;
11023                 char       *attalign;
11024                 bool            attisdropped;
11025                 Oid                     attcollation;
11026
11027                 attname = PQgetvalue(res, i, i_attname);
11028                 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
11029                 attlen = PQgetvalue(res, i, i_attlen);
11030                 attalign = PQgetvalue(res, i, i_attalign);
11031                 attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
11032                 attcollation = atooid(PQgetvalue(res, i, i_attcollation));
11033
11034                 if (attisdropped && !dopt->binary_upgrade)
11035                         continue;
11036
11037                 /* Format properly if not first attr */
11038                 if (actual_atts++ > 0)
11039                         appendPQExpBufferChar(q, ',');
11040                 appendPQExpBufferStr(q, "\n\t");
11041
11042                 if (!attisdropped)
11043                 {
11044                         appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
11045
11046                         /* Add collation if not default for the column type */
11047                         if (OidIsValid(attcollation))
11048                         {
11049                                 CollInfo   *coll;
11050
11051                                 coll = findCollationByOid(attcollation);
11052                                 if (coll)
11053                                         appendPQExpBuffer(q, " COLLATE %s",
11054                                                                           fmtQualifiedDumpable(coll));
11055                         }
11056                 }
11057                 else
11058                 {
11059                         /*
11060                          * This is a dropped attribute and we're in binary_upgrade mode.
11061                          * Insert a placeholder for it in the CREATE TYPE command, and set
11062                          * length and alignment with direct UPDATE to the catalogs
11063                          * afterwards. See similar code in dumpTableSchema().
11064                          */
11065                         appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
11066
11067                         /* stash separately for insertion after the CREATE TYPE */
11068                         appendPQExpBufferStr(dropped,
11069                                                                  "\n-- For binary upgrade, recreate dropped column.\n");
11070                         appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
11071                                                           "SET attlen = %s, "
11072                                                           "attalign = '%s', attbyval = false\n"
11073                                                           "WHERE attname = ", attlen, attalign);
11074                         appendStringLiteralAH(dropped, attname, fout);
11075                         appendPQExpBufferStr(dropped, "\n  AND attrelid = ");
11076                         appendStringLiteralAH(dropped, qualtypname, fout);
11077                         appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
11078
11079                         appendPQExpBuffer(dropped, "ALTER TYPE %s ",
11080                                                           qualtypname);
11081                         appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
11082                                                           fmtId(attname));
11083                 }
11084         }
11085         appendPQExpBufferStr(q, "\n);\n");
11086         appendPQExpBufferStr(q, dropped->data);
11087
11088         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
11089
11090         if (dopt->binary_upgrade)
11091                 binary_upgrade_extension_member(q, &tyinfo->dobj,
11092                                                                                 "TYPE", qtypname,
11093                                                                                 tyinfo->dobj.namespace->dobj.name);
11094
11095         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11096                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
11097                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
11098                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
11099                                                                   .owner = tyinfo->rolname,
11100                                                                   .description = "TYPE",
11101                                                                   .section = SECTION_PRE_DATA,
11102                                                                   .createStmt = q->data,
11103                                                                   .dropStmt = delq->data));
11104
11105
11106         /* Dump Type Comments and Security Labels */
11107         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11108                 dumpComment(fout, "TYPE", qtypname,
11109                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11110                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11111
11112         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11113                 dumpSecLabel(fout, "TYPE", qtypname,
11114                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11115                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11116
11117         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
11118                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
11119                                 qtypname, NULL,
11120                                 tyinfo->dobj.namespace->dobj.name,
11121                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
11122                                 tyinfo->inittypacl, tyinfo->initrtypacl);
11123
11124         PQclear(res);
11125         destroyPQExpBuffer(q);
11126         destroyPQExpBuffer(dropped);
11127         destroyPQExpBuffer(delq);
11128         destroyPQExpBuffer(query);
11129         free(qtypname);
11130         free(qualtypname);
11131
11132         /* Dump any per-column comments */
11133         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11134                 dumpCompositeTypeColComments(fout, tyinfo);
11135 }
11136
11137 /*
11138  * dumpCompositeTypeColComments
11139  *        writes out to fout the queries to recreate comments on the columns of
11140  *        a user-defined stand-alone composite type
11141  */
11142 static void
11143 dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
11144 {
11145         CommentItem *comments;
11146         int                     ncomments;
11147         PGresult   *res;
11148         PQExpBuffer query;
11149         PQExpBuffer target;
11150         Oid                     pgClassOid;
11151         int                     i;
11152         int                     ntups;
11153         int                     i_attname;
11154         int                     i_attnum;
11155
11156         /* do nothing, if --no-comments is supplied */
11157         if (fout->dopt->no_comments)
11158                 return;
11159
11160         query = createPQExpBuffer();
11161
11162         appendPQExpBuffer(query,
11163                                           "SELECT c.tableoid, a.attname, a.attnum "
11164                                           "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
11165                                           "WHERE c.oid = '%u' AND c.oid = a.attrelid "
11166                                           "  AND NOT a.attisdropped "
11167                                           "ORDER BY a.attnum ",
11168                                           tyinfo->typrelid);
11169
11170         /* Fetch column attnames */
11171         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11172
11173         ntups = PQntuples(res);
11174         if (ntups < 1)
11175         {
11176                 PQclear(res);
11177                 destroyPQExpBuffer(query);
11178                 return;
11179         }
11180
11181         pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
11182
11183         /* Search for comments associated with type's pg_class OID */
11184         ncomments = findComments(fout,
11185                                                          pgClassOid,
11186                                                          tyinfo->typrelid,
11187                                                          &comments);
11188
11189         /* If no comments exist, we're done */
11190         if (ncomments <= 0)
11191         {
11192                 PQclear(res);
11193                 destroyPQExpBuffer(query);
11194                 return;
11195         }
11196
11197         /* Build COMMENT ON statements */
11198         target = createPQExpBuffer();
11199
11200         i_attnum = PQfnumber(res, "attnum");
11201         i_attname = PQfnumber(res, "attname");
11202         while (ncomments > 0)
11203         {
11204                 const char *attname;
11205
11206                 attname = NULL;
11207                 for (i = 0; i < ntups; i++)
11208                 {
11209                         if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
11210                         {
11211                                 attname = PQgetvalue(res, i, i_attname);
11212                                 break;
11213                         }
11214                 }
11215                 if (attname)                    /* just in case we don't find it */
11216                 {
11217                         const char *descr = comments->descr;
11218
11219                         resetPQExpBuffer(target);
11220                         appendPQExpBuffer(target, "COLUMN %s.",
11221                                                           fmtId(tyinfo->dobj.name));
11222                         appendPQExpBufferStr(target, fmtId(attname));
11223
11224                         resetPQExpBuffer(query);
11225                         appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
11226                                                           fmtQualifiedDumpable(tyinfo));
11227                         appendPQExpBuffer(query, "%s IS ", fmtId(attname));
11228                         appendStringLiteralAH(query, descr, fout);
11229                         appendPQExpBufferStr(query, ";\n");
11230
11231                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
11232                                                  ARCHIVE_OPTS(.tag = target->data,
11233                                                                           .namespace = tyinfo->dobj.namespace->dobj.name,
11234                                                                           .owner = tyinfo->rolname,
11235                                                                           .description = "COMMENT",
11236                                                                           .section = SECTION_NONE,
11237                                                                           .createStmt = query->data,
11238                                                                           .dropStmt = "",
11239                                                                           .deps = &(tyinfo->dobj.dumpId),
11240                                                                           .nDeps = 1));
11241                 }
11242
11243                 comments++;
11244                 ncomments--;
11245         }
11246
11247         PQclear(res);
11248         destroyPQExpBuffer(query);
11249         destroyPQExpBuffer(target);
11250 }
11251
11252 /*
11253  * dumpShellType
11254  *        writes out to fout the queries to create a shell type
11255  *
11256  * We dump a shell definition in advance of the I/O functions for the type.
11257  */
11258 static void
11259 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
11260 {
11261         DumpOptions *dopt = fout->dopt;
11262         PQExpBuffer q;
11263
11264         /* Skip if not to be dumped */
11265         if (!stinfo->dobj.dump || dopt->dataOnly)
11266                 return;
11267
11268         q = createPQExpBuffer();
11269
11270         /*
11271          * Note the lack of a DROP command for the shell type; any required DROP
11272          * is driven off the base type entry, instead.  This interacts with
11273          * _printTocEntry()'s use of the presence of a DROP command to decide
11274          * whether an entry needs an ALTER OWNER command.  We don't want to alter
11275          * the shell type's owner immediately on creation; that should happen only
11276          * after it's filled in, otherwise the backend complains.
11277          */
11278
11279         if (dopt->binary_upgrade)
11280                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
11281                                                                                                  stinfo->baseType->dobj.catId.oid,
11282                                                                                                  false);
11283
11284         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
11285                                           fmtQualifiedDumpable(stinfo));
11286
11287         if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11288                 ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
11289                                          ARCHIVE_OPTS(.tag = stinfo->dobj.name,
11290                                                                   .namespace = stinfo->dobj.namespace->dobj.name,
11291                                                                   .owner = stinfo->baseType->rolname,
11292                                                                   .description = "SHELL TYPE",
11293                                                                   .section = SECTION_PRE_DATA,
11294                                                                   .createStmt = q->data,
11295                                                                   .dropStmt = ""));
11296
11297         destroyPQExpBuffer(q);
11298 }
11299
11300 /*
11301  * dumpProcLang
11302  *                writes out to fout the queries to recreate a user-defined
11303  *                procedural language
11304  */
11305 static void
11306 dumpProcLang(Archive *fout, ProcLangInfo *plang)
11307 {
11308         DumpOptions *dopt = fout->dopt;
11309         PQExpBuffer defqry;
11310         PQExpBuffer delqry;
11311         bool            useParams;
11312         char       *qlanname;
11313         FuncInfo   *funcInfo;
11314         FuncInfo   *inlineInfo = NULL;
11315         FuncInfo   *validatorInfo = NULL;
11316
11317         /* Skip if not to be dumped */
11318         if (!plang->dobj.dump || dopt->dataOnly)
11319                 return;
11320
11321         /*
11322          * Try to find the support function(s).  It is not an error if we don't
11323          * find them --- if the functions are in the pg_catalog schema, as is
11324          * standard in 8.1 and up, then we won't have loaded them. (In this case
11325          * we will emit a parameterless CREATE LANGUAGE command, which will
11326          * require PL template knowledge in the backend to reload.)
11327          */
11328
11329         funcInfo = findFuncByOid(plang->lanplcallfoid);
11330         if (funcInfo != NULL && !funcInfo->dobj.dump)
11331                 funcInfo = NULL;                /* treat not-dumped same as not-found */
11332
11333         if (OidIsValid(plang->laninline))
11334         {
11335                 inlineInfo = findFuncByOid(plang->laninline);
11336                 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
11337                         inlineInfo = NULL;
11338         }
11339
11340         if (OidIsValid(plang->lanvalidator))
11341         {
11342                 validatorInfo = findFuncByOid(plang->lanvalidator);
11343                 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
11344                         validatorInfo = NULL;
11345         }
11346
11347         /*
11348          * If the functions are dumpable then emit a traditional CREATE LANGUAGE
11349          * with parameters.  Otherwise, we'll write a parameterless command, which
11350          * will rely on data from pg_pltemplate.
11351          */
11352         useParams = (funcInfo != NULL &&
11353                                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
11354                                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
11355
11356         defqry = createPQExpBuffer();
11357         delqry = createPQExpBuffer();
11358
11359         qlanname = pg_strdup(fmtId(plang->dobj.name));
11360
11361         appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
11362                                           qlanname);
11363
11364         if (useParams)
11365         {
11366                 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
11367                                                   plang->lanpltrusted ? "TRUSTED " : "",
11368                                                   qlanname);
11369                 appendPQExpBuffer(defqry, " HANDLER %s",
11370                                                   fmtQualifiedDumpable(funcInfo));
11371                 if (OidIsValid(plang->laninline))
11372                         appendPQExpBuffer(defqry, " INLINE %s",
11373                                                           fmtQualifiedDumpable(inlineInfo));
11374                 if (OidIsValid(plang->lanvalidator))
11375                         appendPQExpBuffer(defqry, " VALIDATOR %s",
11376                                                           fmtQualifiedDumpable(validatorInfo));
11377         }
11378         else
11379         {
11380                 /*
11381                  * If not dumping parameters, then use CREATE OR REPLACE so that the
11382                  * command will not fail if the language is preinstalled in the target
11383                  * database.  We restrict the use of REPLACE to this case so as to
11384                  * eliminate the risk of replacing a language with incompatible
11385                  * parameter settings: this command will only succeed at all if there
11386                  * is a pg_pltemplate entry, and if there is one, the existing entry
11387                  * must match it too.
11388                  */
11389                 appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
11390                                                   qlanname);
11391         }
11392         appendPQExpBufferStr(defqry, ";\n");
11393
11394         if (dopt->binary_upgrade)
11395                 binary_upgrade_extension_member(defqry, &plang->dobj,
11396                                                                                 "LANGUAGE", qlanname, NULL);
11397
11398         if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
11399                 ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
11400                                          ARCHIVE_OPTS(.tag = plang->dobj.name,
11401                                                                   .owner = plang->lanowner,
11402                                                                   .description = "PROCEDURAL LANGUAGE",
11403                                                                   .section = SECTION_PRE_DATA,
11404                                                                   .createStmt = defqry->data,
11405                                                                   .dropStmt = delqry->data,
11406                                                                   ));
11407
11408         /* Dump Proc Lang Comments and Security Labels */
11409         if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
11410                 dumpComment(fout, "LANGUAGE", qlanname,
11411                                         NULL, plang->lanowner,
11412                                         plang->dobj.catId, 0, plang->dobj.dumpId);
11413
11414         if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
11415                 dumpSecLabel(fout, "LANGUAGE", qlanname,
11416                                          NULL, plang->lanowner,
11417                                          plang->dobj.catId, 0, plang->dobj.dumpId);
11418
11419         if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
11420                 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
11421                                 qlanname, NULL, NULL,
11422                                 plang->lanowner, plang->lanacl, plang->rlanacl,
11423                                 plang->initlanacl, plang->initrlanacl);
11424
11425         free(qlanname);
11426
11427         destroyPQExpBuffer(defqry);
11428         destroyPQExpBuffer(delqry);
11429 }
11430
11431 /*
11432  * format_function_arguments: generate function name and argument list
11433  *
11434  * This is used when we can rely on pg_get_function_arguments to format
11435  * the argument list.  Note, however, that pg_get_function_arguments
11436  * does not special-case zero-argument aggregates.
11437  */
11438 static char *
11439 format_function_arguments(FuncInfo *finfo, char *funcargs, bool is_agg)
11440 {
11441         PQExpBufferData fn;
11442
11443         initPQExpBuffer(&fn);
11444         appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
11445         if (is_agg && finfo->nargs == 0)
11446                 appendPQExpBufferStr(&fn, "(*)");
11447         else
11448                 appendPQExpBuffer(&fn, "(%s)", funcargs);
11449         return fn.data;
11450 }
11451
11452 /*
11453  * format_function_arguments_old: generate function name and argument list
11454  *
11455  * The argument type names are qualified if needed.  The function name
11456  * is never qualified.
11457  *
11458  * This is used only with pre-8.4 servers, so we aren't expecting to see
11459  * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
11460  *
11461  * Any or all of allargtypes, argmodes, argnames may be NULL.
11462  */
11463 static char *
11464 format_function_arguments_old(Archive *fout,
11465                                                           FuncInfo *finfo, int nallargs,
11466                                                           char **allargtypes,
11467                                                           char **argmodes,
11468                                                           char **argnames)
11469 {
11470         PQExpBufferData fn;
11471         int                     j;
11472
11473         initPQExpBuffer(&fn);
11474         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11475         for (j = 0; j < nallargs; j++)
11476         {
11477                 Oid                     typid;
11478                 char       *typname;
11479                 const char *argmode;
11480                 const char *argname;
11481
11482                 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
11483                 typname = getFormattedTypeName(fout, typid, zeroAsOpaque);
11484
11485                 if (argmodes)
11486                 {
11487                         switch (argmodes[j][0])
11488                         {
11489                                 case PROARGMODE_IN:
11490                                         argmode = "";
11491                                         break;
11492                                 case PROARGMODE_OUT:
11493                                         argmode = "OUT ";
11494                                         break;
11495                                 case PROARGMODE_INOUT:
11496                                         argmode = "INOUT ";
11497                                         break;
11498                                 default:
11499                                         write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
11500                                         argmode = "";
11501                                         break;
11502                         }
11503                 }
11504                 else
11505                         argmode = "";
11506
11507                 argname = argnames ? argnames[j] : (char *) NULL;
11508                 if (argname && argname[0] == '\0')
11509                         argname = NULL;
11510
11511                 appendPQExpBuffer(&fn, "%s%s%s%s%s",
11512                                                   (j > 0) ? ", " : "",
11513                                                   argmode,
11514                                                   argname ? fmtId(argname) : "",
11515                                                   argname ? " " : "",
11516                                                   typname);
11517                 free(typname);
11518         }
11519         appendPQExpBufferChar(&fn, ')');
11520         return fn.data;
11521 }
11522
11523 /*
11524  * format_function_signature: generate function name and argument list
11525  *
11526  * This is like format_function_arguments_old except that only a minimal
11527  * list of input argument types is generated; this is sufficient to
11528  * reference the function, but not to define it.
11529  *
11530  * If honor_quotes is false then the function name is never quoted.
11531  * This is appropriate for use in TOC tags, but not in SQL commands.
11532  */
11533 static char *
11534 format_function_signature(Archive *fout, FuncInfo *finfo, bool honor_quotes)
11535 {
11536         PQExpBufferData fn;
11537         int                     j;
11538
11539         initPQExpBuffer(&fn);
11540         if (honor_quotes)
11541                 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11542         else
11543                 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
11544         for (j = 0; j < finfo->nargs; j++)
11545         {
11546                 char       *typname;
11547
11548                 if (j > 0)
11549                         appendPQExpBufferStr(&fn, ", ");
11550
11551                 typname = getFormattedTypeName(fout, finfo->argtypes[j],
11552                                                                            zeroAsOpaque);
11553                 appendPQExpBufferStr(&fn, typname);
11554                 free(typname);
11555         }
11556         appendPQExpBufferChar(&fn, ')');
11557         return fn.data;
11558 }
11559
11560
11561 /*
11562  * dumpFunc:
11563  *        dump out one function
11564  */
11565 static void
11566 dumpFunc(Archive *fout, FuncInfo *finfo)
11567 {
11568         DumpOptions *dopt = fout->dopt;
11569         PQExpBuffer query;
11570         PQExpBuffer q;
11571         PQExpBuffer delqry;
11572         PQExpBuffer asPart;
11573         PGresult   *res;
11574         char       *funcsig;            /* identity signature */
11575         char       *funcfullsig = NULL; /* full signature */
11576         char       *funcsig_tag;
11577         char       *proretset;
11578         char       *prosrc;
11579         char       *probin;
11580         char       *funcargs;
11581         char       *funciargs;
11582         char       *funcresult;
11583         char       *proallargtypes;
11584         char       *proargmodes;
11585         char       *proargnames;
11586         char       *protrftypes;
11587         char       *prokind;
11588         char       *provolatile;
11589         char       *proisstrict;
11590         char       *prosecdef;
11591         char       *proleakproof;
11592         char       *proconfig;
11593         char       *procost;
11594         char       *prorows;
11595         char       *prosupport;
11596         char       *proparallel;
11597         char       *lanname;
11598         char       *rettypename;
11599         int                     nallargs;
11600         char      **allargtypes = NULL;
11601         char      **argmodes = NULL;
11602         char      **argnames = NULL;
11603         char      **configitems = NULL;
11604         int                     nconfigitems = 0;
11605         const char *keyword;
11606         int                     i;
11607
11608         /* Skip if not to be dumped */
11609         if (!finfo->dobj.dump || dopt->dataOnly)
11610                 return;
11611
11612         query = createPQExpBuffer();
11613         q = createPQExpBuffer();
11614         delqry = createPQExpBuffer();
11615         asPart = createPQExpBuffer();
11616
11617         /* Fetch function-specific details */
11618         if (fout->remoteVersion >= 120000)
11619         {
11620                 /*
11621                  * prosupport was added in 12
11622                  */
11623                 appendPQExpBuffer(query,
11624                                                   "SELECT proretset, prosrc, probin, "
11625                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11626                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11627                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11628                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11629                                                   "prokind, provolatile, proisstrict, prosecdef, "
11630                                                   "proleakproof, proconfig, procost, prorows, "
11631                                                   "prosupport, proparallel, "
11632                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11633                                                   "FROM pg_catalog.pg_proc "
11634                                                   "WHERE oid = '%u'::pg_catalog.oid",
11635                                                   finfo->dobj.catId.oid);
11636         }
11637         else if (fout->remoteVersion >= 110000)
11638         {
11639                 /*
11640                  * prokind was added in 11
11641                  */
11642                 appendPQExpBuffer(query,
11643                                                   "SELECT proretset, prosrc, probin, "
11644                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11645                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11646                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11647                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11648                                                   "prokind, provolatile, proisstrict, prosecdef, "
11649                                                   "proleakproof, proconfig, procost, prorows, "
11650                                                   "'-' AS prosupport, proparallel, "
11651                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11652                                                   "FROM pg_catalog.pg_proc "
11653                                                   "WHERE oid = '%u'::pg_catalog.oid",
11654                                                   finfo->dobj.catId.oid);
11655         }
11656         else if (fout->remoteVersion >= 90600)
11657         {
11658                 /*
11659                  * proparallel was added in 9.6
11660                  */
11661                 appendPQExpBuffer(query,
11662                                                   "SELECT proretset, prosrc, probin, "
11663                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11664                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11665                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11666                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11667                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11668                                                   "provolatile, proisstrict, prosecdef, "
11669                                                   "proleakproof, proconfig, procost, prorows, "
11670                                                   "'-' AS prosupport, proparallel, "
11671                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11672                                                   "FROM pg_catalog.pg_proc "
11673                                                   "WHERE oid = '%u'::pg_catalog.oid",
11674                                                   finfo->dobj.catId.oid);
11675         }
11676         else if (fout->remoteVersion >= 90500)
11677         {
11678                 /*
11679                  * protrftypes was added in 9.5
11680                  */
11681                 appendPQExpBuffer(query,
11682                                                   "SELECT proretset, prosrc, probin, "
11683                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11684                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11685                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11686                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11687                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11688                                                   "provolatile, proisstrict, prosecdef, "
11689                                                   "proleakproof, proconfig, procost, prorows, "
11690                                                   "'-' AS prosupport, "
11691                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11692                                                   "FROM pg_catalog.pg_proc "
11693                                                   "WHERE oid = '%u'::pg_catalog.oid",
11694                                                   finfo->dobj.catId.oid);
11695         }
11696         else if (fout->remoteVersion >= 90200)
11697         {
11698                 /*
11699                  * proleakproof was added in 9.2
11700                  */
11701                 appendPQExpBuffer(query,
11702                                                   "SELECT proretset, prosrc, probin, "
11703                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11704                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11705                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11706                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11707                                                   "provolatile, proisstrict, prosecdef, "
11708                                                   "proleakproof, proconfig, procost, prorows, "
11709                                                   "'-' AS prosupport, "
11710                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11711                                                   "FROM pg_catalog.pg_proc "
11712                                                   "WHERE oid = '%u'::pg_catalog.oid",
11713                                                   finfo->dobj.catId.oid);
11714         }
11715         else if (fout->remoteVersion >= 80400)
11716         {
11717                 /*
11718                  * In 8.4 and up we rely on pg_get_function_arguments and
11719                  * pg_get_function_result instead of examining proallargtypes etc.
11720                  */
11721                 appendPQExpBuffer(query,
11722                                                   "SELECT proretset, prosrc, probin, "
11723                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11724                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11725                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11726                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11727                                                   "provolatile, proisstrict, prosecdef, "
11728                                                   "false AS proleakproof, "
11729                                                   " proconfig, procost, prorows, "
11730                                                   "'-' AS prosupport, "
11731                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11732                                                   "FROM pg_catalog.pg_proc "
11733                                                   "WHERE oid = '%u'::pg_catalog.oid",
11734                                                   finfo->dobj.catId.oid);
11735         }
11736         else if (fout->remoteVersion >= 80300)
11737         {
11738                 appendPQExpBuffer(query,
11739                                                   "SELECT proretset, prosrc, probin, "
11740                                                   "proallargtypes, proargmodes, proargnames, "
11741                                                   "'f' AS prokind, "
11742                                                   "provolatile, proisstrict, prosecdef, "
11743                                                   "false AS proleakproof, "
11744                                                   "proconfig, procost, prorows, "
11745                                                   "'-' AS prosupport, "
11746                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11747                                                   "FROM pg_catalog.pg_proc "
11748                                                   "WHERE oid = '%u'::pg_catalog.oid",
11749                                                   finfo->dobj.catId.oid);
11750         }
11751         else if (fout->remoteVersion >= 80100)
11752         {
11753                 appendPQExpBuffer(query,
11754                                                   "SELECT proretset, prosrc, probin, "
11755                                                   "proallargtypes, proargmodes, proargnames, "
11756                                                   "'f' AS prokind, "
11757                                                   "provolatile, proisstrict, prosecdef, "
11758                                                   "false AS proleakproof, "
11759                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
11760                                                   "'-' AS prosupport, "
11761                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11762                                                   "FROM pg_catalog.pg_proc "
11763                                                   "WHERE oid = '%u'::pg_catalog.oid",
11764                                                   finfo->dobj.catId.oid);
11765         }
11766         else
11767         {
11768                 appendPQExpBuffer(query,
11769                                                   "SELECT proretset, prosrc, probin, "
11770                                                   "null AS proallargtypes, "
11771                                                   "null AS proargmodes, "
11772                                                   "proargnames, "
11773                                                   "'f' AS prokind, "
11774                                                   "provolatile, proisstrict, prosecdef, "
11775                                                   "false AS proleakproof, "
11776                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
11777                                                   "'-' AS prosupport, "
11778                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11779                                                   "FROM pg_catalog.pg_proc "
11780                                                   "WHERE oid = '%u'::pg_catalog.oid",
11781                                                   finfo->dobj.catId.oid);
11782         }
11783
11784         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11785
11786         proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
11787         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
11788         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
11789         if (fout->remoteVersion >= 80400)
11790         {
11791                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
11792                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
11793                 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
11794                 proallargtypes = proargmodes = proargnames = NULL;
11795         }
11796         else
11797         {
11798                 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
11799                 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
11800                 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
11801                 funcargs = funciargs = funcresult = NULL;
11802         }
11803         if (PQfnumber(res, "protrftypes") != -1)
11804                 protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
11805         else
11806                 protrftypes = NULL;
11807         prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
11808         provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
11809         proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
11810         prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
11811         proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
11812         proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
11813         procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
11814         prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
11815         prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
11816
11817         if (PQfnumber(res, "proparallel") != -1)
11818                 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
11819         else
11820                 proparallel = NULL;
11821
11822         lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
11823
11824         /*
11825          * See backend/commands/functioncmds.c for details of how the 'AS' clause
11826          * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
11827          * versions would set it to "-".  There are no known cases in which prosrc
11828          * is unused, so the tests below for "-" are probably useless.
11829          */
11830         if (probin[0] != '\0' && strcmp(probin, "-") != 0)
11831         {
11832                 appendPQExpBufferStr(asPart, "AS ");
11833                 appendStringLiteralAH(asPart, probin, fout);
11834                 if (strcmp(prosrc, "-") != 0)
11835                 {
11836                         appendPQExpBufferStr(asPart, ", ");
11837
11838                         /*
11839                          * where we have bin, use dollar quoting if allowed and src
11840                          * contains quote or backslash; else use regular quoting.
11841                          */
11842                         if (dopt->disable_dollar_quoting ||
11843                                 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
11844                                 appendStringLiteralAH(asPart, prosrc, fout);
11845                         else
11846                                 appendStringLiteralDQ(asPart, prosrc, NULL);
11847                 }
11848         }
11849         else
11850         {
11851                 if (strcmp(prosrc, "-") != 0)
11852                 {
11853                         appendPQExpBufferStr(asPart, "AS ");
11854                         /* with no bin, dollar quote src unconditionally if allowed */
11855                         if (dopt->disable_dollar_quoting)
11856                                 appendStringLiteralAH(asPart, prosrc, fout);
11857                         else
11858                                 appendStringLiteralDQ(asPart, prosrc, NULL);
11859                 }
11860         }
11861
11862         nallargs = finfo->nargs;        /* unless we learn different from allargs */
11863
11864         if (proallargtypes && *proallargtypes)
11865         {
11866                 int                     nitems = 0;
11867
11868                 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
11869                         nitems < finfo->nargs)
11870                 {
11871                         write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
11872                         if (allargtypes)
11873                                 free(allargtypes);
11874                         allargtypes = NULL;
11875                 }
11876                 else
11877                         nallargs = nitems;
11878         }
11879
11880         if (proargmodes && *proargmodes)
11881         {
11882                 int                     nitems = 0;
11883
11884                 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
11885                         nitems != nallargs)
11886                 {
11887                         write_msg(NULL, "WARNING: could not parse proargmodes array\n");
11888                         if (argmodes)
11889                                 free(argmodes);
11890                         argmodes = NULL;
11891                 }
11892         }
11893
11894         if (proargnames && *proargnames)
11895         {
11896                 int                     nitems = 0;
11897
11898                 if (!parsePGArray(proargnames, &argnames, &nitems) ||
11899                         nitems != nallargs)
11900                 {
11901                         write_msg(NULL, "WARNING: could not parse proargnames array\n");
11902                         if (argnames)
11903                                 free(argnames);
11904                         argnames = NULL;
11905                 }
11906         }
11907
11908         if (proconfig && *proconfig)
11909         {
11910                 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
11911                 {
11912                         write_msg(NULL, "WARNING: could not parse proconfig array\n");
11913                         if (configitems)
11914                                 free(configitems);
11915                         configitems = NULL;
11916                         nconfigitems = 0;
11917                 }
11918         }
11919
11920         if (funcargs)
11921         {
11922                 /* 8.4 or later; we rely on server-side code for most of the work */
11923                 funcfullsig = format_function_arguments(finfo, funcargs, false);
11924                 funcsig = format_function_arguments(finfo, funciargs, false);
11925         }
11926         else
11927                 /* pre-8.4, do it ourselves */
11928                 funcsig = format_function_arguments_old(fout,
11929                                                                                                 finfo, nallargs, allargtypes,
11930                                                                                                 argmodes, argnames);
11931
11932         funcsig_tag = format_function_signature(fout, finfo, false);
11933
11934         if (prokind[0] == PROKIND_PROCEDURE)
11935                 keyword = "PROCEDURE";
11936         else
11937                 keyword = "FUNCTION";   /* works for window functions too */
11938
11939         appendPQExpBuffer(delqry, "DROP %s %s.%s;\n",
11940                                           keyword,
11941                                           fmtId(finfo->dobj.namespace->dobj.name),
11942                                           funcsig);
11943
11944         appendPQExpBuffer(q, "CREATE %s %s.%s",
11945                                           keyword,
11946                                           fmtId(finfo->dobj.namespace->dobj.name),
11947                                           funcfullsig ? funcfullsig :
11948                                           funcsig);
11949
11950         if (prokind[0] == PROKIND_PROCEDURE)
11951                  /* no result type to output */ ;
11952         else if (funcresult)
11953                 appendPQExpBuffer(q, " RETURNS %s", funcresult);
11954         else
11955         {
11956                 rettypename = getFormattedTypeName(fout, finfo->prorettype,
11957                                                                                    zeroAsOpaque);
11958                 appendPQExpBuffer(q, " RETURNS %s%s",
11959                                                   (proretset[0] == 't') ? "SETOF " : "",
11960                                                   rettypename);
11961                 free(rettypename);
11962         }
11963
11964         appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
11965
11966         if (protrftypes != NULL && strcmp(protrftypes, "") != 0)
11967         {
11968                 Oid                *typeids = palloc(FUNC_MAX_ARGS * sizeof(Oid));
11969                 int                     i;
11970
11971                 appendPQExpBufferStr(q, " TRANSFORM ");
11972                 parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
11973                 for (i = 0; typeids[i]; i++)
11974                 {
11975                         if (i != 0)
11976                                 appendPQExpBufferStr(q, ", ");
11977                         appendPQExpBuffer(q, "FOR TYPE %s",
11978                                                           getFormattedTypeName(fout, typeids[i], zeroAsNone));
11979                 }
11980         }
11981
11982         if (prokind[0] == PROKIND_WINDOW)
11983                 appendPQExpBufferStr(q, " WINDOW");
11984
11985         if (provolatile[0] != PROVOLATILE_VOLATILE)
11986         {
11987                 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
11988                         appendPQExpBufferStr(q, " IMMUTABLE");
11989                 else if (provolatile[0] == PROVOLATILE_STABLE)
11990                         appendPQExpBufferStr(q, " STABLE");
11991                 else if (provolatile[0] != PROVOLATILE_VOLATILE)
11992                         exit_horribly(NULL, "unrecognized provolatile value for function \"%s\"\n",
11993                                                   finfo->dobj.name);
11994         }
11995
11996         if (proisstrict[0] == 't')
11997                 appendPQExpBufferStr(q, " STRICT");
11998
11999         if (prosecdef[0] == 't')
12000                 appendPQExpBufferStr(q, " SECURITY DEFINER");
12001
12002         if (proleakproof[0] == 't')
12003                 appendPQExpBufferStr(q, " LEAKPROOF");
12004
12005         /*
12006          * COST and ROWS are emitted only if present and not default, so as not to
12007          * break backwards-compatibility of the dump without need.  Keep this code
12008          * in sync with the defaults in functioncmds.c.
12009          */
12010         if (strcmp(procost, "0") != 0)
12011         {
12012                 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
12013                 {
12014                         /* default cost is 1 */
12015                         if (strcmp(procost, "1") != 0)
12016                                 appendPQExpBuffer(q, " COST %s", procost);
12017                 }
12018                 else
12019                 {
12020                         /* default cost is 100 */
12021                         if (strcmp(procost, "100") != 0)
12022                                 appendPQExpBuffer(q, " COST %s", procost);
12023                 }
12024         }
12025         if (proretset[0] == 't' &&
12026                 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
12027                 appendPQExpBuffer(q, " ROWS %s", prorows);
12028
12029         if (strcmp(prosupport, "-") != 0)
12030         {
12031                 /* We rely on regprocout to provide quoting and qualification */
12032                 appendPQExpBuffer(q, " SUPPORT %s", prosupport);
12033         }
12034
12035         if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
12036         {
12037                 if (proparallel[0] == PROPARALLEL_SAFE)
12038                         appendPQExpBufferStr(q, " PARALLEL SAFE");
12039                 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
12040                         appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
12041                 else if (proparallel[0] != PROPARALLEL_UNSAFE)
12042                         exit_horribly(NULL, "unrecognized proparallel value for function \"%s\"\n",
12043                                                   finfo->dobj.name);
12044         }
12045
12046         for (i = 0; i < nconfigitems; i++)
12047         {
12048                 /* we feel free to scribble on configitems[] here */
12049                 char       *configitem = configitems[i];
12050                 char       *pos;
12051
12052                 pos = strchr(configitem, '=');
12053                 if (pos == NULL)
12054                         continue;
12055                 *pos++ = '\0';
12056                 appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
12057
12058                 /*
12059                  * Variables that are marked GUC_LIST_QUOTE were already fully quoted
12060                  * by flatten_set_variable_args() before they were put into the
12061                  * proconfig array.  However, because the quoting rules used there
12062                  * aren't exactly like SQL's, we have to break the list value apart
12063                  * and then quote the elements as string literals.  (The elements may
12064                  * be double-quoted as-is, but we can't just feed them to the SQL
12065                  * parser; it would do the wrong thing with elements that are
12066                  * zero-length or longer than NAMEDATALEN.)
12067                  *
12068                  * Variables that are not so marked should just be emitted as simple
12069                  * string literals.  If the variable is not known to
12070                  * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
12071                  * to use GUC_LIST_QUOTE for extension variables.
12072                  */
12073                 if (variable_is_guc_list_quote(configitem))
12074                 {
12075                         char      **namelist;
12076                         char      **nameptr;
12077
12078                         /* Parse string into list of identifiers */
12079                         /* this shouldn't fail really */
12080                         if (SplitGUCList(pos, ',', &namelist))
12081                         {
12082                                 for (nameptr = namelist; *nameptr; nameptr++)
12083                                 {
12084                                         if (nameptr != namelist)
12085                                                 appendPQExpBufferStr(q, ", ");
12086                                         appendStringLiteralAH(q, *nameptr, fout);
12087                                 }
12088                         }
12089                         pg_free(namelist);
12090                 }
12091                 else
12092                         appendStringLiteralAH(q, pos, fout);
12093         }
12094
12095         appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
12096
12097         if (dopt->binary_upgrade)
12098                 binary_upgrade_extension_member(q, &finfo->dobj,
12099                                                                                 keyword, funcsig,
12100                                                                                 finfo->dobj.namespace->dobj.name);
12101
12102         if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12103                 ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
12104                                          ARCHIVE_OPTS(.tag = funcsig_tag,
12105                                                                   .namespace = finfo->dobj.namespace->dobj.name,
12106                                                                   .owner = finfo->rolname,
12107                                                                   .description = keyword,
12108                                                                   .section = SECTION_PRE_DATA,
12109                                                                   .createStmt = q->data,
12110                                                                   .dropStmt = delqry->data));
12111
12112         /* Dump Function Comments and Security Labels */
12113         if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12114                 dumpComment(fout, keyword, funcsig,
12115                                         finfo->dobj.namespace->dobj.name, finfo->rolname,
12116                                         finfo->dobj.catId, 0, finfo->dobj.dumpId);
12117
12118         if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
12119                 dumpSecLabel(fout, keyword, funcsig,
12120                                          finfo->dobj.namespace->dobj.name, finfo->rolname,
12121                                          finfo->dobj.catId, 0, finfo->dobj.dumpId);
12122
12123         if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
12124                 dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, keyword,
12125                                 funcsig, NULL,
12126                                 finfo->dobj.namespace->dobj.name,
12127                                 finfo->rolname, finfo->proacl, finfo->rproacl,
12128                                 finfo->initproacl, finfo->initrproacl);
12129
12130         PQclear(res);
12131
12132         destroyPQExpBuffer(query);
12133         destroyPQExpBuffer(q);
12134         destroyPQExpBuffer(delqry);
12135         destroyPQExpBuffer(asPart);
12136         free(funcsig);
12137         if (funcfullsig)
12138                 free(funcfullsig);
12139         free(funcsig_tag);
12140         if (allargtypes)
12141                 free(allargtypes);
12142         if (argmodes)
12143                 free(argmodes);
12144         if (argnames)
12145                 free(argnames);
12146         if (configitems)
12147                 free(configitems);
12148 }
12149
12150
12151 /*
12152  * Dump a user-defined cast
12153  */
12154 static void
12155 dumpCast(Archive *fout, CastInfo *cast)
12156 {
12157         DumpOptions *dopt = fout->dopt;
12158         PQExpBuffer defqry;
12159         PQExpBuffer delqry;
12160         PQExpBuffer labelq;
12161         PQExpBuffer castargs;
12162         FuncInfo   *funcInfo = NULL;
12163         char       *sourceType;
12164         char       *targetType;
12165
12166         /* Skip if not to be dumped */
12167         if (!cast->dobj.dump || dopt->dataOnly)
12168                 return;
12169
12170         /* Cannot dump if we don't have the cast function's info */
12171         if (OidIsValid(cast->castfunc))
12172         {
12173                 funcInfo = findFuncByOid(cast->castfunc);
12174                 if (funcInfo == NULL)
12175                         exit_horribly(NULL, "could not find function definition for function with OID %u\n",
12176                                                   cast->castfunc);
12177         }
12178
12179         defqry = createPQExpBuffer();
12180         delqry = createPQExpBuffer();
12181         labelq = createPQExpBuffer();
12182         castargs = createPQExpBuffer();
12183
12184         sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
12185         targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
12186         appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
12187                                           sourceType, targetType);
12188
12189         appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
12190                                           sourceType, targetType);
12191
12192         switch (cast->castmethod)
12193         {
12194                 case COERCION_METHOD_BINARY:
12195                         appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
12196                         break;
12197                 case COERCION_METHOD_INOUT:
12198                         appendPQExpBufferStr(defqry, "WITH INOUT");
12199                         break;
12200                 case COERCION_METHOD_FUNCTION:
12201                         if (funcInfo)
12202                         {
12203                                 char       *fsig = format_function_signature(fout, funcInfo, true);
12204
12205                                 /*
12206                                  * Always qualify the function name (format_function_signature
12207                                  * won't qualify it).
12208                                  */
12209                                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
12210                                                                   fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
12211                                 free(fsig);
12212                         }
12213                         else
12214                                 write_msg(NULL, "WARNING: bogus value in pg_cast.castfunc or pg_cast.castmethod field\n");
12215                         break;
12216                 default:
12217                         write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
12218         }
12219
12220         if (cast->castcontext == 'a')
12221                 appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
12222         else if (cast->castcontext == 'i')
12223                 appendPQExpBufferStr(defqry, " AS IMPLICIT");
12224         appendPQExpBufferStr(defqry, ";\n");
12225
12226         appendPQExpBuffer(labelq, "CAST (%s AS %s)",
12227                                           sourceType, targetType);
12228
12229         appendPQExpBuffer(castargs, "(%s AS %s)",
12230                                           sourceType, targetType);
12231
12232         if (dopt->binary_upgrade)
12233                 binary_upgrade_extension_member(defqry, &cast->dobj,
12234                                                                                 "CAST", castargs->data, NULL);
12235
12236         if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
12237                 ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
12238                                          ARCHIVE_OPTS(.tag = labelq->data,
12239                                                                   .description = "CAST",
12240                                                                   .owner = "",
12241                                                                   .section = SECTION_PRE_DATA,
12242                                                                   .createStmt = defqry->data,
12243                                                                   .dropStmt = delqry->data));
12244
12245         /* Dump Cast Comments */
12246         if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
12247                 dumpComment(fout, "CAST", castargs->data,
12248                                         NULL, "",
12249                                         cast->dobj.catId, 0, cast->dobj.dumpId);
12250
12251         free(sourceType);
12252         free(targetType);
12253
12254         destroyPQExpBuffer(defqry);
12255         destroyPQExpBuffer(delqry);
12256         destroyPQExpBuffer(labelq);
12257         destroyPQExpBuffer(castargs);
12258 }
12259
12260 /*
12261  * Dump a transform
12262  */
12263 static void
12264 dumpTransform(Archive *fout, TransformInfo *transform)
12265 {
12266         DumpOptions *dopt = fout->dopt;
12267         PQExpBuffer defqry;
12268         PQExpBuffer delqry;
12269         PQExpBuffer labelq;
12270         PQExpBuffer transformargs;
12271         FuncInfo   *fromsqlFuncInfo = NULL;
12272         FuncInfo   *tosqlFuncInfo = NULL;
12273         char       *lanname;
12274         char       *transformType;
12275
12276         /* Skip if not to be dumped */
12277         if (!transform->dobj.dump || dopt->dataOnly)
12278                 return;
12279
12280         /* Cannot dump if we don't have the transform functions' info */
12281         if (OidIsValid(transform->trffromsql))
12282         {
12283                 fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
12284                 if (fromsqlFuncInfo == NULL)
12285                         exit_horribly(NULL, "could not find function definition for function with OID %u\n",
12286                                                   transform->trffromsql);
12287         }
12288         if (OidIsValid(transform->trftosql))
12289         {
12290                 tosqlFuncInfo = findFuncByOid(transform->trftosql);
12291                 if (tosqlFuncInfo == NULL)
12292                         exit_horribly(NULL, "could not find function definition for function with OID %u\n",
12293                                                   transform->trftosql);
12294         }
12295
12296         defqry = createPQExpBuffer();
12297         delqry = createPQExpBuffer();
12298         labelq = createPQExpBuffer();
12299         transformargs = createPQExpBuffer();
12300
12301         lanname = get_language_name(fout, transform->trflang);
12302         transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
12303
12304         appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
12305                                           transformType, lanname);
12306
12307         appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
12308                                           transformType, lanname);
12309
12310         if (!transform->trffromsql && !transform->trftosql)
12311                 write_msg(NULL, "WARNING: bogus transform definition, at least one of trffromsql and trftosql should be nonzero\n");
12312
12313         if (transform->trffromsql)
12314         {
12315                 if (fromsqlFuncInfo)
12316                 {
12317                         char       *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
12318
12319                         /*
12320                          * Always qualify the function name (format_function_signature
12321                          * won't qualify it).
12322                          */
12323                         appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
12324                                                           fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
12325                         free(fsig);
12326                 }
12327                 else
12328                         write_msg(NULL, "WARNING: bogus value in pg_transform.trffromsql field\n");
12329         }
12330
12331         if (transform->trftosql)
12332         {
12333                 if (transform->trffromsql)
12334                         appendPQExpBuffer(defqry, ", ");
12335
12336                 if (tosqlFuncInfo)
12337                 {
12338                         char       *fsig = format_function_signature(fout, tosqlFuncInfo, true);
12339
12340                         /*
12341                          * Always qualify the function name (format_function_signature
12342                          * won't qualify it).
12343                          */
12344                         appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
12345                                                           fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
12346                         free(fsig);
12347                 }
12348                 else
12349                         write_msg(NULL, "WARNING: bogus value in pg_transform.trftosql field\n");
12350         }
12351
12352         appendPQExpBuffer(defqry, ");\n");
12353
12354         appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
12355                                           transformType, lanname);
12356
12357         appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
12358                                           transformType, lanname);
12359
12360         if (dopt->binary_upgrade)
12361                 binary_upgrade_extension_member(defqry, &transform->dobj,
12362                                                                                 "TRANSFORM", transformargs->data, NULL);
12363
12364         if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
12365                 ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
12366                                          ARCHIVE_OPTS(.tag = labelq->data,
12367                                                                   .description = "TRANSFORM",
12368                                                                   .owner = "",
12369                                                                   .section = SECTION_PRE_DATA,
12370                                                                   .createStmt = defqry->data,
12371                                                                   .dropStmt = delqry->data,
12372                                                                   .deps = transform->dobj.dependencies,
12373                                                                   .nDeps = transform->dobj.nDeps));
12374
12375         /* Dump Transform Comments */
12376         if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
12377                 dumpComment(fout, "TRANSFORM", transformargs->data,
12378                                         NULL, "",
12379                                         transform->dobj.catId, 0, transform->dobj.dumpId);
12380
12381         free(lanname);
12382         free(transformType);
12383         destroyPQExpBuffer(defqry);
12384         destroyPQExpBuffer(delqry);
12385         destroyPQExpBuffer(labelq);
12386         destroyPQExpBuffer(transformargs);
12387 }
12388
12389
12390 /*
12391  * dumpOpr
12392  *        write out a single operator definition
12393  */
12394 static void
12395 dumpOpr(Archive *fout, OprInfo *oprinfo)
12396 {
12397         DumpOptions *dopt = fout->dopt;
12398         PQExpBuffer query;
12399         PQExpBuffer q;
12400         PQExpBuffer delq;
12401         PQExpBuffer oprid;
12402         PQExpBuffer details;
12403         PGresult   *res;
12404         int                     i_oprkind;
12405         int                     i_oprcode;
12406         int                     i_oprleft;
12407         int                     i_oprright;
12408         int                     i_oprcom;
12409         int                     i_oprnegate;
12410         int                     i_oprrest;
12411         int                     i_oprjoin;
12412         int                     i_oprcanmerge;
12413         int                     i_oprcanhash;
12414         char       *oprkind;
12415         char       *oprcode;
12416         char       *oprleft;
12417         char       *oprright;
12418         char       *oprcom;
12419         char       *oprnegate;
12420         char       *oprrest;
12421         char       *oprjoin;
12422         char       *oprcanmerge;
12423         char       *oprcanhash;
12424         char       *oprregproc;
12425         char       *oprref;
12426
12427         /* Skip if not to be dumped */
12428         if (!oprinfo->dobj.dump || dopt->dataOnly)
12429                 return;
12430
12431         /*
12432          * some operators are invalid because they were the result of user
12433          * defining operators before commutators exist
12434          */
12435         if (!OidIsValid(oprinfo->oprcode))
12436                 return;
12437
12438         query = createPQExpBuffer();
12439         q = createPQExpBuffer();
12440         delq = createPQExpBuffer();
12441         oprid = createPQExpBuffer();
12442         details = createPQExpBuffer();
12443
12444         if (fout->remoteVersion >= 80300)
12445         {
12446                 appendPQExpBuffer(query, "SELECT oprkind, "
12447                                                   "oprcode::pg_catalog.regprocedure, "
12448                                                   "oprleft::pg_catalog.regtype, "
12449                                                   "oprright::pg_catalog.regtype, "
12450                                                   "oprcom, "
12451                                                   "oprnegate, "
12452                                                   "oprrest::pg_catalog.regprocedure, "
12453                                                   "oprjoin::pg_catalog.regprocedure, "
12454                                                   "oprcanmerge, oprcanhash "
12455                                                   "FROM pg_catalog.pg_operator "
12456                                                   "WHERE oid = '%u'::pg_catalog.oid",
12457                                                   oprinfo->dobj.catId.oid);
12458         }
12459         else
12460         {
12461                 appendPQExpBuffer(query, "SELECT oprkind, "
12462                                                   "oprcode::pg_catalog.regprocedure, "
12463                                                   "oprleft::pg_catalog.regtype, "
12464                                                   "oprright::pg_catalog.regtype, "
12465                                                   "oprcom, "
12466                                                   "oprnegate, "
12467                                                   "oprrest::pg_catalog.regprocedure, "
12468                                                   "oprjoin::pg_catalog.regprocedure, "
12469                                                   "(oprlsortop != 0) AS oprcanmerge, "
12470                                                   "oprcanhash "
12471                                                   "FROM pg_catalog.pg_operator "
12472                                                   "WHERE oid = '%u'::pg_catalog.oid",
12473                                                   oprinfo->dobj.catId.oid);
12474         }
12475
12476         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12477
12478         i_oprkind = PQfnumber(res, "oprkind");
12479         i_oprcode = PQfnumber(res, "oprcode");
12480         i_oprleft = PQfnumber(res, "oprleft");
12481         i_oprright = PQfnumber(res, "oprright");
12482         i_oprcom = PQfnumber(res, "oprcom");
12483         i_oprnegate = PQfnumber(res, "oprnegate");
12484         i_oprrest = PQfnumber(res, "oprrest");
12485         i_oprjoin = PQfnumber(res, "oprjoin");
12486         i_oprcanmerge = PQfnumber(res, "oprcanmerge");
12487         i_oprcanhash = PQfnumber(res, "oprcanhash");
12488
12489         oprkind = PQgetvalue(res, 0, i_oprkind);
12490         oprcode = PQgetvalue(res, 0, i_oprcode);
12491         oprleft = PQgetvalue(res, 0, i_oprleft);
12492         oprright = PQgetvalue(res, 0, i_oprright);
12493         oprcom = PQgetvalue(res, 0, i_oprcom);
12494         oprnegate = PQgetvalue(res, 0, i_oprnegate);
12495         oprrest = PQgetvalue(res, 0, i_oprrest);
12496         oprjoin = PQgetvalue(res, 0, i_oprjoin);
12497         oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
12498         oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
12499
12500         oprregproc = convertRegProcReference(fout, oprcode);
12501         if (oprregproc)
12502         {
12503                 appendPQExpBuffer(details, "    FUNCTION = %s", oprregproc);
12504                 free(oprregproc);
12505         }
12506
12507         appendPQExpBuffer(oprid, "%s (",
12508                                           oprinfo->dobj.name);
12509
12510         /*
12511          * right unary means there's a left arg and left unary means there's a
12512          * right arg
12513          */
12514         if (strcmp(oprkind, "r") == 0 ||
12515                 strcmp(oprkind, "b") == 0)
12516         {
12517                 appendPQExpBuffer(details, ",\n    LEFTARG = %s", oprleft);
12518                 appendPQExpBufferStr(oprid, oprleft);
12519         }
12520         else
12521                 appendPQExpBufferStr(oprid, "NONE");
12522
12523         if (strcmp(oprkind, "l") == 0 ||
12524                 strcmp(oprkind, "b") == 0)
12525         {
12526                 appendPQExpBuffer(details, ",\n    RIGHTARG = %s", oprright);
12527                 appendPQExpBuffer(oprid, ", %s)", oprright);
12528         }
12529         else
12530                 appendPQExpBufferStr(oprid, ", NONE)");
12531
12532         oprref = getFormattedOperatorName(fout, oprcom);
12533         if (oprref)
12534         {
12535                 appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", oprref);
12536                 free(oprref);
12537         }
12538
12539         oprref = getFormattedOperatorName(fout, oprnegate);
12540         if (oprref)
12541         {
12542                 appendPQExpBuffer(details, ",\n    NEGATOR = %s", oprref);
12543                 free(oprref);
12544         }
12545
12546         if (strcmp(oprcanmerge, "t") == 0)
12547                 appendPQExpBufferStr(details, ",\n    MERGES");
12548
12549         if (strcmp(oprcanhash, "t") == 0)
12550                 appendPQExpBufferStr(details, ",\n    HASHES");
12551
12552         oprregproc = convertRegProcReference(fout, oprrest);
12553         if (oprregproc)
12554         {
12555                 appendPQExpBuffer(details, ",\n    RESTRICT = %s", oprregproc);
12556                 free(oprregproc);
12557         }
12558
12559         oprregproc = convertRegProcReference(fout, oprjoin);
12560         if (oprregproc)
12561         {
12562                 appendPQExpBuffer(details, ",\n    JOIN = %s", oprregproc);
12563                 free(oprregproc);
12564         }
12565
12566         appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
12567                                           fmtId(oprinfo->dobj.namespace->dobj.name),
12568                                           oprid->data);
12569
12570         appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
12571                                           fmtId(oprinfo->dobj.namespace->dobj.name),
12572                                           oprinfo->dobj.name, details->data);
12573
12574         if (dopt->binary_upgrade)
12575                 binary_upgrade_extension_member(q, &oprinfo->dobj,
12576                                                                                 "OPERATOR", oprid->data,
12577                                                                                 oprinfo->dobj.namespace->dobj.name);
12578
12579         if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12580                 ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
12581                                          ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
12582                                                                   .namespace = oprinfo->dobj.namespace->dobj.name,
12583                                                                   .owner = oprinfo->rolname,
12584                                                                   .description = "OPERATOR",
12585                                                                   .section = SECTION_PRE_DATA,
12586                                                                   .createStmt = q->data,
12587                                                                   .dropStmt = delq->data));
12588
12589         /* Dump Operator Comments */
12590         if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12591                 dumpComment(fout, "OPERATOR", oprid->data,
12592                                         oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
12593                                         oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
12594
12595         PQclear(res);
12596
12597         destroyPQExpBuffer(query);
12598         destroyPQExpBuffer(q);
12599         destroyPQExpBuffer(delq);
12600         destroyPQExpBuffer(oprid);
12601         destroyPQExpBuffer(details);
12602 }
12603
12604 /*
12605  * Convert a function reference obtained from pg_operator
12606  *
12607  * Returns allocated string of what to print, or NULL if function references
12608  * is InvalidOid. Returned string is expected to be free'd by the caller.
12609  *
12610  * The input is a REGPROCEDURE display; we have to strip the argument-types
12611  * part.
12612  */
12613 static char *
12614 convertRegProcReference(Archive *fout, const char *proc)
12615 {
12616         char       *name;
12617         char       *paren;
12618         bool            inquote;
12619
12620         /* In all cases "-" means a null reference */
12621         if (strcmp(proc, "-") == 0)
12622                 return NULL;
12623
12624         name = pg_strdup(proc);
12625         /* find non-double-quoted left paren */
12626         inquote = false;
12627         for (paren = name; *paren; paren++)
12628         {
12629                 if (*paren == '(' && !inquote)
12630                 {
12631                         *paren = '\0';
12632                         break;
12633                 }
12634                 if (*paren == '"')
12635                         inquote = !inquote;
12636         }
12637         return name;
12638 }
12639
12640 /*
12641  * getFormattedOperatorName - retrieve the operator name for the
12642  * given operator OID (presented in string form).
12643  *
12644  * Returns an allocated string, or NULL if the given OID is invalid.
12645  * Caller is responsible for free'ing result string.
12646  *
12647  * What we produce has the format "OPERATOR(schema.oprname)".  This is only
12648  * useful in commands where the operator's argument types can be inferred from
12649  * context.  We always schema-qualify the name, though.  The predecessor to
12650  * this code tried to skip the schema qualification if possible, but that led
12651  * to wrong results in corner cases, such as if an operator and its negator
12652  * are in different schemas.
12653  */
12654 static char *
12655 getFormattedOperatorName(Archive *fout, const char *oproid)
12656 {
12657         OprInfo    *oprInfo;
12658
12659         /* In all cases "0" means a null reference */
12660         if (strcmp(oproid, "0") == 0)
12661                 return NULL;
12662
12663         oprInfo = findOprByOid(atooid(oproid));
12664         if (oprInfo == NULL)
12665         {
12666                 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
12667                                   oproid);
12668                 return NULL;
12669         }
12670
12671         return psprintf("OPERATOR(%s.%s)",
12672                                         fmtId(oprInfo->dobj.namespace->dobj.name),
12673                                         oprInfo->dobj.name);
12674 }
12675
12676 /*
12677  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
12678  *
12679  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
12680  * argument lists of these functions are predetermined.  Note that the
12681  * caller should ensure we are in the proper schema, because the results
12682  * are search path dependent!
12683  */
12684 static char *
12685 convertTSFunction(Archive *fout, Oid funcOid)
12686 {
12687         char       *result;
12688         char            query[128];
12689         PGresult   *res;
12690
12691         snprintf(query, sizeof(query),
12692                          "SELECT '%u'::pg_catalog.regproc", funcOid);
12693         res = ExecuteSqlQueryForSingleRow(fout, query);
12694
12695         result = pg_strdup(PQgetvalue(res, 0, 0));
12696
12697         PQclear(res);
12698
12699         return result;
12700 }
12701
12702 /*
12703  * dumpAccessMethod
12704  *        write out a single access method definition
12705  */
12706 static void
12707 dumpAccessMethod(Archive *fout, AccessMethodInfo *aminfo)
12708 {
12709         DumpOptions *dopt = fout->dopt;
12710         PQExpBuffer q;
12711         PQExpBuffer delq;
12712         char       *qamname;
12713
12714         /* Skip if not to be dumped */
12715         if (!aminfo->dobj.dump || dopt->dataOnly)
12716                 return;
12717
12718         q = createPQExpBuffer();
12719         delq = createPQExpBuffer();
12720
12721         qamname = pg_strdup(fmtId(aminfo->dobj.name));
12722
12723         appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
12724
12725         switch (aminfo->amtype)
12726         {
12727                 case AMTYPE_INDEX:
12728                         appendPQExpBuffer(q, "TYPE INDEX ");
12729                         break;
12730                 case AMTYPE_TABLE:
12731                         appendPQExpBuffer(q, "TYPE TABLE ");
12732                         break;
12733                 default:
12734                         write_msg(NULL, "WARNING: invalid type \"%c\" of access method \"%s\"\n",
12735                                           aminfo->amtype, qamname);
12736                         destroyPQExpBuffer(q);
12737                         destroyPQExpBuffer(delq);
12738                         free(qamname);
12739                         return;
12740         }
12741
12742         appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
12743
12744         appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
12745                                           qamname);
12746
12747         if (dopt->binary_upgrade)
12748                 binary_upgrade_extension_member(q, &aminfo->dobj,
12749                                                                                 "ACCESS METHOD", qamname, NULL);
12750
12751         if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12752                 ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
12753                                          ARCHIVE_OPTS(.tag = aminfo->dobj.name,
12754                                                                   .description = "ACCESS METHOD",
12755                                                                   .owner = "",
12756                                                                   .section = SECTION_PRE_DATA,
12757                                                                   .createStmt = q->data,
12758                                                                   .dropStmt = delq->data));
12759
12760         /* Dump Access Method Comments */
12761         if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12762                 dumpComment(fout, "ACCESS METHOD", qamname,
12763                                         NULL, "",
12764                                         aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
12765
12766         destroyPQExpBuffer(q);
12767         destroyPQExpBuffer(delq);
12768         free(qamname);
12769 }
12770
12771 /*
12772  * dumpOpclass
12773  *        write out a single operator class definition
12774  */
12775 static void
12776 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
12777 {
12778         DumpOptions *dopt = fout->dopt;
12779         PQExpBuffer query;
12780         PQExpBuffer q;
12781         PQExpBuffer delq;
12782         PQExpBuffer nameusing;
12783         PGresult   *res;
12784         int                     ntups;
12785         int                     i_opcintype;
12786         int                     i_opckeytype;
12787         int                     i_opcdefault;
12788         int                     i_opcfamily;
12789         int                     i_opcfamilyname;
12790         int                     i_opcfamilynsp;
12791         int                     i_amname;
12792         int                     i_amopstrategy;
12793         int                     i_amopreqcheck;
12794         int                     i_amopopr;
12795         int                     i_sortfamily;
12796         int                     i_sortfamilynsp;
12797         int                     i_amprocnum;
12798         int                     i_amproc;
12799         int                     i_amproclefttype;
12800         int                     i_amprocrighttype;
12801         char       *opcintype;
12802         char       *opckeytype;
12803         char       *opcdefault;
12804         char       *opcfamily;
12805         char       *opcfamilyname;
12806         char       *opcfamilynsp;
12807         char       *amname;
12808         char       *amopstrategy;
12809         char       *amopreqcheck;
12810         char       *amopopr;
12811         char       *sortfamily;
12812         char       *sortfamilynsp;
12813         char       *amprocnum;
12814         char       *amproc;
12815         char       *amproclefttype;
12816         char       *amprocrighttype;
12817         bool            needComma;
12818         int                     i;
12819
12820         /* Skip if not to be dumped */
12821         if (!opcinfo->dobj.dump || dopt->dataOnly)
12822                 return;
12823
12824         query = createPQExpBuffer();
12825         q = createPQExpBuffer();
12826         delq = createPQExpBuffer();
12827         nameusing = createPQExpBuffer();
12828
12829         /* Get additional fields from the pg_opclass row */
12830         if (fout->remoteVersion >= 80300)
12831         {
12832                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
12833                                                   "opckeytype::pg_catalog.regtype, "
12834                                                   "opcdefault, opcfamily, "
12835                                                   "opfname AS opcfamilyname, "
12836                                                   "nspname AS opcfamilynsp, "
12837                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
12838                                                   "FROM pg_catalog.pg_opclass c "
12839                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
12840                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12841                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
12842                                                   opcinfo->dobj.catId.oid);
12843         }
12844         else
12845         {
12846                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
12847                                                   "opckeytype::pg_catalog.regtype, "
12848                                                   "opcdefault, NULL AS opcfamily, "
12849                                                   "NULL AS opcfamilyname, "
12850                                                   "NULL AS opcfamilynsp, "
12851                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
12852                                                   "FROM pg_catalog.pg_opclass "
12853                                                   "WHERE oid = '%u'::pg_catalog.oid",
12854                                                   opcinfo->dobj.catId.oid);
12855         }
12856
12857         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12858
12859         i_opcintype = PQfnumber(res, "opcintype");
12860         i_opckeytype = PQfnumber(res, "opckeytype");
12861         i_opcdefault = PQfnumber(res, "opcdefault");
12862         i_opcfamily = PQfnumber(res, "opcfamily");
12863         i_opcfamilyname = PQfnumber(res, "opcfamilyname");
12864         i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
12865         i_amname = PQfnumber(res, "amname");
12866
12867         /* opcintype may still be needed after we PQclear res */
12868         opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
12869         opckeytype = PQgetvalue(res, 0, i_opckeytype);
12870         opcdefault = PQgetvalue(res, 0, i_opcdefault);
12871         /* opcfamily will still be needed after we PQclear res */
12872         opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
12873         opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
12874         opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
12875         /* amname will still be needed after we PQclear res */
12876         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
12877
12878         appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
12879                                           fmtQualifiedDumpable(opcinfo));
12880         appendPQExpBuffer(delq, " USING %s;\n",
12881                                           fmtId(amname));
12882
12883         /* Build the fixed portion of the CREATE command */
12884         appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
12885                                           fmtQualifiedDumpable(opcinfo));
12886         if (strcmp(opcdefault, "t") == 0)
12887                 appendPQExpBufferStr(q, "DEFAULT ");
12888         appendPQExpBuffer(q, "FOR TYPE %s USING %s",
12889                                           opcintype,
12890                                           fmtId(amname));
12891         if (strlen(opcfamilyname) > 0)
12892         {
12893                 appendPQExpBufferStr(q, " FAMILY ");
12894                 appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
12895                 appendPQExpBufferStr(q, fmtId(opcfamilyname));
12896         }
12897         appendPQExpBufferStr(q, " AS\n    ");
12898
12899         needComma = false;
12900
12901         if (strcmp(opckeytype, "-") != 0)
12902         {
12903                 appendPQExpBuffer(q, "STORAGE %s",
12904                                                   opckeytype);
12905                 needComma = true;
12906         }
12907
12908         PQclear(res);
12909
12910         /*
12911          * Now fetch and print the OPERATOR entries (pg_amop rows).
12912          *
12913          * Print only those opfamily members that are tied to the opclass by
12914          * pg_depend entries.
12915          *
12916          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
12917          * older server's opclass in which it is used.  This is to avoid
12918          * hard-to-detect breakage if a newer pg_dump is used to dump from an
12919          * older server and then reload into that old version.  This can go away
12920          * once 8.3 is so old as to not be of interest to anyone.
12921          */
12922         resetPQExpBuffer(query);
12923
12924         if (fout->remoteVersion >= 90100)
12925         {
12926                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12927                                                   "amopopr::pg_catalog.regoperator, "
12928                                                   "opfname AS sortfamily, "
12929                                                   "nspname AS sortfamilynsp "
12930                                                   "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
12931                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
12932                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
12933                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12934                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12935                                                   "AND refobjid = '%u'::pg_catalog.oid "
12936                                                   "AND amopfamily = '%s'::pg_catalog.oid "
12937                                                   "ORDER BY amopstrategy",
12938                                                   opcinfo->dobj.catId.oid,
12939                                                   opcfamily);
12940         }
12941         else if (fout->remoteVersion >= 80400)
12942         {
12943                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12944                                                   "amopopr::pg_catalog.regoperator, "
12945                                                   "NULL AS sortfamily, "
12946                                                   "NULL AS sortfamilynsp "
12947                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12948                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12949                                                   "AND refobjid = '%u'::pg_catalog.oid "
12950                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12951                                                   "AND objid = ao.oid "
12952                                                   "ORDER BY amopstrategy",
12953                                                   opcinfo->dobj.catId.oid);
12954         }
12955         else if (fout->remoteVersion >= 80300)
12956         {
12957                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
12958                                                   "amopopr::pg_catalog.regoperator, "
12959                                                   "NULL AS sortfamily, "
12960                                                   "NULL AS sortfamilynsp "
12961                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12962                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12963                                                   "AND refobjid = '%u'::pg_catalog.oid "
12964                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12965                                                   "AND objid = ao.oid "
12966                                                   "ORDER BY amopstrategy",
12967                                                   opcinfo->dobj.catId.oid);
12968         }
12969         else
12970         {
12971                 /*
12972                  * Here, we print all entries since there are no opfamilies and hence
12973                  * no loose operators to worry about.
12974                  */
12975                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
12976                                                   "amopopr::pg_catalog.regoperator, "
12977                                                   "NULL AS sortfamily, "
12978                                                   "NULL AS sortfamilynsp "
12979                                                   "FROM pg_catalog.pg_amop "
12980                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
12981                                                   "ORDER BY amopstrategy",
12982                                                   opcinfo->dobj.catId.oid);
12983         }
12984
12985         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12986
12987         ntups = PQntuples(res);
12988
12989         i_amopstrategy = PQfnumber(res, "amopstrategy");
12990         i_amopreqcheck = PQfnumber(res, "amopreqcheck");
12991         i_amopopr = PQfnumber(res, "amopopr");
12992         i_sortfamily = PQfnumber(res, "sortfamily");
12993         i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
12994
12995         for (i = 0; i < ntups; i++)
12996         {
12997                 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
12998                 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
12999                 amopopr = PQgetvalue(res, i, i_amopopr);
13000                 sortfamily = PQgetvalue(res, i, i_sortfamily);
13001                 sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
13002
13003                 if (needComma)
13004                         appendPQExpBufferStr(q, " ,\n    ");
13005
13006                 appendPQExpBuffer(q, "OPERATOR %s %s",
13007                                                   amopstrategy, amopopr);
13008
13009                 if (strlen(sortfamily) > 0)
13010                 {
13011                         appendPQExpBufferStr(q, " FOR ORDER BY ");
13012                         appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
13013                         appendPQExpBufferStr(q, fmtId(sortfamily));
13014                 }
13015
13016                 if (strcmp(amopreqcheck, "t") == 0)
13017                         appendPQExpBufferStr(q, " RECHECK");
13018
13019                 needComma = true;
13020         }
13021
13022         PQclear(res);
13023
13024         /*
13025          * Now fetch and print the FUNCTION entries (pg_amproc rows).
13026          *
13027          * Print only those opfamily members that are tied to the opclass by
13028          * pg_depend entries.
13029          *
13030          * We print the amproclefttype/amprocrighttype even though in most cases
13031          * the backend could deduce the right values, because of the corner case
13032          * of a btree sort support function for a cross-type comparison.  That's
13033          * only allowed in 9.2 and later, but for simplicity print them in all
13034          * versions that have the columns.
13035          */
13036         resetPQExpBuffer(query);
13037
13038         if (fout->remoteVersion >= 80300)
13039         {
13040                 appendPQExpBuffer(query, "SELECT amprocnum, "
13041                                                   "amproc::pg_catalog.regprocedure, "
13042                                                   "amproclefttype::pg_catalog.regtype, "
13043                                                   "amprocrighttype::pg_catalog.regtype "
13044                                                   "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
13045                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
13046                                                   "AND refobjid = '%u'::pg_catalog.oid "
13047                                                   "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
13048                                                   "AND objid = ap.oid "
13049                                                   "ORDER BY amprocnum",
13050                                                   opcinfo->dobj.catId.oid);
13051         }
13052         else
13053         {
13054                 appendPQExpBuffer(query, "SELECT amprocnum, "
13055                                                   "amproc::pg_catalog.regprocedure, "
13056                                                   "'' AS amproclefttype, "
13057                                                   "'' AS amprocrighttype "
13058                                                   "FROM pg_catalog.pg_amproc "
13059                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
13060                                                   "ORDER BY amprocnum",
13061                                                   opcinfo->dobj.catId.oid);
13062         }
13063
13064         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13065
13066         ntups = PQntuples(res);
13067
13068         i_amprocnum = PQfnumber(res, "amprocnum");
13069         i_amproc = PQfnumber(res, "amproc");
13070         i_amproclefttype = PQfnumber(res, "amproclefttype");
13071         i_amprocrighttype = PQfnumber(res, "amprocrighttype");
13072
13073         for (i = 0; i < ntups; i++)
13074         {
13075                 amprocnum = PQgetvalue(res, i, i_amprocnum);
13076                 amproc = PQgetvalue(res, i, i_amproc);
13077                 amproclefttype = PQgetvalue(res, i, i_amproclefttype);
13078                 amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
13079
13080                 if (needComma)
13081                         appendPQExpBufferStr(q, " ,\n    ");
13082
13083                 appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
13084
13085                 if (*amproclefttype && *amprocrighttype)
13086                         appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
13087
13088                 appendPQExpBuffer(q, " %s", amproc);
13089
13090                 needComma = true;
13091         }
13092
13093         PQclear(res);
13094
13095         /*
13096          * If needComma is still false it means we haven't added anything after
13097          * the AS keyword.  To avoid printing broken SQL, append a dummy STORAGE
13098          * clause with the same datatype.  This isn't sanctioned by the
13099          * documentation, but actually DefineOpClass will treat it as a no-op.
13100          */
13101         if (!needComma)
13102                 appendPQExpBuffer(q, "STORAGE %s", opcintype);
13103
13104         appendPQExpBufferStr(q, ";\n");
13105
13106         appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
13107         appendPQExpBuffer(nameusing, " USING %s",
13108                                           fmtId(amname));
13109
13110         if (dopt->binary_upgrade)
13111                 binary_upgrade_extension_member(q, &opcinfo->dobj,
13112                                                                                 "OPERATOR CLASS", nameusing->data,
13113                                                                                 opcinfo->dobj.namespace->dobj.name);
13114
13115         if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13116                 ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
13117                                          ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
13118                                                                   .namespace = opcinfo->dobj.namespace->dobj.name,
13119                                                                   .owner = opcinfo->rolname,
13120                                                                   .description = "OPERATOR CLASS",
13121                                                                   .section = SECTION_PRE_DATA,
13122                                                                   .createStmt = q->data,
13123                                                                   .dropStmt = delq->data));
13124
13125         /* Dump Operator Class Comments */
13126         if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13127                 dumpComment(fout, "OPERATOR CLASS", nameusing->data,
13128                                         opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
13129                                         opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
13130
13131         free(opcintype);
13132         free(opcfamily);
13133         free(amname);
13134         destroyPQExpBuffer(query);
13135         destroyPQExpBuffer(q);
13136         destroyPQExpBuffer(delq);
13137         destroyPQExpBuffer(nameusing);
13138 }
13139
13140 /*
13141  * dumpOpfamily
13142  *        write out a single operator family definition
13143  *
13144  * Note: this also dumps any "loose" operator members that aren't bound to a
13145  * specific opclass within the opfamily.
13146  */
13147 static void
13148 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
13149 {
13150         DumpOptions *dopt = fout->dopt;
13151         PQExpBuffer query;
13152         PQExpBuffer q;
13153         PQExpBuffer delq;
13154         PQExpBuffer nameusing;
13155         PGresult   *res;
13156         PGresult   *res_ops;
13157         PGresult   *res_procs;
13158         int                     ntups;
13159         int                     i_amname;
13160         int                     i_amopstrategy;
13161         int                     i_amopreqcheck;
13162         int                     i_amopopr;
13163         int                     i_sortfamily;
13164         int                     i_sortfamilynsp;
13165         int                     i_amprocnum;
13166         int                     i_amproc;
13167         int                     i_amproclefttype;
13168         int                     i_amprocrighttype;
13169         char       *amname;
13170         char       *amopstrategy;
13171         char       *amopreqcheck;
13172         char       *amopopr;
13173         char       *sortfamily;
13174         char       *sortfamilynsp;
13175         char       *amprocnum;
13176         char       *amproc;
13177         char       *amproclefttype;
13178         char       *amprocrighttype;
13179         bool            needComma;
13180         int                     i;
13181
13182         /* Skip if not to be dumped */
13183         if (!opfinfo->dobj.dump || dopt->dataOnly)
13184                 return;
13185
13186         query = createPQExpBuffer();
13187         q = createPQExpBuffer();
13188         delq = createPQExpBuffer();
13189         nameusing = createPQExpBuffer();
13190
13191         /*
13192          * Fetch only those opfamily members that are tied directly to the
13193          * opfamily by pg_depend entries.
13194          *
13195          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
13196          * older server's opclass in which it is used.  This is to avoid
13197          * hard-to-detect breakage if a newer pg_dump is used to dump from an
13198          * older server and then reload into that old version.  This can go away
13199          * once 8.3 is so old as to not be of interest to anyone.
13200          */
13201         if (fout->remoteVersion >= 90100)
13202         {
13203                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
13204                                                   "amopopr::pg_catalog.regoperator, "
13205                                                   "opfname AS sortfamily, "
13206                                                   "nspname AS sortfamilynsp "
13207                                                   "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
13208                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
13209                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
13210                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
13211                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13212                                                   "AND refobjid = '%u'::pg_catalog.oid "
13213                                                   "AND amopfamily = '%u'::pg_catalog.oid "
13214                                                   "ORDER BY amopstrategy",
13215                                                   opfinfo->dobj.catId.oid,
13216                                                   opfinfo->dobj.catId.oid);
13217         }
13218         else if (fout->remoteVersion >= 80400)
13219         {
13220                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
13221                                                   "amopopr::pg_catalog.regoperator, "
13222                                                   "NULL AS sortfamily, "
13223                                                   "NULL AS sortfamilynsp "
13224                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
13225                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13226                                                   "AND refobjid = '%u'::pg_catalog.oid "
13227                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
13228                                                   "AND objid = ao.oid "
13229                                                   "ORDER BY amopstrategy",
13230                                                   opfinfo->dobj.catId.oid);
13231         }
13232         else
13233         {
13234                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
13235                                                   "amopopr::pg_catalog.regoperator, "
13236                                                   "NULL AS sortfamily, "
13237                                                   "NULL AS sortfamilynsp "
13238                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
13239                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13240                                                   "AND refobjid = '%u'::pg_catalog.oid "
13241                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
13242                                                   "AND objid = ao.oid "
13243                                                   "ORDER BY amopstrategy",
13244                                                   opfinfo->dobj.catId.oid);
13245         }
13246
13247         res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13248
13249         resetPQExpBuffer(query);
13250
13251         appendPQExpBuffer(query, "SELECT amprocnum, "
13252                                           "amproc::pg_catalog.regprocedure, "
13253                                           "amproclefttype::pg_catalog.regtype, "
13254                                           "amprocrighttype::pg_catalog.regtype "
13255                                           "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
13256                                           "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13257                                           "AND refobjid = '%u'::pg_catalog.oid "
13258                                           "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
13259                                           "AND objid = ap.oid "
13260                                           "ORDER BY amprocnum",
13261                                           opfinfo->dobj.catId.oid);
13262
13263         res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13264
13265         /* Get additional fields from the pg_opfamily row */
13266         resetPQExpBuffer(query);
13267
13268         appendPQExpBuffer(query, "SELECT "
13269                                           "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
13270                                           "FROM pg_catalog.pg_opfamily "
13271                                           "WHERE oid = '%u'::pg_catalog.oid",
13272                                           opfinfo->dobj.catId.oid);
13273
13274         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13275
13276         i_amname = PQfnumber(res, "amname");
13277
13278         /* amname will still be needed after we PQclear res */
13279         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
13280
13281         appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
13282                                           fmtQualifiedDumpable(opfinfo));
13283         appendPQExpBuffer(delq, " USING %s;\n",
13284                                           fmtId(amname));
13285
13286         /* Build the fixed portion of the CREATE command */
13287         appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
13288                                           fmtQualifiedDumpable(opfinfo));
13289         appendPQExpBuffer(q, " USING %s;\n",
13290                                           fmtId(amname));
13291
13292         PQclear(res);
13293
13294         /* Do we need an ALTER to add loose members? */
13295         if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
13296         {
13297                 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
13298                                                   fmtQualifiedDumpable(opfinfo));
13299                 appendPQExpBuffer(q, " USING %s ADD\n    ",
13300                                                   fmtId(amname));
13301
13302                 needComma = false;
13303
13304                 /*
13305                  * Now fetch and print the OPERATOR entries (pg_amop rows).
13306                  */
13307                 ntups = PQntuples(res_ops);
13308
13309                 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
13310                 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
13311                 i_amopopr = PQfnumber(res_ops, "amopopr");
13312                 i_sortfamily = PQfnumber(res_ops, "sortfamily");
13313                 i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
13314
13315                 for (i = 0; i < ntups; i++)
13316                 {
13317                         amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
13318                         amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
13319                         amopopr = PQgetvalue(res_ops, i, i_amopopr);
13320                         sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
13321                         sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
13322
13323                         if (needComma)
13324                                 appendPQExpBufferStr(q, " ,\n    ");
13325
13326                         appendPQExpBuffer(q, "OPERATOR %s %s",
13327                                                           amopstrategy, amopopr);
13328
13329                         if (strlen(sortfamily) > 0)
13330                         {
13331                                 appendPQExpBufferStr(q, " FOR ORDER BY ");
13332                                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
13333                                 appendPQExpBufferStr(q, fmtId(sortfamily));
13334                         }
13335
13336                         if (strcmp(amopreqcheck, "t") == 0)
13337                                 appendPQExpBufferStr(q, " RECHECK");
13338
13339                         needComma = true;
13340                 }
13341
13342                 /*
13343                  * Now fetch and print the FUNCTION entries (pg_amproc rows).
13344                  */
13345                 ntups = PQntuples(res_procs);
13346
13347                 i_amprocnum = PQfnumber(res_procs, "amprocnum");
13348                 i_amproc = PQfnumber(res_procs, "amproc");
13349                 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
13350                 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
13351
13352                 for (i = 0; i < ntups; i++)
13353                 {
13354                         amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
13355                         amproc = PQgetvalue(res_procs, i, i_amproc);
13356                         amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
13357                         amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
13358
13359                         if (needComma)
13360                                 appendPQExpBufferStr(q, " ,\n    ");
13361
13362                         appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
13363                                                           amprocnum, amproclefttype, amprocrighttype,
13364                                                           amproc);
13365
13366                         needComma = true;
13367                 }
13368
13369                 appendPQExpBufferStr(q, ";\n");
13370         }
13371
13372         appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
13373         appendPQExpBuffer(nameusing, " USING %s",
13374                                           fmtId(amname));
13375
13376         if (dopt->binary_upgrade)
13377                 binary_upgrade_extension_member(q, &opfinfo->dobj,
13378                                                                                 "OPERATOR FAMILY", nameusing->data,
13379                                                                                 opfinfo->dobj.namespace->dobj.name);
13380
13381         if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13382                 ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
13383                                          ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
13384                                                                   .namespace = opfinfo->dobj.namespace->dobj.name,
13385                                                                   .owner = opfinfo->rolname,
13386                                                                   .description = "OPERATOR FAMILY",
13387                                                                   .section = SECTION_PRE_DATA,
13388                                                                   .createStmt = q->data,
13389                                                                   .dropStmt = delq->data));
13390
13391         /* Dump Operator Family Comments */
13392         if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13393                 dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
13394                                         opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
13395                                         opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
13396
13397         free(amname);
13398         PQclear(res_ops);
13399         PQclear(res_procs);
13400         destroyPQExpBuffer(query);
13401         destroyPQExpBuffer(q);
13402         destroyPQExpBuffer(delq);
13403         destroyPQExpBuffer(nameusing);
13404 }
13405
13406 /*
13407  * dumpCollation
13408  *        write out a single collation definition
13409  */
13410 static void
13411 dumpCollation(Archive *fout, CollInfo *collinfo)
13412 {
13413         DumpOptions *dopt = fout->dopt;
13414         PQExpBuffer query;
13415         PQExpBuffer q;
13416         PQExpBuffer delq;
13417         char       *qcollname;
13418         PGresult   *res;
13419         int                     i_collprovider;
13420         int                     i_collisdeterministic;
13421         int                     i_collcollate;
13422         int                     i_collctype;
13423         const char *collprovider;
13424         const char *collcollate;
13425         const char *collctype;
13426
13427         /* Skip if not to be dumped */
13428         if (!collinfo->dobj.dump || dopt->dataOnly)
13429                 return;
13430
13431         query = createPQExpBuffer();
13432         q = createPQExpBuffer();
13433         delq = createPQExpBuffer();
13434
13435         qcollname = pg_strdup(fmtId(collinfo->dobj.name));
13436
13437         /* Get collation-specific details */
13438         appendPQExpBuffer(query, "SELECT ");
13439
13440         if (fout->remoteVersion >= 100000)
13441                 appendPQExpBuffer(query,
13442                                                   "collprovider, "
13443                                                   "collversion, ");
13444         else
13445                 appendPQExpBuffer(query,
13446                                                   "'c' AS collprovider, "
13447                                                   "NULL AS collversion, ");
13448
13449         if (fout->remoteVersion >= 120000)
13450                 appendPQExpBuffer(query,
13451                                                   "collisdeterministic, ");
13452         else
13453                 appendPQExpBuffer(query,
13454                                                   "true AS collisdeterministic, ");
13455
13456         appendPQExpBuffer(query,
13457                                           "collcollate, "
13458                                           "collctype "
13459                                           "FROM pg_catalog.pg_collation c "
13460                                           "WHERE c.oid = '%u'::pg_catalog.oid",
13461                                           collinfo->dobj.catId.oid);
13462
13463         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13464
13465         i_collprovider = PQfnumber(res, "collprovider");
13466         i_collisdeterministic = PQfnumber(res, "collisdeterministic");
13467         i_collcollate = PQfnumber(res, "collcollate");
13468         i_collctype = PQfnumber(res, "collctype");
13469
13470         collprovider = PQgetvalue(res, 0, i_collprovider);
13471         collcollate = PQgetvalue(res, 0, i_collcollate);
13472         collctype = PQgetvalue(res, 0, i_collctype);
13473
13474         appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
13475                                           fmtQualifiedDumpable(collinfo));
13476
13477         appendPQExpBuffer(q, "CREATE COLLATION %s (",
13478                                           fmtQualifiedDumpable(collinfo));
13479
13480         appendPQExpBufferStr(q, "provider = ");
13481         if (collprovider[0] == 'c')
13482                 appendPQExpBufferStr(q, "libc");
13483         else if (collprovider[0] == 'i')
13484                 appendPQExpBufferStr(q, "icu");
13485         else if (collprovider[0] == 'd')
13486                 /* to allow dumping pg_catalog; not accepted on input */
13487                 appendPQExpBufferStr(q, "default");
13488         else
13489                 exit_horribly(NULL,
13490                                           "unrecognized collation provider: %s\n",
13491                                           collprovider);
13492
13493         if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
13494                 appendPQExpBufferStr(q, ", deterministic = false");
13495
13496         if (strcmp(collcollate, collctype) == 0)
13497         {
13498                 appendPQExpBufferStr(q, ", locale = ");
13499                 appendStringLiteralAH(q, collcollate, fout);
13500         }
13501         else
13502         {
13503                 appendPQExpBufferStr(q, ", lc_collate = ");
13504                 appendStringLiteralAH(q, collcollate, fout);
13505                 appendPQExpBufferStr(q, ", lc_ctype = ");
13506                 appendStringLiteralAH(q, collctype, fout);
13507         }
13508
13509         /*
13510          * For binary upgrade, carry over the collation version.  For normal
13511          * dump/restore, omit the version, so that it is computed upon restore.
13512          */
13513         if (dopt->binary_upgrade)
13514         {
13515                 int                     i_collversion;
13516
13517                 i_collversion = PQfnumber(res, "collversion");
13518                 if (!PQgetisnull(res, 0, i_collversion))
13519                 {
13520                         appendPQExpBufferStr(q, ", version = ");
13521                         appendStringLiteralAH(q,
13522                                                                   PQgetvalue(res, 0, i_collversion),
13523                                                                   fout);
13524                 }
13525         }
13526
13527         appendPQExpBufferStr(q, ");\n");
13528
13529         if (dopt->binary_upgrade)
13530                 binary_upgrade_extension_member(q, &collinfo->dobj,
13531                                                                                 "COLLATION", qcollname,
13532                                                                                 collinfo->dobj.namespace->dobj.name);
13533
13534         if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13535                 ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
13536                                          ARCHIVE_OPTS(.tag = collinfo->dobj.name,
13537                                                                   .namespace = collinfo->dobj.namespace->dobj.name,
13538                                                                   .owner = collinfo->rolname,
13539                                                                   .description = "COLLATION",
13540                                                                   .section = SECTION_PRE_DATA,
13541                                                                   .createStmt = q->data,
13542                                                                   .dropStmt = delq->data));
13543
13544         /* Dump Collation Comments */
13545         if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13546                 dumpComment(fout, "COLLATION", qcollname,
13547                                         collinfo->dobj.namespace->dobj.name, collinfo->rolname,
13548                                         collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
13549
13550         PQclear(res);
13551
13552         destroyPQExpBuffer(query);
13553         destroyPQExpBuffer(q);
13554         destroyPQExpBuffer(delq);
13555         free(qcollname);
13556 }
13557
13558 /*
13559  * dumpConversion
13560  *        write out a single conversion definition
13561  */
13562 static void
13563 dumpConversion(Archive *fout, ConvInfo *convinfo)
13564 {
13565         DumpOptions *dopt = fout->dopt;
13566         PQExpBuffer query;
13567         PQExpBuffer q;
13568         PQExpBuffer delq;
13569         char       *qconvname;
13570         PGresult   *res;
13571         int                     i_conforencoding;
13572         int                     i_contoencoding;
13573         int                     i_conproc;
13574         int                     i_condefault;
13575         const char *conforencoding;
13576         const char *contoencoding;
13577         const char *conproc;
13578         bool            condefault;
13579
13580         /* Skip if not to be dumped */
13581         if (!convinfo->dobj.dump || dopt->dataOnly)
13582                 return;
13583
13584         query = createPQExpBuffer();
13585         q = createPQExpBuffer();
13586         delq = createPQExpBuffer();
13587
13588         qconvname = pg_strdup(fmtId(convinfo->dobj.name));
13589
13590         /* Get conversion-specific details */
13591         appendPQExpBuffer(query, "SELECT "
13592                                           "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
13593                                           "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
13594                                           "conproc, condefault "
13595                                           "FROM pg_catalog.pg_conversion c "
13596                                           "WHERE c.oid = '%u'::pg_catalog.oid",
13597                                           convinfo->dobj.catId.oid);
13598
13599         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13600
13601         i_conforencoding = PQfnumber(res, "conforencoding");
13602         i_contoencoding = PQfnumber(res, "contoencoding");
13603         i_conproc = PQfnumber(res, "conproc");
13604         i_condefault = PQfnumber(res, "condefault");
13605
13606         conforencoding = PQgetvalue(res, 0, i_conforencoding);
13607         contoencoding = PQgetvalue(res, 0, i_contoencoding);
13608         conproc = PQgetvalue(res, 0, i_conproc);
13609         condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
13610
13611         appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
13612                                           fmtQualifiedDumpable(convinfo));
13613
13614         appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
13615                                           (condefault) ? "DEFAULT " : "",
13616                                           fmtQualifiedDumpable(convinfo));
13617         appendStringLiteralAH(q, conforencoding, fout);
13618         appendPQExpBufferStr(q, " TO ");
13619         appendStringLiteralAH(q, contoencoding, fout);
13620         /* regproc output is already sufficiently quoted */
13621         appendPQExpBuffer(q, " FROM %s;\n", conproc);
13622
13623         if (dopt->binary_upgrade)
13624                 binary_upgrade_extension_member(q, &convinfo->dobj,
13625                                                                                 "CONVERSION", qconvname,
13626                                                                                 convinfo->dobj.namespace->dobj.name);
13627
13628         if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13629                 ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
13630                                          ARCHIVE_OPTS(.tag = convinfo->dobj.name,
13631                                                                   .namespace = convinfo->dobj.namespace->dobj.name,
13632                                                                   .owner = convinfo->rolname,
13633                                                                   .description = "CONVERSION",
13634                                                                   .section = SECTION_PRE_DATA,
13635                                                                   .createStmt = q->data,
13636                                                                   .dropStmt = delq->data));
13637
13638         /* Dump Conversion Comments */
13639         if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13640                 dumpComment(fout, "CONVERSION", qconvname,
13641                                         convinfo->dobj.namespace->dobj.name, convinfo->rolname,
13642                                         convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
13643
13644         PQclear(res);
13645
13646         destroyPQExpBuffer(query);
13647         destroyPQExpBuffer(q);
13648         destroyPQExpBuffer(delq);
13649         free(qconvname);
13650 }
13651
13652 /*
13653  * format_aggregate_signature: generate aggregate name and argument list
13654  *
13655  * The argument type names are qualified if needed.  The aggregate name
13656  * is never qualified.
13657  */
13658 static char *
13659 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
13660 {
13661         PQExpBufferData buf;
13662         int                     j;
13663
13664         initPQExpBuffer(&buf);
13665         if (honor_quotes)
13666                 appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
13667         else
13668                 appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
13669
13670         if (agginfo->aggfn.nargs == 0)
13671                 appendPQExpBuffer(&buf, "(*)");
13672         else
13673         {
13674                 appendPQExpBufferChar(&buf, '(');
13675                 for (j = 0; j < agginfo->aggfn.nargs; j++)
13676                 {
13677                         char       *typname;
13678
13679                         typname = getFormattedTypeName(fout, agginfo->aggfn.argtypes[j],
13680                                                                                    zeroAsOpaque);
13681
13682                         appendPQExpBuffer(&buf, "%s%s",
13683                                                           (j > 0) ? ", " : "",
13684                                                           typname);
13685                         free(typname);
13686                 }
13687                 appendPQExpBufferChar(&buf, ')');
13688         }
13689         return buf.data;
13690 }
13691
13692 /*
13693  * dumpAgg
13694  *        write out a single aggregate definition
13695  */
13696 static void
13697 dumpAgg(Archive *fout, AggInfo *agginfo)
13698 {
13699         DumpOptions *dopt = fout->dopt;
13700         PQExpBuffer query;
13701         PQExpBuffer q;
13702         PQExpBuffer delq;
13703         PQExpBuffer details;
13704         char       *aggsig;                     /* identity signature */
13705         char       *aggfullsig = NULL;  /* full signature */
13706         char       *aggsig_tag;
13707         PGresult   *res;
13708         int                     i_aggtransfn;
13709         int                     i_aggfinalfn;
13710         int                     i_aggcombinefn;
13711         int                     i_aggserialfn;
13712         int                     i_aggdeserialfn;
13713         int                     i_aggmtransfn;
13714         int                     i_aggminvtransfn;
13715         int                     i_aggmfinalfn;
13716         int                     i_aggfinalextra;
13717         int                     i_aggmfinalextra;
13718         int                     i_aggfinalmodify;
13719         int                     i_aggmfinalmodify;
13720         int                     i_aggsortop;
13721         int                     i_aggkind;
13722         int                     i_aggtranstype;
13723         int                     i_aggtransspace;
13724         int                     i_aggmtranstype;
13725         int                     i_aggmtransspace;
13726         int                     i_agginitval;
13727         int                     i_aggminitval;
13728         int                     i_convertok;
13729         int                     i_proparallel;
13730         const char *aggtransfn;
13731         const char *aggfinalfn;
13732         const char *aggcombinefn;
13733         const char *aggserialfn;
13734         const char *aggdeserialfn;
13735         const char *aggmtransfn;
13736         const char *aggminvtransfn;
13737         const char *aggmfinalfn;
13738         bool            aggfinalextra;
13739         bool            aggmfinalextra;
13740         char            aggfinalmodify;
13741         char            aggmfinalmodify;
13742         const char *aggsortop;
13743         char       *aggsortconvop;
13744         char            aggkind;
13745         const char *aggtranstype;
13746         const char *aggtransspace;
13747         const char *aggmtranstype;
13748         const char *aggmtransspace;
13749         const char *agginitval;
13750         const char *aggminitval;
13751         bool            convertok;
13752         const char *proparallel;
13753         char            defaultfinalmodify;
13754
13755         /* Skip if not to be dumped */
13756         if (!agginfo->aggfn.dobj.dump || dopt->dataOnly)
13757                 return;
13758
13759         query = createPQExpBuffer();
13760         q = createPQExpBuffer();
13761         delq = createPQExpBuffer();
13762         details = createPQExpBuffer();
13763
13764         /* Get aggregate-specific details */
13765         if (fout->remoteVersion >= 110000)
13766         {
13767                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13768                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13769                                                   "aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
13770                                                   "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13771                                                   "aggfinalextra, aggmfinalextra, "
13772                                                   "aggfinalmodify, aggmfinalmodify, "
13773                                                   "aggsortop, "
13774                                                   "aggkind, "
13775                                                   "aggtransspace, agginitval, "
13776                                                   "aggmtransspace, aggminitval, "
13777                                                   "true AS convertok, "
13778                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13779                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs, "
13780                                                   "p.proparallel "
13781                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13782                                                   "WHERE a.aggfnoid = p.oid "
13783                                                   "AND p.oid = '%u'::pg_catalog.oid",
13784                                                   agginfo->aggfn.dobj.catId.oid);
13785         }
13786         else if (fout->remoteVersion >= 90600)
13787         {
13788                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13789                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13790                                                   "aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
13791                                                   "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13792                                                   "aggfinalextra, aggmfinalextra, "
13793                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13794                                                   "aggsortop, "
13795                                                   "aggkind, "
13796                                                   "aggtransspace, agginitval, "
13797                                                   "aggmtransspace, aggminitval, "
13798                                                   "true AS convertok, "
13799                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13800                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs, "
13801                                                   "p.proparallel "
13802                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13803                                                   "WHERE a.aggfnoid = p.oid "
13804                                                   "AND p.oid = '%u'::pg_catalog.oid",
13805                                                   agginfo->aggfn.dobj.catId.oid);
13806         }
13807         else if (fout->remoteVersion >= 90400)
13808         {
13809                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13810                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13811                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13812                                                   "'-' AS aggdeserialfn, aggmtransfn, aggminvtransfn, "
13813                                                   "aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13814                                                   "aggfinalextra, aggmfinalextra, "
13815                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13816                                                   "aggsortop, "
13817                                                   "aggkind, "
13818                                                   "aggtransspace, agginitval, "
13819                                                   "aggmtransspace, aggminitval, "
13820                                                   "true AS convertok, "
13821                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13822                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
13823                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13824                                                   "WHERE a.aggfnoid = p.oid "
13825                                                   "AND p.oid = '%u'::pg_catalog.oid",
13826                                                   agginfo->aggfn.dobj.catId.oid);
13827         }
13828         else if (fout->remoteVersion >= 80400)
13829         {
13830                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13831                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13832                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13833                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13834                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13835                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13836                                                   "false AS aggmfinalextra, "
13837                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13838                                                   "aggsortop, "
13839                                                   "'n' AS aggkind, "
13840                                                   "0 AS aggtransspace, agginitval, "
13841                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13842                                                   "true AS convertok, "
13843                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13844                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
13845                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13846                                                   "WHERE a.aggfnoid = p.oid "
13847                                                   "AND p.oid = '%u'::pg_catalog.oid",
13848                                                   agginfo->aggfn.dobj.catId.oid);
13849         }
13850         else if (fout->remoteVersion >= 80100)
13851         {
13852                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13853                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13854                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13855                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13856                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13857                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13858                                                   "false AS aggmfinalextra, "
13859                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13860                                                   "aggsortop, "
13861                                                   "'n' AS aggkind, "
13862                                                   "0 AS aggtransspace, agginitval, "
13863                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13864                                                   "true AS convertok "
13865                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13866                                                   "WHERE a.aggfnoid = p.oid "
13867                                                   "AND p.oid = '%u'::pg_catalog.oid",
13868                                                   agginfo->aggfn.dobj.catId.oid);
13869         }
13870         else
13871         {
13872                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13873                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13874                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13875                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13876                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13877                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13878                                                   "false AS aggmfinalextra, "
13879                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13880                                                   "0 AS aggsortop, "
13881                                                   "'n' AS aggkind, "
13882                                                   "0 AS aggtransspace, agginitval, "
13883                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13884                                                   "true AS convertok "
13885                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13886                                                   "WHERE a.aggfnoid = p.oid "
13887                                                   "AND p.oid = '%u'::pg_catalog.oid",
13888                                                   agginfo->aggfn.dobj.catId.oid);
13889         }
13890
13891         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13892
13893         i_aggtransfn = PQfnumber(res, "aggtransfn");
13894         i_aggfinalfn = PQfnumber(res, "aggfinalfn");
13895         i_aggcombinefn = PQfnumber(res, "aggcombinefn");
13896         i_aggserialfn = PQfnumber(res, "aggserialfn");
13897         i_aggdeserialfn = PQfnumber(res, "aggdeserialfn");
13898         i_aggmtransfn = PQfnumber(res, "aggmtransfn");
13899         i_aggminvtransfn = PQfnumber(res, "aggminvtransfn");
13900         i_aggmfinalfn = PQfnumber(res, "aggmfinalfn");
13901         i_aggfinalextra = PQfnumber(res, "aggfinalextra");
13902         i_aggmfinalextra = PQfnumber(res, "aggmfinalextra");
13903         i_aggfinalmodify = PQfnumber(res, "aggfinalmodify");
13904         i_aggmfinalmodify = PQfnumber(res, "aggmfinalmodify");
13905         i_aggsortop = PQfnumber(res, "aggsortop");
13906         i_aggkind = PQfnumber(res, "aggkind");
13907         i_aggtranstype = PQfnumber(res, "aggtranstype");
13908         i_aggtransspace = PQfnumber(res, "aggtransspace");
13909         i_aggmtranstype = PQfnumber(res, "aggmtranstype");
13910         i_aggmtransspace = PQfnumber(res, "aggmtransspace");
13911         i_agginitval = PQfnumber(res, "agginitval");
13912         i_aggminitval = PQfnumber(res, "aggminitval");
13913         i_convertok = PQfnumber(res, "convertok");
13914         i_proparallel = PQfnumber(res, "proparallel");
13915
13916         aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
13917         aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
13918         aggcombinefn = PQgetvalue(res, 0, i_aggcombinefn);
13919         aggserialfn = PQgetvalue(res, 0, i_aggserialfn);
13920         aggdeserialfn = PQgetvalue(res, 0, i_aggdeserialfn);
13921         aggmtransfn = PQgetvalue(res, 0, i_aggmtransfn);
13922         aggminvtransfn = PQgetvalue(res, 0, i_aggminvtransfn);
13923         aggmfinalfn = PQgetvalue(res, 0, i_aggmfinalfn);
13924         aggfinalextra = (PQgetvalue(res, 0, i_aggfinalextra)[0] == 't');
13925         aggmfinalextra = (PQgetvalue(res, 0, i_aggmfinalextra)[0] == 't');
13926         aggfinalmodify = PQgetvalue(res, 0, i_aggfinalmodify)[0];
13927         aggmfinalmodify = PQgetvalue(res, 0, i_aggmfinalmodify)[0];
13928         aggsortop = PQgetvalue(res, 0, i_aggsortop);
13929         aggkind = PQgetvalue(res, 0, i_aggkind)[0];
13930         aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
13931         aggtransspace = PQgetvalue(res, 0, i_aggtransspace);
13932         aggmtranstype = PQgetvalue(res, 0, i_aggmtranstype);
13933         aggmtransspace = PQgetvalue(res, 0, i_aggmtransspace);
13934         agginitval = PQgetvalue(res, 0, i_agginitval);
13935         aggminitval = PQgetvalue(res, 0, i_aggminitval);
13936         convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
13937
13938         if (fout->remoteVersion >= 80400)
13939         {
13940                 /* 8.4 or later; we rely on server-side code for most of the work */
13941                 char       *funcargs;
13942                 char       *funciargs;
13943
13944                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
13945                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
13946                 aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
13947                 aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
13948         }
13949         else
13950                 /* pre-8.4, do it ourselves */
13951                 aggsig = format_aggregate_signature(agginfo, fout, true);
13952
13953         aggsig_tag = format_aggregate_signature(agginfo, fout, false);
13954
13955         if (i_proparallel != -1)
13956                 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
13957         else
13958                 proparallel = NULL;
13959
13960         if (!convertok)
13961         {
13962                 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
13963                                   aggsig);
13964
13965                 if (aggfullsig)
13966                         free(aggfullsig);
13967
13968                 free(aggsig);
13969
13970                 return;
13971         }
13972
13973         /* identify default modify flag for aggkind (must match DefineAggregate) */
13974         defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
13975         /* replace omitted flags for old versions */
13976         if (aggfinalmodify == '0')
13977                 aggfinalmodify = defaultfinalmodify;
13978         if (aggmfinalmodify == '0')
13979                 aggmfinalmodify = defaultfinalmodify;
13980
13981         /* regproc and regtype output is already sufficiently quoted */
13982         appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
13983                                           aggtransfn, aggtranstype);
13984
13985         if (strcmp(aggtransspace, "0") != 0)
13986         {
13987                 appendPQExpBuffer(details, ",\n    SSPACE = %s",
13988                                                   aggtransspace);
13989         }
13990
13991         if (!PQgetisnull(res, 0, i_agginitval))
13992         {
13993                 appendPQExpBufferStr(details, ",\n    INITCOND = ");
13994                 appendStringLiteralAH(details, agginitval, fout);
13995         }
13996
13997         if (strcmp(aggfinalfn, "-") != 0)
13998         {
13999                 appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
14000                                                   aggfinalfn);
14001                 if (aggfinalextra)
14002                         appendPQExpBufferStr(details, ",\n    FINALFUNC_EXTRA");
14003                 if (aggfinalmodify != defaultfinalmodify)
14004                 {
14005                         switch (aggfinalmodify)
14006                         {
14007                                 case AGGMODIFY_READ_ONLY:
14008                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_ONLY");
14009                                         break;
14010                                 case AGGMODIFY_SHAREABLE:
14011                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = SHAREABLE");
14012                                         break;
14013                                 case AGGMODIFY_READ_WRITE:
14014                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_WRITE");
14015                                         break;
14016                                 default:
14017                                         exit_horribly(NULL, "unrecognized aggfinalmodify value for aggregate \"%s\"\n",
14018                                                                   agginfo->aggfn.dobj.name);
14019                                         break;
14020                         }
14021                 }
14022         }
14023
14024         if (strcmp(aggcombinefn, "-") != 0)
14025                 appendPQExpBuffer(details, ",\n    COMBINEFUNC = %s", aggcombinefn);
14026
14027         if (strcmp(aggserialfn, "-") != 0)
14028                 appendPQExpBuffer(details, ",\n    SERIALFUNC = %s", aggserialfn);
14029
14030         if (strcmp(aggdeserialfn, "-") != 0)
14031                 appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s", aggdeserialfn);
14032
14033         if (strcmp(aggmtransfn, "-") != 0)
14034         {
14035                 appendPQExpBuffer(details, ",\n    MSFUNC = %s,\n    MINVFUNC = %s,\n    MSTYPE = %s",
14036                                                   aggmtransfn,
14037                                                   aggminvtransfn,
14038                                                   aggmtranstype);
14039         }
14040
14041         if (strcmp(aggmtransspace, "0") != 0)
14042         {
14043                 appendPQExpBuffer(details, ",\n    MSSPACE = %s",
14044                                                   aggmtransspace);
14045         }
14046
14047         if (!PQgetisnull(res, 0, i_aggminitval))
14048         {
14049                 appendPQExpBufferStr(details, ",\n    MINITCOND = ");
14050                 appendStringLiteralAH(details, aggminitval, fout);
14051         }
14052
14053         if (strcmp(aggmfinalfn, "-") != 0)
14054         {
14055                 appendPQExpBuffer(details, ",\n    MFINALFUNC = %s",
14056                                                   aggmfinalfn);
14057                 if (aggmfinalextra)
14058                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_EXTRA");
14059                 if (aggmfinalmodify != defaultfinalmodify)
14060                 {
14061                         switch (aggmfinalmodify)
14062                         {
14063                                 case AGGMODIFY_READ_ONLY:
14064                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_ONLY");
14065                                         break;
14066                                 case AGGMODIFY_SHAREABLE:
14067                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = SHAREABLE");
14068                                         break;
14069                                 case AGGMODIFY_READ_WRITE:
14070                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_WRITE");
14071                                         break;
14072                                 default:
14073                                         exit_horribly(NULL, "unrecognized aggmfinalmodify value for aggregate \"%s\"\n",
14074                                                                   agginfo->aggfn.dobj.name);
14075                                         break;
14076                         }
14077                 }
14078         }
14079
14080         aggsortconvop = getFormattedOperatorName(fout, aggsortop);
14081         if (aggsortconvop)
14082         {
14083                 appendPQExpBuffer(details, ",\n    SORTOP = %s",
14084                                                   aggsortconvop);
14085                 free(aggsortconvop);
14086         }
14087
14088         if (aggkind == AGGKIND_HYPOTHETICAL)
14089                 appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
14090
14091         if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
14092         {
14093                 if (proparallel[0] == PROPARALLEL_SAFE)
14094                         appendPQExpBufferStr(details, ",\n    PARALLEL = safe");
14095                 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
14096                         appendPQExpBufferStr(details, ",\n    PARALLEL = restricted");
14097                 else if (proparallel[0] != PROPARALLEL_UNSAFE)
14098                         exit_horribly(NULL, "unrecognized proparallel value for function \"%s\"\n",
14099                                                   agginfo->aggfn.dobj.name);
14100         }
14101
14102         appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
14103                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
14104                                           aggsig);
14105
14106         appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
14107                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
14108                                           aggfullsig ? aggfullsig : aggsig, details->data);
14109
14110         if (dopt->binary_upgrade)
14111                 binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
14112                                                                                 "AGGREGATE", aggsig,
14113                                                                                 agginfo->aggfn.dobj.namespace->dobj.name);
14114
14115         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
14116                 ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
14117                                          agginfo->aggfn.dobj.dumpId,
14118                                          ARCHIVE_OPTS(.tag = aggsig_tag,
14119                                                                   .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
14120                                                                   .owner = agginfo->aggfn.rolname,
14121                                                                   .description = "AGGREGATE",
14122                                                                   .section = SECTION_PRE_DATA,
14123                                                                   .createStmt = q->data,
14124                                                                   .dropStmt = delq->data));
14125
14126         /* Dump Aggregate Comments */
14127         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
14128                 dumpComment(fout, "AGGREGATE", aggsig,
14129                                         agginfo->aggfn.dobj.namespace->dobj.name,
14130                                         agginfo->aggfn.rolname,
14131                                         agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
14132
14133         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
14134                 dumpSecLabel(fout, "AGGREGATE", aggsig,
14135                                          agginfo->aggfn.dobj.namespace->dobj.name,
14136                                          agginfo->aggfn.rolname,
14137                                          agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
14138
14139         /*
14140          * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
14141          * command look like a function's GRANT; in particular this affects the
14142          * syntax for zero-argument aggregates and ordered-set aggregates.
14143          */
14144         free(aggsig);
14145
14146         aggsig = format_function_signature(fout, &agginfo->aggfn, true);
14147
14148         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
14149                 dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
14150                                 "FUNCTION", aggsig, NULL,
14151                                 agginfo->aggfn.dobj.namespace->dobj.name,
14152                                 agginfo->aggfn.rolname, agginfo->aggfn.proacl,
14153                                 agginfo->aggfn.rproacl,
14154                                 agginfo->aggfn.initproacl, agginfo->aggfn.initrproacl);
14155
14156         free(aggsig);
14157         if (aggfullsig)
14158                 free(aggfullsig);
14159         free(aggsig_tag);
14160
14161         PQclear(res);
14162
14163         destroyPQExpBuffer(query);
14164         destroyPQExpBuffer(q);
14165         destroyPQExpBuffer(delq);
14166         destroyPQExpBuffer(details);
14167 }
14168
14169 /*
14170  * dumpTSParser
14171  *        write out a single text search parser
14172  */
14173 static void
14174 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
14175 {
14176         DumpOptions *dopt = fout->dopt;
14177         PQExpBuffer q;
14178         PQExpBuffer delq;
14179         char       *qprsname;
14180
14181         /* Skip if not to be dumped */
14182         if (!prsinfo->dobj.dump || dopt->dataOnly)
14183                 return;
14184
14185         q = createPQExpBuffer();
14186         delq = createPQExpBuffer();
14187
14188         qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
14189
14190         appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
14191                                           fmtQualifiedDumpable(prsinfo));
14192
14193         appendPQExpBuffer(q, "    START = %s,\n",
14194                                           convertTSFunction(fout, prsinfo->prsstart));
14195         appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
14196                                           convertTSFunction(fout, prsinfo->prstoken));
14197         appendPQExpBuffer(q, "    END = %s,\n",
14198                                           convertTSFunction(fout, prsinfo->prsend));
14199         if (prsinfo->prsheadline != InvalidOid)
14200                 appendPQExpBuffer(q, "    HEADLINE = %s,\n",
14201                                                   convertTSFunction(fout, prsinfo->prsheadline));
14202         appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
14203                                           convertTSFunction(fout, prsinfo->prslextype));
14204
14205         appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
14206                                           fmtQualifiedDumpable(prsinfo));
14207
14208         if (dopt->binary_upgrade)
14209                 binary_upgrade_extension_member(q, &prsinfo->dobj,
14210                                                                                 "TEXT SEARCH PARSER", qprsname,
14211                                                                                 prsinfo->dobj.namespace->dobj.name);
14212
14213         if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14214                 ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
14215                                          ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
14216                                                                   .namespace = prsinfo->dobj.namespace->dobj.name,
14217                                                                   .description = "TEXT SEARCH PARSER",
14218                                                                   .owner = "",
14219                                                                   .section = SECTION_PRE_DATA,
14220                                                                   .createStmt = q->data,
14221                                                                   .dropStmt = delq->data));
14222
14223         /* Dump Parser Comments */
14224         if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14225                 dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
14226                                         prsinfo->dobj.namespace->dobj.name, "",
14227                                         prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
14228
14229         destroyPQExpBuffer(q);
14230         destroyPQExpBuffer(delq);
14231         free(qprsname);
14232 }
14233
14234 /*
14235  * dumpTSDictionary
14236  *        write out a single text search dictionary
14237  */
14238 static void
14239 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
14240 {
14241         DumpOptions *dopt = fout->dopt;
14242         PQExpBuffer q;
14243         PQExpBuffer delq;
14244         PQExpBuffer query;
14245         char       *qdictname;
14246         PGresult   *res;
14247         char       *nspname;
14248         char       *tmplname;
14249
14250         /* Skip if not to be dumped */
14251         if (!dictinfo->dobj.dump || dopt->dataOnly)
14252                 return;
14253
14254         q = createPQExpBuffer();
14255         delq = createPQExpBuffer();
14256         query = createPQExpBuffer();
14257
14258         qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
14259
14260         /* Fetch name and namespace of the dictionary's template */
14261         appendPQExpBuffer(query, "SELECT nspname, tmplname "
14262                                           "FROM pg_ts_template p, pg_namespace n "
14263                                           "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
14264                                           dictinfo->dicttemplate);
14265         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14266         nspname = PQgetvalue(res, 0, 0);
14267         tmplname = PQgetvalue(res, 0, 1);
14268
14269         appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
14270                                           fmtQualifiedDumpable(dictinfo));
14271
14272         appendPQExpBufferStr(q, "    TEMPLATE = ");
14273         appendPQExpBuffer(q, "%s.", fmtId(nspname));
14274         appendPQExpBufferStr(q, fmtId(tmplname));
14275
14276         PQclear(res);
14277
14278         /* the dictinitoption can be dumped straight into the command */
14279         if (dictinfo->dictinitoption)
14280                 appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
14281
14282         appendPQExpBufferStr(q, " );\n");
14283
14284         appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
14285                                           fmtQualifiedDumpable(dictinfo));
14286
14287         if (dopt->binary_upgrade)
14288                 binary_upgrade_extension_member(q, &dictinfo->dobj,
14289                                                                                 "TEXT SEARCH DICTIONARY", qdictname,
14290                                                                                 dictinfo->dobj.namespace->dobj.name);
14291
14292         if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14293                 ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
14294                                          ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
14295                                                                   .namespace = dictinfo->dobj.namespace->dobj.name,
14296                                                                   .owner = dictinfo->rolname,
14297                                                                   .description = "TEXT SEARCH DICTIONARY",
14298                                                                   .section = SECTION_PRE_DATA,
14299                                                                   .createStmt = q->data,
14300                                                                   .dropStmt = delq->data));
14301
14302         /* Dump Dictionary Comments */
14303         if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14304                 dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
14305                                         dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
14306                                         dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
14307
14308         destroyPQExpBuffer(q);
14309         destroyPQExpBuffer(delq);
14310         destroyPQExpBuffer(query);
14311         free(qdictname);
14312 }
14313
14314 /*
14315  * dumpTSTemplate
14316  *        write out a single text search template
14317  */
14318 static void
14319 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
14320 {
14321         DumpOptions *dopt = fout->dopt;
14322         PQExpBuffer q;
14323         PQExpBuffer delq;
14324         char       *qtmplname;
14325
14326         /* Skip if not to be dumped */
14327         if (!tmplinfo->dobj.dump || dopt->dataOnly)
14328                 return;
14329
14330         q = createPQExpBuffer();
14331         delq = createPQExpBuffer();
14332
14333         qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
14334
14335         appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
14336                                           fmtQualifiedDumpable(tmplinfo));
14337
14338         if (tmplinfo->tmplinit != InvalidOid)
14339                 appendPQExpBuffer(q, "    INIT = %s,\n",
14340                                                   convertTSFunction(fout, tmplinfo->tmplinit));
14341         appendPQExpBuffer(q, "    LEXIZE = %s );\n",
14342                                           convertTSFunction(fout, tmplinfo->tmpllexize));
14343
14344         appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
14345                                           fmtQualifiedDumpable(tmplinfo));
14346
14347         if (dopt->binary_upgrade)
14348                 binary_upgrade_extension_member(q, &tmplinfo->dobj,
14349                                                                                 "TEXT SEARCH TEMPLATE", qtmplname,
14350                                                                                 tmplinfo->dobj.namespace->dobj.name);
14351
14352         if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14353                 ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
14354                                          ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
14355                                                                   .namespace = tmplinfo->dobj.namespace->dobj.name,
14356                                                                   .description = "TEXT SEARCH TEMPLATE",
14357                                                                   .owner = "",
14358                                                                   .section = SECTION_PRE_DATA,
14359                                                                   .createStmt = q->data,
14360                                                                   .dropStmt = delq->data));
14361
14362         /* Dump Template Comments */
14363         if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14364                 dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
14365                                         tmplinfo->dobj.namespace->dobj.name, "",
14366                                         tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
14367
14368         destroyPQExpBuffer(q);
14369         destroyPQExpBuffer(delq);
14370         free(qtmplname);
14371 }
14372
14373 /*
14374  * dumpTSConfig
14375  *        write out a single text search configuration
14376  */
14377 static void
14378 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
14379 {
14380         DumpOptions *dopt = fout->dopt;
14381         PQExpBuffer q;
14382         PQExpBuffer delq;
14383         PQExpBuffer query;
14384         char       *qcfgname;
14385         PGresult   *res;
14386         char       *nspname;
14387         char       *prsname;
14388         int                     ntups,
14389                                 i;
14390         int                     i_tokenname;
14391         int                     i_dictname;
14392
14393         /* Skip if not to be dumped */
14394         if (!cfginfo->dobj.dump || dopt->dataOnly)
14395                 return;
14396
14397         q = createPQExpBuffer();
14398         delq = createPQExpBuffer();
14399         query = createPQExpBuffer();
14400
14401         qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
14402
14403         /* Fetch name and namespace of the config's parser */
14404         appendPQExpBuffer(query, "SELECT nspname, prsname "
14405                                           "FROM pg_ts_parser p, pg_namespace n "
14406                                           "WHERE p.oid = '%u' AND n.oid = prsnamespace",
14407                                           cfginfo->cfgparser);
14408         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14409         nspname = PQgetvalue(res, 0, 0);
14410         prsname = PQgetvalue(res, 0, 1);
14411
14412         appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
14413                                           fmtQualifiedDumpable(cfginfo));
14414
14415         appendPQExpBuffer(q, "    PARSER = %s.", fmtId(nspname));
14416         appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
14417
14418         PQclear(res);
14419
14420         resetPQExpBuffer(query);
14421         appendPQExpBuffer(query,
14422                                           "SELECT\n"
14423                                           "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
14424                                           "    WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
14425                                           "  m.mapdict::pg_catalog.regdictionary AS dictname\n"
14426                                           "FROM pg_catalog.pg_ts_config_map AS m\n"
14427                                           "WHERE m.mapcfg = '%u'\n"
14428                                           "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
14429                                           cfginfo->cfgparser, cfginfo->dobj.catId.oid);
14430
14431         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14432         ntups = PQntuples(res);
14433
14434         i_tokenname = PQfnumber(res, "tokenname");
14435         i_dictname = PQfnumber(res, "dictname");
14436
14437         for (i = 0; i < ntups; i++)
14438         {
14439                 char       *tokenname = PQgetvalue(res, i, i_tokenname);
14440                 char       *dictname = PQgetvalue(res, i, i_dictname);
14441
14442                 if (i == 0 ||
14443                         strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
14444                 {
14445                         /* starting a new token type, so start a new command */
14446                         if (i > 0)
14447                                 appendPQExpBufferStr(q, ";\n");
14448                         appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
14449                                                           fmtQualifiedDumpable(cfginfo));
14450                         /* tokenname needs quoting, dictname does NOT */
14451                         appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
14452                                                           fmtId(tokenname), dictname);
14453                 }
14454                 else
14455                         appendPQExpBuffer(q, ", %s", dictname);
14456         }
14457
14458         if (ntups > 0)
14459                 appendPQExpBufferStr(q, ";\n");
14460
14461         PQclear(res);
14462
14463         appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
14464                                           fmtQualifiedDumpable(cfginfo));
14465
14466         if (dopt->binary_upgrade)
14467                 binary_upgrade_extension_member(q, &cfginfo->dobj,
14468                                                                                 "TEXT SEARCH CONFIGURATION", qcfgname,
14469                                                                                 cfginfo->dobj.namespace->dobj.name);
14470
14471         if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14472                 ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
14473                                          ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
14474                                                                   .namespace = cfginfo->dobj.namespace->dobj.name,
14475                                                                   .owner = cfginfo->rolname,
14476                                                                   .description = "TEXT SEARCH CONFIGURATION",
14477                                                                   .section = SECTION_PRE_DATA,
14478                                                                   .createStmt = q->data,
14479                                                                   .dropStmt = delq->data));
14480
14481         /* Dump Configuration Comments */
14482         if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14483                 dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
14484                                         cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
14485                                         cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
14486
14487         destroyPQExpBuffer(q);
14488         destroyPQExpBuffer(delq);
14489         destroyPQExpBuffer(query);
14490         free(qcfgname);
14491 }
14492
14493 /*
14494  * dumpForeignDataWrapper
14495  *        write out a single foreign-data wrapper definition
14496  */
14497 static void
14498 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
14499 {
14500         DumpOptions *dopt = fout->dopt;
14501         PQExpBuffer q;
14502         PQExpBuffer delq;
14503         char       *qfdwname;
14504
14505         /* Skip if not to be dumped */
14506         if (!fdwinfo->dobj.dump || dopt->dataOnly)
14507                 return;
14508
14509         q = createPQExpBuffer();
14510         delq = createPQExpBuffer();
14511
14512         qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
14513
14514         appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
14515                                           qfdwname);
14516
14517         if (strcmp(fdwinfo->fdwhandler, "-") != 0)
14518                 appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
14519
14520         if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
14521                 appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
14522
14523         if (strlen(fdwinfo->fdwoptions) > 0)
14524                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
14525
14526         appendPQExpBufferStr(q, ";\n");
14527
14528         appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
14529                                           qfdwname);
14530
14531         if (dopt->binary_upgrade)
14532                 binary_upgrade_extension_member(q, &fdwinfo->dobj,
14533                                                                                 "FOREIGN DATA WRAPPER", qfdwname,
14534                                                                                 NULL);
14535
14536         if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14537                 ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14538                                          ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
14539                                                                   .owner = fdwinfo->rolname,
14540                                                                   .description = "FOREIGN DATA WRAPPER",
14541                                                                   .section = SECTION_PRE_DATA,
14542                                                                   .createStmt = q->data,
14543                                                                   .dropStmt = delq->data));
14544
14545         /* Dump Foreign Data Wrapper Comments */
14546         if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14547                 dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
14548                                         NULL, fdwinfo->rolname,
14549                                         fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
14550
14551         /* Handle the ACL */
14552         if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
14553                 dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14554                                 "FOREIGN DATA WRAPPER", qfdwname, NULL,
14555                                 NULL, fdwinfo->rolname,
14556                                 fdwinfo->fdwacl, fdwinfo->rfdwacl,
14557                                 fdwinfo->initfdwacl, fdwinfo->initrfdwacl);
14558
14559         free(qfdwname);
14560
14561         destroyPQExpBuffer(q);
14562         destroyPQExpBuffer(delq);
14563 }
14564
14565 /*
14566  * dumpForeignServer
14567  *        write out a foreign server definition
14568  */
14569 static void
14570 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
14571 {
14572         DumpOptions *dopt = fout->dopt;
14573         PQExpBuffer q;
14574         PQExpBuffer delq;
14575         PQExpBuffer query;
14576         PGresult   *res;
14577         char       *qsrvname;
14578         char       *fdwname;
14579
14580         /* Skip if not to be dumped */
14581         if (!srvinfo->dobj.dump || dopt->dataOnly)
14582                 return;
14583
14584         q = createPQExpBuffer();
14585         delq = createPQExpBuffer();
14586         query = createPQExpBuffer();
14587
14588         qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
14589
14590         /* look up the foreign-data wrapper */
14591         appendPQExpBuffer(query, "SELECT fdwname "
14592                                           "FROM pg_foreign_data_wrapper w "
14593                                           "WHERE w.oid = '%u'",
14594                                           srvinfo->srvfdw);
14595         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14596         fdwname = PQgetvalue(res, 0, 0);
14597
14598         appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
14599         if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
14600         {
14601                 appendPQExpBufferStr(q, " TYPE ");
14602                 appendStringLiteralAH(q, srvinfo->srvtype, fout);
14603         }
14604         if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
14605         {
14606                 appendPQExpBufferStr(q, " VERSION ");
14607                 appendStringLiteralAH(q, srvinfo->srvversion, fout);
14608         }
14609
14610         appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
14611         appendPQExpBufferStr(q, fmtId(fdwname));
14612
14613         if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
14614                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
14615
14616         appendPQExpBufferStr(q, ";\n");
14617
14618         appendPQExpBuffer(delq, "DROP SERVER %s;\n",
14619                                           qsrvname);
14620
14621         if (dopt->binary_upgrade)
14622                 binary_upgrade_extension_member(q, &srvinfo->dobj,
14623                                                                                 "SERVER", qsrvname, NULL);
14624
14625         if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14626                 ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14627                                          ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
14628                                                                   .owner = srvinfo->rolname,
14629                                                                   .description = "SERVER",
14630                                                                   .section = SECTION_PRE_DATA,
14631                                                                   .createStmt = q->data,
14632                                                                   .dropStmt = delq->data));
14633
14634         /* Dump Foreign Server Comments */
14635         if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14636                 dumpComment(fout, "SERVER", qsrvname,
14637                                         NULL, srvinfo->rolname,
14638                                         srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
14639
14640         /* Handle the ACL */
14641         if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
14642                 dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14643                                 "FOREIGN SERVER", qsrvname, NULL,
14644                                 NULL, srvinfo->rolname,
14645                                 srvinfo->srvacl, srvinfo->rsrvacl,
14646                                 srvinfo->initsrvacl, srvinfo->initrsrvacl);
14647
14648         /* Dump user mappings */
14649         if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
14650                 dumpUserMappings(fout,
14651                                                  srvinfo->dobj.name, NULL,
14652                                                  srvinfo->rolname,
14653                                                  srvinfo->dobj.catId, srvinfo->dobj.dumpId);
14654
14655         free(qsrvname);
14656
14657         destroyPQExpBuffer(q);
14658         destroyPQExpBuffer(delq);
14659         destroyPQExpBuffer(query);
14660 }
14661
14662 /*
14663  * dumpUserMappings
14664  *
14665  * This routine is used to dump any user mappings associated with the
14666  * server handed to this routine. Should be called after ArchiveEntry()
14667  * for the server.
14668  */
14669 static void
14670 dumpUserMappings(Archive *fout,
14671                                  const char *servername, const char *namespace,
14672                                  const char *owner,
14673                                  CatalogId catalogId, DumpId dumpId)
14674 {
14675         PQExpBuffer q;
14676         PQExpBuffer delq;
14677         PQExpBuffer query;
14678         PQExpBuffer tag;
14679         PGresult   *res;
14680         int                     ntups;
14681         int                     i_usename;
14682         int                     i_umoptions;
14683         int                     i;
14684
14685         q = createPQExpBuffer();
14686         tag = createPQExpBuffer();
14687         delq = createPQExpBuffer();
14688         query = createPQExpBuffer();
14689
14690         /*
14691          * We read from the publicly accessible view pg_user_mappings, so as not
14692          * to fail if run by a non-superuser.  Note that the view will show
14693          * umoptions as null if the user hasn't got privileges for the associated
14694          * server; this means that pg_dump will dump such a mapping, but with no
14695          * OPTIONS clause.  A possible alternative is to skip such mappings
14696          * altogether, but it's not clear that that's an improvement.
14697          */
14698         appendPQExpBuffer(query,
14699                                           "SELECT usename, "
14700                                           "array_to_string(ARRAY("
14701                                           "SELECT quote_ident(option_name) || ' ' || "
14702                                           "quote_literal(option_value) "
14703                                           "FROM pg_options_to_table(umoptions) "
14704                                           "ORDER BY option_name"
14705                                           "), E',\n    ') AS umoptions "
14706                                           "FROM pg_user_mappings "
14707                                           "WHERE srvid = '%u' "
14708                                           "ORDER BY usename",
14709                                           catalogId.oid);
14710
14711         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14712
14713         ntups = PQntuples(res);
14714         i_usename = PQfnumber(res, "usename");
14715         i_umoptions = PQfnumber(res, "umoptions");
14716
14717         for (i = 0; i < ntups; i++)
14718         {
14719                 char       *usename;
14720                 char       *umoptions;
14721
14722                 usename = PQgetvalue(res, i, i_usename);
14723                 umoptions = PQgetvalue(res, i, i_umoptions);
14724
14725                 resetPQExpBuffer(q);
14726                 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
14727                 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
14728
14729                 if (umoptions && strlen(umoptions) > 0)
14730                         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
14731
14732                 appendPQExpBufferStr(q, ";\n");
14733
14734                 resetPQExpBuffer(delq);
14735                 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
14736                 appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
14737
14738                 resetPQExpBuffer(tag);
14739                 appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
14740                                                   usename, servername);
14741
14742                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14743                                          ARCHIVE_OPTS(.tag = tag->data,
14744                                                                   .namespace = namespace,
14745                                                                   .owner = owner,
14746                                                                   .description = "USER MAPPING",
14747                                                                   .section = SECTION_PRE_DATA,
14748                                                                   .createStmt = q->data,
14749                                                                   .dropStmt = delq->data));
14750         }
14751
14752         PQclear(res);
14753
14754         destroyPQExpBuffer(query);
14755         destroyPQExpBuffer(delq);
14756         destroyPQExpBuffer(tag);
14757         destroyPQExpBuffer(q);
14758 }
14759
14760 /*
14761  * Write out default privileges information
14762  */
14763 static void
14764 dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
14765 {
14766         DumpOptions *dopt = fout->dopt;
14767         PQExpBuffer q;
14768         PQExpBuffer tag;
14769         const char *type;
14770
14771         /* Skip if not to be dumped */
14772         if (!daclinfo->dobj.dump || dopt->dataOnly || dopt->aclsSkip)
14773                 return;
14774
14775         q = createPQExpBuffer();
14776         tag = createPQExpBuffer();
14777
14778         switch (daclinfo->defaclobjtype)
14779         {
14780                 case DEFACLOBJ_RELATION:
14781                         type = "TABLES";
14782                         break;
14783                 case DEFACLOBJ_SEQUENCE:
14784                         type = "SEQUENCES";
14785                         break;
14786                 case DEFACLOBJ_FUNCTION:
14787                         type = "FUNCTIONS";
14788                         break;
14789                 case DEFACLOBJ_TYPE:
14790                         type = "TYPES";
14791                         break;
14792                 case DEFACLOBJ_NAMESPACE:
14793                         type = "SCHEMAS";
14794                         break;
14795                 default:
14796                         /* shouldn't get here */
14797                         exit_horribly(NULL,
14798                                                   "unrecognized object type in default privileges: %d\n",
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                 exit_horribly(NULL, "could not parse default ACL list (%s)\n",
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                                                                   .dropStmt = ""));
14829
14830         destroyPQExpBuffer(tag);
14831         destroyPQExpBuffer(q);
14832 }
14833
14834 /*----------
14835  * Write out grant/revoke information
14836  *
14837  * 'objCatId' is the catalog ID of the underlying object.
14838  * 'objDumpId' is the dump ID of the underlying object.
14839  * 'type' must be one of
14840  *              TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
14841  *              FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
14842  * 'name' is the formatted name of the object.  Must be quoted etc. already.
14843  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
14844  *              (Currently we assume that subname is only provided for table columns.)
14845  * 'nspname' is the namespace the object is in (NULL if none).
14846  * 'owner' is the owner, NULL if there is no owner (for languages).
14847  * 'acls' contains the ACL string of the object from the appropriate system
14848  *              catalog field; it will be passed to buildACLCommands for building the
14849  *              appropriate GRANT commands.
14850  * 'racls' contains the ACL string of any initial-but-now-revoked ACLs of the
14851  *              object; it will be passed to buildACLCommands for building the
14852  *              appropriate REVOKE commands.
14853  * 'initacls' In binary-upgrade mode, ACL string of the object's initial
14854  *              privileges, to be recorded into pg_init_privs
14855  * 'initracls' In binary-upgrade mode, ACL string of the object's
14856  *              revoked-from-default privileges, to be recorded into pg_init_privs
14857  *
14858  * NB: initacls/initracls are needed because extensions can set privileges on
14859  * an object during the extension's script file and we record those into
14860  * pg_init_privs as that object's initial privileges.
14861  *----------
14862  */
14863 static void
14864 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
14865                 const char *type, const char *name, const char *subname,
14866                 const char *nspname, const char *owner,
14867                 const char *acls, const char *racls,
14868                 const char *initacls, const char *initracls)
14869 {
14870         DumpOptions *dopt = fout->dopt;
14871         PQExpBuffer sql;
14872
14873         /* Do nothing if ACL dump is not enabled */
14874         if (dopt->aclsSkip)
14875                 return;
14876
14877         /* --data-only skips ACLs *except* BLOB ACLs */
14878         if (dopt->dataOnly && strcmp(type, "LARGE OBJECT") != 0)
14879                 return;
14880
14881         sql = createPQExpBuffer();
14882
14883         /*
14884          * Check to see if this object has had any initial ACLs included for it.
14885          * If so, we are in binary upgrade mode and these are the ACLs to turn
14886          * into GRANT and REVOKE statements to set and record the initial
14887          * privileges for an extension object.  Let the backend know that these
14888          * are to be recorded by calling binary_upgrade_set_record_init_privs()
14889          * before and after.
14890          */
14891         if (strlen(initacls) != 0 || strlen(initracls) != 0)
14892         {
14893                 appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
14894                 if (!buildACLCommands(name, subname, nspname, type,
14895                                                           initacls, initracls, owner,
14896                                                           "", fout->remoteVersion, sql))
14897                         exit_horribly(NULL,
14898                                                   "could not parse initial GRANT ACL list (%s) or initial REVOKE ACL list (%s) for object \"%s\" (%s)\n",
14899                                                   initacls, initracls, name, type);
14900                 appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
14901         }
14902
14903         if (!buildACLCommands(name, subname, nspname, type,
14904                                                   acls, racls, owner,
14905                                                   "", fout->remoteVersion, sql))
14906                 exit_horribly(NULL,
14907                                           "could not parse GRANT ACL list (%s) or REVOKE ACL list (%s) for object \"%s\" (%s)\n",
14908                                           acls, racls, name, type);
14909
14910         if (sql->len > 0)
14911         {
14912                 PQExpBuffer tag = createPQExpBuffer();
14913
14914                 if (subname)
14915                         appendPQExpBuffer(tag, "COLUMN %s.%s", name, subname);
14916                 else
14917                         appendPQExpBuffer(tag, "%s %s", type, name);
14918
14919                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14920                                          ARCHIVE_OPTS(.tag = tag->data,
14921                                                                   .namespace = nspname,
14922                                                                   .owner = owner,
14923                                                                   .description = "ACL",
14924                                                                   .section = SECTION_NONE,
14925                                                                   .createStmt = sql->data,
14926                                                                   .dropStmt = "",
14927                                                                   .deps = &objDumpId,
14928                                                                   .nDeps = 1));
14929                 destroyPQExpBuffer(tag);
14930         }
14931
14932         destroyPQExpBuffer(sql);
14933 }
14934
14935 /*
14936  * dumpSecLabel
14937  *
14938  * This routine is used to dump any security labels associated with the
14939  * object handed to this routine. The routine takes the object type
14940  * and object name (ready to print, except for schema decoration), plus
14941  * the namespace and owner of the object (for labeling the ArchiveEntry),
14942  * plus catalog ID and subid which are the lookup key for pg_seclabel,
14943  * plus the dump ID for the object (for setting a dependency).
14944  * If a matching pg_seclabel entry is found, it is dumped.
14945  *
14946  * Note: although this routine takes a dumpId for dependency purposes,
14947  * that purpose is just to mark the dependency in the emitted dump file
14948  * for possible future use by pg_restore.  We do NOT use it for determining
14949  * ordering of the label in the dump file, because this routine is called
14950  * after dependency sorting occurs.  This routine should be called just after
14951  * calling ArchiveEntry() for the specified object.
14952  */
14953 static void
14954 dumpSecLabel(Archive *fout, const char *type, const char *name,
14955                          const char *namespace, const char *owner,
14956                          CatalogId catalogId, int subid, DumpId dumpId)
14957 {
14958         DumpOptions *dopt = fout->dopt;
14959         SecLabelItem *labels;
14960         int                     nlabels;
14961         int                     i;
14962         PQExpBuffer query;
14963
14964         /* do nothing, if --no-security-labels is supplied */
14965         if (dopt->no_security_labels)
14966                 return;
14967
14968         /* Security labels are schema not data ... except blob labels are data */
14969         if (strcmp(type, "LARGE OBJECT") != 0)
14970         {
14971                 if (dopt->dataOnly)
14972                         return;
14973         }
14974         else
14975         {
14976                 /* We do dump blob security labels in binary-upgrade mode */
14977                 if (dopt->schemaOnly && !dopt->binary_upgrade)
14978                         return;
14979         }
14980
14981         /* Search for security labels associated with catalogId, using table */
14982         nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
14983
14984         query = createPQExpBuffer();
14985
14986         for (i = 0; i < nlabels; i++)
14987         {
14988                 /*
14989                  * Ignore label entries for which the subid doesn't match.
14990                  */
14991                 if (labels[i].objsubid != subid)
14992                         continue;
14993
14994                 appendPQExpBuffer(query,
14995                                                   "SECURITY LABEL FOR %s ON %s ",
14996                                                   fmtId(labels[i].provider), type);
14997                 if (namespace && *namespace)
14998                         appendPQExpBuffer(query, "%s.", fmtId(namespace));
14999                 appendPQExpBuffer(query, "%s IS ", name);
15000                 appendStringLiteralAH(query, labels[i].label, fout);
15001                 appendPQExpBufferStr(query, ";\n");
15002         }
15003
15004         if (query->len > 0)
15005         {
15006                 PQExpBuffer tag = createPQExpBuffer();
15007
15008                 appendPQExpBuffer(tag, "%s %s", type, name);
15009                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
15010                                          ARCHIVE_OPTS(.tag = tag->data,
15011                                                                   .namespace = namespace,
15012                                                                   .owner = owner,
15013                                                                   .description = "SECURITY LABEL",
15014                                                                   .section = SECTION_NONE,
15015                                                                   .createStmt = query->data,
15016                                                                   .dropStmt = "",
15017                                                                   .deps = &dumpId,
15018                                                                   .nDeps = 1));
15019                 destroyPQExpBuffer(tag);
15020         }
15021
15022         destroyPQExpBuffer(query);
15023 }
15024
15025 /*
15026  * dumpTableSecLabel
15027  *
15028  * As above, but dump security label for both the specified table (or view)
15029  * and its columns.
15030  */
15031 static void
15032 dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
15033 {
15034         DumpOptions *dopt = fout->dopt;
15035         SecLabelItem *labels;
15036         int                     nlabels;
15037         int                     i;
15038         PQExpBuffer query;
15039         PQExpBuffer target;
15040
15041         /* do nothing, if --no-security-labels is supplied */
15042         if (dopt->no_security_labels)
15043                 return;
15044
15045         /* SecLabel are SCHEMA not data */
15046         if (dopt->dataOnly)
15047                 return;
15048
15049         /* Search for comments associated with relation, using table */
15050         nlabels = findSecLabels(fout,
15051                                                         tbinfo->dobj.catId.tableoid,
15052                                                         tbinfo->dobj.catId.oid,
15053                                                         &labels);
15054
15055         /* If security labels exist, build SECURITY LABEL statements */
15056         if (nlabels <= 0)
15057                 return;
15058
15059         query = createPQExpBuffer();
15060         target = createPQExpBuffer();
15061
15062         for (i = 0; i < nlabels; i++)
15063         {
15064                 const char *colname;
15065                 const char *provider = labels[i].provider;
15066                 const char *label = labels[i].label;
15067                 int                     objsubid = labels[i].objsubid;
15068
15069                 resetPQExpBuffer(target);
15070                 if (objsubid == 0)
15071                 {
15072                         appendPQExpBuffer(target, "%s %s", reltypename,
15073                                                           fmtQualifiedDumpable(tbinfo));
15074                 }
15075                 else
15076                 {
15077                         colname = getAttrName(objsubid, tbinfo);
15078                         /* first fmtXXX result must be consumed before calling again */
15079                         appendPQExpBuffer(target, "COLUMN %s",
15080                                                           fmtQualifiedDumpable(tbinfo));
15081                         appendPQExpBuffer(target, ".%s", fmtId(colname));
15082                 }
15083                 appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
15084                                                   fmtId(provider), target->data);
15085                 appendStringLiteralAH(query, label, fout);
15086                 appendPQExpBufferStr(query, ";\n");
15087         }
15088         if (query->len > 0)
15089         {
15090                 resetPQExpBuffer(target);
15091                 appendPQExpBuffer(target, "%s %s", reltypename,
15092                                                   fmtId(tbinfo->dobj.name));
15093                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
15094                                          ARCHIVE_OPTS(.tag = target->data,
15095                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
15096                                                                   .owner = tbinfo->rolname,
15097                                                                   .description = "SECURITY LABEL",
15098                                                                   .section = SECTION_NONE,
15099                                                                   .createStmt = query->data,
15100                                                                   .dropStmt = "",
15101                                                                   .deps = &(tbinfo->dobj.dumpId),
15102                                                                   .nDeps = 1));
15103         }
15104         destroyPQExpBuffer(query);
15105         destroyPQExpBuffer(target);
15106 }
15107
15108 /*
15109  * findSecLabels
15110  *
15111  * Find the security label(s), if any, associated with the given object.
15112  * All the objsubid values associated with the given classoid/objoid are
15113  * found with one search.
15114  */
15115 static int
15116 findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
15117 {
15118         /* static storage for table of security labels */
15119         static SecLabelItem *labels = NULL;
15120         static int      nlabels = -1;
15121
15122         SecLabelItem *middle = NULL;
15123         SecLabelItem *low;
15124         SecLabelItem *high;
15125         int                     nmatch;
15126
15127         /* Get security labels if we didn't already */
15128         if (nlabels < 0)
15129                 nlabels = collectSecLabels(fout, &labels);
15130
15131         if (nlabels <= 0)                       /* no labels, so no match is possible */
15132         {
15133                 *items = NULL;
15134                 return 0;
15135         }
15136
15137         /*
15138          * Do binary search to find some item matching the object.
15139          */
15140         low = &labels[0];
15141         high = &labels[nlabels - 1];
15142         while (low <= high)
15143         {
15144                 middle = low + (high - low) / 2;
15145
15146                 if (classoid < middle->classoid)
15147                         high = middle - 1;
15148                 else if (classoid > middle->classoid)
15149                         low = middle + 1;
15150                 else if (objoid < middle->objoid)
15151                         high = middle - 1;
15152                 else if (objoid > middle->objoid)
15153                         low = middle + 1;
15154                 else
15155                         break;                          /* found a match */
15156         }
15157
15158         if (low > high)                         /* no matches */
15159         {
15160                 *items = NULL;
15161                 return 0;
15162         }
15163
15164         /*
15165          * Now determine how many items match the object.  The search loop
15166          * invariant still holds: only items between low and high inclusive could
15167          * match.
15168          */
15169         nmatch = 1;
15170         while (middle > low)
15171         {
15172                 if (classoid != middle[-1].classoid ||
15173                         objoid != middle[-1].objoid)
15174                         break;
15175                 middle--;
15176                 nmatch++;
15177         }
15178
15179         *items = middle;
15180
15181         middle += nmatch;
15182         while (middle <= high)
15183         {
15184                 if (classoid != middle->classoid ||
15185                         objoid != middle->objoid)
15186                         break;
15187                 middle++;
15188                 nmatch++;
15189         }
15190
15191         return nmatch;
15192 }
15193
15194 /*
15195  * collectSecLabels
15196  *
15197  * Construct a table of all security labels available for database objects.
15198  * It's much faster to pull them all at once.
15199  *
15200  * The table is sorted by classoid/objid/objsubid for speed in lookup.
15201  */
15202 static int
15203 collectSecLabels(Archive *fout, SecLabelItem **items)
15204 {
15205         PGresult   *res;
15206         PQExpBuffer query;
15207         int                     i_label;
15208         int                     i_provider;
15209         int                     i_classoid;
15210         int                     i_objoid;
15211         int                     i_objsubid;
15212         int                     ntups;
15213         int                     i;
15214         SecLabelItem *labels;
15215
15216         query = createPQExpBuffer();
15217
15218         appendPQExpBufferStr(query,
15219                                                  "SELECT label, provider, classoid, objoid, objsubid "
15220                                                  "FROM pg_catalog.pg_seclabel "
15221                                                  "ORDER BY classoid, objoid, objsubid");
15222
15223         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15224
15225         /* Construct lookup table containing OIDs in numeric form */
15226         i_label = PQfnumber(res, "label");
15227         i_provider = PQfnumber(res, "provider");
15228         i_classoid = PQfnumber(res, "classoid");
15229         i_objoid = PQfnumber(res, "objoid");
15230         i_objsubid = PQfnumber(res, "objsubid");
15231
15232         ntups = PQntuples(res);
15233
15234         labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
15235
15236         for (i = 0; i < ntups; i++)
15237         {
15238                 labels[i].label = PQgetvalue(res, i, i_label);
15239                 labels[i].provider = PQgetvalue(res, i, i_provider);
15240                 labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
15241                 labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
15242                 labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
15243         }
15244
15245         /* Do NOT free the PGresult since we are keeping pointers into it */
15246         destroyPQExpBuffer(query);
15247
15248         *items = labels;
15249         return ntups;
15250 }
15251
15252 /*
15253  * dumpTable
15254  *        write out to fout the declarations (not data) of a user-defined table
15255  */
15256 static void
15257 dumpTable(Archive *fout, TableInfo *tbinfo)
15258 {
15259         DumpOptions *dopt = fout->dopt;
15260         char       *namecopy;
15261
15262         /*
15263          * noop if we are not dumping anything about this table, or if we are
15264          * doing a data-only dump
15265          */
15266         if (!tbinfo->dobj.dump || dopt->dataOnly)
15267                 return;
15268
15269         if (tbinfo->relkind == RELKIND_SEQUENCE)
15270                 dumpSequence(fout, tbinfo);
15271         else
15272                 dumpTableSchema(fout, tbinfo);
15273
15274         /* Handle the ACL here */
15275         namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
15276         if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15277         {
15278                 const char *objtype =
15279                 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
15280
15281                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
15282                                 objtype, namecopy, NULL,
15283                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15284                                 tbinfo->relacl, tbinfo->rrelacl,
15285                                 tbinfo->initrelacl, tbinfo->initrrelacl);
15286         }
15287
15288         /*
15289          * Handle column ACLs, if any.  Note: we pull these with a separate query
15290          * rather than trying to fetch them during getTableAttrs, so that we won't
15291          * miss ACLs on system columns.
15292          */
15293         if (fout->remoteVersion >= 80400 && tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15294         {
15295                 PQExpBuffer query = createPQExpBuffer();
15296                 PGresult   *res;
15297                 int                     i;
15298
15299                 if (fout->remoteVersion >= 90600)
15300                 {
15301                         PQExpBuffer acl_subquery = createPQExpBuffer();
15302                         PQExpBuffer racl_subquery = createPQExpBuffer();
15303                         PQExpBuffer initacl_subquery = createPQExpBuffer();
15304                         PQExpBuffer initracl_subquery = createPQExpBuffer();
15305
15306                         buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
15307                                                         initracl_subquery, "at.attacl", "c.relowner", "'c'",
15308                                                         dopt->binary_upgrade);
15309
15310                         appendPQExpBuffer(query,
15311                                                           "SELECT at.attname, "
15312                                                           "%s AS attacl, "
15313                                                           "%s AS rattacl, "
15314                                                           "%s AS initattacl, "
15315                                                           "%s AS initrattacl "
15316                                                           "FROM pg_catalog.pg_attribute at "
15317                                                           "JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
15318                                                           "LEFT JOIN pg_catalog.pg_init_privs pip ON "
15319                                                           "(at.attrelid = pip.objoid "
15320                                                           "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
15321                                                           "AND at.attnum = pip.objsubid) "
15322                                                           "WHERE at.attrelid = '%u'::pg_catalog.oid AND "
15323                                                           "NOT at.attisdropped "
15324                                                           "AND ("
15325                                                           "%s IS NOT NULL OR "
15326                                                           "%s IS NOT NULL OR "
15327                                                           "%s IS NOT NULL OR "
15328                                                           "%s IS NOT NULL)"
15329                                                           "ORDER BY at.attnum",
15330                                                           acl_subquery->data,
15331                                                           racl_subquery->data,
15332                                                           initacl_subquery->data,
15333                                                           initracl_subquery->data,
15334                                                           tbinfo->dobj.catId.oid,
15335                                                           acl_subquery->data,
15336                                                           racl_subquery->data,
15337                                                           initacl_subquery->data,
15338                                                           initracl_subquery->data);
15339
15340                         destroyPQExpBuffer(acl_subquery);
15341                         destroyPQExpBuffer(racl_subquery);
15342                         destroyPQExpBuffer(initacl_subquery);
15343                         destroyPQExpBuffer(initracl_subquery);
15344                 }
15345                 else
15346                 {
15347                         appendPQExpBuffer(query,
15348                                                           "SELECT attname, attacl, NULL as rattacl, "
15349                                                           "NULL AS initattacl, NULL AS initrattacl "
15350                                                           "FROM pg_catalog.pg_attribute "
15351                                                           "WHERE attrelid = '%u'::pg_catalog.oid AND NOT attisdropped "
15352                                                           "AND attacl IS NOT NULL "
15353                                                           "ORDER BY attnum",
15354                                                           tbinfo->dobj.catId.oid);
15355                 }
15356
15357                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15358
15359                 for (i = 0; i < PQntuples(res); i++)
15360                 {
15361                         char       *attname = PQgetvalue(res, i, 0);
15362                         char       *attacl = PQgetvalue(res, i, 1);
15363                         char       *rattacl = PQgetvalue(res, i, 2);
15364                         char       *initattacl = PQgetvalue(res, i, 3);
15365                         char       *initrattacl = PQgetvalue(res, i, 4);
15366                         char       *attnamecopy;
15367
15368                         attnamecopy = pg_strdup(fmtId(attname));
15369                         /* Column's GRANT type is always TABLE */
15370                         dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
15371                                         "TABLE", namecopy, attnamecopy,
15372                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15373                                         attacl, rattacl, initattacl, initrattacl);
15374                         free(attnamecopy);
15375                 }
15376                 PQclear(res);
15377                 destroyPQExpBuffer(query);
15378         }
15379
15380         free(namecopy);
15381
15382         return;
15383 }
15384
15385 /*
15386  * Create the AS clause for a view or materialized view. The semicolon is
15387  * stripped because a materialized view must add a WITH NO DATA clause.
15388  *
15389  * This returns a new buffer which must be freed by the caller.
15390  */
15391 static PQExpBuffer
15392 createViewAsClause(Archive *fout, TableInfo *tbinfo)
15393 {
15394         PQExpBuffer query = createPQExpBuffer();
15395         PQExpBuffer result = createPQExpBuffer();
15396         PGresult   *res;
15397         int                     len;
15398
15399         /* Fetch the view definition */
15400         appendPQExpBuffer(query,
15401                                           "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
15402                                           tbinfo->dobj.catId.oid);
15403
15404         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15405
15406         if (PQntuples(res) != 1)
15407         {
15408                 if (PQntuples(res) < 1)
15409                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned no data\n",
15410                                                   tbinfo->dobj.name);
15411                 else
15412                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
15413                                                   tbinfo->dobj.name);
15414         }
15415
15416         len = PQgetlength(res, 0, 0);
15417
15418         if (len == 0)
15419                 exit_horribly(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
15420                                           tbinfo->dobj.name);
15421
15422         /* Strip off the trailing semicolon so that other things may follow. */
15423         Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
15424         appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
15425
15426         PQclear(res);
15427         destroyPQExpBuffer(query);
15428
15429         return result;
15430 }
15431
15432 /*
15433  * Create a dummy AS clause for a view.  This is used when the real view
15434  * definition has to be postponed because of circular dependencies.
15435  * We must duplicate the view's external properties -- column names and types
15436  * (including collation) -- so that it works for subsequent references.
15437  *
15438  * This returns a new buffer which must be freed by the caller.
15439  */
15440 static PQExpBuffer
15441 createDummyViewAsClause(Archive *fout, TableInfo *tbinfo)
15442 {
15443         PQExpBuffer result = createPQExpBuffer();
15444         int                     j;
15445
15446         appendPQExpBufferStr(result, "SELECT");
15447
15448         for (j = 0; j < tbinfo->numatts; j++)
15449         {
15450                 if (j > 0)
15451                         appendPQExpBufferChar(result, ',');
15452                 appendPQExpBufferStr(result, "\n    ");
15453
15454                 appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
15455
15456                 /*
15457                  * Must add collation if not default for the type, because CREATE OR
15458                  * REPLACE VIEW won't change it
15459                  */
15460                 if (OidIsValid(tbinfo->attcollation[j]))
15461                 {
15462                         CollInfo   *coll;
15463
15464                         coll = findCollationByOid(tbinfo->attcollation[j]);
15465                         if (coll)
15466                                 appendPQExpBuffer(result, " COLLATE %s",
15467                                                                   fmtQualifiedDumpable(coll));
15468                 }
15469
15470                 appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
15471         }
15472
15473         return result;
15474 }
15475
15476 /*
15477  * dumpTableSchema
15478  *        write the declaration (not data) of one user-defined table or view
15479  */
15480 static void
15481 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
15482 {
15483         DumpOptions *dopt = fout->dopt;
15484         PQExpBuffer q = createPQExpBuffer();
15485         PQExpBuffer delq = createPQExpBuffer();
15486         char       *qrelname;
15487         char       *qualrelname;
15488         int                     numParents;
15489         TableInfo **parents;
15490         int                     actual_atts;    /* number of attrs in this CREATE statement */
15491         const char *reltypename;
15492         char       *storage;
15493         int                     j,
15494                                 k;
15495
15496         qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
15497         qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
15498
15499
15500         if (tbinfo->hasoids)
15501                 write_msg(NULL,
15502                                   "WARNING: WITH OIDS is not supported anymore (table \"%s\")\n",
15503                                   qrelname);
15504
15505         if (dopt->binary_upgrade)
15506                 binary_upgrade_set_type_oids_by_rel_oid(fout, q,
15507                                                                                                 tbinfo->dobj.catId.oid);
15508
15509         /* Is it a table or a view? */
15510         if (tbinfo->relkind == RELKIND_VIEW)
15511         {
15512                 PQExpBuffer result;
15513
15514                 /*
15515                  * Note: keep this code in sync with the is_view case in dumpRule()
15516                  */
15517
15518                 reltypename = "VIEW";
15519
15520                 appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
15521
15522                 if (dopt->binary_upgrade)
15523                         binary_upgrade_set_pg_class_oids(fout, q,
15524                                                                                          tbinfo->dobj.catId.oid, false);
15525
15526                 appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
15527
15528                 if (tbinfo->dummy_view)
15529                         result = createDummyViewAsClause(fout, tbinfo);
15530                 else
15531                 {
15532                         if (nonemptyReloptions(tbinfo->reloptions))
15533                         {
15534                                 appendPQExpBufferStr(q, " WITH (");
15535                                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15536                                 appendPQExpBufferChar(q, ')');
15537                         }
15538                         result = createViewAsClause(fout, tbinfo);
15539                 }
15540                 appendPQExpBuffer(q, " AS\n%s", result->data);
15541                 destroyPQExpBuffer(result);
15542
15543                 if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
15544                         appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
15545                 appendPQExpBufferStr(q, ";\n");
15546         }
15547         else
15548         {
15549                 char       *ftoptions = NULL;
15550                 char       *srvname = NULL;
15551
15552                 switch (tbinfo->relkind)
15553                 {
15554                         case RELKIND_FOREIGN_TABLE:
15555                                 {
15556                                         PQExpBuffer query = createPQExpBuffer();
15557                                         PGresult   *res;
15558                                         int                     i_srvname;
15559                                         int                     i_ftoptions;
15560
15561                                         reltypename = "FOREIGN TABLE";
15562
15563                                         /* retrieve name of foreign server and generic options */
15564                                         appendPQExpBuffer(query,
15565                                                                           "SELECT fs.srvname, "
15566                                                                           "pg_catalog.array_to_string(ARRAY("
15567                                                                           "SELECT pg_catalog.quote_ident(option_name) || "
15568                                                                           "' ' || pg_catalog.quote_literal(option_value) "
15569                                                                           "FROM pg_catalog.pg_options_to_table(ftoptions) "
15570                                                                           "ORDER BY option_name"
15571                                                                           "), E',\n    ') AS ftoptions "
15572                                                                           "FROM pg_catalog.pg_foreign_table ft "
15573                                                                           "JOIN pg_catalog.pg_foreign_server fs "
15574                                                                           "ON (fs.oid = ft.ftserver) "
15575                                                                           "WHERE ft.ftrelid = '%u'",
15576                                                                           tbinfo->dobj.catId.oid);
15577                                         res = ExecuteSqlQueryForSingleRow(fout, query->data);
15578                                         i_srvname = PQfnumber(res, "srvname");
15579                                         i_ftoptions = PQfnumber(res, "ftoptions");
15580                                         srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
15581                                         ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
15582                                         PQclear(res);
15583                                         destroyPQExpBuffer(query);
15584                                         break;
15585                                 }
15586                         case RELKIND_MATVIEW:
15587                                 reltypename = "MATERIALIZED VIEW";
15588                                 break;
15589                         default:
15590                                 reltypename = "TABLE";
15591                 }
15592
15593                 numParents = tbinfo->numParents;
15594                 parents = tbinfo->parents;
15595
15596                 appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
15597
15598                 if (dopt->binary_upgrade)
15599                         binary_upgrade_set_pg_class_oids(fout, q,
15600                                                                                          tbinfo->dobj.catId.oid, false);
15601
15602                 appendPQExpBuffer(q, "CREATE %s%s %s",
15603                                                   tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
15604                                                   "UNLOGGED " : "",
15605                                                   reltypename,
15606                                                   qualrelname);
15607
15608                 /*
15609                  * Attach to type, if reloftype; except in case of a binary upgrade,
15610                  * we dump the table normally and attach it to the type afterward.
15611                  */
15612                 if (tbinfo->reloftype && !dopt->binary_upgrade)
15613                         appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
15614
15615                 /*
15616                  * If the table is a partition, dump it as such; except in the case of
15617                  * a binary upgrade, we dump the table normally and attach it to the
15618                  * parent afterward.
15619                  */
15620                 if (tbinfo->ispartition && !dopt->binary_upgrade)
15621                 {
15622                         TableInfo  *parentRel = tbinfo->parents[0];
15623
15624                         /*
15625                          * With partitions, unlike inheritance, there can only be one
15626                          * parent.
15627                          */
15628                         if (tbinfo->numParents != 1)
15629                                 exit_horribly(NULL, "invalid number of parents %d for table \"%s\"\n",
15630                                                           tbinfo->numParents, tbinfo->dobj.name);
15631
15632                         appendPQExpBuffer(q, " PARTITION OF %s",
15633                                                           fmtQualifiedDumpable(parentRel));
15634                 }
15635
15636                 if (tbinfo->relkind != RELKIND_MATVIEW)
15637                 {
15638                         /* Dump the attributes */
15639                         actual_atts = 0;
15640                         for (j = 0; j < tbinfo->numatts; j++)
15641                         {
15642                                 /*
15643                                  * Normally, dump if it's locally defined in this table, and
15644                                  * not dropped.  But for binary upgrade, we'll dump all the
15645                                  * columns, and then fix up the dropped and nonlocal cases
15646                                  * below.
15647                                  */
15648                                 if (shouldPrintColumn(dopt, tbinfo, j))
15649                                 {
15650                                         /*
15651                                          * Default value --- suppress if to be printed separately.
15652                                          */
15653                                         bool            has_default = (tbinfo->attrdefs[j] != NULL &&
15654                                                                                            !tbinfo->attrdefs[j]->separate);
15655
15656                                         /*
15657                                          * Not Null constraint --- suppress if inherited, except
15658                                          * in binary-upgrade case where that won't work.
15659                                          */
15660                                         bool            has_notnull = (tbinfo->notnull[j] &&
15661                                                                                            (!tbinfo->inhNotNull[j] ||
15662                                                                                                 dopt->binary_upgrade));
15663
15664                                         /*
15665                                          * Skip column if fully defined by reloftype or the
15666                                          * partition parent.
15667                                          */
15668                                         if ((tbinfo->reloftype || tbinfo->ispartition) &&
15669                                                 !has_default && !has_notnull && !dopt->binary_upgrade)
15670                                                 continue;
15671
15672                                         /* Format properly if not first attr */
15673                                         if (actual_atts == 0)
15674                                                 appendPQExpBufferStr(q, " (");
15675                                         else
15676                                                 appendPQExpBufferChar(q, ',');
15677                                         appendPQExpBufferStr(q, "\n    ");
15678                                         actual_atts++;
15679
15680                                         /* Attribute name */
15681                                         appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
15682
15683                                         if (tbinfo->attisdropped[j])
15684                                         {
15685                                                 /*
15686                                                  * ALTER TABLE DROP COLUMN clears
15687                                                  * pg_attribute.atttypid, so we will not have gotten a
15688                                                  * valid type name; insert INTEGER as a stopgap. We'll
15689                                                  * clean things up later.
15690                                                  */
15691                                                 appendPQExpBufferStr(q, " INTEGER /* dummy */");
15692                                                 /* Skip all the rest, too */
15693                                                 continue;
15694                                         }
15695
15696                                         /*
15697                                          * Attribute type
15698                                          *
15699                                          * In binary-upgrade mode, we always include the type. If
15700                                          * we aren't in binary-upgrade mode, then we skip the type
15701                                          * when creating a typed table ('OF type_name') or a
15702                                          * partition ('PARTITION OF'), since the type comes from
15703                                          * the parent/partitioned table.
15704                                          */
15705                                         if (dopt->binary_upgrade || (!tbinfo->reloftype && !tbinfo->ispartition))
15706                                         {
15707                                                 appendPQExpBuffer(q, " %s",
15708                                                                                   tbinfo->atttypnames[j]);
15709                                         }
15710
15711                                         /* Add collation if not default for the type */
15712                                         if (OidIsValid(tbinfo->attcollation[j]))
15713                                         {
15714                                                 CollInfo   *coll;
15715
15716                                                 coll = findCollationByOid(tbinfo->attcollation[j]);
15717                                                 if (coll)
15718                                                         appendPQExpBuffer(q, " COLLATE %s",
15719                                                                                           fmtQualifiedDumpable(coll));
15720                                         }
15721
15722                                         if (has_default)
15723                                                 appendPQExpBuffer(q, " DEFAULT %s",
15724                                                                                   tbinfo->attrdefs[j]->adef_expr);
15725
15726                                         if (has_notnull)
15727                                                 appendPQExpBufferStr(q, " NOT NULL");
15728                                 }
15729                         }
15730
15731                         /*
15732                          * Add non-inherited CHECK constraints, if any.
15733                          */
15734                         for (j = 0; j < tbinfo->ncheck; j++)
15735                         {
15736                                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
15737
15738                                 if (constr->separate || !constr->conislocal)
15739                                         continue;
15740
15741                                 if (actual_atts == 0)
15742                                         appendPQExpBufferStr(q, " (\n    ");
15743                                 else
15744                                         appendPQExpBufferStr(q, ",\n    ");
15745
15746                                 appendPQExpBuffer(q, "CONSTRAINT %s ",
15747                                                                   fmtId(constr->dobj.name));
15748                                 appendPQExpBufferStr(q, constr->condef);
15749
15750                                 actual_atts++;
15751                         }
15752
15753                         if (actual_atts)
15754                                 appendPQExpBufferStr(q, "\n)");
15755                         else if (!((tbinfo->reloftype || tbinfo->ispartition) &&
15756                                            !dopt->binary_upgrade))
15757                         {
15758                                 /*
15759                                  * We must have a parenthesized attribute list, even though
15760                                  * empty, when not using the OF TYPE or PARTITION OF syntax.
15761                                  */
15762                                 appendPQExpBufferStr(q, " (\n)");
15763                         }
15764
15765                         if (tbinfo->ispartition && !dopt->binary_upgrade)
15766                         {
15767                                 appendPQExpBufferChar(q, '\n');
15768                                 appendPQExpBufferStr(q, tbinfo->partbound);
15769                         }
15770
15771                         /* Emit the INHERITS clause, except if this is a partition. */
15772                         if (numParents > 0 &&
15773                                 !tbinfo->ispartition &&
15774                                 !dopt->binary_upgrade)
15775                         {
15776                                 appendPQExpBufferStr(q, "\nINHERITS (");
15777                                 for (k = 0; k < numParents; k++)
15778                                 {
15779                                         TableInfo  *parentRel = parents[k];
15780
15781                                         if (k > 0)
15782                                                 appendPQExpBufferStr(q, ", ");
15783                                         appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
15784                                 }
15785                                 appendPQExpBufferChar(q, ')');
15786                         }
15787
15788                         if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15789                                 appendPQExpBuffer(q, "\nPARTITION BY %s", tbinfo->partkeydef);
15790
15791                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
15792                                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
15793                 }
15794
15795                 if (nonemptyReloptions(tbinfo->reloptions) ||
15796                         nonemptyReloptions(tbinfo->toast_reloptions))
15797                 {
15798                         bool            addcomma = false;
15799
15800                         appendPQExpBufferStr(q, "\nWITH (");
15801                         if (nonemptyReloptions(tbinfo->reloptions))
15802                         {
15803                                 addcomma = true;
15804                                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15805                         }
15806                         if (nonemptyReloptions(tbinfo->toast_reloptions))
15807                         {
15808                                 if (addcomma)
15809                                         appendPQExpBufferStr(q, ", ");
15810                                 appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
15811                                                                                 fout);
15812                         }
15813                         appendPQExpBufferChar(q, ')');
15814                 }
15815
15816                 /* Dump generic options if any */
15817                 if (ftoptions && ftoptions[0])
15818                         appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
15819
15820                 /*
15821                  * For materialized views, create the AS clause just like a view. At
15822                  * this point, we always mark the view as not populated.
15823                  */
15824                 if (tbinfo->relkind == RELKIND_MATVIEW)
15825                 {
15826                         PQExpBuffer result;
15827
15828                         result = createViewAsClause(fout, tbinfo);
15829                         appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
15830                                                           result->data);
15831                         destroyPQExpBuffer(result);
15832                 }
15833                 else
15834                         appendPQExpBufferStr(q, ";\n");
15835
15836                 /*
15837                  * in binary upgrade mode, update the catalog with any missing values
15838                  * that might be present.
15839                  */
15840                 if (dopt->binary_upgrade)
15841                 {
15842                         for (j = 0; j < tbinfo->numatts; j++)
15843                         {
15844                                 if (tbinfo->attmissingval[j][0] != '\0')
15845                                 {
15846                                         appendPQExpBufferStr(q, "\n-- set missing value.\n");
15847                                         appendPQExpBufferStr(q,
15848                                                                                  "SELECT pg_catalog.binary_upgrade_set_missing_value(");
15849                                         appendStringLiteralAH(q, qualrelname, fout);
15850                                         appendPQExpBufferStr(q, "::pg_catalog.regclass,");
15851                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15852                                         appendPQExpBufferStr(q, ",");
15853                                         appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
15854                                         appendPQExpBufferStr(q, ");\n\n");
15855                                 }
15856                         }
15857                 }
15858
15859                 /*
15860                  * To create binary-compatible heap files, we have to ensure the same
15861                  * physical column order, including dropped columns, as in the
15862                  * original.  Therefore, we create dropped columns above and drop them
15863                  * here, also updating their attlen/attalign values so that the
15864                  * dropped column can be skipped properly.  (We do not bother with
15865                  * restoring the original attbyval setting.)  Also, inheritance
15866                  * relationships are set up by doing ALTER TABLE INHERIT rather than
15867                  * using an INHERITS clause --- the latter would possibly mess up the
15868                  * column order.  That also means we have to take care about setting
15869                  * attislocal correctly, plus fix up any inherited CHECK constraints.
15870                  * Analogously, we set up typed tables using ALTER TABLE / OF here.
15871                  *
15872                  * We process foreign and partitioned tables here, even though they
15873                  * lack heap storage, because they can participate in inheritance
15874                  * relationships and we want this stuff to be consistent across the
15875                  * inheritance tree.  We can exclude indexes, toast tables, sequences
15876                  * and matviews, even though they have storage, because we don't
15877                  * support altering or dropping columns in them, nor can they be part
15878                  * of inheritance trees.
15879                  */
15880                 if (dopt->binary_upgrade &&
15881                         (tbinfo->relkind == RELKIND_RELATION ||
15882                          tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
15883                          tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
15884                 {
15885                         for (j = 0; j < tbinfo->numatts; j++)
15886                         {
15887                                 if (tbinfo->attisdropped[j])
15888                                 {
15889                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
15890                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
15891                                                                           "SET attlen = %d, "
15892                                                                           "attalign = '%c', attbyval = false\n"
15893                                                                           "WHERE attname = ",
15894                                                                           tbinfo->attlen[j],
15895                                                                           tbinfo->attalign[j]);
15896                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15897                                         appendPQExpBufferStr(q, "\n  AND attrelid = ");
15898                                         appendStringLiteralAH(q, qualrelname, fout);
15899                                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15900
15901                                         if (tbinfo->relkind == RELKIND_RELATION ||
15902                                                 tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15903                                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15904                                                                                   qualrelname);
15905                                         else
15906                                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE ONLY %s ",
15907                                                                                   qualrelname);
15908                                         appendPQExpBuffer(q, "DROP COLUMN %s;\n",
15909                                                                           fmtId(tbinfo->attnames[j]));
15910                                 }
15911                                 else if (!tbinfo->attislocal[j])
15912                                 {
15913                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
15914                                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
15915                                                                                  "SET attislocal = false\n"
15916                                                                                  "WHERE attname = ");
15917                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15918                                         appendPQExpBufferStr(q, "\n  AND attrelid = ");
15919                                         appendStringLiteralAH(q, qualrelname, fout);
15920                                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15921                                 }
15922                         }
15923
15924                         for (k = 0; k < tbinfo->ncheck; k++)
15925                         {
15926                                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
15927
15928                                 if (constr->separate || constr->conislocal)
15929                                         continue;
15930
15931                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
15932                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15933                                                                   qualrelname);
15934                                 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
15935                                                                   fmtId(constr->dobj.name));
15936                                 appendPQExpBuffer(q, "%s;\n", constr->condef);
15937                                 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
15938                                                                          "SET conislocal = false\n"
15939                                                                          "WHERE contype = 'c' AND conname = ");
15940                                 appendStringLiteralAH(q, constr->dobj.name, fout);
15941                                 appendPQExpBufferStr(q, "\n  AND conrelid = ");
15942                                 appendStringLiteralAH(q, qualrelname, fout);
15943                                 appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15944                         }
15945
15946                         if (numParents > 0)
15947                         {
15948                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance and partitioning this way.\n");
15949                                 for (k = 0; k < numParents; k++)
15950                                 {
15951                                         TableInfo  *parentRel = parents[k];
15952
15953                                         /* In the partitioning case, we alter the parent */
15954                                         if (tbinfo->ispartition)
15955                                                 appendPQExpBuffer(q,
15956                                                                                   "ALTER TABLE ONLY %s ATTACH PARTITION ",
15957                                                                                   fmtQualifiedDumpable(parentRel));
15958                                         else
15959                                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
15960                                                                                   qualrelname);
15961
15962                                         /* Partition needs specifying the bounds */
15963                                         if (tbinfo->ispartition)
15964                                                 appendPQExpBuffer(q, "%s %s;\n",
15965                                                                                   qualrelname,
15966                                                                                   tbinfo->partbound);
15967                                         else
15968                                                 appendPQExpBuffer(q, "%s;\n",
15969                                                                                   fmtQualifiedDumpable(parentRel));
15970                                 }
15971                         }
15972
15973                         if (tbinfo->reloftype)
15974                         {
15975                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
15976                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
15977                                                                   qualrelname,
15978                                                                   tbinfo->reloftype);
15979                         }
15980                 }
15981
15982                 /*
15983                  * In binary_upgrade mode, arrange to restore the old relfrozenxid and
15984                  * relminmxid of all vacuumable relations.  (While vacuum.c processes
15985                  * TOAST tables semi-independently, here we see them only as children
15986                  * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
15987                  * child toast table is handled below.)
15988                  */
15989                 if (dopt->binary_upgrade &&
15990                         (tbinfo->relkind == RELKIND_RELATION ||
15991                          tbinfo->relkind == RELKIND_MATVIEW))
15992                 {
15993                         appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
15994                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
15995                                                           "SET relfrozenxid = '%u', relminmxid = '%u'\n"
15996                                                           "WHERE oid = ",
15997                                                           tbinfo->frozenxid, tbinfo->minmxid);
15998                         appendStringLiteralAH(q, qualrelname, fout);
15999                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16000
16001                         if (tbinfo->toast_oid)
16002                         {
16003                                 /*
16004                                  * The toast table will have the same OID at restore, so we
16005                                  * can safely target it by OID.
16006                                  */
16007                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
16008                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
16009                                                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
16010                                                                   "WHERE oid = '%u';\n",
16011                                                                   tbinfo->toast_frozenxid,
16012                                                                   tbinfo->toast_minmxid, tbinfo->toast_oid);
16013                         }
16014                 }
16015
16016                 /*
16017                  * In binary_upgrade mode, restore matviews' populated status by
16018                  * poking pg_class directly.  This is pretty ugly, but we can't use
16019                  * REFRESH MATERIALIZED VIEW since it's possible that some underlying
16020                  * matview is not populated even though this matview is; in any case,
16021                  * we want to transfer the matview's heap storage, not run REFRESH.
16022                  */
16023                 if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
16024                         tbinfo->relispopulated)
16025                 {
16026                         appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
16027                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
16028                                                                  "SET relispopulated = 't'\n"
16029                                                                  "WHERE oid = ");
16030                         appendStringLiteralAH(q, qualrelname, fout);
16031                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16032                 }
16033
16034                 /*
16035                  * Dump additional per-column properties that we can't handle in the
16036                  * main CREATE TABLE command.
16037                  */
16038                 for (j = 0; j < tbinfo->numatts; j++)
16039                 {
16040                         /* None of this applies to dropped columns */
16041                         if (tbinfo->attisdropped[j])
16042                                 continue;
16043
16044                         /*
16045                          * If we didn't dump the column definition explicitly above, and
16046                          * it is NOT NULL and did not inherit that property from a parent,
16047                          * we have to mark it separately.
16048                          */
16049                         if (!shouldPrintColumn(dopt, tbinfo, j) &&
16050                                 tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
16051                         {
16052                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16053                                                                   qualrelname);
16054                                 appendPQExpBuffer(q, "ALTER COLUMN %s SET NOT NULL;\n",
16055                                                                   fmtId(tbinfo->attnames[j]));
16056                         }
16057
16058                         /*
16059                          * Dump per-column statistics information. We only issue an ALTER
16060                          * TABLE statement if the attstattarget entry for this column is
16061                          * non-negative (i.e. it's not the default value)
16062                          */
16063                         if (tbinfo->attstattarget[j] >= 0)
16064                         {
16065                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16066                                                                   qualrelname);
16067                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
16068                                                                   fmtId(tbinfo->attnames[j]));
16069                                 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
16070                                                                   tbinfo->attstattarget[j]);
16071                         }
16072
16073                         /*
16074                          * Dump per-column storage information.  The statement is only
16075                          * dumped if the storage has been changed from the type's default.
16076                          */
16077                         if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
16078                         {
16079                                 switch (tbinfo->attstorage[j])
16080                                 {
16081                                         case 'p':
16082                                                 storage = "PLAIN";
16083                                                 break;
16084                                         case 'e':
16085                                                 storage = "EXTERNAL";
16086                                                 break;
16087                                         case 'm':
16088                                                 storage = "MAIN";
16089                                                 break;
16090                                         case 'x':
16091                                                 storage = "EXTENDED";
16092                                                 break;
16093                                         default:
16094                                                 storage = NULL;
16095                                 }
16096
16097                                 /*
16098                                  * Only dump the statement if it's a storage type we recognize
16099                                  */
16100                                 if (storage != NULL)
16101                                 {
16102                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16103                                                                           qualrelname);
16104                                         appendPQExpBuffer(q, "ALTER COLUMN %s ",
16105                                                                           fmtId(tbinfo->attnames[j]));
16106                                         appendPQExpBuffer(q, "SET STORAGE %s;\n",
16107                                                                           storage);
16108                                 }
16109                         }
16110
16111                         /*
16112                          * Dump per-column attributes.
16113                          */
16114                         if (tbinfo->attoptions[j][0] != '\0')
16115                         {
16116                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16117                                                                   qualrelname);
16118                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
16119                                                                   fmtId(tbinfo->attnames[j]));
16120                                 appendPQExpBuffer(q, "SET (%s);\n",
16121                                                                   tbinfo->attoptions[j]);
16122                         }
16123
16124                         /*
16125                          * Dump per-column fdw options.
16126                          */
16127                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
16128                                 tbinfo->attfdwoptions[j][0] != '\0')
16129                         {
16130                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
16131                                                                   qualrelname);
16132                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
16133                                                                   fmtId(tbinfo->attnames[j]));
16134                                 appendPQExpBuffer(q, "OPTIONS (\n    %s\n);\n",
16135                                                                   tbinfo->attfdwoptions[j]);
16136                         }
16137                 }
16138
16139                 if (ftoptions)
16140                         free(ftoptions);
16141                 if (srvname)
16142                         free(srvname);
16143         }
16144
16145         /*
16146          * dump properties we only have ALTER TABLE syntax for
16147          */
16148         if ((tbinfo->relkind == RELKIND_RELATION ||
16149                  tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
16150                  tbinfo->relkind == RELKIND_MATVIEW) &&
16151                 tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
16152         {
16153                 if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
16154                 {
16155                         /* nothing to do, will be set when the index is dumped */
16156                 }
16157                 else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
16158                 {
16159                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
16160                                                           qualrelname);
16161                 }
16162                 else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
16163                 {
16164                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
16165                                                           qualrelname);
16166                 }
16167         }
16168
16169         if (tbinfo->forcerowsec)
16170                 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
16171                                                   qualrelname);
16172
16173         if (dopt->binary_upgrade)
16174                 binary_upgrade_extension_member(q, &tbinfo->dobj,
16175                                                                                 reltypename, qrelname,
16176                                                                                 tbinfo->dobj.namespace->dobj.name);
16177
16178         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16179         {
16180                 char *tableam = NULL;
16181
16182                 if (tbinfo->relkind == RELKIND_RELATION ||
16183                         tbinfo->relkind == RELKIND_MATVIEW)
16184                         tableam = tbinfo->amname;
16185
16186                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
16187                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
16188                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
16189                                                                   .tablespace = (tbinfo->relkind == RELKIND_VIEW) ?
16190                                                                   NULL : tbinfo->reltablespace,
16191                                                                   .tableam = tableam,
16192                                                                   .owner = tbinfo->rolname,
16193                                                                   .description = reltypename,
16194                                                                   .section = tbinfo->postponed_def ?
16195                                                                   SECTION_POST_DATA : SECTION_PRE_DATA,
16196                                                                   .createStmt = q->data,
16197                                                                   .dropStmt = delq->data));
16198         }
16199
16200         /* Dump Table Comments */
16201         if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16202                 dumpTableComment(fout, tbinfo, reltypename);
16203
16204         /* Dump Table Security Labels */
16205         if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
16206                 dumpTableSecLabel(fout, tbinfo, reltypename);
16207
16208         /* Dump comments on inlined table constraints */
16209         for (j = 0; j < tbinfo->ncheck; j++)
16210         {
16211                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
16212
16213                 if (constr->separate || !constr->conislocal)
16214                         continue;
16215
16216                 if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16217                         dumpTableConstraintComment(fout, constr);
16218         }
16219
16220         destroyPQExpBuffer(q);
16221         destroyPQExpBuffer(delq);
16222         free(qrelname);
16223         free(qualrelname);
16224 }
16225
16226 /*
16227  * dumpAttrDef --- dump an attribute's default-value declaration
16228  */
16229 static void
16230 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
16231 {
16232         DumpOptions *dopt = fout->dopt;
16233         TableInfo  *tbinfo = adinfo->adtable;
16234         int                     adnum = adinfo->adnum;
16235         PQExpBuffer q;
16236         PQExpBuffer delq;
16237         char       *qualrelname;
16238         char       *tag;
16239
16240         /* Skip if table definition not to be dumped */
16241         if (!tbinfo->dobj.dump || dopt->dataOnly)
16242                 return;
16243
16244         /* Skip if not "separate"; it was dumped in the table's definition */
16245         if (!adinfo->separate)
16246                 return;
16247
16248         q = createPQExpBuffer();
16249         delq = createPQExpBuffer();
16250
16251         qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
16252
16253         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16254                                           qualrelname);
16255         appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
16256                                           fmtId(tbinfo->attnames[adnum - 1]),
16257                                           adinfo->adef_expr);
16258
16259         appendPQExpBuffer(delq, "ALTER TABLE %s ",
16260                                           qualrelname);
16261         appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
16262                                           fmtId(tbinfo->attnames[adnum - 1]));
16263
16264         tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
16265
16266         if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16267                 ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
16268                                          ARCHIVE_OPTS(.tag = tag,
16269                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
16270                                                                   .owner = tbinfo->rolname,
16271                                                                   .description = "DEFAULT",
16272                                                                   .section = SECTION_PRE_DATA,
16273                                                                   .createStmt = q->data,
16274                                                                   .dropStmt = delq->data));
16275
16276         free(tag);
16277         destroyPQExpBuffer(q);
16278         destroyPQExpBuffer(delq);
16279         free(qualrelname);
16280 }
16281
16282 /*
16283  * getAttrName: extract the correct name for an attribute
16284  *
16285  * The array tblInfo->attnames[] only provides names of user attributes;
16286  * if a system attribute number is supplied, we have to fake it.
16287  * We also do a little bit of bounds checking for safety's sake.
16288  */
16289 static const char *
16290 getAttrName(int attrnum, TableInfo *tblInfo)
16291 {
16292         if (attrnum > 0 && attrnum <= tblInfo->numatts)
16293                 return tblInfo->attnames[attrnum - 1];
16294         switch (attrnum)
16295         {
16296                 case SelfItemPointerAttributeNumber:
16297                         return "ctid";
16298                 case MinTransactionIdAttributeNumber:
16299                         return "xmin";
16300                 case MinCommandIdAttributeNumber:
16301                         return "cmin";
16302                 case MaxTransactionIdAttributeNumber:
16303                         return "xmax";
16304                 case MaxCommandIdAttributeNumber:
16305                         return "cmax";
16306                 case TableOidAttributeNumber:
16307                         return "tableoid";
16308         }
16309         exit_horribly(NULL, "invalid column number %d for table \"%s\"\n",
16310                                   attrnum, tblInfo->dobj.name);
16311         return NULL;                            /* keep compiler quiet */
16312 }
16313
16314 /*
16315  * dumpIndex
16316  *        write out to fout a user-defined index
16317  */
16318 static void
16319 dumpIndex(Archive *fout, IndxInfo *indxinfo)
16320 {
16321         DumpOptions *dopt = fout->dopt;
16322         TableInfo  *tbinfo = indxinfo->indextable;
16323         bool            is_constraint = (indxinfo->indexconstraint != 0);
16324         PQExpBuffer q;
16325         PQExpBuffer delq;
16326         char       *qindxname;
16327
16328         if (dopt->dataOnly)
16329                 return;
16330
16331         q = createPQExpBuffer();
16332         delq = createPQExpBuffer();
16333
16334         qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
16335
16336         /*
16337          * If there's an associated constraint, don't dump the index per se, but
16338          * do dump any comment for it.  (This is safe because dependency ordering
16339          * will have ensured the constraint is emitted first.)  Note that the
16340          * emitted comment has to be shown as depending on the constraint, not the
16341          * index, in such cases.
16342          */
16343         if (!is_constraint)
16344         {
16345                 char       *indstatcols = indxinfo->indstatcols;
16346                 char       *indstatvals = indxinfo->indstatvals;
16347                 char      **indstatcolsarray = NULL;
16348                 char      **indstatvalsarray = NULL;
16349                 int                     nstatcols;
16350                 int                     nstatvals;
16351
16352                 if (dopt->binary_upgrade)
16353                         binary_upgrade_set_pg_class_oids(fout, q,
16354                                                                                          indxinfo->dobj.catId.oid, true);
16355
16356                 /* Plain secondary index */
16357                 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
16358
16359                 /*
16360                  * Append ALTER TABLE commands as needed to set properties that we
16361                  * only have ALTER TABLE syntax for.  Keep this in sync with the
16362                  * similar code in dumpConstraint!
16363                  */
16364
16365                 /* If the index is clustered, we need to record that. */
16366                 if (indxinfo->indisclustered)
16367                 {
16368                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16369                                                           fmtQualifiedDumpable(tbinfo));
16370                         /* index name is not qualified in this syntax */
16371                         appendPQExpBuffer(q, " ON %s;\n",
16372                                                           qindxname);
16373                 }
16374
16375                 /*
16376                  * If the index has any statistics on some of its columns, generate
16377                  * the associated ALTER INDEX queries.
16378                  */
16379                 if (parsePGArray(indstatcols, &indstatcolsarray, &nstatcols) &&
16380                         parsePGArray(indstatvals, &indstatvalsarray, &nstatvals) &&
16381                         nstatcols == nstatvals)
16382                 {
16383                         int                     j;
16384
16385                         for (j = 0; j < nstatcols; j++)
16386                         {
16387                                 appendPQExpBuffer(q, "ALTER INDEX %s ",
16388                                                                   fmtQualifiedDumpable(indxinfo));
16389
16390                                 /*
16391                                  * Note that this is a column number, so no quotes should be
16392                                  * used.
16393                                  */
16394                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
16395                                                                   indstatcolsarray[j]);
16396                                 appendPQExpBuffer(q, "SET STATISTICS %s;\n",
16397                                                                   indstatvalsarray[j]);
16398                         }
16399                 }
16400
16401                 /* If the index defines identity, we need to record that. */
16402                 if (indxinfo->indisreplident)
16403                 {
16404                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
16405                                                           fmtQualifiedDumpable(tbinfo));
16406                         /* index name is not qualified in this syntax */
16407                         appendPQExpBuffer(q, " INDEX %s;\n",
16408                                                           qindxname);
16409                 }
16410
16411                 appendPQExpBuffer(delq, "DROP INDEX %s;\n",
16412                                                   fmtQualifiedDumpable(indxinfo));
16413
16414                 if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16415                         ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
16416                                                  ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
16417                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
16418                                                                           .tablespace = indxinfo->tablespace,
16419                                                                           .owner = tbinfo->rolname,
16420                                                                           .description = "INDEX",
16421                                                                           .section = SECTION_POST_DATA,
16422                                                                           .createStmt = q->data,
16423                                                                           .dropStmt = delq->data));
16424
16425                 if (indstatcolsarray)
16426                         free(indstatcolsarray);
16427                 if (indstatvalsarray)
16428                         free(indstatvalsarray);
16429         }
16430
16431         /* Dump Index Comments */
16432         if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16433                 dumpComment(fout, "INDEX", qindxname,
16434                                         tbinfo->dobj.namespace->dobj.name,
16435                                         tbinfo->rolname,
16436                                         indxinfo->dobj.catId, 0,
16437                                         is_constraint ? indxinfo->indexconstraint :
16438                                         indxinfo->dobj.dumpId);
16439
16440         destroyPQExpBuffer(q);
16441         destroyPQExpBuffer(delq);
16442         free(qindxname);
16443 }
16444
16445 /*
16446  * dumpIndexAttach
16447  *        write out to fout a partitioned-index attachment clause
16448  */
16449 static void
16450 dumpIndexAttach(Archive *fout, IndexAttachInfo *attachinfo)
16451 {
16452         if (fout->dopt->dataOnly)
16453                 return;
16454
16455         if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
16456         {
16457                 PQExpBuffer q = createPQExpBuffer();
16458
16459                 appendPQExpBuffer(q, "ALTER INDEX %s ",
16460                                                   fmtQualifiedDumpable(attachinfo->parentIdx));
16461                 appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
16462                                                   fmtQualifiedDumpable(attachinfo->partitionIdx));
16463
16464                 ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
16465                                          ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
16466                                                                   .namespace = attachinfo->dobj.namespace->dobj.name,
16467                                                                   .description = "INDEX ATTACH",
16468                                                                   .owner = "",
16469                                                                   .section = SECTION_POST_DATA,
16470                                                                   .createStmt = q->data,
16471                                                                   .dropStmt = ""));
16472
16473                 destroyPQExpBuffer(q);
16474         }
16475 }
16476
16477 /*
16478  * dumpStatisticsExt
16479  *        write out to fout an extended statistics object
16480  */
16481 static void
16482 dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo)
16483 {
16484         DumpOptions *dopt = fout->dopt;
16485         PQExpBuffer q;
16486         PQExpBuffer delq;
16487         PQExpBuffer query;
16488         char       *qstatsextname;
16489         PGresult   *res;
16490         char       *stxdef;
16491
16492         /* Skip if not to be dumped */
16493         if (!statsextinfo->dobj.dump || dopt->dataOnly)
16494                 return;
16495
16496         q = createPQExpBuffer();
16497         delq = createPQExpBuffer();
16498         query = createPQExpBuffer();
16499
16500         qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
16501
16502         appendPQExpBuffer(query, "SELECT "
16503                                           "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
16504                                           statsextinfo->dobj.catId.oid);
16505
16506         res = ExecuteSqlQueryForSingleRow(fout, query->data);
16507
16508         stxdef = PQgetvalue(res, 0, 0);
16509
16510         /* Result of pg_get_statisticsobjdef is complete except for semicolon */
16511         appendPQExpBuffer(q, "%s;\n", stxdef);
16512
16513         appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
16514                                           fmtQualifiedDumpable(statsextinfo));
16515
16516         if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16517                 ArchiveEntry(fout, statsextinfo->dobj.catId,
16518                                          statsextinfo->dobj.dumpId,
16519                                          ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
16520                                                                   .namespace = statsextinfo->dobj.namespace->dobj.name,
16521                                                                   .owner = statsextinfo->rolname,
16522                                                                   .description = "STATISTICS",
16523                                                                   .section = SECTION_POST_DATA,
16524                                                                   .createStmt = q->data,
16525                                                                   .dropStmt = delq->data));
16526
16527         /* Dump Statistics Comments */
16528         if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16529                 dumpComment(fout, "STATISTICS", qstatsextname,
16530                                         statsextinfo->dobj.namespace->dobj.name,
16531                                         statsextinfo->rolname,
16532                                         statsextinfo->dobj.catId, 0,
16533                                         statsextinfo->dobj.dumpId);
16534
16535         PQclear(res);
16536         destroyPQExpBuffer(q);
16537         destroyPQExpBuffer(delq);
16538         destroyPQExpBuffer(query);
16539         free(qstatsextname);
16540 }
16541
16542 /*
16543  * dumpConstraint
16544  *        write out to fout a user-defined constraint
16545  */
16546 static void
16547 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
16548 {
16549         DumpOptions *dopt = fout->dopt;
16550         TableInfo  *tbinfo = coninfo->contable;
16551         PQExpBuffer q;
16552         PQExpBuffer delq;
16553         char       *tag = NULL;
16554
16555         /* Skip if not to be dumped */
16556         if (!coninfo->dobj.dump || dopt->dataOnly)
16557                 return;
16558
16559         q = createPQExpBuffer();
16560         delq = createPQExpBuffer();
16561
16562         if (coninfo->contype == 'p' ||
16563                 coninfo->contype == 'u' ||
16564                 coninfo->contype == 'x')
16565         {
16566                 /* Index-related constraint */
16567                 IndxInfo   *indxinfo;
16568                 int                     k;
16569
16570                 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
16571
16572                 if (indxinfo == NULL)
16573                         exit_horribly(NULL, "missing index for constraint \"%s\"\n",
16574                                                   coninfo->dobj.name);
16575
16576                 if (dopt->binary_upgrade)
16577                         binary_upgrade_set_pg_class_oids(fout, q,
16578                                                                                          indxinfo->dobj.catId.oid, true);
16579
16580                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
16581                                                   fmtQualifiedDumpable(tbinfo));
16582                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
16583                                                   fmtId(coninfo->dobj.name));
16584
16585                 if (coninfo->condef)
16586                 {
16587                         /* pg_get_constraintdef should have provided everything */
16588                         appendPQExpBuffer(q, "%s;\n", coninfo->condef);
16589                 }
16590                 else
16591                 {
16592                         appendPQExpBuffer(q, "%s (",
16593                                                           coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
16594                         for (k = 0; k < indxinfo->indnkeyattrs; k++)
16595                         {
16596                                 int                     indkey = (int) indxinfo->indkeys[k];
16597                                 const char *attname;
16598
16599                                 if (indkey == InvalidAttrNumber)
16600                                         break;
16601                                 attname = getAttrName(indkey, tbinfo);
16602
16603                                 appendPQExpBuffer(q, "%s%s",
16604                                                                   (k == 0) ? "" : ", ",
16605                                                                   fmtId(attname));
16606                         }
16607
16608                         if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
16609                                 appendPQExpBuffer(q, ") INCLUDE (");
16610
16611                         for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
16612                         {
16613                                 int                     indkey = (int) indxinfo->indkeys[k];
16614                                 const char *attname;
16615
16616                                 if (indkey == InvalidAttrNumber)
16617                                         break;
16618                                 attname = getAttrName(indkey, tbinfo);
16619
16620                                 appendPQExpBuffer(q, "%s%s",
16621                                                                   (k == indxinfo->indnkeyattrs) ? "" : ", ",
16622                                                                   fmtId(attname));
16623                         }
16624
16625                         appendPQExpBufferChar(q, ')');
16626
16627                         if (nonemptyReloptions(indxinfo->indreloptions))
16628                         {
16629                                 appendPQExpBufferStr(q, " WITH (");
16630                                 appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
16631                                 appendPQExpBufferChar(q, ')');
16632                         }
16633
16634                         if (coninfo->condeferrable)
16635                         {
16636                                 appendPQExpBufferStr(q, " DEFERRABLE");
16637                                 if (coninfo->condeferred)
16638                                         appendPQExpBufferStr(q, " INITIALLY DEFERRED");
16639                         }
16640
16641                         appendPQExpBufferStr(q, ";\n");
16642                 }
16643
16644                 /*
16645                  * Append ALTER TABLE commands as needed to set properties that we
16646                  * only have ALTER TABLE syntax for.  Keep this in sync with the
16647                  * similar code in dumpIndex!
16648                  */
16649
16650                 /* If the index is clustered, we need to record that. */
16651                 if (indxinfo->indisclustered)
16652                 {
16653                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16654                                                           fmtQualifiedDumpable(tbinfo));
16655                         /* index name is not qualified in this syntax */
16656                         appendPQExpBuffer(q, " ON %s;\n",
16657                                                           fmtId(indxinfo->dobj.name));
16658                 }
16659
16660                 /* If the index defines identity, we need to record that. */
16661                 if (indxinfo->indisreplident)
16662                 {
16663                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
16664                                                           fmtQualifiedDumpable(tbinfo));
16665                         /* index name is not qualified in this syntax */
16666                         appendPQExpBuffer(q, " INDEX %s;\n",
16667                                                           fmtId(indxinfo->dobj.name));
16668                 }
16669
16670                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s ",
16671                                                   fmtQualifiedDumpable(tbinfo));
16672                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16673                                                   fmtId(coninfo->dobj.name));
16674
16675                 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16676
16677                 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16678                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16679                                                  ARCHIVE_OPTS(.tag = tag,
16680                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
16681                                                                           .tablespace = indxinfo->tablespace,
16682                                                                           .owner = tbinfo->rolname,
16683                                                                           .description = "CONSTRAINT",
16684                                                                           .section = SECTION_POST_DATA,
16685                                                                           .createStmt = q->data,
16686                                                                           .dropStmt = delq->data));
16687         }
16688         else if (coninfo->contype == 'f')
16689         {
16690                 char       *only;
16691
16692                 /*
16693                  * Foreign keys on partitioned tables are always declared as
16694                  * inheriting to partitions; for all other cases, emit them as
16695                  * applying ONLY directly to the named table, because that's how they
16696                  * work for regular inherited tables.
16697                  */
16698                 only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
16699
16700                 /*
16701                  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
16702                  * current table data is not processed
16703                  */
16704                 appendPQExpBuffer(q, "ALTER TABLE %s%s\n",
16705                                                   only, fmtQualifiedDumpable(tbinfo));
16706                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16707                                                   fmtId(coninfo->dobj.name),
16708                                                   coninfo->condef);
16709
16710                 appendPQExpBuffer(delq, "ALTER TABLE %s%s ",
16711                                                   only, fmtQualifiedDumpable(tbinfo));
16712                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16713                                                   fmtId(coninfo->dobj.name));
16714
16715                 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16716
16717                 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16718                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16719                                                  ARCHIVE_OPTS(.tag = tag,
16720                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
16721                                                                           .owner = tbinfo->rolname,
16722                                                                           .description = "FK CONSTRAINT",
16723                                                                           .section = SECTION_POST_DATA,
16724                                                                           .createStmt = q->data,
16725                                                                           .dropStmt = delq->data));
16726         }
16727         else if (coninfo->contype == 'c' && tbinfo)
16728         {
16729                 /* CHECK constraint on a table */
16730
16731                 /* Ignore if not to be dumped separately, or if it was inherited */
16732                 if (coninfo->separate && coninfo->conislocal)
16733                 {
16734                         /* not ONLY since we want it to propagate to children */
16735                         appendPQExpBuffer(q, "ALTER TABLE %s\n",
16736                                                           fmtQualifiedDumpable(tbinfo));
16737                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16738                                                           fmtId(coninfo->dobj.name),
16739                                                           coninfo->condef);
16740
16741                         appendPQExpBuffer(delq, "ALTER TABLE %s ",
16742                                                           fmtQualifiedDumpable(tbinfo));
16743                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16744                                                           fmtId(coninfo->dobj.name));
16745
16746                         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16747
16748                         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16749                                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16750                                                          ARCHIVE_OPTS(.tag = tag,
16751                                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
16752                                                                                   .owner = tbinfo->rolname,
16753                                                                                   .description = "CHECK CONSTRAINT",
16754                                                                                   .section = SECTION_POST_DATA,
16755                                                                                   .createStmt = q->data,
16756                                                                                   .dropStmt = delq->data));
16757                 }
16758         }
16759         else if (coninfo->contype == 'c' && tbinfo == NULL)
16760         {
16761                 /* CHECK constraint on a domain */
16762                 TypeInfo   *tyinfo = coninfo->condomain;
16763
16764                 /* Ignore if not to be dumped separately */
16765                 if (coninfo->separate)
16766                 {
16767                         appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
16768                                                           fmtQualifiedDumpable(tyinfo));
16769                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16770                                                           fmtId(coninfo->dobj.name),
16771                                                           coninfo->condef);
16772
16773                         appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
16774                                                           fmtQualifiedDumpable(tyinfo));
16775                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16776                                                           fmtId(coninfo->dobj.name));
16777
16778                         tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
16779
16780                         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16781                                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16782                                                          ARCHIVE_OPTS(.tag = tag,
16783                                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
16784                                                                                   .owner = tyinfo->rolname,
16785                                                                                   .description = "CHECK CONSTRAINT",
16786                                                                                   .section = SECTION_POST_DATA,
16787                                                                                   .createStmt = q->data,
16788                                                                                   .dropStmt = delq->data));
16789                 }
16790         }
16791         else
16792         {
16793                 exit_horribly(NULL, "unrecognized constraint type: %c\n",
16794                                           coninfo->contype);
16795         }
16796
16797         /* Dump Constraint Comments --- only works for table constraints */
16798         if (tbinfo && coninfo->separate &&
16799                 coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16800                 dumpTableConstraintComment(fout, coninfo);
16801
16802         free(tag);
16803         destroyPQExpBuffer(q);
16804         destroyPQExpBuffer(delq);
16805 }
16806
16807 /*
16808  * dumpTableConstraintComment --- dump a constraint's comment if any
16809  *
16810  * This is split out because we need the function in two different places
16811  * depending on whether the constraint is dumped as part of CREATE TABLE
16812  * or as a separate ALTER command.
16813  */
16814 static void
16815 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
16816 {
16817         TableInfo  *tbinfo = coninfo->contable;
16818         PQExpBuffer conprefix = createPQExpBuffer();
16819         char       *qtabname;
16820
16821         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
16822
16823         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
16824                                           fmtId(coninfo->dobj.name));
16825
16826         if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16827                 dumpComment(fout, conprefix->data, qtabname,
16828                                         tbinfo->dobj.namespace->dobj.name,
16829                                         tbinfo->rolname,
16830                                         coninfo->dobj.catId, 0,
16831                                         coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
16832
16833         destroyPQExpBuffer(conprefix);
16834         free(qtabname);
16835 }
16836
16837 /*
16838  * findLastBuiltinOid_V71 -
16839  *
16840  * find the last built in oid
16841  *
16842  * For 7.1 through 8.0, we do this by retrieving datlastsysoid from the
16843  * pg_database entry for the current database.  (Note: current_database()
16844  * requires 7.3; pg_dump requires 8.0 now.)
16845  */
16846 static Oid
16847 findLastBuiltinOid_V71(Archive *fout)
16848 {
16849         PGresult   *res;
16850         Oid                     last_oid;
16851
16852         res = ExecuteSqlQueryForSingleRow(fout,
16853                                                                           "SELECT datlastsysoid FROM pg_database WHERE datname = current_database()");
16854         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
16855         PQclear(res);
16856
16857         return last_oid;
16858 }
16859
16860 /*
16861  * dumpSequence
16862  *        write the declaration (not data) of one user-defined sequence
16863  */
16864 static void
16865 dumpSequence(Archive *fout, TableInfo *tbinfo)
16866 {
16867         DumpOptions *dopt = fout->dopt;
16868         PGresult   *res;
16869         char       *startv,
16870                            *incby,
16871                            *maxv,
16872                            *minv,
16873                            *cache,
16874                            *seqtype;
16875         bool            cycled;
16876         bool            is_ascending;
16877         int64           default_minv,
16878                                 default_maxv;
16879         char            bufm[32],
16880                                 bufx[32];
16881         PQExpBuffer query = createPQExpBuffer();
16882         PQExpBuffer delqry = createPQExpBuffer();
16883         char       *qseqname;
16884
16885         qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
16886
16887         if (fout->remoteVersion >= 100000)
16888         {
16889                 appendPQExpBuffer(query,
16890                                                   "SELECT format_type(seqtypid, NULL), "
16891                                                   "seqstart, seqincrement, "
16892                                                   "seqmax, seqmin, "
16893                                                   "seqcache, seqcycle "
16894                                                   "FROM pg_catalog.pg_sequence "
16895                                                   "WHERE seqrelid = '%u'::oid",
16896                                                   tbinfo->dobj.catId.oid);
16897         }
16898         else if (fout->remoteVersion >= 80400)
16899         {
16900                 /*
16901                  * Before PostgreSQL 10, sequence metadata is in the sequence itself.
16902                  *
16903                  * Note: it might seem that 'bigint' potentially needs to be
16904                  * schema-qualified, but actually that's a keyword.
16905                  */
16906                 appendPQExpBuffer(query,
16907                                                   "SELECT 'bigint' AS sequence_type, "
16908                                                   "start_value, increment_by, max_value, min_value, "
16909                                                   "cache_value, is_cycled FROM %s",
16910                                                   fmtQualifiedDumpable(tbinfo));
16911         }
16912         else
16913         {
16914                 appendPQExpBuffer(query,
16915                                                   "SELECT 'bigint' AS sequence_type, "
16916                                                   "0 AS start_value, increment_by, max_value, min_value, "
16917                                                   "cache_value, is_cycled FROM %s",
16918                                                   fmtQualifiedDumpable(tbinfo));
16919         }
16920
16921         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16922
16923         if (PQntuples(res) != 1)
16924         {
16925                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
16926                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
16927                                                                  PQntuples(res)),
16928                                   tbinfo->dobj.name, PQntuples(res));
16929                 exit_nicely(1);
16930         }
16931
16932         seqtype = PQgetvalue(res, 0, 0);
16933         startv = PQgetvalue(res, 0, 1);
16934         incby = PQgetvalue(res, 0, 2);
16935         maxv = PQgetvalue(res, 0, 3);
16936         minv = PQgetvalue(res, 0, 4);
16937         cache = PQgetvalue(res, 0, 5);
16938         cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
16939
16940         /* Calculate default limits for a sequence of this type */
16941         is_ascending = (incby[0] != '-');
16942         if (strcmp(seqtype, "smallint") == 0)
16943         {
16944                 default_minv = is_ascending ? 1 : PG_INT16_MIN;
16945                 default_maxv = is_ascending ? PG_INT16_MAX : -1;
16946         }
16947         else if (strcmp(seqtype, "integer") == 0)
16948         {
16949                 default_minv = is_ascending ? 1 : PG_INT32_MIN;
16950                 default_maxv = is_ascending ? PG_INT32_MAX : -1;
16951         }
16952         else if (strcmp(seqtype, "bigint") == 0)
16953         {
16954                 default_minv = is_ascending ? 1 : PG_INT64_MIN;
16955                 default_maxv = is_ascending ? PG_INT64_MAX : -1;
16956         }
16957         else
16958         {
16959                 exit_horribly(NULL, "unrecognized sequence type: %s\n", seqtype);
16960                 default_minv = default_maxv = 0;        /* keep compiler quiet */
16961         }
16962
16963         /*
16964          * 64-bit strtol() isn't very portable, so convert the limits to strings
16965          * and compare that way.
16966          */
16967         snprintf(bufm, sizeof(bufm), INT64_FORMAT, default_minv);
16968         snprintf(bufx, sizeof(bufx), INT64_FORMAT, default_maxv);
16969
16970         /* Don't print minv/maxv if they match the respective default limit */
16971         if (strcmp(minv, bufm) == 0)
16972                 minv = NULL;
16973         if (strcmp(maxv, bufx) == 0)
16974                 maxv = NULL;
16975
16976         /*
16977          * Identity sequences are not to be dropped separately.
16978          */
16979         if (!tbinfo->is_identity_sequence)
16980         {
16981                 appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
16982                                                   fmtQualifiedDumpable(tbinfo));
16983         }
16984
16985         resetPQExpBuffer(query);
16986
16987         if (dopt->binary_upgrade)
16988         {
16989                 binary_upgrade_set_pg_class_oids(fout, query,
16990                                                                                  tbinfo->dobj.catId.oid, false);
16991                 binary_upgrade_set_type_oids_by_rel_oid(fout, query,
16992                                                                                                 tbinfo->dobj.catId.oid);
16993         }
16994
16995         if (tbinfo->is_identity_sequence)
16996         {
16997                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
16998
16999                 appendPQExpBuffer(query,
17000                                                   "ALTER TABLE %s ",
17001                                                   fmtQualifiedDumpable(owning_tab));
17002                 appendPQExpBuffer(query,
17003                                                   "ALTER COLUMN %s ADD GENERATED ",
17004                                                   fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
17005                 if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
17006                         appendPQExpBuffer(query, "ALWAYS");
17007                 else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
17008                         appendPQExpBuffer(query, "BY DEFAULT");
17009                 appendPQExpBuffer(query, " AS IDENTITY (\n    SEQUENCE NAME %s\n",
17010                                                   fmtQualifiedDumpable(tbinfo));
17011         }
17012         else
17013         {
17014                 appendPQExpBuffer(query,
17015                                                   "CREATE SEQUENCE %s\n",
17016                                                   fmtQualifiedDumpable(tbinfo));
17017
17018                 if (strcmp(seqtype, "bigint") != 0)
17019                         appendPQExpBuffer(query, "    AS %s\n", seqtype);
17020         }
17021
17022         if (fout->remoteVersion >= 80400)
17023                 appendPQExpBuffer(query, "    START WITH %s\n", startv);
17024
17025         appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
17026
17027         if (minv)
17028                 appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
17029         else
17030                 appendPQExpBufferStr(query, "    NO MINVALUE\n");
17031
17032         if (maxv)
17033                 appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
17034         else
17035                 appendPQExpBufferStr(query, "    NO MAXVALUE\n");
17036
17037         appendPQExpBuffer(query,
17038                                           "    CACHE %s%s",
17039                                           cache, (cycled ? "\n    CYCLE" : ""));
17040
17041         if (tbinfo->is_identity_sequence)
17042                 appendPQExpBufferStr(query, "\n);\n");
17043         else
17044                 appendPQExpBufferStr(query, ";\n");
17045
17046         /* binary_upgrade:      no need to clear TOAST table oid */
17047
17048         if (dopt->binary_upgrade)
17049                 binary_upgrade_extension_member(query, &tbinfo->dobj,
17050                                                                                 "SEQUENCE", qseqname,
17051                                                                                 tbinfo->dobj.namespace->dobj.name);
17052
17053         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17054                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
17055                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17056                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17057                                                                   .owner = tbinfo->rolname,
17058                                                                   .description = "SEQUENCE",
17059                                                                   .section = SECTION_PRE_DATA,
17060                                                                   .createStmt = query->data,
17061                                                                   .dropStmt = delqry->data));
17062
17063         /*
17064          * If the sequence is owned by a table column, emit the ALTER for it as a
17065          * separate TOC entry immediately following the sequence's own entry. It's
17066          * OK to do this rather than using full sorting logic, because the
17067          * dependency that tells us it's owned will have forced the table to be
17068          * created first.  We can't just include the ALTER in the TOC entry
17069          * because it will fail if we haven't reassigned the sequence owner to
17070          * match the table's owner.
17071          *
17072          * We need not schema-qualify the table reference because both sequence
17073          * and table must be in the same schema.
17074          */
17075         if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
17076         {
17077                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
17078
17079                 if (owning_tab == NULL)
17080                         exit_horribly(NULL, "failed sanity check, parent table with OID %u of sequence with OID %u not found\n",
17081                                                   tbinfo->owning_tab, tbinfo->dobj.catId.oid);
17082
17083                 if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
17084                 {
17085                         resetPQExpBuffer(query);
17086                         appendPQExpBuffer(query, "ALTER SEQUENCE %s",
17087                                                           fmtQualifiedDumpable(tbinfo));
17088                         appendPQExpBuffer(query, " OWNED BY %s",
17089                                                           fmtQualifiedDumpable(owning_tab));
17090                         appendPQExpBuffer(query, ".%s;\n",
17091                                                           fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
17092
17093                         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17094                                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
17095                                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17096                                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17097                                                                                   .owner = tbinfo->rolname,
17098                                                                                   .description = "SEQUENCE OWNED BY",
17099                                                                                   .section = SECTION_PRE_DATA,
17100                                                                                   .createStmt = query->data,
17101                                                                                   .dropStmt = "",
17102                                                                                   .deps = &(tbinfo->dobj.dumpId),
17103                                                                                   .nDeps = 1));
17104                 }
17105         }
17106
17107         /* Dump Sequence Comments and Security Labels */
17108         if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17109                 dumpComment(fout, "SEQUENCE", qseqname,
17110                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17111                                         tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
17112
17113         if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
17114                 dumpSecLabel(fout, "SEQUENCE", qseqname,
17115                                          tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17116                                          tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
17117
17118         PQclear(res);
17119
17120         destroyPQExpBuffer(query);
17121         destroyPQExpBuffer(delqry);
17122         free(qseqname);
17123 }
17124
17125 /*
17126  * dumpSequenceData
17127  *        write the data of one user-defined sequence
17128  */
17129 static void
17130 dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
17131 {
17132         TableInfo  *tbinfo = tdinfo->tdtable;
17133         PGresult   *res;
17134         char       *last;
17135         bool            called;
17136         PQExpBuffer query = createPQExpBuffer();
17137
17138         appendPQExpBuffer(query,
17139                                           "SELECT last_value, is_called FROM %s",
17140                                           fmtQualifiedDumpable(tbinfo));
17141
17142         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17143
17144         if (PQntuples(res) != 1)
17145         {
17146                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
17147                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
17148                                                                  PQntuples(res)),
17149                                   tbinfo->dobj.name, PQntuples(res));
17150                 exit_nicely(1);
17151         }
17152
17153         last = PQgetvalue(res, 0, 0);
17154         called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
17155
17156         resetPQExpBuffer(query);
17157         appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
17158         appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
17159         appendPQExpBuffer(query, ", %s, %s);\n",
17160                                           last, (called ? "true" : "false"));
17161
17162         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
17163                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
17164                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17165                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17166                                                                   .owner = tbinfo->rolname,
17167                                                                   .description = "SEQUENCE SET",
17168                                                                   .section = SECTION_DATA,
17169                                                                   .createStmt = query->data,
17170                                                                   .dropStmt = "",
17171                                                                   .deps = &(tbinfo->dobj.dumpId),
17172                                                                   .nDeps = 1));
17173
17174         PQclear(res);
17175
17176         destroyPQExpBuffer(query);
17177 }
17178
17179 /*
17180  * dumpTrigger
17181  *        write the declaration of one user-defined table trigger
17182  */
17183 static void
17184 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
17185 {
17186         DumpOptions *dopt = fout->dopt;
17187         TableInfo  *tbinfo = tginfo->tgtable;
17188         PQExpBuffer query;
17189         PQExpBuffer delqry;
17190         PQExpBuffer trigprefix;
17191         char       *qtabname;
17192         char       *tgargs;
17193         size_t          lentgargs;
17194         const char *p;
17195         int                     findx;
17196         char       *tag;
17197
17198         /*
17199          * we needn't check dobj.dump because TriggerInfo wouldn't have been
17200          * created in the first place for non-dumpable triggers
17201          */
17202         if (dopt->dataOnly)
17203                 return;
17204
17205         query = createPQExpBuffer();
17206         delqry = createPQExpBuffer();
17207         trigprefix = createPQExpBuffer();
17208
17209         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17210
17211         appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
17212                                           fmtId(tginfo->dobj.name));
17213         appendPQExpBuffer(delqry, "ON %s;\n",
17214                                           fmtQualifiedDumpable(tbinfo));
17215
17216         if (tginfo->tgdef)
17217         {
17218                 appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
17219         }
17220         else
17221         {
17222                 if (tginfo->tgisconstraint)
17223                 {
17224                         appendPQExpBufferStr(query, "CREATE CONSTRAINT TRIGGER ");
17225                         appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
17226                 }
17227                 else
17228                 {
17229                         appendPQExpBufferStr(query, "CREATE TRIGGER ");
17230                         appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
17231                 }
17232                 appendPQExpBufferStr(query, "\n    ");
17233
17234                 /* Trigger type */
17235                 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
17236                         appendPQExpBufferStr(query, "BEFORE");
17237                 else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
17238                         appendPQExpBufferStr(query, "AFTER");
17239                 else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
17240                         appendPQExpBufferStr(query, "INSTEAD OF");
17241                 else
17242                 {
17243                         write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
17244                         exit_nicely(1);
17245                 }
17246
17247                 findx = 0;
17248                 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
17249                 {
17250                         appendPQExpBufferStr(query, " INSERT");
17251                         findx++;
17252                 }
17253                 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
17254                 {
17255                         if (findx > 0)
17256                                 appendPQExpBufferStr(query, " OR DELETE");
17257                         else
17258                                 appendPQExpBufferStr(query, " DELETE");
17259                         findx++;
17260                 }
17261                 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
17262                 {
17263                         if (findx > 0)
17264                                 appendPQExpBufferStr(query, " OR UPDATE");
17265                         else
17266                                 appendPQExpBufferStr(query, " UPDATE");
17267                         findx++;
17268                 }
17269                 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
17270                 {
17271                         if (findx > 0)
17272                                 appendPQExpBufferStr(query, " OR TRUNCATE");
17273                         else
17274                                 appendPQExpBufferStr(query, " TRUNCATE");
17275                         findx++;
17276                 }
17277                 appendPQExpBuffer(query, " ON %s\n",
17278                                                   fmtQualifiedDumpable(tbinfo));
17279
17280                 if (tginfo->tgisconstraint)
17281                 {
17282                         if (OidIsValid(tginfo->tgconstrrelid))
17283                         {
17284                                 /* regclass output is already quoted */
17285                                 appendPQExpBuffer(query, "    FROM %s\n    ",
17286                                                                   tginfo->tgconstrrelname);
17287                         }
17288                         if (!tginfo->tgdeferrable)
17289                                 appendPQExpBufferStr(query, "NOT ");
17290                         appendPQExpBufferStr(query, "DEFERRABLE INITIALLY ");
17291                         if (tginfo->tginitdeferred)
17292                                 appendPQExpBufferStr(query, "DEFERRED\n");
17293                         else
17294                                 appendPQExpBufferStr(query, "IMMEDIATE\n");
17295                 }
17296
17297                 if (TRIGGER_FOR_ROW(tginfo->tgtype))
17298                         appendPQExpBufferStr(query, "    FOR EACH ROW\n    ");
17299                 else
17300                         appendPQExpBufferStr(query, "    FOR EACH STATEMENT\n    ");
17301
17302                 /* regproc output is already sufficiently quoted */
17303                 appendPQExpBuffer(query, "EXECUTE FUNCTION %s(",
17304                                                   tginfo->tgfname);
17305
17306                 tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
17307                                                                                   &lentgargs);
17308                 p = tgargs;
17309                 for (findx = 0; findx < tginfo->tgnargs; findx++)
17310                 {
17311                         /* find the embedded null that terminates this trigger argument */
17312                         size_t          tlen = strlen(p);
17313
17314                         if (p + tlen >= tgargs + lentgargs)
17315                         {
17316                                 /* hm, not found before end of bytea value... */
17317                                 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
17318                                                   tginfo->tgargs,
17319                                                   tginfo->dobj.name,
17320                                                   tbinfo->dobj.name);
17321                                 exit_nicely(1);
17322                         }
17323
17324                         if (findx > 0)
17325                                 appendPQExpBufferStr(query, ", ");
17326                         appendStringLiteralAH(query, p, fout);
17327                         p += tlen + 1;
17328                 }
17329                 free(tgargs);
17330                 appendPQExpBufferStr(query, ");\n");
17331         }
17332
17333         if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
17334         {
17335                 appendPQExpBuffer(query, "\nALTER TABLE %s ",
17336                                                   fmtQualifiedDumpable(tbinfo));
17337                 switch (tginfo->tgenabled)
17338                 {
17339                         case 'D':
17340                         case 'f':
17341                                 appendPQExpBufferStr(query, "DISABLE");
17342                                 break;
17343                         case 'A':
17344                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
17345                                 break;
17346                         case 'R':
17347                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
17348                                 break;
17349                         default:
17350                                 appendPQExpBufferStr(query, "ENABLE");
17351                                 break;
17352                 }
17353                 appendPQExpBuffer(query, " TRIGGER %s;\n",
17354                                                   fmtId(tginfo->dobj.name));
17355         }
17356
17357         appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
17358                                           fmtId(tginfo->dobj.name));
17359
17360         tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
17361
17362         if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17363                 ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
17364                                          ARCHIVE_OPTS(.tag = tag,
17365                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17366                                                                   .owner = tbinfo->rolname,
17367                                                                   .description = "TRIGGER",
17368                                                                   .section = SECTION_POST_DATA,
17369                                                                   .createStmt = query->data,
17370                                                                   .dropStmt = delqry->data));
17371
17372         if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17373                 dumpComment(fout, trigprefix->data, qtabname,
17374                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17375                                         tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
17376
17377         free(tag);
17378         destroyPQExpBuffer(query);
17379         destroyPQExpBuffer(delqry);
17380         destroyPQExpBuffer(trigprefix);
17381         free(qtabname);
17382 }
17383
17384 /*
17385  * dumpEventTrigger
17386  *        write the declaration of one user-defined event trigger
17387  */
17388 static void
17389 dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
17390 {
17391         DumpOptions *dopt = fout->dopt;
17392         PQExpBuffer query;
17393         PQExpBuffer delqry;
17394         char       *qevtname;
17395
17396         /* Skip if not to be dumped */
17397         if (!evtinfo->dobj.dump || dopt->dataOnly)
17398                 return;
17399
17400         query = createPQExpBuffer();
17401         delqry = createPQExpBuffer();
17402
17403         qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
17404
17405         appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
17406         appendPQExpBufferStr(query, qevtname);
17407         appendPQExpBufferStr(query, " ON ");
17408         appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
17409
17410         if (strcmp("", evtinfo->evttags) != 0)
17411         {
17412                 appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
17413                 appendPQExpBufferStr(query, evtinfo->evttags);
17414                 appendPQExpBufferChar(query, ')');
17415         }
17416
17417         appendPQExpBufferStr(query, "\n   EXECUTE FUNCTION ");
17418         appendPQExpBufferStr(query, evtinfo->evtfname);
17419         appendPQExpBufferStr(query, "();\n");
17420
17421         if (evtinfo->evtenabled != 'O')
17422         {
17423                 appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
17424                                                   qevtname);
17425                 switch (evtinfo->evtenabled)
17426                 {
17427                         case 'D':
17428                                 appendPQExpBufferStr(query, "DISABLE");
17429                                 break;
17430                         case 'A':
17431                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
17432                                 break;
17433                         case 'R':
17434                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
17435                                 break;
17436                         default:
17437                                 appendPQExpBufferStr(query, "ENABLE");
17438                                 break;
17439                 }
17440                 appendPQExpBufferStr(query, ";\n");
17441         }
17442
17443         appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
17444                                           qevtname);
17445
17446         if (dopt->binary_upgrade)
17447                 binary_upgrade_extension_member(query, &evtinfo->dobj,
17448                                                                                 "EVENT TRIGGER", qevtname, NULL);
17449
17450         if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17451                 ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
17452                                          ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
17453                                                                   .owner = evtinfo->evtowner,
17454                                                                   .description = "EVENT TRIGGER",
17455                                                                   .section = SECTION_POST_DATA,
17456                                                                   .createStmt = query->data,
17457                                                                   .dropStmt = delqry->data));
17458
17459         if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17460                 dumpComment(fout, "EVENT TRIGGER", qevtname,
17461                                         NULL, evtinfo->evtowner,
17462                                         evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
17463
17464         destroyPQExpBuffer(query);
17465         destroyPQExpBuffer(delqry);
17466         free(qevtname);
17467 }
17468
17469 /*
17470  * dumpRule
17471  *              Dump a rule
17472  */
17473 static void
17474 dumpRule(Archive *fout, RuleInfo *rinfo)
17475 {
17476         DumpOptions *dopt = fout->dopt;
17477         TableInfo  *tbinfo = rinfo->ruletable;
17478         bool            is_view;
17479         PQExpBuffer query;
17480         PQExpBuffer cmd;
17481         PQExpBuffer delcmd;
17482         PQExpBuffer ruleprefix;
17483         char       *qtabname;
17484         PGresult   *res;
17485         char       *tag;
17486
17487         /* Skip if not to be dumped */
17488         if (!rinfo->dobj.dump || dopt->dataOnly)
17489                 return;
17490
17491         /*
17492          * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
17493          * we do not want to dump it as a separate object.
17494          */
17495         if (!rinfo->separate)
17496                 return;
17497
17498         /*
17499          * If it's an ON SELECT rule, we want to print it as a view definition,
17500          * instead of a rule.
17501          */
17502         is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
17503
17504         query = createPQExpBuffer();
17505         cmd = createPQExpBuffer();
17506         delcmd = createPQExpBuffer();
17507         ruleprefix = createPQExpBuffer();
17508
17509         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17510
17511         if (is_view)
17512         {
17513                 PQExpBuffer result;
17514
17515                 /*
17516                  * We need OR REPLACE here because we'll be replacing a dummy view.
17517                  * Otherwise this should look largely like the regular view dump code.
17518                  */
17519                 appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
17520                                                   fmtQualifiedDumpable(tbinfo));
17521                 if (nonemptyReloptions(tbinfo->reloptions))
17522                 {
17523                         appendPQExpBufferStr(cmd, " WITH (");
17524                         appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
17525                         appendPQExpBufferChar(cmd, ')');
17526                 }
17527                 result = createViewAsClause(fout, tbinfo);
17528                 appendPQExpBuffer(cmd, " AS\n%s", result->data);
17529                 destroyPQExpBuffer(result);
17530                 if (tbinfo->checkoption != NULL)
17531                         appendPQExpBuffer(cmd, "\n  WITH %s CHECK OPTION",
17532                                                           tbinfo->checkoption);
17533                 appendPQExpBufferStr(cmd, ";\n");
17534         }
17535         else
17536         {
17537                 /* In the rule case, just print pg_get_ruledef's result verbatim */
17538                 appendPQExpBuffer(query,
17539                                                   "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
17540                                                   rinfo->dobj.catId.oid);
17541
17542                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17543
17544                 if (PQntuples(res) != 1)
17545                 {
17546                         write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
17547                                           rinfo->dobj.name, tbinfo->dobj.name);
17548                         exit_nicely(1);
17549                 }
17550
17551                 printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
17552
17553                 PQclear(res);
17554         }
17555
17556         /*
17557          * Add the command to alter the rules replication firing semantics if it
17558          * differs from the default.
17559          */
17560         if (rinfo->ev_enabled != 'O')
17561         {
17562                 appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
17563                 switch (rinfo->ev_enabled)
17564                 {
17565                         case 'A':
17566                                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
17567                                                                   fmtId(rinfo->dobj.name));
17568                                 break;
17569                         case 'R':
17570                                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
17571                                                                   fmtId(rinfo->dobj.name));
17572                                 break;
17573                         case 'D':
17574                                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
17575                                                                   fmtId(rinfo->dobj.name));
17576                                 break;
17577                 }
17578         }
17579
17580         if (is_view)
17581         {
17582                 /*
17583                  * We can't DROP a view's ON SELECT rule.  Instead, use CREATE OR
17584                  * REPLACE VIEW to replace the rule with something with minimal
17585                  * dependencies.
17586                  */
17587                 PQExpBuffer result;
17588
17589                 appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
17590                                                   fmtQualifiedDumpable(tbinfo));
17591                 result = createDummyViewAsClause(fout, tbinfo);
17592                 appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
17593                 destroyPQExpBuffer(result);
17594         }
17595         else
17596         {
17597                 appendPQExpBuffer(delcmd, "DROP RULE %s ",
17598                                                   fmtId(rinfo->dobj.name));
17599                 appendPQExpBuffer(delcmd, "ON %s;\n",
17600                                                   fmtQualifiedDumpable(tbinfo));
17601         }
17602
17603         appendPQExpBuffer(ruleprefix, "RULE %s ON",
17604                                           fmtId(rinfo->dobj.name));
17605
17606         tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
17607
17608         if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17609                 ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
17610                                          ARCHIVE_OPTS(.tag = tag,
17611                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17612                                                                   .owner = tbinfo->rolname,
17613                                                                   .description = "RULE",
17614                                                                   .section = SECTION_POST_DATA,
17615                                                                   .createStmt = cmd->data,
17616                                                                   .dropStmt = delcmd->data));
17617
17618         /* Dump rule comments */
17619         if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17620                 dumpComment(fout, ruleprefix->data, qtabname,
17621                                         tbinfo->dobj.namespace->dobj.name,
17622                                         tbinfo->rolname,
17623                                         rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
17624
17625         free(tag);
17626         destroyPQExpBuffer(query);
17627         destroyPQExpBuffer(cmd);
17628         destroyPQExpBuffer(delcmd);
17629         destroyPQExpBuffer(ruleprefix);
17630         free(qtabname);
17631 }
17632
17633 /*
17634  * getExtensionMembership --- obtain extension membership data
17635  *
17636  * We need to identify objects that are extension members as soon as they're
17637  * loaded, so that we can correctly determine whether they need to be dumped.
17638  * Generally speaking, extension member objects will get marked as *not* to
17639  * be dumped, as they will be recreated by the single CREATE EXTENSION
17640  * command.  However, in binary upgrade mode we still need to dump the members
17641  * individually.
17642  */
17643 void
17644 getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
17645                                            int numExtensions)
17646 {
17647         PQExpBuffer query;
17648         PGresult   *res;
17649         int                     ntups,
17650                                 nextmembers,
17651                                 i;
17652         int                     i_classid,
17653                                 i_objid,
17654                                 i_refobjid;
17655         ExtensionMemberId *extmembers;
17656         ExtensionInfo *ext;
17657
17658         /* Nothing to do if no extensions */
17659         if (numExtensions == 0)
17660                 return;
17661
17662         query = createPQExpBuffer();
17663
17664         /* refclassid constraint is redundant but may speed the search */
17665         appendPQExpBufferStr(query, "SELECT "
17666                                                  "classid, objid, refobjid "
17667                                                  "FROM pg_depend "
17668                                                  "WHERE refclassid = 'pg_extension'::regclass "
17669                                                  "AND deptype = 'e' "
17670                                                  "ORDER BY 3");
17671
17672         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17673
17674         ntups = PQntuples(res);
17675
17676         i_classid = PQfnumber(res, "classid");
17677         i_objid = PQfnumber(res, "objid");
17678         i_refobjid = PQfnumber(res, "refobjid");
17679
17680         extmembers = (ExtensionMemberId *) pg_malloc(ntups * sizeof(ExtensionMemberId));
17681         nextmembers = 0;
17682
17683         /*
17684          * Accumulate data into extmembers[].
17685          *
17686          * Since we ordered the SELECT by referenced ID, we can expect that
17687          * multiple entries for the same extension will appear together; this
17688          * saves on searches.
17689          */
17690         ext = NULL;
17691
17692         for (i = 0; i < ntups; i++)
17693         {
17694                 CatalogId       objId;
17695                 Oid                     extId;
17696
17697                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17698                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
17699                 extId = atooid(PQgetvalue(res, i, i_refobjid));
17700
17701                 if (ext == NULL ||
17702                         ext->dobj.catId.oid != extId)
17703                         ext = findExtensionByOid(extId);
17704
17705                 if (ext == NULL)
17706                 {
17707                         /* shouldn't happen */
17708                         fprintf(stderr, "could not find referenced extension %u\n", extId);
17709                         continue;
17710                 }
17711
17712                 extmembers[nextmembers].catId = objId;
17713                 extmembers[nextmembers].ext = ext;
17714                 nextmembers++;
17715         }
17716
17717         PQclear(res);
17718
17719         /* Remember the data for use later */
17720         setExtensionMembership(extmembers, nextmembers);
17721
17722         destroyPQExpBuffer(query);
17723 }
17724
17725 /*
17726  * processExtensionTables --- deal with extension configuration tables
17727  *
17728  * There are two parts to this process:
17729  *
17730  * 1. Identify and create dump records for extension configuration tables.
17731  *
17732  *        Extensions can mark tables as "configuration", which means that the user
17733  *        is able and expected to modify those tables after the extension has been
17734  *        loaded.  For these tables, we dump out only the data- the structure is
17735  *        expected to be handled at CREATE EXTENSION time, including any indexes or
17736  *        foreign keys, which brings us to-
17737  *
17738  * 2. Record FK dependencies between configuration tables.
17739  *
17740  *        Due to the FKs being created at CREATE EXTENSION time and therefore before
17741  *        the data is loaded, we have to work out what the best order for reloading
17742  *        the data is, to avoid FK violations when the tables are restored.  This is
17743  *        not perfect- we can't handle circular dependencies and if any exist they
17744  *        will cause an invalid dump to be produced (though at least all of the data
17745  *        is included for a user to manually restore).  This is currently documented
17746  *        but perhaps we can provide a better solution in the future.
17747  */
17748 void
17749 processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
17750                                            int numExtensions)
17751 {
17752         DumpOptions *dopt = fout->dopt;
17753         PQExpBuffer query;
17754         PGresult   *res;
17755         int                     ntups,
17756                                 i;
17757         int                     i_conrelid,
17758                                 i_confrelid;
17759
17760         /* Nothing to do if no extensions */
17761         if (numExtensions == 0)
17762                 return;
17763
17764         /*
17765          * Identify extension configuration tables and create TableDataInfo
17766          * objects for them, ensuring their data will be dumped even though the
17767          * tables themselves won't be.
17768          *
17769          * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
17770          * user data in a configuration table is treated like schema data. This
17771          * seems appropriate since system data in a config table would get
17772          * reloaded by CREATE EXTENSION.
17773          */
17774         for (i = 0; i < numExtensions; i++)
17775         {
17776                 ExtensionInfo *curext = &(extinfo[i]);
17777                 char       *extconfig = curext->extconfig;
17778                 char       *extcondition = curext->extcondition;
17779                 char      **extconfigarray = NULL;
17780                 char      **extconditionarray = NULL;
17781                 int                     nconfigitems;
17782                 int                     nconditionitems;
17783
17784                 if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
17785                         parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
17786                         nconfigitems == nconditionitems)
17787                 {
17788                         int                     j;
17789
17790                         for (j = 0; j < nconfigitems; j++)
17791                         {
17792                                 TableInfo  *configtbl;
17793                                 Oid                     configtbloid = atooid(extconfigarray[j]);
17794                                 bool            dumpobj =
17795                                 curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
17796
17797                                 configtbl = findTableByOid(configtbloid);
17798                                 if (configtbl == NULL)
17799                                         continue;
17800
17801                                 /*
17802                                  * Tables of not-to-be-dumped extensions shouldn't be dumped
17803                                  * unless the table or its schema is explicitly included
17804                                  */
17805                                 if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
17806                                 {
17807                                         /* check table explicitly requested */
17808                                         if (table_include_oids.head != NULL &&
17809                                                 simple_oid_list_member(&table_include_oids,
17810                                                                                            configtbloid))
17811                                                 dumpobj = true;
17812
17813                                         /* check table's schema explicitly requested */
17814                                         if (configtbl->dobj.namespace->dobj.dump &
17815                                                 DUMP_COMPONENT_DATA)
17816                                                 dumpobj = true;
17817                                 }
17818
17819                                 /* check table excluded by an exclusion switch */
17820                                 if (table_exclude_oids.head != NULL &&
17821                                         simple_oid_list_member(&table_exclude_oids,
17822                                                                                    configtbloid))
17823                                         dumpobj = false;
17824
17825                                 /* check schema excluded by an exclusion switch */
17826                                 if (simple_oid_list_member(&schema_exclude_oids,
17827                                                                                    configtbl->dobj.namespace->dobj.catId.oid))
17828                                         dumpobj = false;
17829
17830                                 if (dumpobj)
17831                                 {
17832                                         makeTableDataInfo(dopt, configtbl);
17833                                         if (configtbl->dataObj != NULL)
17834                                         {
17835                                                 if (strlen(extconditionarray[j]) > 0)
17836                                                         configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
17837                                         }
17838                                 }
17839                         }
17840                 }
17841                 if (extconfigarray)
17842                         free(extconfigarray);
17843                 if (extconditionarray)
17844                         free(extconditionarray);
17845         }
17846
17847         /*
17848          * Now that all the TableInfoData objects have been created for all the
17849          * extensions, check their FK dependencies and register them to try and
17850          * dump the data out in an order that they can be restored in.
17851          *
17852          * Note that this is not a problem for user tables as their FKs are
17853          * recreated after the data has been loaded.
17854          */
17855
17856         query = createPQExpBuffer();
17857
17858         printfPQExpBuffer(query,
17859                                           "SELECT conrelid, confrelid "
17860                                           "FROM pg_constraint "
17861                                           "JOIN pg_depend ON (objid = confrelid) "
17862                                           "WHERE contype = 'f' "
17863                                           "AND refclassid = 'pg_extension'::regclass "
17864                                           "AND classid = 'pg_class'::regclass;");
17865
17866         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17867         ntups = PQntuples(res);
17868
17869         i_conrelid = PQfnumber(res, "conrelid");
17870         i_confrelid = PQfnumber(res, "confrelid");
17871
17872         /* Now get the dependencies and register them */
17873         for (i = 0; i < ntups; i++)
17874         {
17875                 Oid                     conrelid,
17876                                         confrelid;
17877                 TableInfo  *reftable,
17878                                    *contable;
17879
17880                 conrelid = atooid(PQgetvalue(res, i, i_conrelid));
17881                 confrelid = atooid(PQgetvalue(res, i, i_confrelid));
17882                 contable = findTableByOid(conrelid);
17883                 reftable = findTableByOid(confrelid);
17884
17885                 if (reftable == NULL ||
17886                         reftable->dataObj == NULL ||
17887                         contable == NULL ||
17888                         contable->dataObj == NULL)
17889                         continue;
17890
17891                 /*
17892                  * Make referencing TABLE_DATA object depend on the referenced table's
17893                  * TABLE_DATA object.
17894                  */
17895                 addObjectDependency(&contable->dataObj->dobj,
17896                                                         reftable->dataObj->dobj.dumpId);
17897         }
17898         PQclear(res);
17899         destroyPQExpBuffer(query);
17900 }
17901
17902 /*
17903  * getDependencies --- obtain available dependency data
17904  */
17905 static void
17906 getDependencies(Archive *fout)
17907 {
17908         PQExpBuffer query;
17909         PGresult   *res;
17910         int                     ntups,
17911                                 i;
17912         int                     i_classid,
17913                                 i_objid,
17914                                 i_refclassid,
17915                                 i_refobjid,
17916                                 i_deptype;
17917         DumpableObject *dobj,
17918                            *refdobj;
17919
17920         if (g_verbose)
17921                 write_msg(NULL, "reading dependency data\n");
17922
17923         query = createPQExpBuffer();
17924
17925         /*
17926          * PIN dependencies aren't interesting, and EXTENSION dependencies were
17927          * already processed by getExtensionMembership.
17928          */
17929         appendPQExpBufferStr(query, "SELECT "
17930                                                  "classid, objid, refclassid, refobjid, deptype "
17931                                                  "FROM pg_depend "
17932                                                  "WHERE deptype != 'p' AND deptype != 'e' "
17933                                                  "ORDER BY 1,2");
17934
17935         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17936
17937         ntups = PQntuples(res);
17938
17939         i_classid = PQfnumber(res, "classid");
17940         i_objid = PQfnumber(res, "objid");
17941         i_refclassid = PQfnumber(res, "refclassid");
17942         i_refobjid = PQfnumber(res, "refobjid");
17943         i_deptype = PQfnumber(res, "deptype");
17944
17945         /*
17946          * Since we ordered the SELECT by referencing ID, we can expect that
17947          * multiple entries for the same object will appear together; this saves
17948          * on searches.
17949          */
17950         dobj = NULL;
17951
17952         for (i = 0; i < ntups; i++)
17953         {
17954                 CatalogId       objId;
17955                 CatalogId       refobjId;
17956                 char            deptype;
17957
17958                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17959                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
17960                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
17961                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
17962                 deptype = *(PQgetvalue(res, i, i_deptype));
17963
17964                 if (dobj == NULL ||
17965                         dobj->catId.tableoid != objId.tableoid ||
17966                         dobj->catId.oid != objId.oid)
17967                         dobj = findObjectByCatalogId(objId);
17968
17969                 /*
17970                  * Failure to find objects mentioned in pg_depend is not unexpected,
17971                  * since for example we don't collect info about TOAST tables.
17972                  */
17973                 if (dobj == NULL)
17974                 {
17975 #ifdef NOT_USED
17976                         fprintf(stderr, "no referencing object %u %u\n",
17977                                         objId.tableoid, objId.oid);
17978 #endif
17979                         continue;
17980                 }
17981
17982                 refdobj = findObjectByCatalogId(refobjId);
17983
17984                 if (refdobj == NULL)
17985                 {
17986 #ifdef NOT_USED
17987                         fprintf(stderr, "no referenced object %u %u\n",
17988                                         refobjId.tableoid, refobjId.oid);
17989 #endif
17990                         continue;
17991                 }
17992
17993                 /*
17994                  * Ordinarily, table rowtypes have implicit dependencies on their
17995                  * tables.  However, for a composite type the implicit dependency goes
17996                  * the other way in pg_depend; which is the right thing for DROP but
17997                  * it doesn't produce the dependency ordering we need. So in that one
17998                  * case, we reverse the direction of the dependency.
17999                  */
18000                 if (deptype == 'i' &&
18001                         dobj->objType == DO_TABLE &&
18002                         refdobj->objType == DO_TYPE)
18003                         addObjectDependency(refdobj, dobj->dumpId);
18004                 else
18005                         /* normal case */
18006                         addObjectDependency(dobj, refdobj->dumpId);
18007         }
18008
18009         PQclear(res);
18010
18011         destroyPQExpBuffer(query);
18012 }
18013
18014
18015 /*
18016  * createBoundaryObjects - create dummy DumpableObjects to represent
18017  * dump section boundaries.
18018  */
18019 static DumpableObject *
18020 createBoundaryObjects(void)
18021 {
18022         DumpableObject *dobjs;
18023
18024         dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
18025
18026         dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
18027         dobjs[0].catId = nilCatalogId;
18028         AssignDumpId(dobjs + 0);
18029         dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
18030
18031         dobjs[1].objType = DO_POST_DATA_BOUNDARY;
18032         dobjs[1].catId = nilCatalogId;
18033         AssignDumpId(dobjs + 1);
18034         dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
18035
18036         return dobjs;
18037 }
18038
18039 /*
18040  * addBoundaryDependencies - add dependencies as needed to enforce the dump
18041  * section boundaries.
18042  */
18043 static void
18044 addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
18045                                                 DumpableObject *boundaryObjs)
18046 {
18047         DumpableObject *preDataBound = boundaryObjs + 0;
18048         DumpableObject *postDataBound = boundaryObjs + 1;
18049         int                     i;
18050
18051         for (i = 0; i < numObjs; i++)
18052         {
18053                 DumpableObject *dobj = dobjs[i];
18054
18055                 /*
18056                  * The classification of object types here must match the SECTION_xxx
18057                  * values assigned during subsequent ArchiveEntry calls!
18058                  */
18059                 switch (dobj->objType)
18060                 {
18061                         case DO_NAMESPACE:
18062                         case DO_EXTENSION:
18063                         case DO_TYPE:
18064                         case DO_SHELL_TYPE:
18065                         case DO_FUNC:
18066                         case DO_AGG:
18067                         case DO_OPERATOR:
18068                         case DO_ACCESS_METHOD:
18069                         case DO_OPCLASS:
18070                         case DO_OPFAMILY:
18071                         case DO_COLLATION:
18072                         case DO_CONVERSION:
18073                         case DO_TABLE:
18074                         case DO_ATTRDEF:
18075                         case DO_PROCLANG:
18076                         case DO_CAST:
18077                         case DO_DUMMY_TYPE:
18078                         case DO_TSPARSER:
18079                         case DO_TSDICT:
18080                         case DO_TSTEMPLATE:
18081                         case DO_TSCONFIG:
18082                         case DO_FDW:
18083                         case DO_FOREIGN_SERVER:
18084                         case DO_TRANSFORM:
18085                         case DO_BLOB:
18086                                 /* Pre-data objects: must come before the pre-data boundary */
18087                                 addObjectDependency(preDataBound, dobj->dumpId);
18088                                 break;
18089                         case DO_TABLE_DATA:
18090                         case DO_SEQUENCE_SET:
18091                         case DO_BLOB_DATA:
18092                                 /* Data objects: must come between the boundaries */
18093                                 addObjectDependency(dobj, preDataBound->dumpId);
18094                                 addObjectDependency(postDataBound, dobj->dumpId);
18095                                 break;
18096                         case DO_INDEX:
18097                         case DO_INDEX_ATTACH:
18098                         case DO_STATSEXT:
18099                         case DO_REFRESH_MATVIEW:
18100                         case DO_TRIGGER:
18101                         case DO_EVENT_TRIGGER:
18102                         case DO_DEFAULT_ACL:
18103                         case DO_POLICY:
18104                         case DO_PUBLICATION:
18105                         case DO_PUBLICATION_REL:
18106                         case DO_SUBSCRIPTION:
18107                                 /* Post-data objects: must come after the post-data boundary */
18108                                 addObjectDependency(dobj, postDataBound->dumpId);
18109                                 break;
18110                         case DO_RULE:
18111                                 /* Rules are post-data, but only if dumped separately */
18112                                 if (((RuleInfo *) dobj)->separate)
18113                                         addObjectDependency(dobj, postDataBound->dumpId);
18114                                 break;
18115                         case DO_CONSTRAINT:
18116                         case DO_FK_CONSTRAINT:
18117                                 /* Constraints are post-data, but only if dumped separately */
18118                                 if (((ConstraintInfo *) dobj)->separate)
18119                                         addObjectDependency(dobj, postDataBound->dumpId);
18120                                 break;
18121                         case DO_PRE_DATA_BOUNDARY:
18122                                 /* nothing to do */
18123                                 break;
18124                         case DO_POST_DATA_BOUNDARY:
18125                                 /* must come after the pre-data boundary */
18126                                 addObjectDependency(dobj, preDataBound->dumpId);
18127                                 break;
18128                 }
18129         }
18130 }
18131
18132
18133 /*
18134  * BuildArchiveDependencies - create dependency data for archive TOC entries
18135  *
18136  * The raw dependency data obtained by getDependencies() is not terribly
18137  * useful in an archive dump, because in many cases there are dependency
18138  * chains linking through objects that don't appear explicitly in the dump.
18139  * For example, a view will depend on its _RETURN rule while the _RETURN rule
18140  * will depend on other objects --- but the rule will not appear as a separate
18141  * object in the dump.  We need to adjust the view's dependencies to include
18142  * whatever the rule depends on that is included in the dump.
18143  *
18144  * Just to make things more complicated, there are also "special" dependencies
18145  * such as the dependency of a TABLE DATA item on its TABLE, which we must
18146  * not rearrange because pg_restore knows that TABLE DATA only depends on
18147  * its table.  In these cases we must leave the dependencies strictly as-is
18148  * even if they refer to not-to-be-dumped objects.
18149  *
18150  * To handle this, the convention is that "special" dependencies are created
18151  * during ArchiveEntry calls, and an archive TOC item that has any such
18152  * entries will not be touched here.  Otherwise, we recursively search the
18153  * DumpableObject data structures to build the correct dependencies for each
18154  * archive TOC item.
18155  */
18156 static void
18157 BuildArchiveDependencies(Archive *fout)
18158 {
18159         ArchiveHandle *AH = (ArchiveHandle *) fout;
18160         TocEntry   *te;
18161
18162         /* Scan all TOC entries in the archive */
18163         for (te = AH->toc->next; te != AH->toc; te = te->next)
18164         {
18165                 DumpableObject *dobj;
18166                 DumpId     *dependencies;
18167                 int                     nDeps;
18168                 int                     allocDeps;
18169
18170                 /* No need to process entries that will not be dumped */
18171                 if (te->reqs == 0)
18172                         continue;
18173                 /* Ignore entries that already have "special" dependencies */
18174                 if (te->nDeps > 0)
18175                         continue;
18176                 /* Otherwise, look up the item's original DumpableObject, if any */
18177                 dobj = findObjectByDumpId(te->dumpId);
18178                 if (dobj == NULL)
18179                         continue;
18180                 /* No work if it has no dependencies */
18181                 if (dobj->nDeps <= 0)
18182                         continue;
18183                 /* Set up work array */
18184                 allocDeps = 64;
18185                 dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
18186                 nDeps = 0;
18187                 /* Recursively find all dumpable dependencies */
18188                 findDumpableDependencies(AH, dobj,
18189                                                                  &dependencies, &nDeps, &allocDeps);
18190                 /* And save 'em ... */
18191                 if (nDeps > 0)
18192                 {
18193                         dependencies = (DumpId *) pg_realloc(dependencies,
18194                                                                                                  nDeps * sizeof(DumpId));
18195                         te->dependencies = dependencies;
18196                         te->nDeps = nDeps;
18197                 }
18198                 else
18199                         free(dependencies);
18200         }
18201 }
18202
18203 /* Recursive search subroutine for BuildArchiveDependencies */
18204 static void
18205 findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
18206                                                  DumpId **dependencies, int *nDeps, int *allocDeps)
18207 {
18208         int                     i;
18209
18210         /*
18211          * Ignore section boundary objects: if we search through them, we'll
18212          * report lots of bogus dependencies.
18213          */
18214         if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
18215                 dobj->objType == DO_POST_DATA_BOUNDARY)
18216                 return;
18217
18218         for (i = 0; i < dobj->nDeps; i++)
18219         {
18220                 DumpId          depid = dobj->dependencies[i];
18221
18222                 if (TocIDRequired(AH, depid) != 0)
18223                 {
18224                         /* Object will be dumped, so just reference it as a dependency */
18225                         if (*nDeps >= *allocDeps)
18226                         {
18227                                 *allocDeps *= 2;
18228                                 *dependencies = (DumpId *) pg_realloc(*dependencies,
18229                                                                                                           *allocDeps * sizeof(DumpId));
18230                         }
18231                         (*dependencies)[*nDeps] = depid;
18232                         (*nDeps)++;
18233                 }
18234                 else
18235                 {
18236                         /*
18237                          * Object will not be dumped, so recursively consider its deps. We
18238                          * rely on the assumption that sortDumpableObjects already broke
18239                          * any dependency loops, else we might recurse infinitely.
18240                          */
18241                         DumpableObject *otherdobj = findObjectByDumpId(depid);
18242
18243                         if (otherdobj)
18244                                 findDumpableDependencies(AH, otherdobj,
18245                                                                                  dependencies, nDeps, allocDeps);
18246                 }
18247         }
18248 }
18249
18250
18251 /*
18252  * getFormattedTypeName - retrieve a nicely-formatted type name for the
18253  * given type OID.
18254  *
18255  * This does not guarantee to schema-qualify the output, so it should not
18256  * be used to create the target object name for CREATE or ALTER commands.
18257  *
18258  * TODO: there might be some value in caching the results.
18259  */
18260 static char *
18261 getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
18262 {
18263         char       *result;
18264         PQExpBuffer query;
18265         PGresult   *res;
18266
18267         if (oid == 0)
18268         {
18269                 if ((opts & zeroAsOpaque) != 0)
18270                         return pg_strdup(g_opaque_type);
18271                 else if ((opts & zeroAsAny) != 0)
18272                         return pg_strdup("'any'");
18273                 else if ((opts & zeroAsStar) != 0)
18274                         return pg_strdup("*");
18275                 else if ((opts & zeroAsNone) != 0)
18276                         return pg_strdup("NONE");
18277         }
18278
18279         query = createPQExpBuffer();
18280         appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
18281                                           oid);
18282
18283         res = ExecuteSqlQueryForSingleRow(fout, query->data);
18284
18285         /* result of format_type is already quoted */
18286         result = pg_strdup(PQgetvalue(res, 0, 0));
18287
18288         PQclear(res);
18289         destroyPQExpBuffer(query);
18290
18291         return result;
18292 }
18293
18294 /*
18295  * Return a column list clause for the given relation.
18296  *
18297  * Special case: if there are no undropped columns in the relation, return
18298  * "", not an invalid "()" column list.
18299  */
18300 static const char *
18301 fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
18302 {
18303         int                     numatts = ti->numatts;
18304         char      **attnames = ti->attnames;
18305         bool       *attisdropped = ti->attisdropped;
18306         bool            needComma;
18307         int                     i;
18308
18309         appendPQExpBufferChar(buffer, '(');
18310         needComma = false;
18311         for (i = 0; i < numatts; i++)
18312         {
18313                 if (attisdropped[i])
18314                         continue;
18315                 if (needComma)
18316                         appendPQExpBufferStr(buffer, ", ");
18317                 appendPQExpBufferStr(buffer, fmtId(attnames[i]));
18318                 needComma = true;
18319         }
18320
18321         if (!needComma)
18322                 return "";                              /* no undropped columns */
18323
18324         appendPQExpBufferChar(buffer, ')');
18325         return buffer->data;
18326 }
18327
18328 /*
18329  * Check if a reloptions array is nonempty.
18330  */
18331 static bool
18332 nonemptyReloptions(const char *reloptions)
18333 {
18334         /* Don't want to print it if it's just "{}" */
18335         return (reloptions != NULL && strlen(reloptions) > 2);
18336 }
18337
18338 /*
18339  * Format a reloptions array and append it to the given buffer.
18340  *
18341  * "prefix" is prepended to the option names; typically it's "" or "toast.".
18342  */
18343 static void
18344 appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
18345                                                 const char *prefix, Archive *fout)
18346 {
18347         bool            res;
18348
18349         res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
18350                                                                 fout->std_strings);
18351         if (!res)
18352                 write_msg(NULL, "WARNING: could not parse reloptions array\n");
18353 }