]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_dump.c
Generated columns
[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 (tbinfo->attgenerated[field])
2055                                 {
2056                                         archputs("DEFAULT", fout);
2057                                         continue;
2058                                 }
2059                                 if (PQgetisnull(res, tuple, field))
2060                                 {
2061                                         archputs("NULL", fout);
2062                                         continue;
2063                                 }
2064
2065                                 /* XXX This code is partially duplicated in ruleutils.c */
2066                                 switch (PQftype(res, field))
2067                                 {
2068                                         case INT2OID:
2069                                         case INT4OID:
2070                                         case INT8OID:
2071                                         case OIDOID:
2072                                         case FLOAT4OID:
2073                                         case FLOAT8OID:
2074                                         case NUMERICOID:
2075                                                 {
2076                                                         /*
2077                                                          * These types are printed without quotes unless
2078                                                          * they contain values that aren't accepted by the
2079                                                          * scanner unquoted (e.g., 'NaN').  Note that
2080                                                          * strtod() and friends might accept NaN, so we
2081                                                          * can't use that to test.
2082                                                          *
2083                                                          * In reality we only need to defend against
2084                                                          * infinity and NaN, so we need not get too crazy
2085                                                          * about pattern matching here.
2086                                                          */
2087                                                         const char *s = PQgetvalue(res, tuple, field);
2088
2089                                                         if (strspn(s, "0123456789 +-eE.") == strlen(s))
2090                                                                 archputs(s, fout);
2091                                                         else
2092                                                                 archprintf(fout, "'%s'", s);
2093                                                 }
2094                                                 break;
2095
2096                                         case BITOID:
2097                                         case VARBITOID:
2098                                                 archprintf(fout, "B'%s'",
2099                                                                    PQgetvalue(res, tuple, field));
2100                                                 break;
2101
2102                                         case BOOLOID:
2103                                                 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
2104                                                         archputs("true", fout);
2105                                                 else
2106                                                         archputs("false", fout);
2107                                                 break;
2108
2109                                         default:
2110                                                 /* All other types are printed as string literals. */
2111                                                 resetPQExpBuffer(q);
2112                                                 appendStringLiteralAH(q,
2113                                                                                           PQgetvalue(res, tuple, field),
2114                                                                                           fout);
2115                                                 archputs(q->data, fout);
2116                                                 break;
2117                                 }
2118                         }
2119
2120                         /* Terminate the row ... */
2121                         archputs(")", fout);
2122
2123                         /* ... and the statement, if the target no. of rows is reached */
2124                         if (++rows_this_statement >= rows_per_statement)
2125                         {
2126                                 if (dopt->do_nothing)
2127                                         archputs(" ON CONFLICT DO NOTHING;\n", fout);
2128                                 else
2129                                         archputs(";\n", fout);
2130                                 /* Reset the row counter */
2131                                 rows_this_statement = 0;
2132                         }
2133                 }
2134
2135                 if (PQntuples(res) <= 0)
2136                 {
2137                         PQclear(res);
2138                         break;
2139                 }
2140                 PQclear(res);
2141         }
2142
2143         /* Terminate any statements that didn't make the row count. */
2144         if (rows_this_statement > 0)
2145         {
2146                 if (dopt->do_nothing)
2147                         archputs(" ON CONFLICT DO NOTHING;\n", fout);
2148                 else
2149                         archputs(";\n", fout);
2150         }
2151
2152         archputs("\n\n", fout);
2153
2154         ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
2155
2156         destroyPQExpBuffer(q);
2157         if (insertStmt != NULL)
2158                 destroyPQExpBuffer(insertStmt);
2159
2160         return 1;
2161 }
2162
2163 /*
2164  * getRootTableInfo:
2165  *     get the root TableInfo for the given partition table.
2166  */
2167 static TableInfo *
2168 getRootTableInfo(TableInfo *tbinfo)
2169 {
2170         TableInfo  *parentTbinfo;
2171
2172         Assert(tbinfo->ispartition);
2173         Assert(tbinfo->numParents == 1);
2174
2175         parentTbinfo = tbinfo->parents[0];
2176         while (parentTbinfo->ispartition)
2177         {
2178                 Assert(parentTbinfo->numParents == 1);
2179                 parentTbinfo = parentTbinfo->parents[0];
2180         }
2181
2182         return parentTbinfo;
2183 }
2184
2185 /*
2186  * dumpTableData -
2187  *        dump the contents of a single table
2188  *
2189  * Actually, this just makes an ArchiveEntry for the table contents.
2190  */
2191 static void
2192 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
2193 {
2194         DumpOptions *dopt = fout->dopt;
2195         TableInfo  *tbinfo = tdinfo->tdtable;
2196         PQExpBuffer copyBuf = createPQExpBuffer();
2197         PQExpBuffer clistBuf = createPQExpBuffer();
2198         DataDumperPtr dumpFn;
2199         char       *copyStmt;
2200         const char *copyFrom;
2201
2202         if (!dopt->dump_inserts)
2203         {
2204                 /* Dump/restore using COPY */
2205                 dumpFn = dumpTableData_copy;
2206
2207                 /*
2208                  * When load-via-partition-root is set, get the root table name for
2209                  * the partition table, so that we can reload data through the root
2210                  * table.
2211                  */
2212                 if (dopt->load_via_partition_root && tbinfo->ispartition)
2213                 {
2214                         TableInfo  *parentTbinfo;
2215
2216                         parentTbinfo = getRootTableInfo(tbinfo);
2217                         copyFrom = fmtQualifiedDumpable(parentTbinfo);
2218                 }
2219                 else
2220                         copyFrom = fmtQualifiedDumpable(tbinfo);
2221
2222                 /* must use 2 steps here 'cause fmtId is nonreentrant */
2223                 appendPQExpBuffer(copyBuf, "COPY %s ",
2224                                                   copyFrom);
2225                 appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
2226                                                   fmtCopyColumnList(tbinfo, clistBuf));
2227                 copyStmt = copyBuf->data;
2228         }
2229         else
2230         {
2231                 /* Restore using INSERT */
2232                 dumpFn = dumpTableData_insert;
2233                 copyStmt = NULL;
2234         }
2235
2236         /*
2237          * Note: although the TableDataInfo is a full DumpableObject, we treat its
2238          * dependency on its table as "special" and pass it to ArchiveEntry now.
2239          * See comments for BuildArchiveDependencies.
2240          */
2241         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2242         {
2243                 TocEntry   *te;
2244
2245                 te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
2246                                                   ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
2247                                                                            .namespace = tbinfo->dobj.namespace->dobj.name,
2248                                                                            .owner = tbinfo->rolname,
2249                                                                            .description = "TABLE DATA",
2250                                                                            .section = SECTION_DATA,
2251                                                                            .createStmt = "",
2252                                                                            .dropStmt = "",
2253                                                                            .copyStmt = copyStmt,
2254                                                                            .deps = &(tbinfo->dobj.dumpId),
2255                                                                            .nDeps = 1,
2256                                                                            .dumpFn = dumpFn,
2257                                                                            .dumpArg = tdinfo));
2258
2259                 /*
2260                  * Set the TocEntry's dataLength in case we are doing a parallel dump
2261                  * and want to order dump jobs by table size.  We choose to measure
2262                  * dataLength in table pages during dump, so no scaling is needed.
2263                  * However, relpages is declared as "integer" in pg_class, and hence
2264                  * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
2265                  * Cast so that we get the right interpretation of table sizes
2266                  * exceeding INT_MAX pages.
2267                  */
2268                 te->dataLength = (BlockNumber) tbinfo->relpages;
2269         }
2270
2271         destroyPQExpBuffer(copyBuf);
2272         destroyPQExpBuffer(clistBuf);
2273 }
2274
2275 /*
2276  * refreshMatViewData -
2277  *        load or refresh the contents of a single materialized view
2278  *
2279  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
2280  * statement.
2281  */
2282 static void
2283 refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
2284 {
2285         TableInfo  *tbinfo = tdinfo->tdtable;
2286         PQExpBuffer q;
2287
2288         /* If the materialized view is not flagged as populated, skip this. */
2289         if (!tbinfo->relispopulated)
2290                 return;
2291
2292         q = createPQExpBuffer();
2293
2294         appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
2295                                           fmtQualifiedDumpable(tbinfo));
2296
2297         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2298                 ArchiveEntry(fout,
2299                                          tdinfo->dobj.catId,    /* catalog ID */
2300                                          tdinfo->dobj.dumpId,   /* dump ID */
2301                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
2302                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
2303                                                                   .owner = tbinfo->rolname,
2304                                                                   .description = "MATERIALIZED VIEW DATA",
2305                                                                   .section = SECTION_POST_DATA,
2306                                                                   .createStmt = q->data,
2307                                                                   .dropStmt = "",
2308                                                                   .deps = tdinfo->dobj.dependencies,
2309                                                                   .nDeps = tdinfo->dobj.nDeps));
2310
2311         destroyPQExpBuffer(q);
2312 }
2313
2314 /*
2315  * getTableData -
2316  *        set up dumpable objects representing the contents of tables
2317  */
2318 static void
2319 getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
2320 {
2321         int                     i;
2322
2323         for (i = 0; i < numTables; i++)
2324         {
2325                 if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
2326                         (!relkind || tblinfo[i].relkind == relkind))
2327                         makeTableDataInfo(dopt, &(tblinfo[i]));
2328         }
2329 }
2330
2331 /*
2332  * Make a dumpable object for the data of this specific table
2333  *
2334  * Note: we make a TableDataInfo if and only if we are going to dump the
2335  * table data; the "dump" flag in such objects isn't used.
2336  */
2337 static void
2338 makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
2339 {
2340         TableDataInfo *tdinfo;
2341
2342         /*
2343          * Nothing to do if we already decided to dump the table.  This will
2344          * happen for "config" tables.
2345          */
2346         if (tbinfo->dataObj != NULL)
2347                 return;
2348
2349         /* Skip VIEWs (no data to dump) */
2350         if (tbinfo->relkind == RELKIND_VIEW)
2351                 return;
2352         /* Skip FOREIGN TABLEs (no data to dump) */
2353         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2354                 return;
2355         /* Skip partitioned tables (data in partitions) */
2356         if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
2357                 return;
2358
2359         /* Don't dump data in unlogged tables, if so requested */
2360         if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
2361                 dopt->no_unlogged_table_data)
2362                 return;
2363
2364         /* Check that the data is not explicitly excluded */
2365         if (simple_oid_list_member(&tabledata_exclude_oids,
2366                                                            tbinfo->dobj.catId.oid))
2367                 return;
2368
2369         /* OK, let's dump it */
2370         tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
2371
2372         if (tbinfo->relkind == RELKIND_MATVIEW)
2373                 tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
2374         else if (tbinfo->relkind == RELKIND_SEQUENCE)
2375                 tdinfo->dobj.objType = DO_SEQUENCE_SET;
2376         else
2377                 tdinfo->dobj.objType = DO_TABLE_DATA;
2378
2379         /*
2380          * Note: use tableoid 0 so that this object won't be mistaken for
2381          * something that pg_depend entries apply to.
2382          */
2383         tdinfo->dobj.catId.tableoid = 0;
2384         tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
2385         AssignDumpId(&tdinfo->dobj);
2386         tdinfo->dobj.name = tbinfo->dobj.name;
2387         tdinfo->dobj.namespace = tbinfo->dobj.namespace;
2388         tdinfo->tdtable = tbinfo;
2389         tdinfo->filtercond = NULL;      /* might get set later */
2390         addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
2391
2392         tbinfo->dataObj = tdinfo;
2393 }
2394
2395 /*
2396  * The refresh for a materialized view must be dependent on the refresh for
2397  * any materialized view that this one is dependent on.
2398  *
2399  * This must be called after all the objects are created, but before they are
2400  * sorted.
2401  */
2402 static void
2403 buildMatViewRefreshDependencies(Archive *fout)
2404 {
2405         PQExpBuffer query;
2406         PGresult   *res;
2407         int                     ntups,
2408                                 i;
2409         int                     i_classid,
2410                                 i_objid,
2411                                 i_refobjid;
2412
2413         /* No Mat Views before 9.3. */
2414         if (fout->remoteVersion < 90300)
2415                 return;
2416
2417         query = createPQExpBuffer();
2418
2419         appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
2420                                                  "( "
2421                                                  "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
2422                                                  "FROM pg_depend d1 "
2423                                                  "JOIN pg_class c1 ON c1.oid = d1.objid "
2424                                                  "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
2425                                                  " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
2426                                                  "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
2427                                                  "AND d2.objid = r1.oid "
2428                                                  "AND d2.refobjid <> d1.objid "
2429                                                  "JOIN pg_class c2 ON c2.oid = d2.refobjid "
2430                                                  "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2431                                                  CppAsString2(RELKIND_VIEW) ") "
2432                                                  "WHERE d1.classid = 'pg_class'::regclass "
2433                                                  "UNION "
2434                                                  "SELECT w.objid, d3.refobjid, c3.relkind "
2435                                                  "FROM w "
2436                                                  "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
2437                                                  "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
2438                                                  "AND d3.objid = r3.oid "
2439                                                  "AND d3.refobjid <> w.refobjid "
2440                                                  "JOIN pg_class c3 ON c3.oid = d3.refobjid "
2441                                                  "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2442                                                  CppAsString2(RELKIND_VIEW) ") "
2443                                                  ") "
2444                                                  "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
2445                                                  "FROM w "
2446                                                  "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
2447
2448         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2449
2450         ntups = PQntuples(res);
2451
2452         i_classid = PQfnumber(res, "classid");
2453         i_objid = PQfnumber(res, "objid");
2454         i_refobjid = PQfnumber(res, "refobjid");
2455
2456         for (i = 0; i < ntups; i++)
2457         {
2458                 CatalogId       objId;
2459                 CatalogId       refobjId;
2460                 DumpableObject *dobj;
2461                 DumpableObject *refdobj;
2462                 TableInfo  *tbinfo;
2463                 TableInfo  *reftbinfo;
2464
2465                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
2466                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
2467                 refobjId.tableoid = objId.tableoid;
2468                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
2469
2470                 dobj = findObjectByCatalogId(objId);
2471                 if (dobj == NULL)
2472                         continue;
2473
2474                 Assert(dobj->objType == DO_TABLE);
2475                 tbinfo = (TableInfo *) dobj;
2476                 Assert(tbinfo->relkind == RELKIND_MATVIEW);
2477                 dobj = (DumpableObject *) tbinfo->dataObj;
2478                 if (dobj == NULL)
2479                         continue;
2480                 Assert(dobj->objType == DO_REFRESH_MATVIEW);
2481
2482                 refdobj = findObjectByCatalogId(refobjId);
2483                 if (refdobj == NULL)
2484                         continue;
2485
2486                 Assert(refdobj->objType == DO_TABLE);
2487                 reftbinfo = (TableInfo *) refdobj;
2488                 Assert(reftbinfo->relkind == RELKIND_MATVIEW);
2489                 refdobj = (DumpableObject *) reftbinfo->dataObj;
2490                 if (refdobj == NULL)
2491                         continue;
2492                 Assert(refdobj->objType == DO_REFRESH_MATVIEW);
2493
2494                 addObjectDependency(dobj, refdobj->dumpId);
2495
2496                 if (!reftbinfo->relispopulated)
2497                         tbinfo->relispopulated = false;
2498         }
2499
2500         PQclear(res);
2501
2502         destroyPQExpBuffer(query);
2503 }
2504
2505 /*
2506  * getTableDataFKConstraints -
2507  *        add dump-order dependencies reflecting foreign key constraints
2508  *
2509  * This code is executed only in a data-only dump --- in schema+data dumps
2510  * we handle foreign key issues by not creating the FK constraints until
2511  * after the data is loaded.  In a data-only dump, however, we want to
2512  * order the table data objects in such a way that a table's referenced
2513  * tables are restored first.  (In the presence of circular references or
2514  * self-references this may be impossible; we'll detect and complain about
2515  * that during the dependency sorting step.)
2516  */
2517 static void
2518 getTableDataFKConstraints(void)
2519 {
2520         DumpableObject **dobjs;
2521         int                     numObjs;
2522         int                     i;
2523
2524         /* Search through all the dumpable objects for FK constraints */
2525         getDumpableObjects(&dobjs, &numObjs);
2526         for (i = 0; i < numObjs; i++)
2527         {
2528                 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
2529                 {
2530                         ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
2531                         TableInfo  *ftable;
2532
2533                         /* Not interesting unless both tables are to be dumped */
2534                         if (cinfo->contable == NULL ||
2535                                 cinfo->contable->dataObj == NULL)
2536                                 continue;
2537                         ftable = findTableByOid(cinfo->confrelid);
2538                         if (ftable == NULL ||
2539                                 ftable->dataObj == NULL)
2540                                 continue;
2541
2542                         /*
2543                          * Okay, make referencing table's TABLE_DATA object depend on the
2544                          * referenced table's TABLE_DATA object.
2545                          */
2546                         addObjectDependency(&cinfo->contable->dataObj->dobj,
2547                                                                 ftable->dataObj->dobj.dumpId);
2548                 }
2549         }
2550         free(dobjs);
2551 }
2552
2553
2554 /*
2555  * guessConstraintInheritance:
2556  *      In pre-8.4 databases, we can't tell for certain which constraints
2557  *      are inherited.  We assume a CHECK constraint is inherited if its name
2558  *      matches the name of any constraint in the parent.  Originally this code
2559  *      tried to compare the expression texts, but that can fail for various
2560  *      reasons --- for example, if the parent and child tables are in different
2561  *      schemas, reverse-listing of function calls may produce different text
2562  *      (schema-qualified or not) depending on search path.
2563  *
2564  *      In 8.4 and up we can rely on the conislocal field to decide which
2565  *      constraints must be dumped; much safer.
2566  *
2567  *      This function assumes all conislocal flags were initialized to true.
2568  *      It clears the flag on anything that seems to be inherited.
2569  */
2570 static void
2571 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
2572 {
2573         int                     i,
2574                                 j,
2575                                 k;
2576
2577         for (i = 0; i < numTables; i++)
2578         {
2579                 TableInfo  *tbinfo = &(tblinfo[i]);
2580                 int                     numParents;
2581                 TableInfo **parents;
2582                 TableInfo  *parent;
2583
2584                 /* Sequences and views never have parents */
2585                 if (tbinfo->relkind == RELKIND_SEQUENCE ||
2586                         tbinfo->relkind == RELKIND_VIEW)
2587                         continue;
2588
2589                 /* Don't bother computing anything for non-target tables, either */
2590                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
2591                         continue;
2592
2593                 numParents = tbinfo->numParents;
2594                 parents = tbinfo->parents;
2595
2596                 if (numParents == 0)
2597                         continue;                       /* nothing to see here, move along */
2598
2599                 /* scan for inherited CHECK constraints */
2600                 for (j = 0; j < tbinfo->ncheck; j++)
2601                 {
2602                         ConstraintInfo *constr;
2603
2604                         constr = &(tbinfo->checkexprs[j]);
2605
2606                         for (k = 0; k < numParents; k++)
2607                         {
2608                                 int                     l;
2609
2610                                 parent = parents[k];
2611                                 for (l = 0; l < parent->ncheck; l++)
2612                                 {
2613                                         ConstraintInfo *pconstr = &(parent->checkexprs[l]);
2614
2615                                         if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
2616                                         {
2617                                                 constr->conislocal = false;
2618                                                 break;
2619                                         }
2620                                 }
2621                                 if (!constr->conislocal)
2622                                         break;
2623                         }
2624                 }
2625         }
2626 }
2627
2628
2629 /*
2630  * dumpDatabase:
2631  *      dump the database definition
2632  */
2633 static void
2634 dumpDatabase(Archive *fout)
2635 {
2636         DumpOptions *dopt = fout->dopt;
2637         PQExpBuffer dbQry = createPQExpBuffer();
2638         PQExpBuffer delQry = createPQExpBuffer();
2639         PQExpBuffer creaQry = createPQExpBuffer();
2640         PQExpBuffer labelq = createPQExpBuffer();
2641         PGconn     *conn = GetConnection(fout);
2642         PGresult   *res;
2643         int                     i_tableoid,
2644                                 i_oid,
2645                                 i_datname,
2646                                 i_dba,
2647                                 i_encoding,
2648                                 i_collate,
2649                                 i_ctype,
2650                                 i_frozenxid,
2651                                 i_minmxid,
2652                                 i_datacl,
2653                                 i_rdatacl,
2654                                 i_datistemplate,
2655                                 i_datconnlimit,
2656                                 i_tablespace;
2657         CatalogId       dbCatId;
2658         DumpId          dbDumpId;
2659         const char *datname,
2660                            *dba,
2661                            *encoding,
2662                            *collate,
2663                            *ctype,
2664                            *datacl,
2665                            *rdatacl,
2666                            *datistemplate,
2667                            *datconnlimit,
2668                            *tablespace;
2669         uint32          frozenxid,
2670                                 minmxid;
2671         char       *qdatname;
2672
2673         if (g_verbose)
2674                 write_msg(NULL, "saving database definition\n");
2675
2676         /* Fetch the database-level properties for this database */
2677         if (fout->remoteVersion >= 90600)
2678         {
2679                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2680                                                   "(%s datdba) AS dba, "
2681                                                   "pg_encoding_to_char(encoding) AS encoding, "
2682                                                   "datcollate, datctype, datfrozenxid, datminmxid, "
2683                                                   "(SELECT array_agg(acl ORDER BY acl::text COLLATE \"C\") FROM ( "
2684                                                   "  SELECT unnest(coalesce(datacl,acldefault('d',datdba))) AS acl "
2685                                                   "  EXCEPT SELECT unnest(acldefault('d',datdba))) as datacls)"
2686                                                   " AS datacl, "
2687                                                   "(SELECT array_agg(acl ORDER BY acl::text COLLATE \"C\") FROM ( "
2688                                                   "  SELECT unnest(acldefault('d',datdba)) AS acl "
2689                                                   "  EXCEPT SELECT unnest(coalesce(datacl,acldefault('d',datdba)))) as rdatacls)"
2690                                                   " AS rdatacl, "
2691                                                   "datistemplate, datconnlimit, "
2692                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2693                                                   "shobj_description(oid, 'pg_database') AS description "
2694
2695                                                   "FROM pg_database "
2696                                                   "WHERE datname = current_database()",
2697                                                   username_subquery);
2698         }
2699         else if (fout->remoteVersion >= 90300)
2700         {
2701                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2702                                                   "(%s datdba) AS dba, "
2703                                                   "pg_encoding_to_char(encoding) AS encoding, "
2704                                                   "datcollate, datctype, datfrozenxid, datminmxid, "
2705                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2706                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2707                                                   "shobj_description(oid, 'pg_database') AS description "
2708
2709                                                   "FROM pg_database "
2710                                                   "WHERE datname = current_database()",
2711                                                   username_subquery);
2712         }
2713         else if (fout->remoteVersion >= 80400)
2714         {
2715                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2716                                                   "(%s datdba) AS dba, "
2717                                                   "pg_encoding_to_char(encoding) AS encoding, "
2718                                                   "datcollate, datctype, datfrozenxid, 0 AS datminmxid, "
2719                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2720                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2721                                                   "shobj_description(oid, 'pg_database') AS description "
2722
2723                                                   "FROM pg_database "
2724                                                   "WHERE datname = current_database()",
2725                                                   username_subquery);
2726         }
2727         else if (fout->remoteVersion >= 80200)
2728         {
2729                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2730                                                   "(%s datdba) AS dba, "
2731                                                   "pg_encoding_to_char(encoding) AS encoding, "
2732                                                   "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2733                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2734                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2735                                                   "shobj_description(oid, 'pg_database') AS description "
2736
2737                                                   "FROM pg_database "
2738                                                   "WHERE datname = current_database()",
2739                                                   username_subquery);
2740         }
2741         else
2742         {
2743                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2744                                                   "(%s datdba) AS dba, "
2745                                                   "pg_encoding_to_char(encoding) AS encoding, "
2746                                                   "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2747                                                   "datacl, '' as rdatacl, datistemplate, "
2748                                                   "-1 as datconnlimit, "
2749                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
2750                                                   "FROM pg_database "
2751                                                   "WHERE datname = current_database()",
2752                                                   username_subquery);
2753         }
2754
2755         res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
2756
2757         i_tableoid = PQfnumber(res, "tableoid");
2758         i_oid = PQfnumber(res, "oid");
2759         i_datname = PQfnumber(res, "datname");
2760         i_dba = PQfnumber(res, "dba");
2761         i_encoding = PQfnumber(res, "encoding");
2762         i_collate = PQfnumber(res, "datcollate");
2763         i_ctype = PQfnumber(res, "datctype");
2764         i_frozenxid = PQfnumber(res, "datfrozenxid");
2765         i_minmxid = PQfnumber(res, "datminmxid");
2766         i_datacl = PQfnumber(res, "datacl");
2767         i_rdatacl = PQfnumber(res, "rdatacl");
2768         i_datistemplate = PQfnumber(res, "datistemplate");
2769         i_datconnlimit = PQfnumber(res, "datconnlimit");
2770         i_tablespace = PQfnumber(res, "tablespace");
2771
2772         dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
2773         dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
2774         datname = PQgetvalue(res, 0, i_datname);
2775         dba = PQgetvalue(res, 0, i_dba);
2776         encoding = PQgetvalue(res, 0, i_encoding);
2777         collate = PQgetvalue(res, 0, i_collate);
2778         ctype = PQgetvalue(res, 0, i_ctype);
2779         frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
2780         minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
2781         datacl = PQgetvalue(res, 0, i_datacl);
2782         rdatacl = PQgetvalue(res, 0, i_rdatacl);
2783         datistemplate = PQgetvalue(res, 0, i_datistemplate);
2784         datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
2785         tablespace = PQgetvalue(res, 0, i_tablespace);
2786
2787         qdatname = pg_strdup(fmtId(datname));
2788
2789         /*
2790          * Prepare the CREATE DATABASE command.  We must specify encoding, locale,
2791          * and tablespace since those can't be altered later.  Other DB properties
2792          * are left to the DATABASE PROPERTIES entry, so that they can be applied
2793          * after reconnecting to the target DB.
2794          */
2795         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
2796                                           qdatname);
2797         if (strlen(encoding) > 0)
2798         {
2799                 appendPQExpBufferStr(creaQry, " ENCODING = ");
2800                 appendStringLiteralAH(creaQry, encoding, fout);
2801         }
2802         if (strlen(collate) > 0)
2803         {
2804                 appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
2805                 appendStringLiteralAH(creaQry, collate, fout);
2806         }
2807         if (strlen(ctype) > 0)
2808         {
2809                 appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
2810                 appendStringLiteralAH(creaQry, ctype, fout);
2811         }
2812
2813         /*
2814          * Note: looking at dopt->outputNoTablespaces here is completely the wrong
2815          * thing; the decision whether to specify a tablespace should be left till
2816          * pg_restore, so that pg_restore --no-tablespaces applies.  Ideally we'd
2817          * label the DATABASE entry with the tablespace and let the normal
2818          * tablespace selection logic work ... but CREATE DATABASE doesn't pay
2819          * attention to default_tablespace, so that won't work.
2820          */
2821         if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
2822                 !dopt->outputNoTablespaces)
2823                 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
2824                                                   fmtId(tablespace));
2825         appendPQExpBufferStr(creaQry, ";\n");
2826
2827         appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
2828                                           qdatname);
2829
2830         dbDumpId = createDumpId();
2831
2832         ArchiveEntry(fout,
2833                                  dbCatId,               /* catalog ID */
2834                                  dbDumpId,              /* dump ID */
2835                                  ARCHIVE_OPTS(.tag = datname,
2836                                                           .owner = dba,
2837                                                           .description = "DATABASE",
2838                                                           .section = SECTION_PRE_DATA,
2839                                                           .createStmt = creaQry->data,
2840                                                           .dropStmt = delQry->data));
2841
2842         /* Compute correct tag for archive entry */
2843         appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
2844
2845         /* Dump DB comment if any */
2846         if (fout->remoteVersion >= 80200)
2847         {
2848                 /*
2849                  * 8.2 and up keep comments on shared objects in a shared table, so we
2850                  * cannot use the dumpComment() code used for other database objects.
2851                  * Be careful that the ArchiveEntry parameters match that function.
2852                  */
2853                 char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
2854
2855                 if (comment && *comment && !dopt->no_comments)
2856                 {
2857                         resetPQExpBuffer(dbQry);
2858
2859                         /*
2860                          * Generates warning when loaded into a differently-named
2861                          * database.
2862                          */
2863                         appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
2864                         appendStringLiteralAH(dbQry, comment, fout);
2865                         appendPQExpBufferStr(dbQry, ";\n");
2866
2867                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2868                                                  ARCHIVE_OPTS(.tag = labelq->data,
2869                                                                           .owner = dba,
2870                                                                           .description = "COMMENT",
2871                                                                           .section = SECTION_NONE,
2872                                                                           .createStmt = dbQry->data,
2873                                                                           .dropStmt = "",
2874                                                                           .deps = &dbDumpId,
2875                                                                           .nDeps = 1));
2876                 }
2877         }
2878         else
2879         {
2880                 dumpComment(fout, "DATABASE", qdatname, NULL, dba,
2881                                         dbCatId, 0, dbDumpId);
2882         }
2883
2884         /* Dump DB security label, if enabled */
2885         if (!dopt->no_security_labels && fout->remoteVersion >= 90200)
2886         {
2887                 PGresult   *shres;
2888                 PQExpBuffer seclabelQry;
2889
2890                 seclabelQry = createPQExpBuffer();
2891
2892                 buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
2893                 shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
2894                 resetPQExpBuffer(seclabelQry);
2895                 emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
2896                 if (seclabelQry->len > 0)
2897                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2898                                                  ARCHIVE_OPTS(.tag = labelq->data,
2899                                                                           .owner = dba,
2900                                                                           .description = "SECURITY LABEL",
2901                                                                           .section = SECTION_NONE,
2902                                                                           .createStmt = seclabelQry->data,
2903                                                                           .dropStmt = "",
2904                                                                           .deps = &dbDumpId,
2905                                                                           .nDeps = 1));
2906                 destroyPQExpBuffer(seclabelQry);
2907                 PQclear(shres);
2908         }
2909
2910         /*
2911          * Dump ACL if any.  Note that we do not support initial privileges
2912          * (pg_init_privs) on databases.
2913          */
2914         dumpACL(fout, dbCatId, dbDumpId, "DATABASE",
2915                         qdatname, NULL, NULL,
2916                         dba, datacl, rdatacl, "", "");
2917
2918         /*
2919          * Now construct a DATABASE PROPERTIES archive entry to restore any
2920          * non-default database-level properties.  (The reason this must be
2921          * separate is that we cannot put any additional commands into the TOC
2922          * entry that has CREATE DATABASE.  pg_restore would execute such a group
2923          * in an implicit transaction block, and the backend won't allow CREATE
2924          * DATABASE in that context.)
2925          */
2926         resetPQExpBuffer(creaQry);
2927         resetPQExpBuffer(delQry);
2928
2929         if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
2930                 appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
2931                                                   qdatname, datconnlimit);
2932
2933         if (strcmp(datistemplate, "t") == 0)
2934         {
2935                 appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
2936                                                   qdatname);
2937
2938                 /*
2939                  * The backend won't accept DROP DATABASE on a template database.  We
2940                  * can deal with that by removing the template marking before the DROP
2941                  * gets issued.  We'd prefer to use ALTER DATABASE IF EXISTS here, but
2942                  * since no such command is currently supported, fake it with a direct
2943                  * UPDATE on pg_database.
2944                  */
2945                 appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
2946                                                          "SET datistemplate = false WHERE datname = ");
2947                 appendStringLiteralAH(delQry, datname, fout);
2948                 appendPQExpBufferStr(delQry, ";\n");
2949         }
2950
2951         /* Add database-specific SET options */
2952         dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
2953
2954         /*
2955          * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
2956          * entry, too, for lack of a better place.
2957          */
2958         if (dopt->binary_upgrade)
2959         {
2960                 appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
2961                 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
2962                                                   "SET datfrozenxid = '%u', datminmxid = '%u'\n"
2963                                                   "WHERE datname = ",
2964                                                   frozenxid, minmxid);
2965                 appendStringLiteralAH(creaQry, datname, fout);
2966                 appendPQExpBufferStr(creaQry, ";\n");
2967         }
2968
2969         if (creaQry->len > 0)
2970                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
2971                                          ARCHIVE_OPTS(.tag = datname,
2972                                                                   .owner = dba,
2973                                                                   .description = "DATABASE PROPERTIES",
2974                                                                   .section = SECTION_PRE_DATA,
2975                                                                   .createStmt = creaQry->data,
2976                                                                   .dropStmt = delQry->data,
2977                                                                   .deps = &dbDumpId));
2978
2979         /*
2980          * pg_largeobject comes from the old system intact, so set its
2981          * relfrozenxids and relminmxids.
2982          */
2983         if (dopt->binary_upgrade)
2984         {
2985                 PGresult   *lo_res;
2986                 PQExpBuffer loFrozenQry = createPQExpBuffer();
2987                 PQExpBuffer loOutQry = createPQExpBuffer();
2988                 int                     i_relfrozenxid,
2989                                         i_relminmxid;
2990
2991                 /*
2992                  * pg_largeobject
2993                  */
2994                 if (fout->remoteVersion >= 90300)
2995                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
2996                                                           "FROM pg_catalog.pg_class\n"
2997                                                           "WHERE oid = %u;\n",
2998                                                           LargeObjectRelationId);
2999                 else
3000                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
3001                                                           "FROM pg_catalog.pg_class\n"
3002                                                           "WHERE oid = %u;\n",
3003                                                           LargeObjectRelationId);
3004
3005                 lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
3006
3007                 i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
3008                 i_relminmxid = PQfnumber(lo_res, "relminmxid");
3009
3010                 appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
3011                 appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
3012                                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
3013                                                   "WHERE oid = %u;\n",
3014                                                   atooid(PQgetvalue(lo_res, 0, i_relfrozenxid)),
3015                                                   atooid(PQgetvalue(lo_res, 0, i_relminmxid)),
3016                                                   LargeObjectRelationId);
3017                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
3018                                          ARCHIVE_OPTS(.tag = "pg_largeobject",
3019                                                                   .description = "pg_largeobject",
3020                                                                   .owner = "",
3021                                                                   .section = SECTION_PRE_DATA,
3022                                                                   .createStmt = loOutQry->data,
3023                                                                   .dropStmt = ""));
3024
3025                 PQclear(lo_res);
3026
3027                 destroyPQExpBuffer(loFrozenQry);
3028                 destroyPQExpBuffer(loOutQry);
3029         }
3030
3031         PQclear(res);
3032
3033         free(qdatname);
3034         destroyPQExpBuffer(dbQry);
3035         destroyPQExpBuffer(delQry);
3036         destroyPQExpBuffer(creaQry);
3037         destroyPQExpBuffer(labelq);
3038 }
3039
3040 /*
3041  * Collect any database-specific or role-and-database-specific SET options
3042  * for this database, and append them to outbuf.
3043  */
3044 static void
3045 dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
3046                                    const char *dbname, Oid dboid)
3047 {
3048         PGconn     *conn = GetConnection(AH);
3049         PQExpBuffer buf = createPQExpBuffer();
3050         PGresult   *res;
3051         int                     count = 1;
3052
3053         /*
3054          * First collect database-specific options.  Pre-8.4 server versions lack
3055          * unnest(), so we do this the hard way by querying once per subscript.
3056          */
3057         for (;;)
3058         {
3059                 if (AH->remoteVersion >= 90000)
3060                         printfPQExpBuffer(buf, "SELECT setconfig[%d] FROM pg_db_role_setting "
3061                                                           "WHERE setrole = 0 AND setdatabase = '%u'::oid",
3062                                                           count, dboid);
3063                 else
3064                         printfPQExpBuffer(buf, "SELECT datconfig[%d] FROM pg_database WHERE oid = '%u'::oid", count, dboid);
3065
3066                 res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3067
3068                 if (PQntuples(res) == 1 &&
3069                         !PQgetisnull(res, 0, 0))
3070                 {
3071                         makeAlterConfigCommand(conn, PQgetvalue(res, 0, 0),
3072                                                                    "DATABASE", dbname, NULL, NULL,
3073                                                                    outbuf);
3074                         PQclear(res);
3075                         count++;
3076                 }
3077                 else
3078                 {
3079                         PQclear(res);
3080                         break;
3081                 }
3082         }
3083
3084         /* Now look for role-and-database-specific options */
3085         if (AH->remoteVersion >= 90000)
3086         {
3087                 /* Here we can assume we have unnest() */
3088                 printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
3089                                                   "FROM pg_db_role_setting s, pg_roles r "
3090                                                   "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
3091                                                   dboid);
3092
3093                 res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3094
3095                 if (PQntuples(res) > 0)
3096                 {
3097                         int                     i;
3098
3099                         for (i = 0; i < PQntuples(res); i++)
3100                                 makeAlterConfigCommand(conn, PQgetvalue(res, i, 1),
3101                                                                            "ROLE", PQgetvalue(res, i, 0),
3102                                                                            "DATABASE", dbname,
3103                                                                            outbuf);
3104                 }
3105
3106                 PQclear(res);
3107         }
3108
3109         destroyPQExpBuffer(buf);
3110 }
3111
3112 /*
3113  * dumpEncoding: put the correct encoding into the archive
3114  */
3115 static void
3116 dumpEncoding(Archive *AH)
3117 {
3118         const char *encname = pg_encoding_to_char(AH->encoding);
3119         PQExpBuffer qry = createPQExpBuffer();
3120
3121         if (g_verbose)
3122                 write_msg(NULL, "saving encoding = %s\n", encname);
3123
3124         appendPQExpBufferStr(qry, "SET client_encoding = ");
3125         appendStringLiteralAH(qry, encname, AH);
3126         appendPQExpBufferStr(qry, ";\n");
3127
3128         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3129                                  ARCHIVE_OPTS(.tag = "ENCODING",
3130                                                           .description = "ENCODING",
3131                                                           .owner = "",
3132                                                           .section = SECTION_PRE_DATA,
3133                                                           .createStmt = qry->data,
3134                                                           .dropStmt = ""));
3135
3136         destroyPQExpBuffer(qry);
3137 }
3138
3139
3140 /*
3141  * dumpStdStrings: put the correct escape string behavior into the archive
3142  */
3143 static void
3144 dumpStdStrings(Archive *AH)
3145 {
3146         const char *stdstrings = AH->std_strings ? "on" : "off";
3147         PQExpBuffer qry = createPQExpBuffer();
3148
3149         if (g_verbose)
3150                 write_msg(NULL, "saving standard_conforming_strings = %s\n",
3151                                   stdstrings);
3152
3153         appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
3154                                           stdstrings);
3155
3156         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3157                                  ARCHIVE_OPTS(.tag = "STDSTRINGS",
3158                                                           .description = "STDSTRINGS",
3159                                                           .owner = "",
3160                                                           .section = SECTION_PRE_DATA,
3161                                                           .createStmt = qry->data,
3162                                                           .dropStmt = ""));
3163
3164         destroyPQExpBuffer(qry);
3165 }
3166
3167 /*
3168  * dumpSearchPath: record the active search_path in the archive
3169  */
3170 static void
3171 dumpSearchPath(Archive *AH)
3172 {
3173         PQExpBuffer qry = createPQExpBuffer();
3174         PQExpBuffer path = createPQExpBuffer();
3175         PGresult   *res;
3176         char      **schemanames = NULL;
3177         int                     nschemanames = 0;
3178         int                     i;
3179
3180         /*
3181          * We use the result of current_schemas(), not the search_path GUC,
3182          * because that might contain wildcards such as "$user", which won't
3183          * necessarily have the same value during restore.  Also, this way avoids
3184          * listing schemas that may appear in search_path but not actually exist,
3185          * which seems like a prudent exclusion.
3186          */
3187         res = ExecuteSqlQueryForSingleRow(AH,
3188                                                                           "SELECT pg_catalog.current_schemas(false)");
3189
3190         if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
3191                 exit_horribly(NULL, "could not parse result of current_schemas()\n");
3192
3193         /*
3194          * We use set_config(), not a simple "SET search_path" command, because
3195          * the latter has less-clean behavior if the search path is empty.  While
3196          * that's likely to get fixed at some point, it seems like a good idea to
3197          * be as backwards-compatible as possible in what we put into archives.
3198          */
3199         for (i = 0; i < nschemanames; i++)
3200         {
3201                 if (i > 0)
3202                         appendPQExpBufferStr(path, ", ");
3203                 appendPQExpBufferStr(path, fmtId(schemanames[i]));
3204         }
3205
3206         appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
3207         appendStringLiteralAH(qry, path->data, AH);
3208         appendPQExpBufferStr(qry, ", false);\n");
3209
3210         if (g_verbose)
3211                 write_msg(NULL, "saving search_path = %s\n", path->data);
3212
3213         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3214                                  ARCHIVE_OPTS(.tag = "SEARCHPATH",
3215                                                           .description = "SEARCHPATH",
3216                                                           .owner = "",
3217                                                           .section = SECTION_PRE_DATA,
3218                                                           .createStmt = qry->data,
3219                                                           .dropStmt = ""));
3220
3221         /* Also save it in AH->searchpath, in case we're doing plain text dump */
3222         AH->searchpath = pg_strdup(qry->data);
3223
3224         if (schemanames)
3225                 free(schemanames);
3226         PQclear(res);
3227         destroyPQExpBuffer(qry);
3228         destroyPQExpBuffer(path);
3229 }
3230
3231
3232 /*
3233  * getBlobs:
3234  *      Collect schema-level data about large objects
3235  */
3236 static void
3237 getBlobs(Archive *fout)
3238 {
3239         DumpOptions *dopt = fout->dopt;
3240         PQExpBuffer blobQry = createPQExpBuffer();
3241         BlobInfo   *binfo;
3242         DumpableObject *bdata;
3243         PGresult   *res;
3244         int                     ntups;
3245         int                     i;
3246         int                     i_oid;
3247         int                     i_lomowner;
3248         int                     i_lomacl;
3249         int                     i_rlomacl;
3250         int                     i_initlomacl;
3251         int                     i_initrlomacl;
3252
3253         /* Verbose message */
3254         if (g_verbose)
3255                 write_msg(NULL, "reading large objects\n");
3256
3257         /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
3258         if (fout->remoteVersion >= 90600)
3259         {
3260                 PQExpBuffer acl_subquery = createPQExpBuffer();
3261                 PQExpBuffer racl_subquery = createPQExpBuffer();
3262                 PQExpBuffer init_acl_subquery = createPQExpBuffer();
3263                 PQExpBuffer init_racl_subquery = createPQExpBuffer();
3264
3265                 buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
3266                                                 init_racl_subquery, "l.lomacl", "l.lomowner", "'L'",
3267                                                 dopt->binary_upgrade);
3268
3269                 appendPQExpBuffer(blobQry,
3270                                                   "SELECT l.oid, (%s l.lomowner) AS rolname, "
3271                                                   "%s AS lomacl, "
3272                                                   "%s AS rlomacl, "
3273                                                   "%s AS initlomacl, "
3274                                                   "%s AS initrlomacl "
3275                                                   "FROM pg_largeobject_metadata l "
3276                                                   "LEFT JOIN pg_init_privs pip ON "
3277                                                   "(l.oid = pip.objoid "
3278                                                   "AND pip.classoid = 'pg_largeobject'::regclass "
3279                                                   "AND pip.objsubid = 0) ",
3280                                                   username_subquery,
3281                                                   acl_subquery->data,
3282                                                   racl_subquery->data,
3283                                                   init_acl_subquery->data,
3284                                                   init_racl_subquery->data);
3285
3286                 destroyPQExpBuffer(acl_subquery);
3287                 destroyPQExpBuffer(racl_subquery);
3288                 destroyPQExpBuffer(init_acl_subquery);
3289                 destroyPQExpBuffer(init_racl_subquery);
3290         }
3291         else if (fout->remoteVersion >= 90000)
3292                 appendPQExpBuffer(blobQry,
3293                                                   "SELECT oid, (%s lomowner) AS rolname, lomacl, "
3294                                                   "NULL AS rlomacl, NULL AS initlomacl, "
3295                                                   "NULL AS initrlomacl "
3296                                                   " FROM pg_largeobject_metadata",
3297                                                   username_subquery);
3298         else
3299                 appendPQExpBufferStr(blobQry,
3300                                                          "SELECT DISTINCT loid AS oid, "
3301                                                          "NULL::name AS rolname, NULL::oid AS lomacl, "
3302                                                          "NULL::oid AS rlomacl, NULL::oid AS initlomacl, "
3303                                                          "NULL::oid AS initrlomacl "
3304                                                          " FROM pg_largeobject");
3305
3306         res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
3307
3308         i_oid = PQfnumber(res, "oid");
3309         i_lomowner = PQfnumber(res, "rolname");
3310         i_lomacl = PQfnumber(res, "lomacl");
3311         i_rlomacl = PQfnumber(res, "rlomacl");
3312         i_initlomacl = PQfnumber(res, "initlomacl");
3313         i_initrlomacl = PQfnumber(res, "initrlomacl");
3314
3315         ntups = PQntuples(res);
3316
3317         /*
3318          * Each large object has its own BLOB archive entry.
3319          */
3320         binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
3321
3322         for (i = 0; i < ntups; i++)
3323         {
3324                 binfo[i].dobj.objType = DO_BLOB;
3325                 binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
3326                 binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3327                 AssignDumpId(&binfo[i].dobj);
3328
3329                 binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oid));
3330                 binfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_lomowner));
3331                 binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, i_lomacl));
3332                 binfo[i].rblobacl = pg_strdup(PQgetvalue(res, i, i_rlomacl));
3333                 binfo[i].initblobacl = pg_strdup(PQgetvalue(res, i, i_initlomacl));
3334                 binfo[i].initrblobacl = pg_strdup(PQgetvalue(res, i, i_initrlomacl));
3335
3336                 if (PQgetisnull(res, i, i_lomacl) &&
3337                         PQgetisnull(res, i, i_rlomacl) &&
3338                         PQgetisnull(res, i, i_initlomacl) &&
3339                         PQgetisnull(res, i, i_initrlomacl))
3340                         binfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
3341
3342                 /*
3343                  * In binary-upgrade mode for blobs, we do *not* dump out the blob
3344                  * data, as it will be copied by pg_upgrade, which simply copies the
3345                  * pg_largeobject table. We *do* however dump out anything but the
3346                  * data, as pg_upgrade copies just pg_largeobject, but not
3347                  * pg_largeobject_metadata, after the dump is restored.
3348                  */
3349                 if (dopt->binary_upgrade)
3350                         binfo[i].dobj.dump &= ~DUMP_COMPONENT_DATA;
3351         }
3352
3353         /*
3354          * If we have any large objects, a "BLOBS" archive entry is needed. This
3355          * is just a placeholder for sorting; it carries no data now.
3356          */
3357         if (ntups > 0)
3358         {
3359                 bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
3360                 bdata->objType = DO_BLOB_DATA;
3361                 bdata->catId = nilCatalogId;
3362                 AssignDumpId(bdata);
3363                 bdata->name = pg_strdup("BLOBS");
3364         }
3365
3366         PQclear(res);
3367         destroyPQExpBuffer(blobQry);
3368 }
3369
3370 /*
3371  * dumpBlob
3372  *
3373  * dump the definition (metadata) of the given large object
3374  */
3375 static void
3376 dumpBlob(Archive *fout, BlobInfo *binfo)
3377 {
3378         PQExpBuffer cquery = createPQExpBuffer();
3379         PQExpBuffer dquery = createPQExpBuffer();
3380
3381         appendPQExpBuffer(cquery,
3382                                           "SELECT pg_catalog.lo_create('%s');\n",
3383                                           binfo->dobj.name);
3384
3385         appendPQExpBuffer(dquery,
3386                                           "SELECT pg_catalog.lo_unlink('%s');\n",
3387                                           binfo->dobj.name);
3388
3389         if (binfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
3390                 ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
3391                                          ARCHIVE_OPTS(.tag = binfo->dobj.name,
3392                                                                   .owner = binfo->rolname,
3393                                                                   .description = "BLOB",
3394                                                                   .section = SECTION_PRE_DATA,
3395                                                                   .createStmt = cquery->data,
3396                                                                   .dropStmt = dquery->data));
3397
3398         /* Dump comment if any */
3399         if (binfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3400                 dumpComment(fout, "LARGE OBJECT", binfo->dobj.name,
3401                                         NULL, binfo->rolname,
3402                                         binfo->dobj.catId, 0, binfo->dobj.dumpId);
3403
3404         /* Dump security label if any */
3405         if (binfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3406                 dumpSecLabel(fout, "LARGE OBJECT", binfo->dobj.name,
3407                                          NULL, binfo->rolname,
3408                                          binfo->dobj.catId, 0, binfo->dobj.dumpId);
3409
3410         /* Dump ACL if any */
3411         if (binfo->blobacl && (binfo->dobj.dump & DUMP_COMPONENT_ACL))
3412                 dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
3413                                 binfo->dobj.name, NULL,
3414                                 NULL, binfo->rolname, binfo->blobacl, binfo->rblobacl,
3415                                 binfo->initblobacl, binfo->initrblobacl);
3416
3417         destroyPQExpBuffer(cquery);
3418         destroyPQExpBuffer(dquery);
3419 }
3420
3421 /*
3422  * dumpBlobs:
3423  *      dump the data contents of all large objects
3424  */
3425 static int
3426 dumpBlobs(Archive *fout, void *arg)
3427 {
3428         const char *blobQry;
3429         const char *blobFetchQry;
3430         PGconn     *conn = GetConnection(fout);
3431         PGresult   *res;
3432         char            buf[LOBBUFSIZE];
3433         int                     ntups;
3434         int                     i;
3435         int                     cnt;
3436
3437         if (g_verbose)
3438                 write_msg(NULL, "saving large objects\n");
3439
3440         /*
3441          * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
3442          * the already-in-memory dumpable objects instead...
3443          */
3444         if (fout->remoteVersion >= 90000)
3445                 blobQry =
3446                         "DECLARE bloboid CURSOR FOR "
3447                         "SELECT oid FROM pg_largeobject_metadata ORDER BY 1";
3448         else
3449                 blobQry =
3450                         "DECLARE bloboid CURSOR FOR "
3451                         "SELECT DISTINCT loid FROM pg_largeobject ORDER BY 1";
3452
3453         ExecuteSqlStatement(fout, blobQry);
3454
3455         /* Command to fetch from cursor */
3456         blobFetchQry = "FETCH 1000 IN bloboid";
3457
3458         do
3459         {
3460                 /* Do a fetch */
3461                 res = ExecuteSqlQuery(fout, blobFetchQry, PGRES_TUPLES_OK);
3462
3463                 /* Process the tuples, if any */
3464                 ntups = PQntuples(res);
3465                 for (i = 0; i < ntups; i++)
3466                 {
3467                         Oid                     blobOid;
3468                         int                     loFd;
3469
3470                         blobOid = atooid(PQgetvalue(res, i, 0));
3471                         /* Open the BLOB */
3472                         loFd = lo_open(conn, blobOid, INV_READ);
3473                         if (loFd == -1)
3474                                 exit_horribly(NULL, "could not open large object %u: %s",
3475                                                           blobOid, PQerrorMessage(conn));
3476
3477                         StartBlob(fout, blobOid);
3478
3479                         /* Now read it in chunks, sending data to archive */
3480                         do
3481                         {
3482                                 cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
3483                                 if (cnt < 0)
3484                                         exit_horribly(NULL, "error reading large object %u: %s",
3485                                                                   blobOid, PQerrorMessage(conn));
3486
3487                                 WriteData(fout, buf, cnt);
3488                         } while (cnt > 0);
3489
3490                         lo_close(conn, loFd);
3491
3492                         EndBlob(fout, blobOid);
3493                 }
3494
3495                 PQclear(res);
3496         } while (ntups > 0);
3497
3498         return 1;
3499 }
3500
3501 /*
3502  * getPolicies
3503  *        get information about policies on a dumpable table.
3504  */
3505 void
3506 getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
3507 {
3508         PQExpBuffer query;
3509         PGresult   *res;
3510         PolicyInfo *polinfo;
3511         int                     i_oid;
3512         int                     i_tableoid;
3513         int                     i_polname;
3514         int                     i_polcmd;
3515         int                     i_polpermissive;
3516         int                     i_polroles;
3517         int                     i_polqual;
3518         int                     i_polwithcheck;
3519         int                     i,
3520                                 j,
3521                                 ntups;
3522
3523         if (fout->remoteVersion < 90500)
3524                 return;
3525
3526         query = createPQExpBuffer();
3527
3528         for (i = 0; i < numTables; i++)
3529         {
3530                 TableInfo  *tbinfo = &tblinfo[i];
3531
3532                 /* Ignore row security on tables not to be dumped */
3533                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
3534                         continue;
3535
3536                 if (g_verbose)
3537                         write_msg(NULL, "reading row security enabled for table \"%s.%s\"\n",
3538                                           tbinfo->dobj.namespace->dobj.name,
3539                                           tbinfo->dobj.name);
3540
3541                 /*
3542                  * Get row security enabled information for the table. We represent
3543                  * RLS being enabled on a table by creating a PolicyInfo object with
3544                  * null polname.
3545                  */
3546                 if (tbinfo->rowsec)
3547                 {
3548                         /*
3549                          * Note: use tableoid 0 so that this object won't be mistaken for
3550                          * something that pg_depend entries apply to.
3551                          */
3552                         polinfo = pg_malloc(sizeof(PolicyInfo));
3553                         polinfo->dobj.objType = DO_POLICY;
3554                         polinfo->dobj.catId.tableoid = 0;
3555                         polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
3556                         AssignDumpId(&polinfo->dobj);
3557                         polinfo->dobj.namespace = tbinfo->dobj.namespace;
3558                         polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
3559                         polinfo->poltable = tbinfo;
3560                         polinfo->polname = NULL;
3561                         polinfo->polcmd = '\0';
3562                         polinfo->polpermissive = 0;
3563                         polinfo->polroles = NULL;
3564                         polinfo->polqual = NULL;
3565                         polinfo->polwithcheck = NULL;
3566                 }
3567
3568                 if (g_verbose)
3569                         write_msg(NULL, "reading policies for table \"%s.%s\"\n",
3570                                           tbinfo->dobj.namespace->dobj.name,
3571                                           tbinfo->dobj.name);
3572
3573                 resetPQExpBuffer(query);
3574
3575                 /* Get the policies for the table. */
3576                 if (fout->remoteVersion >= 100000)
3577                         appendPQExpBuffer(query,
3578                                                           "SELECT oid, tableoid, pol.polname, pol.polcmd, pol.polpermissive, "
3579                                                           "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3580                                                           "   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, "
3581                                                           "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3582                                                           "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3583                                                           "FROM pg_catalog.pg_policy pol "
3584                                                           "WHERE polrelid = '%u'",
3585                                                           tbinfo->dobj.catId.oid);
3586                 else
3587                         appendPQExpBuffer(query,
3588                                                           "SELECT oid, tableoid, pol.polname, pol.polcmd, 't' as polpermissive, "
3589                                                           "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3590                                                           "   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, "
3591                                                           "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3592                                                           "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3593                                                           "FROM pg_catalog.pg_policy pol "
3594                                                           "WHERE polrelid = '%u'",
3595                                                           tbinfo->dobj.catId.oid);
3596                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3597
3598                 ntups = PQntuples(res);
3599
3600                 if (ntups == 0)
3601                 {
3602                         /*
3603                          * No explicit policies to handle (only the default-deny policy,
3604                          * which is handled as part of the table definition).  Clean up
3605                          * and return.
3606                          */
3607                         PQclear(res);
3608                         continue;
3609                 }
3610
3611                 i_oid = PQfnumber(res, "oid");
3612                 i_tableoid = PQfnumber(res, "tableoid");
3613                 i_polname = PQfnumber(res, "polname");
3614                 i_polcmd = PQfnumber(res, "polcmd");
3615                 i_polpermissive = PQfnumber(res, "polpermissive");
3616                 i_polroles = PQfnumber(res, "polroles");
3617                 i_polqual = PQfnumber(res, "polqual");
3618                 i_polwithcheck = PQfnumber(res, "polwithcheck");
3619
3620                 polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
3621
3622                 for (j = 0; j < ntups; j++)
3623                 {
3624                         polinfo[j].dobj.objType = DO_POLICY;
3625                         polinfo[j].dobj.catId.tableoid =
3626                                 atooid(PQgetvalue(res, j, i_tableoid));
3627                         polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3628                         AssignDumpId(&polinfo[j].dobj);
3629                         polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3630                         polinfo[j].poltable = tbinfo;
3631                         polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
3632                         polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
3633
3634                         polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
3635                         polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
3636
3637                         if (PQgetisnull(res, j, i_polroles))
3638                                 polinfo[j].polroles = NULL;
3639                         else
3640                                 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
3641
3642                         if (PQgetisnull(res, j, i_polqual))
3643                                 polinfo[j].polqual = NULL;
3644                         else
3645                                 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
3646
3647                         if (PQgetisnull(res, j, i_polwithcheck))
3648                                 polinfo[j].polwithcheck = NULL;
3649                         else
3650                                 polinfo[j].polwithcheck
3651                                         = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
3652                 }
3653                 PQclear(res);
3654         }
3655         destroyPQExpBuffer(query);
3656 }
3657
3658 /*
3659  * dumpPolicy
3660  *        dump the definition of the given policy
3661  */
3662 static void
3663 dumpPolicy(Archive *fout, PolicyInfo *polinfo)
3664 {
3665         DumpOptions *dopt = fout->dopt;
3666         TableInfo  *tbinfo = polinfo->poltable;
3667         PQExpBuffer query;
3668         PQExpBuffer delqry;
3669         const char *cmd;
3670         char       *tag;
3671
3672         if (dopt->dataOnly)
3673                 return;
3674
3675         /*
3676          * If polname is NULL, then this record is just indicating that ROW LEVEL
3677          * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
3678          * ROW LEVEL SECURITY.
3679          */
3680         if (polinfo->polname == NULL)
3681         {
3682                 query = createPQExpBuffer();
3683
3684                 appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
3685                                                   fmtQualifiedDumpable(tbinfo));
3686
3687                 /*
3688                  * We must emit the ROW SECURITY object's dependency on its table
3689                  * explicitly, because it will not match anything in pg_depend (unlike
3690                  * the case for other PolicyInfo objects).
3691                  */
3692                 if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3693                         ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3694                                                  ARCHIVE_OPTS(.tag = polinfo->dobj.name,
3695                                                                           .namespace = polinfo->dobj.namespace->dobj.name,
3696                                                                           .owner = tbinfo->rolname,
3697                                                                           .description = "ROW SECURITY",
3698                                                                           .section = SECTION_POST_DATA,
3699                                                                           .createStmt = query->data,
3700                                                                           .dropStmt = "",
3701                                                                           .deps = &(tbinfo->dobj.dumpId),
3702                                                                           .nDeps = 1));
3703
3704                 destroyPQExpBuffer(query);
3705                 return;
3706         }
3707
3708         if (polinfo->polcmd == '*')
3709                 cmd = "";
3710         else if (polinfo->polcmd == 'r')
3711                 cmd = " FOR SELECT";
3712         else if (polinfo->polcmd == 'a')
3713                 cmd = " FOR INSERT";
3714         else if (polinfo->polcmd == 'w')
3715                 cmd = " FOR UPDATE";
3716         else if (polinfo->polcmd == 'd')
3717                 cmd = " FOR DELETE";
3718         else
3719         {
3720                 write_msg(NULL, "unexpected policy command type: %c\n",
3721                                   polinfo->polcmd);
3722                 exit_nicely(1);
3723         }
3724
3725         query = createPQExpBuffer();
3726         delqry = createPQExpBuffer();
3727
3728         appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
3729
3730         appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
3731                                           !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
3732
3733         if (polinfo->polroles != NULL)
3734                 appendPQExpBuffer(query, " TO %s", polinfo->polroles);
3735
3736         if (polinfo->polqual != NULL)
3737                 appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
3738
3739         if (polinfo->polwithcheck != NULL)
3740                 appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
3741
3742         appendPQExpBuffer(query, ";\n");
3743
3744         appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
3745         appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
3746
3747         tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
3748
3749         if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3750                 ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3751                                          ARCHIVE_OPTS(.tag = tag,
3752                                                                   .namespace = polinfo->dobj.namespace->dobj.name,
3753                                                                   .owner = tbinfo->rolname,
3754                                                                   .description = "POLICY",
3755                                                                   .section = SECTION_POST_DATA,
3756                                                                   .createStmt = query->data,
3757                                                                   .dropStmt = delqry->data));
3758
3759         free(tag);
3760         destroyPQExpBuffer(query);
3761         destroyPQExpBuffer(delqry);
3762 }
3763
3764 /*
3765  * getPublications
3766  *        get information about publications
3767  */
3768 void
3769 getPublications(Archive *fout)
3770 {
3771         DumpOptions *dopt = fout->dopt;
3772         PQExpBuffer query;
3773         PGresult   *res;
3774         PublicationInfo *pubinfo;
3775         int                     i_tableoid;
3776         int                     i_oid;
3777         int                     i_pubname;
3778         int                     i_rolname;
3779         int                     i_puballtables;
3780         int                     i_pubinsert;
3781         int                     i_pubupdate;
3782         int                     i_pubdelete;
3783         int                     i_pubtruncate;
3784         int                     i,
3785                                 ntups;
3786
3787         if (dopt->no_publications || fout->remoteVersion < 100000)
3788                 return;
3789
3790         query = createPQExpBuffer();
3791
3792         resetPQExpBuffer(query);
3793
3794         /* Get the publications. */
3795         if (fout->remoteVersion >= 110000)
3796                 appendPQExpBuffer(query,
3797                                                   "SELECT p.tableoid, p.oid, p.pubname, "
3798                                                   "(%s p.pubowner) AS rolname, "
3799                                                   "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, p.pubtruncate "
3800                                                   "FROM pg_publication p",
3801                                                   username_subquery);
3802         else
3803                 appendPQExpBuffer(query,
3804                                                   "SELECT p.tableoid, p.oid, p.pubname, "
3805                                                   "(%s p.pubowner) AS rolname, "
3806                                                   "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, false AS pubtruncate "
3807                                                   "FROM pg_publication p",
3808                                                   username_subquery);
3809
3810         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3811
3812         ntups = PQntuples(res);
3813
3814         i_tableoid = PQfnumber(res, "tableoid");
3815         i_oid = PQfnumber(res, "oid");
3816         i_pubname = PQfnumber(res, "pubname");
3817         i_rolname = PQfnumber(res, "rolname");
3818         i_puballtables = PQfnumber(res, "puballtables");
3819         i_pubinsert = PQfnumber(res, "pubinsert");
3820         i_pubupdate = PQfnumber(res, "pubupdate");
3821         i_pubdelete = PQfnumber(res, "pubdelete");
3822         i_pubtruncate = PQfnumber(res, "pubtruncate");
3823
3824         pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
3825
3826         for (i = 0; i < ntups; i++)
3827         {
3828                 pubinfo[i].dobj.objType = DO_PUBLICATION;
3829                 pubinfo[i].dobj.catId.tableoid =
3830                         atooid(PQgetvalue(res, i, i_tableoid));
3831                 pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3832                 AssignDumpId(&pubinfo[i].dobj);
3833                 pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
3834                 pubinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3835                 pubinfo[i].puballtables =
3836                         (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
3837                 pubinfo[i].pubinsert =
3838                         (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
3839                 pubinfo[i].pubupdate =
3840                         (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
3841                 pubinfo[i].pubdelete =
3842                         (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
3843                 pubinfo[i].pubtruncate =
3844                         (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
3845
3846                 if (strlen(pubinfo[i].rolname) == 0)
3847                         write_msg(NULL, "WARNING: owner of publication \"%s\" appears to be invalid\n",
3848                                           pubinfo[i].dobj.name);
3849
3850                 /* Decide whether we want to dump it */
3851                 selectDumpableObject(&(pubinfo[i].dobj), fout);
3852         }
3853         PQclear(res);
3854
3855         destroyPQExpBuffer(query);
3856 }
3857
3858 /*
3859  * dumpPublication
3860  *        dump the definition of the given publication
3861  */
3862 static void
3863 dumpPublication(Archive *fout, PublicationInfo *pubinfo)
3864 {
3865         PQExpBuffer delq;
3866         PQExpBuffer query;
3867         char       *qpubname;
3868         bool            first = true;
3869
3870         if (!(pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3871                 return;
3872
3873         delq = createPQExpBuffer();
3874         query = createPQExpBuffer();
3875
3876         qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
3877
3878         appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
3879                                           qpubname);
3880
3881         appendPQExpBuffer(query, "CREATE PUBLICATION %s",
3882                                           qpubname);
3883
3884         if (pubinfo->puballtables)
3885                 appendPQExpBufferStr(query, " FOR ALL TABLES");
3886
3887         appendPQExpBufferStr(query, " WITH (publish = '");
3888         if (pubinfo->pubinsert)
3889         {
3890                 appendPQExpBufferStr(query, "insert");
3891                 first = false;
3892         }
3893
3894         if (pubinfo->pubupdate)
3895         {
3896                 if (!first)
3897                         appendPQExpBufferStr(query, ", ");
3898
3899                 appendPQExpBufferStr(query, "update");
3900                 first = false;
3901         }
3902
3903         if (pubinfo->pubdelete)
3904         {
3905                 if (!first)
3906                         appendPQExpBufferStr(query, ", ");
3907
3908                 appendPQExpBufferStr(query, "delete");
3909                 first = false;
3910         }
3911
3912         if (pubinfo->pubtruncate)
3913         {
3914                 if (!first)
3915                         appendPQExpBufferStr(query, ", ");
3916
3917                 appendPQExpBufferStr(query, "truncate");
3918                 first = false;
3919         }
3920
3921         appendPQExpBufferStr(query, "');\n");
3922
3923         ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
3924                                  ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
3925                                                           .owner = pubinfo->rolname,
3926                                                           .description = "PUBLICATION",
3927                                                           .section = SECTION_POST_DATA,
3928                                                           .createStmt = query->data,
3929                                                           .dropStmt = delq->data));
3930
3931         if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3932                 dumpComment(fout, "PUBLICATION", qpubname,
3933                                         NULL, pubinfo->rolname,
3934                                         pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
3935
3936         if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3937                 dumpSecLabel(fout, "PUBLICATION", qpubname,
3938                                          NULL, pubinfo->rolname,
3939                                          pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
3940
3941         destroyPQExpBuffer(delq);
3942         destroyPQExpBuffer(query);
3943         free(qpubname);
3944 }
3945
3946 /*
3947  * getPublicationTables
3948  *        get information about publication membership for dumpable tables.
3949  */
3950 void
3951 getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
3952 {
3953         PQExpBuffer query;
3954         PGresult   *res;
3955         PublicationRelInfo *pubrinfo;
3956         DumpOptions *dopt = fout->dopt;
3957         int                     i_tableoid;
3958         int                     i_oid;
3959         int                     i_pubname;
3960         int                     i,
3961                                 j,
3962                                 ntups;
3963
3964         if (dopt->no_publications || fout->remoteVersion < 100000)
3965                 return;
3966
3967         query = createPQExpBuffer();
3968
3969         for (i = 0; i < numTables; i++)
3970         {
3971                 TableInfo  *tbinfo = &tblinfo[i];
3972
3973                 /* Only plain tables can be aded to publications. */
3974                 if (tbinfo->relkind != RELKIND_RELATION)
3975                         continue;
3976
3977                 /*
3978                  * Ignore publication membership of tables whose definitions are not
3979                  * to be dumped.
3980                  */
3981                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3982                         continue;
3983
3984                 if (g_verbose)
3985                         write_msg(NULL, "reading publication membership for table \"%s.%s\"\n",
3986                                           tbinfo->dobj.namespace->dobj.name,
3987                                           tbinfo->dobj.name);
3988
3989                 resetPQExpBuffer(query);
3990
3991                 /* Get the publication membership for the table. */
3992                 appendPQExpBuffer(query,
3993                                                   "SELECT pr.tableoid, pr.oid, p.pubname "
3994                                                   "FROM pg_publication_rel pr, pg_publication p "
3995                                                   "WHERE pr.prrelid = '%u'"
3996                                                   "  AND p.oid = pr.prpubid",
3997                                                   tbinfo->dobj.catId.oid);
3998                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3999
4000                 ntups = PQntuples(res);
4001
4002                 if (ntups == 0)
4003                 {
4004                         /*
4005                          * Table is not member of any publications. Clean up and return.
4006                          */
4007                         PQclear(res);
4008                         continue;
4009                 }
4010
4011                 i_tableoid = PQfnumber(res, "tableoid");
4012                 i_oid = PQfnumber(res, "oid");
4013                 i_pubname = PQfnumber(res, "pubname");
4014
4015                 pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
4016
4017                 for (j = 0; j < ntups; j++)
4018                 {
4019                         pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
4020                         pubrinfo[j].dobj.catId.tableoid =
4021                                 atooid(PQgetvalue(res, j, i_tableoid));
4022                         pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
4023                         AssignDumpId(&pubrinfo[j].dobj);
4024                         pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4025                         pubrinfo[j].dobj.name = tbinfo->dobj.name;
4026                         pubrinfo[j].pubname = pg_strdup(PQgetvalue(res, j, i_pubname));
4027                         pubrinfo[j].pubtable = tbinfo;
4028
4029                         /* Decide whether we want to dump it */
4030                         selectDumpablePublicationTable(&(pubrinfo[j].dobj), fout);
4031                 }
4032                 PQclear(res);
4033         }
4034         destroyPQExpBuffer(query);
4035 }
4036
4037 /*
4038  * dumpPublicationTable
4039  *        dump the definition of the given publication table mapping
4040  */
4041 static void
4042 dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo)
4043 {
4044         TableInfo  *tbinfo = pubrinfo->pubtable;
4045         PQExpBuffer query;
4046         char       *tag;
4047
4048         if (!(pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
4049                 return;
4050
4051         tag = psprintf("%s %s", pubrinfo->pubname, tbinfo->dobj.name);
4052
4053         query = createPQExpBuffer();
4054
4055         appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
4056                                           fmtId(pubrinfo->pubname));
4057         appendPQExpBuffer(query, " %s;\n",
4058                                           fmtQualifiedDumpable(tbinfo));
4059
4060         /*
4061          * There is no point in creating drop query as drop query as the drop is
4062          * done by table drop.
4063          */
4064         ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
4065                                  ARCHIVE_OPTS(.tag = tag,
4066                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
4067                                                           .description = "PUBLICATION TABLE",
4068                                                           .owner = "",
4069                                                           .section = SECTION_POST_DATA,
4070                                                           .createStmt = query->data,
4071                                                           .dropStmt = ""));
4072
4073         free(tag);
4074         destroyPQExpBuffer(query);
4075 }
4076
4077 /*
4078  * Is the currently connected user a superuser?
4079  */
4080 static bool
4081 is_superuser(Archive *fout)
4082 {
4083         ArchiveHandle *AH = (ArchiveHandle *) fout;
4084         const char *val;
4085
4086         val = PQparameterStatus(AH->connection, "is_superuser");
4087
4088         if (val && strcmp(val, "on") == 0)
4089                 return true;
4090
4091         return false;
4092 }
4093
4094 /*
4095  * getSubscriptions
4096  *        get information about subscriptions
4097  */
4098 void
4099 getSubscriptions(Archive *fout)
4100 {
4101         DumpOptions *dopt = fout->dopt;
4102         PQExpBuffer query;
4103         PGresult   *res;
4104         SubscriptionInfo *subinfo;
4105         int                     i_tableoid;
4106         int                     i_oid;
4107         int                     i_subname;
4108         int                     i_rolname;
4109         int                     i_subconninfo;
4110         int                     i_subslotname;
4111         int                     i_subsynccommit;
4112         int                     i_subpublications;
4113         int                     i,
4114                                 ntups;
4115
4116         if (dopt->no_subscriptions || fout->remoteVersion < 100000)
4117                 return;
4118
4119         if (!is_superuser(fout))
4120         {
4121                 int                     n;
4122
4123                 res = ExecuteSqlQuery(fout,
4124                                                           "SELECT count(*) FROM pg_subscription "
4125                                                           "WHERE subdbid = (SELECT oid FROM pg_database"
4126                                                           "                 WHERE datname = current_database())",
4127                                                           PGRES_TUPLES_OK);
4128                 n = atoi(PQgetvalue(res, 0, 0));
4129                 if (n > 0)
4130                         write_msg(NULL, "WARNING: subscriptions not dumped because current user is not a superuser\n");
4131                 PQclear(res);
4132                 return;
4133         }
4134
4135         query = createPQExpBuffer();
4136
4137         resetPQExpBuffer(query);
4138
4139         /* Get the subscriptions in current database. */
4140         appendPQExpBuffer(query,
4141                                           "SELECT s.tableoid, s.oid, s.subname,"
4142                                           "(%s s.subowner) AS rolname, "
4143                                           " s.subconninfo, s.subslotname, s.subsynccommit, "
4144                                           " s.subpublications "
4145                                           "FROM pg_subscription s "
4146                                           "WHERE s.subdbid = (SELECT oid FROM pg_database"
4147                                           "                   WHERE datname = current_database())",
4148                                           username_subquery);
4149         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4150
4151         ntups = PQntuples(res);
4152
4153         i_tableoid = PQfnumber(res, "tableoid");
4154         i_oid = PQfnumber(res, "oid");
4155         i_subname = PQfnumber(res, "subname");
4156         i_rolname = PQfnumber(res, "rolname");
4157         i_subconninfo = PQfnumber(res, "subconninfo");
4158         i_subslotname = PQfnumber(res, "subslotname");
4159         i_subsynccommit = PQfnumber(res, "subsynccommit");
4160         i_subpublications = PQfnumber(res, "subpublications");
4161
4162         subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
4163
4164         for (i = 0; i < ntups; i++)
4165         {
4166                 subinfo[i].dobj.objType = DO_SUBSCRIPTION;
4167                 subinfo[i].dobj.catId.tableoid =
4168                         atooid(PQgetvalue(res, i, i_tableoid));
4169                 subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4170                 AssignDumpId(&subinfo[i].dobj);
4171                 subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
4172                 subinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4173                 subinfo[i].subconninfo = pg_strdup(PQgetvalue(res, i, i_subconninfo));
4174                 if (PQgetisnull(res, i, i_subslotname))
4175                         subinfo[i].subslotname = NULL;
4176                 else
4177                         subinfo[i].subslotname = pg_strdup(PQgetvalue(res, i, i_subslotname));
4178                 subinfo[i].subsynccommit =
4179                         pg_strdup(PQgetvalue(res, i, i_subsynccommit));
4180                 subinfo[i].subpublications =
4181                         pg_strdup(PQgetvalue(res, i, i_subpublications));
4182
4183                 if (strlen(subinfo[i].rolname) == 0)
4184                         write_msg(NULL, "WARNING: owner of subscription \"%s\" appears to be invalid\n",
4185                                           subinfo[i].dobj.name);
4186
4187                 /* Decide whether we want to dump it */
4188                 selectDumpableObject(&(subinfo[i].dobj), fout);
4189         }
4190         PQclear(res);
4191
4192         destroyPQExpBuffer(query);
4193 }
4194
4195 /*
4196  * dumpSubscription
4197  *        dump the definition of the given subscription
4198  */
4199 static void
4200 dumpSubscription(Archive *fout, SubscriptionInfo *subinfo)
4201 {
4202         PQExpBuffer delq;
4203         PQExpBuffer query;
4204         PQExpBuffer publications;
4205         char       *qsubname;
4206         char      **pubnames = NULL;
4207         int                     npubnames = 0;
4208         int                     i;
4209
4210         if (!(subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
4211                 return;
4212
4213         delq = createPQExpBuffer();
4214         query = createPQExpBuffer();
4215
4216         qsubname = pg_strdup(fmtId(subinfo->dobj.name));
4217
4218         appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
4219                                           qsubname);
4220
4221         appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
4222                                           qsubname);
4223         appendStringLiteralAH(query, subinfo->subconninfo, fout);
4224
4225         /* Build list of quoted publications and append them to query. */
4226         if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
4227         {
4228                 write_msg(NULL,
4229                                   "WARNING: could not parse subpublications array\n");
4230                 if (pubnames)
4231                         free(pubnames);
4232                 pubnames = NULL;
4233                 npubnames = 0;
4234         }
4235
4236         publications = createPQExpBuffer();
4237         for (i = 0; i < npubnames; i++)
4238         {
4239                 if (i > 0)
4240                         appendPQExpBufferStr(publications, ", ");
4241
4242                 appendPQExpBufferStr(publications, fmtId(pubnames[i]));
4243         }
4244
4245         appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
4246         if (subinfo->subslotname)
4247                 appendStringLiteralAH(query, subinfo->subslotname, fout);
4248         else
4249                 appendPQExpBufferStr(query, "NONE");
4250
4251         if (strcmp(subinfo->subsynccommit, "off") != 0)
4252                 appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
4253
4254         appendPQExpBufferStr(query, ");\n");
4255
4256         ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
4257                                  ARCHIVE_OPTS(.tag = subinfo->dobj.name,
4258                                                           .owner = subinfo->rolname,
4259                                                           .description = "SUBSCRIPTION",
4260                                                           .section = SECTION_POST_DATA,
4261                                                           .createStmt = query->data,
4262                                                           .dropStmt = delq->data));
4263
4264         if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4265                 dumpComment(fout, "SUBSCRIPTION", qsubname,
4266                                         NULL, subinfo->rolname,
4267                                         subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
4268
4269         if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
4270                 dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
4271                                          NULL, subinfo->rolname,
4272                                          subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
4273
4274         destroyPQExpBuffer(publications);
4275         if (pubnames)
4276                 free(pubnames);
4277
4278         destroyPQExpBuffer(delq);
4279         destroyPQExpBuffer(query);
4280         free(qsubname);
4281 }
4282
4283 static void
4284 binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
4285                                                                                  PQExpBuffer upgrade_buffer,
4286                                                                                  Oid pg_type_oid,
4287                                                                                  bool force_array_type)
4288 {
4289         PQExpBuffer upgrade_query = createPQExpBuffer();
4290         PGresult   *res;
4291         Oid                     pg_type_array_oid;
4292
4293         appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
4294         appendPQExpBuffer(upgrade_buffer,
4295                                           "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4296                                           pg_type_oid);
4297
4298         /* we only support old >= 8.3 for binary upgrades */
4299         appendPQExpBuffer(upgrade_query,
4300                                           "SELECT typarray "
4301                                           "FROM pg_catalog.pg_type "
4302                                           "WHERE oid = '%u'::pg_catalog.oid;",
4303                                           pg_type_oid);
4304
4305         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4306
4307         pg_type_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
4308
4309         PQclear(res);
4310
4311         if (!OidIsValid(pg_type_array_oid) && force_array_type)
4312         {
4313                 /*
4314                  * If the old version didn't assign an array type, but the new version
4315                  * does, we must select an unused type OID to assign.  This currently
4316                  * only happens for domains, when upgrading pre-v11 to v11 and up.
4317                  *
4318                  * Note: local state here is kind of ugly, but we must have some,
4319                  * since we mustn't choose the same unused OID more than once.
4320                  */
4321                 static Oid      next_possible_free_oid = FirstNormalObjectId;
4322                 bool            is_dup;
4323
4324                 do
4325                 {
4326                         ++next_possible_free_oid;
4327                         printfPQExpBuffer(upgrade_query,
4328                                                           "SELECT EXISTS(SELECT 1 "
4329                                                           "FROM pg_catalog.pg_type "
4330                                                           "WHERE oid = '%u'::pg_catalog.oid);",
4331                                                           next_possible_free_oid);
4332                         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4333                         is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
4334                         PQclear(res);
4335                 } while (is_dup);
4336
4337                 pg_type_array_oid = next_possible_free_oid;
4338         }
4339
4340         if (OidIsValid(pg_type_array_oid))
4341         {
4342                 appendPQExpBufferStr(upgrade_buffer,
4343                                                          "\n-- For binary upgrade, must preserve pg_type array oid\n");
4344                 appendPQExpBuffer(upgrade_buffer,
4345                                                   "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4346                                                   pg_type_array_oid);
4347         }
4348
4349         destroyPQExpBuffer(upgrade_query);
4350 }
4351
4352 static bool
4353 binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
4354                                                                                 PQExpBuffer upgrade_buffer,
4355                                                                                 Oid pg_rel_oid)
4356 {
4357         PQExpBuffer upgrade_query = createPQExpBuffer();
4358         PGresult   *upgrade_res;
4359         Oid                     pg_type_oid;
4360         bool            toast_set = false;
4361
4362         /*
4363          * We only support old >= 8.3 for binary upgrades.
4364          *
4365          * We purposefully ignore toast OIDs for partitioned tables; the reason is
4366          * that versions 10 and 11 have them, but 12 does not, so emitting them
4367          * causes the upgrade to fail.
4368          */
4369         appendPQExpBuffer(upgrade_query,
4370                                           "SELECT c.reltype AS crel, t.reltype AS trel "
4371                                           "FROM pg_catalog.pg_class c "
4372                                           "LEFT JOIN pg_catalog.pg_class t ON "
4373                                           "  (c.reltoastrelid = t.oid AND c.relkind <> '%c') "
4374                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
4375                                           RELKIND_PARTITIONED_TABLE, pg_rel_oid);
4376
4377         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4378
4379         pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
4380
4381         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
4382                                                                                          pg_type_oid, false);
4383
4384         if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
4385         {
4386                 /* Toast tables do not have pg_type array rows */
4387                 Oid                     pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
4388                                                                                                                   PQfnumber(upgrade_res, "trel")));
4389
4390                 appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
4391                 appendPQExpBuffer(upgrade_buffer,
4392                                                   "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4393                                                   pg_type_toast_oid);
4394
4395                 toast_set = true;
4396         }
4397
4398         PQclear(upgrade_res);
4399         destroyPQExpBuffer(upgrade_query);
4400
4401         return toast_set;
4402 }
4403
4404 static void
4405 binary_upgrade_set_pg_class_oids(Archive *fout,
4406                                                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid,
4407                                                                  bool is_index)
4408 {
4409         PQExpBuffer upgrade_query = createPQExpBuffer();
4410         PGresult   *upgrade_res;
4411         Oid                     pg_class_reltoastrelid;
4412         Oid                     pg_index_indexrelid;
4413
4414         appendPQExpBuffer(upgrade_query,
4415                                           "SELECT c.reltoastrelid, i.indexrelid "
4416                                           "FROM pg_catalog.pg_class c LEFT JOIN "
4417                                           "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
4418                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
4419                                           pg_class_oid);
4420
4421         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4422
4423         pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
4424         pg_index_indexrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "indexrelid")));
4425
4426         appendPQExpBufferStr(upgrade_buffer,
4427                                                  "\n-- For binary upgrade, must preserve pg_class oids\n");
4428
4429         if (!is_index)
4430         {
4431                 appendPQExpBuffer(upgrade_buffer,
4432                                                   "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
4433                                                   pg_class_oid);
4434                 /* only tables have toast tables, not indexes */
4435                 if (OidIsValid(pg_class_reltoastrelid))
4436                 {
4437                         /*
4438                          * One complexity is that the table definition might not require
4439                          * the creation of a TOAST table, and the TOAST table might have
4440                          * been created long after table creation, when the table was
4441                          * loaded with wide data.  By setting the TOAST oid we force
4442                          * creation of the TOAST heap and TOAST index by the backend so we
4443                          * can cleanly copy the files during binary upgrade.
4444                          */
4445
4446                         appendPQExpBuffer(upgrade_buffer,
4447                                                           "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
4448                                                           pg_class_reltoastrelid);
4449
4450                         /* every toast table has an index */
4451                         appendPQExpBuffer(upgrade_buffer,
4452                                                           "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
4453                                                           pg_index_indexrelid);
4454                 }
4455         }
4456         else
4457                 appendPQExpBuffer(upgrade_buffer,
4458                                                   "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
4459                                                   pg_class_oid);
4460
4461         appendPQExpBufferChar(upgrade_buffer, '\n');
4462
4463         PQclear(upgrade_res);
4464         destroyPQExpBuffer(upgrade_query);
4465 }
4466
4467 /*
4468  * If the DumpableObject is a member of an extension, add a suitable
4469  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
4470  *
4471  * For somewhat historical reasons, objname should already be quoted,
4472  * but not objnamespace (if any).
4473  */
4474 static void
4475 binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
4476                                                                 DumpableObject *dobj,
4477                                                                 const char *objtype,
4478                                                                 const char *objname,
4479                                                                 const char *objnamespace)
4480 {
4481         DumpableObject *extobj = NULL;
4482         int                     i;
4483
4484         if (!dobj->ext_member)
4485                 return;
4486
4487         /*
4488          * Find the parent extension.  We could avoid this search if we wanted to
4489          * add a link field to DumpableObject, but the space costs of that would
4490          * be considerable.  We assume that member objects could only have a
4491          * direct dependency on their own extension, not any others.
4492          */
4493         for (i = 0; i < dobj->nDeps; i++)
4494         {
4495                 extobj = findObjectByDumpId(dobj->dependencies[i]);
4496                 if (extobj && extobj->objType == DO_EXTENSION)
4497                         break;
4498                 extobj = NULL;
4499         }
4500         if (extobj == NULL)
4501                 exit_horribly(NULL, "could not find parent extension for %s %s\n",
4502                                           objtype, objname);
4503
4504         appendPQExpBufferStr(upgrade_buffer,
4505                                                  "\n-- For binary upgrade, handle extension membership the hard way\n");
4506         appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
4507                                           fmtId(extobj->name),
4508                                           objtype);
4509         if (objnamespace && *objnamespace)
4510                 appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
4511         appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
4512 }
4513
4514 /*
4515  * getNamespaces:
4516  *        read all namespaces in the system catalogs and return them in the
4517  * NamespaceInfo* structure
4518  *
4519  *      numNamespaces is set to the number of namespaces read in
4520  */
4521 NamespaceInfo *
4522 getNamespaces(Archive *fout, int *numNamespaces)
4523 {
4524         DumpOptions *dopt = fout->dopt;
4525         PGresult   *res;
4526         int                     ntups;
4527         int                     i;
4528         PQExpBuffer query;
4529         NamespaceInfo *nsinfo;
4530         int                     i_tableoid;
4531         int                     i_oid;
4532         int                     i_nspname;
4533         int                     i_rolname;
4534         int                     i_nspacl;
4535         int                     i_rnspacl;
4536         int                     i_initnspacl;
4537         int                     i_initrnspacl;
4538
4539         query = createPQExpBuffer();
4540
4541         /*
4542          * we fetch all namespaces including system ones, so that every object we
4543          * read in can be linked to a containing namespace.
4544          */
4545         if (fout->remoteVersion >= 90600)
4546         {
4547                 PQExpBuffer acl_subquery = createPQExpBuffer();
4548                 PQExpBuffer racl_subquery = createPQExpBuffer();
4549                 PQExpBuffer init_acl_subquery = createPQExpBuffer();
4550                 PQExpBuffer init_racl_subquery = createPQExpBuffer();
4551
4552                 buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
4553                                                 init_racl_subquery, "n.nspacl", "n.nspowner", "'n'",
4554                                                 dopt->binary_upgrade);
4555
4556                 appendPQExpBuffer(query, "SELECT n.tableoid, n.oid, n.nspname, "
4557                                                   "(%s nspowner) AS rolname, "
4558                                                   "%s as nspacl, "
4559                                                   "%s as rnspacl, "
4560                                                   "%s as initnspacl, "
4561                                                   "%s as initrnspacl "
4562                                                   "FROM pg_namespace n "
4563                                                   "LEFT JOIN pg_init_privs pip "
4564                                                   "ON (n.oid = pip.objoid "
4565                                                   "AND pip.classoid = 'pg_namespace'::regclass "
4566                                                   "AND pip.objsubid = 0",
4567                                                   username_subquery,
4568                                                   acl_subquery->data,
4569                                                   racl_subquery->data,
4570                                                   init_acl_subquery->data,
4571                                                   init_racl_subquery->data);
4572
4573                 appendPQExpBuffer(query, ") ");
4574
4575                 destroyPQExpBuffer(acl_subquery);
4576                 destroyPQExpBuffer(racl_subquery);
4577                 destroyPQExpBuffer(init_acl_subquery);
4578                 destroyPQExpBuffer(init_racl_subquery);
4579         }
4580         else
4581                 appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
4582                                                   "(%s nspowner) AS rolname, "
4583                                                   "nspacl, NULL as rnspacl, "
4584                                                   "NULL AS initnspacl, NULL as initrnspacl "
4585                                                   "FROM pg_namespace",
4586                                                   username_subquery);
4587
4588         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4589
4590         ntups = PQntuples(res);
4591
4592         nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
4593
4594         i_tableoid = PQfnumber(res, "tableoid");
4595         i_oid = PQfnumber(res, "oid");
4596         i_nspname = PQfnumber(res, "nspname");
4597         i_rolname = PQfnumber(res, "rolname");
4598         i_nspacl = PQfnumber(res, "nspacl");
4599         i_rnspacl = PQfnumber(res, "rnspacl");
4600         i_initnspacl = PQfnumber(res, "initnspacl");
4601         i_initrnspacl = PQfnumber(res, "initrnspacl");
4602
4603         for (i = 0; i < ntups; i++)
4604         {
4605                 nsinfo[i].dobj.objType = DO_NAMESPACE;
4606                 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4607                 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4608                 AssignDumpId(&nsinfo[i].dobj);
4609                 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
4610                 nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4611                 nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
4612                 nsinfo[i].rnspacl = pg_strdup(PQgetvalue(res, i, i_rnspacl));
4613                 nsinfo[i].initnspacl = pg_strdup(PQgetvalue(res, i, i_initnspacl));
4614                 nsinfo[i].initrnspacl = pg_strdup(PQgetvalue(res, i, i_initrnspacl));
4615
4616                 /* Decide whether to dump this namespace */
4617                 selectDumpableNamespace(&nsinfo[i], fout);
4618
4619                 /*
4620                  * Do not try to dump ACL if the ACL is empty or the default.
4621                  *
4622                  * This is useful because, for some schemas/objects, the only
4623                  * component we are going to try and dump is the ACL and if we can
4624                  * remove that then 'dump' goes to zero/false and we don't consider
4625                  * this object for dumping at all later on.
4626                  */
4627                 if (PQgetisnull(res, i, i_nspacl) && PQgetisnull(res, i, i_rnspacl) &&
4628                         PQgetisnull(res, i, i_initnspacl) &&
4629                         PQgetisnull(res, i, i_initrnspacl))
4630                         nsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4631
4632                 if (strlen(nsinfo[i].rolname) == 0)
4633                         write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
4634                                           nsinfo[i].dobj.name);
4635         }
4636
4637         PQclear(res);
4638         destroyPQExpBuffer(query);
4639
4640         *numNamespaces = ntups;
4641
4642         return nsinfo;
4643 }
4644
4645 /*
4646  * findNamespace:
4647  *              given a namespace OID, look up the info read by getNamespaces
4648  */
4649 static NamespaceInfo *
4650 findNamespace(Archive *fout, Oid nsoid)
4651 {
4652         NamespaceInfo *nsinfo;
4653
4654         nsinfo = findNamespaceByOid(nsoid);
4655         if (nsinfo == NULL)
4656                 exit_horribly(NULL, "schema with OID %u does not exist\n", nsoid);
4657         return nsinfo;
4658 }
4659
4660 /*
4661  * getExtensions:
4662  *        read all extensions in the system catalogs and return them in the
4663  * ExtensionInfo* structure
4664  *
4665  *      numExtensions is set to the number of extensions read in
4666  */
4667 ExtensionInfo *
4668 getExtensions(Archive *fout, int *numExtensions)
4669 {
4670         DumpOptions *dopt = fout->dopt;
4671         PGresult   *res;
4672         int                     ntups;
4673         int                     i;
4674         PQExpBuffer query;
4675         ExtensionInfo *extinfo;
4676         int                     i_tableoid;
4677         int                     i_oid;
4678         int                     i_extname;
4679         int                     i_nspname;
4680         int                     i_extrelocatable;
4681         int                     i_extversion;
4682         int                     i_extconfig;
4683         int                     i_extcondition;
4684
4685         /*
4686          * Before 9.1, there are no extensions.
4687          */
4688         if (fout->remoteVersion < 90100)
4689         {
4690                 *numExtensions = 0;
4691                 return NULL;
4692         }
4693
4694         query = createPQExpBuffer();
4695
4696         appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
4697                                                  "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
4698                                                  "FROM pg_extension x "
4699                                                  "JOIN pg_namespace n ON n.oid = x.extnamespace");
4700
4701         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4702
4703         ntups = PQntuples(res);
4704
4705         extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
4706
4707         i_tableoid = PQfnumber(res, "tableoid");
4708         i_oid = PQfnumber(res, "oid");
4709         i_extname = PQfnumber(res, "extname");
4710         i_nspname = PQfnumber(res, "nspname");
4711         i_extrelocatable = PQfnumber(res, "extrelocatable");
4712         i_extversion = PQfnumber(res, "extversion");
4713         i_extconfig = PQfnumber(res, "extconfig");
4714         i_extcondition = PQfnumber(res, "extcondition");
4715
4716         for (i = 0; i < ntups; i++)
4717         {
4718                 extinfo[i].dobj.objType = DO_EXTENSION;
4719                 extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4720                 extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4721                 AssignDumpId(&extinfo[i].dobj);
4722                 extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
4723                 extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
4724                 extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
4725                 extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
4726                 extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
4727                 extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
4728
4729                 /* Decide whether we want to dump it */
4730                 selectDumpableExtension(&(extinfo[i]), dopt);
4731         }
4732
4733         PQclear(res);
4734         destroyPQExpBuffer(query);
4735
4736         *numExtensions = ntups;
4737
4738         return extinfo;
4739 }
4740
4741 /*
4742  * getTypes:
4743  *        read all types in the system catalogs and return them in the
4744  * TypeInfo* structure
4745  *
4746  *      numTypes is set to the number of types read in
4747  *
4748  * NB: this must run after getFuncs() because we assume we can do
4749  * findFuncByOid().
4750  */
4751 TypeInfo *
4752 getTypes(Archive *fout, int *numTypes)
4753 {
4754         DumpOptions *dopt = fout->dopt;
4755         PGresult   *res;
4756         int                     ntups;
4757         int                     i;
4758         PQExpBuffer query = createPQExpBuffer();
4759         TypeInfo   *tyinfo;
4760         ShellTypeInfo *stinfo;
4761         int                     i_tableoid;
4762         int                     i_oid;
4763         int                     i_typname;
4764         int                     i_typnamespace;
4765         int                     i_typacl;
4766         int                     i_rtypacl;
4767         int                     i_inittypacl;
4768         int                     i_initrtypacl;
4769         int                     i_rolname;
4770         int                     i_typelem;
4771         int                     i_typrelid;
4772         int                     i_typrelkind;
4773         int                     i_typtype;
4774         int                     i_typisdefined;
4775         int                     i_isarray;
4776
4777         /*
4778          * we include even the built-in types because those may be used as array
4779          * elements by user-defined types
4780          *
4781          * we filter out the built-in types when we dump out the types
4782          *
4783          * same approach for undefined (shell) types and array types
4784          *
4785          * Note: as of 8.3 we can reliably detect whether a type is an
4786          * auto-generated array type by checking the element type's typarray.
4787          * (Before that the test is capable of generating false positives.) We
4788          * still check for name beginning with '_', though, so as to avoid the
4789          * cost of the subselect probe for all standard types.  This would have to
4790          * be revisited if the backend ever allows renaming of array types.
4791          */
4792
4793         if (fout->remoteVersion >= 90600)
4794         {
4795                 PQExpBuffer acl_subquery = createPQExpBuffer();
4796                 PQExpBuffer racl_subquery = createPQExpBuffer();
4797                 PQExpBuffer initacl_subquery = createPQExpBuffer();
4798                 PQExpBuffer initracl_subquery = createPQExpBuffer();
4799
4800                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
4801                                                 initracl_subquery, "t.typacl", "t.typowner", "'T'",
4802                                                 dopt->binary_upgrade);
4803
4804                 appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, t.typname, "
4805                                                   "t.typnamespace, "
4806                                                   "%s AS typacl, "
4807                                                   "%s AS rtypacl, "
4808                                                   "%s AS inittypacl, "
4809                                                   "%s AS initrtypacl, "
4810                                                   "(%s t.typowner) AS rolname, "
4811                                                   "t.typelem, t.typrelid, "
4812                                                   "CASE WHEN t.typrelid = 0 THEN ' '::\"char\" "
4813                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = t.typrelid) END AS typrelkind, "
4814                                                   "t.typtype, t.typisdefined, "
4815                                                   "t.typname[0] = '_' AND t.typelem != 0 AND "
4816                                                   "(SELECT typarray FROM pg_type te WHERE oid = t.typelem) = t.oid AS isarray "
4817                                                   "FROM pg_type t "
4818                                                   "LEFT JOIN pg_init_privs pip ON "
4819                                                   "(t.oid = pip.objoid "
4820                                                   "AND pip.classoid = 'pg_type'::regclass "
4821                                                   "AND pip.objsubid = 0) ",
4822                                                   acl_subquery->data,
4823                                                   racl_subquery->data,
4824                                                   initacl_subquery->data,
4825                                                   initracl_subquery->data,
4826                                                   username_subquery);
4827
4828                 destroyPQExpBuffer(acl_subquery);
4829                 destroyPQExpBuffer(racl_subquery);
4830                 destroyPQExpBuffer(initacl_subquery);
4831                 destroyPQExpBuffer(initracl_subquery);
4832         }
4833         else if (fout->remoteVersion >= 90200)
4834         {
4835                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4836                                                   "typnamespace, typacl, NULL as rtypacl, "
4837                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4838                                                   "(%s typowner) AS rolname, "
4839                                                   "typelem, typrelid, "
4840                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4841                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4842                                                   "typtype, typisdefined, "
4843                                                   "typname[0] = '_' AND typelem != 0 AND "
4844                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4845                                                   "FROM pg_type",
4846                                                   username_subquery);
4847         }
4848         else if (fout->remoteVersion >= 80300)
4849         {
4850                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4851                                                   "typnamespace, NULL AS typacl, NULL as rtypacl, "
4852                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4853                                                   "(%s typowner) AS rolname, "
4854                                                   "typelem, typrelid, "
4855                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4856                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4857                                                   "typtype, typisdefined, "
4858                                                   "typname[0] = '_' AND typelem != 0 AND "
4859                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4860                                                   "FROM pg_type",
4861                                                   username_subquery);
4862         }
4863         else
4864         {
4865                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4866                                                   "typnamespace, NULL AS typacl, NULL as rtypacl, "
4867                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4868                                                   "(%s typowner) AS rolname, "
4869                                                   "typelem, typrelid, "
4870                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4871                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4872                                                   "typtype, typisdefined, "
4873                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
4874                                                   "FROM pg_type",
4875                                                   username_subquery);
4876         }
4877
4878         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4879
4880         ntups = PQntuples(res);
4881
4882         tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
4883
4884         i_tableoid = PQfnumber(res, "tableoid");
4885         i_oid = PQfnumber(res, "oid");
4886         i_typname = PQfnumber(res, "typname");
4887         i_typnamespace = PQfnumber(res, "typnamespace");
4888         i_typacl = PQfnumber(res, "typacl");
4889         i_rtypacl = PQfnumber(res, "rtypacl");
4890         i_inittypacl = PQfnumber(res, "inittypacl");
4891         i_initrtypacl = PQfnumber(res, "initrtypacl");
4892         i_rolname = PQfnumber(res, "rolname");
4893         i_typelem = PQfnumber(res, "typelem");
4894         i_typrelid = PQfnumber(res, "typrelid");
4895         i_typrelkind = PQfnumber(res, "typrelkind");
4896         i_typtype = PQfnumber(res, "typtype");
4897         i_typisdefined = PQfnumber(res, "typisdefined");
4898         i_isarray = PQfnumber(res, "isarray");
4899
4900         for (i = 0; i < ntups; i++)
4901         {
4902                 tyinfo[i].dobj.objType = DO_TYPE;
4903                 tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4904                 tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4905                 AssignDumpId(&tyinfo[i].dobj);
4906                 tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
4907                 tyinfo[i].dobj.namespace =
4908                         findNamespace(fout,
4909                                                   atooid(PQgetvalue(res, i, i_typnamespace)));
4910                 tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4911                 tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
4912                 tyinfo[i].rtypacl = pg_strdup(PQgetvalue(res, i, i_rtypacl));
4913                 tyinfo[i].inittypacl = pg_strdup(PQgetvalue(res, i, i_inittypacl));
4914                 tyinfo[i].initrtypacl = pg_strdup(PQgetvalue(res, i, i_initrtypacl));
4915                 tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
4916                 tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
4917                 tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
4918                 tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
4919                 tyinfo[i].shellType = NULL;
4920
4921                 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
4922                         tyinfo[i].isDefined = true;
4923                 else
4924                         tyinfo[i].isDefined = false;
4925
4926                 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
4927                         tyinfo[i].isArray = true;
4928                 else
4929                         tyinfo[i].isArray = false;
4930
4931                 /* Decide whether we want to dump it */
4932                 selectDumpableType(&tyinfo[i], fout);
4933
4934                 /* Do not try to dump ACL if no ACL exists. */
4935                 if (PQgetisnull(res, i, i_typacl) && PQgetisnull(res, i, i_rtypacl) &&
4936                         PQgetisnull(res, i, i_inittypacl) &&
4937                         PQgetisnull(res, i, i_initrtypacl))
4938                         tyinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4939
4940                 /*
4941                  * If it's a domain, fetch info about its constraints, if any
4942                  */
4943                 tyinfo[i].nDomChecks = 0;
4944                 tyinfo[i].domChecks = NULL;
4945                 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4946                         tyinfo[i].typtype == TYPTYPE_DOMAIN)
4947                         getDomainConstraints(fout, &(tyinfo[i]));
4948
4949                 /*
4950                  * If it's a base type, make a DumpableObject representing a shell
4951                  * definition of the type.  We will need to dump that ahead of the I/O
4952                  * functions for the type.  Similarly, range types need a shell
4953                  * definition in case they have a canonicalize function.
4954                  *
4955                  * Note: the shell type doesn't have a catId.  You might think it
4956                  * should copy the base type's catId, but then it might capture the
4957                  * pg_depend entries for the type, which we don't want.
4958                  */
4959                 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4960                         (tyinfo[i].typtype == TYPTYPE_BASE ||
4961                          tyinfo[i].typtype == TYPTYPE_RANGE))
4962                 {
4963                         stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
4964                         stinfo->dobj.objType = DO_SHELL_TYPE;
4965                         stinfo->dobj.catId = nilCatalogId;
4966                         AssignDumpId(&stinfo->dobj);
4967                         stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
4968                         stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
4969                         stinfo->baseType = &(tyinfo[i]);
4970                         tyinfo[i].shellType = stinfo;
4971
4972                         /*
4973                          * Initially mark the shell type as not to be dumped.  We'll only
4974                          * dump it if the I/O or canonicalize functions need to be dumped;
4975                          * this is taken care of while sorting dependencies.
4976                          */
4977                         stinfo->dobj.dump = DUMP_COMPONENT_NONE;
4978                 }
4979
4980                 if (strlen(tyinfo[i].rolname) == 0)
4981                         write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
4982                                           tyinfo[i].dobj.name);
4983         }
4984
4985         *numTypes = ntups;
4986
4987         PQclear(res);
4988
4989         destroyPQExpBuffer(query);
4990
4991         return tyinfo;
4992 }
4993
4994 /*
4995  * getOperators:
4996  *        read all operators in the system catalogs and return them in the
4997  * OprInfo* structure
4998  *
4999  *      numOprs is set to the number of operators read in
5000  */
5001 OprInfo *
5002 getOperators(Archive *fout, int *numOprs)
5003 {
5004         PGresult   *res;
5005         int                     ntups;
5006         int                     i;
5007         PQExpBuffer query = createPQExpBuffer();
5008         OprInfo    *oprinfo;
5009         int                     i_tableoid;
5010         int                     i_oid;
5011         int                     i_oprname;
5012         int                     i_oprnamespace;
5013         int                     i_rolname;
5014         int                     i_oprkind;
5015         int                     i_oprcode;
5016
5017         /*
5018          * find all operators, including builtin operators; we filter out
5019          * system-defined operators at dump-out time.
5020          */
5021
5022         appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
5023                                           "oprnamespace, "
5024                                           "(%s oprowner) AS rolname, "
5025                                           "oprkind, "
5026                                           "oprcode::oid AS oprcode "
5027                                           "FROM pg_operator",
5028                                           username_subquery);
5029
5030         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5031
5032         ntups = PQntuples(res);
5033         *numOprs = ntups;
5034
5035         oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
5036
5037         i_tableoid = PQfnumber(res, "tableoid");
5038         i_oid = PQfnumber(res, "oid");
5039         i_oprname = PQfnumber(res, "oprname");
5040         i_oprnamespace = PQfnumber(res, "oprnamespace");
5041         i_rolname = PQfnumber(res, "rolname");
5042         i_oprkind = PQfnumber(res, "oprkind");
5043         i_oprcode = PQfnumber(res, "oprcode");
5044
5045         for (i = 0; i < ntups; i++)
5046         {
5047                 oprinfo[i].dobj.objType = DO_OPERATOR;
5048                 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5049                 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5050                 AssignDumpId(&oprinfo[i].dobj);
5051                 oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
5052                 oprinfo[i].dobj.namespace =
5053                         findNamespace(fout,
5054                                                   atooid(PQgetvalue(res, i, i_oprnamespace)));
5055                 oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5056                 oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
5057                 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
5058
5059                 /* Decide whether we want to dump it */
5060                 selectDumpableObject(&(oprinfo[i].dobj), fout);
5061
5062                 /* Operators do not currently have ACLs. */
5063                 oprinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5064
5065                 if (strlen(oprinfo[i].rolname) == 0)
5066                         write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
5067                                           oprinfo[i].dobj.name);
5068         }
5069
5070         PQclear(res);
5071
5072         destroyPQExpBuffer(query);
5073
5074         return oprinfo;
5075 }
5076
5077 /*
5078  * getCollations:
5079  *        read all collations in the system catalogs and return them in the
5080  * CollInfo* structure
5081  *
5082  *      numCollations is set to the number of collations read in
5083  */
5084 CollInfo *
5085 getCollations(Archive *fout, int *numCollations)
5086 {
5087         PGresult   *res;
5088         int                     ntups;
5089         int                     i;
5090         PQExpBuffer query;
5091         CollInfo   *collinfo;
5092         int                     i_tableoid;
5093         int                     i_oid;
5094         int                     i_collname;
5095         int                     i_collnamespace;
5096         int                     i_rolname;
5097
5098         /* Collations didn't exist pre-9.1 */
5099         if (fout->remoteVersion < 90100)
5100         {
5101                 *numCollations = 0;
5102                 return NULL;
5103         }
5104
5105         query = createPQExpBuffer();
5106
5107         /*
5108          * find all collations, including builtin collations; we filter out
5109          * system-defined collations at dump-out time.
5110          */
5111
5112         appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
5113                                           "collnamespace, "
5114                                           "(%s collowner) AS rolname "
5115                                           "FROM pg_collation",
5116                                           username_subquery);
5117
5118         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5119
5120         ntups = PQntuples(res);
5121         *numCollations = ntups;
5122
5123         collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
5124
5125         i_tableoid = PQfnumber(res, "tableoid");
5126         i_oid = PQfnumber(res, "oid");
5127         i_collname = PQfnumber(res, "collname");
5128         i_collnamespace = PQfnumber(res, "collnamespace");
5129         i_rolname = PQfnumber(res, "rolname");
5130
5131         for (i = 0; i < ntups; i++)
5132         {
5133                 collinfo[i].dobj.objType = DO_COLLATION;
5134                 collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5135                 collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5136                 AssignDumpId(&collinfo[i].dobj);
5137                 collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
5138                 collinfo[i].dobj.namespace =
5139                         findNamespace(fout,
5140                                                   atooid(PQgetvalue(res, i, i_collnamespace)));
5141                 collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5142
5143                 /* Decide whether we want to dump it */
5144                 selectDumpableObject(&(collinfo[i].dobj), fout);
5145
5146                 /* Collations do not currently have ACLs. */
5147                 collinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5148         }
5149
5150         PQclear(res);
5151
5152         destroyPQExpBuffer(query);
5153
5154         return collinfo;
5155 }
5156
5157 /*
5158  * getConversions:
5159  *        read all conversions in the system catalogs and return them in the
5160  * ConvInfo* structure
5161  *
5162  *      numConversions is set to the number of conversions read in
5163  */
5164 ConvInfo *
5165 getConversions(Archive *fout, int *numConversions)
5166 {
5167         PGresult   *res;
5168         int                     ntups;
5169         int                     i;
5170         PQExpBuffer query;
5171         ConvInfo   *convinfo;
5172         int                     i_tableoid;
5173         int                     i_oid;
5174         int                     i_conname;
5175         int                     i_connamespace;
5176         int                     i_rolname;
5177
5178         query = createPQExpBuffer();
5179
5180         /*
5181          * find all conversions, including builtin conversions; we filter out
5182          * system-defined conversions at dump-out time.
5183          */
5184
5185         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5186                                           "connamespace, "
5187                                           "(%s conowner) AS rolname "
5188                                           "FROM pg_conversion",
5189                                           username_subquery);
5190
5191         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5192
5193         ntups = PQntuples(res);
5194         *numConversions = ntups;
5195
5196         convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
5197
5198         i_tableoid = PQfnumber(res, "tableoid");
5199         i_oid = PQfnumber(res, "oid");
5200         i_conname = PQfnumber(res, "conname");
5201         i_connamespace = PQfnumber(res, "connamespace");
5202         i_rolname = PQfnumber(res, "rolname");
5203
5204         for (i = 0; i < ntups; i++)
5205         {
5206                 convinfo[i].dobj.objType = DO_CONVERSION;
5207                 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5208                 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5209                 AssignDumpId(&convinfo[i].dobj);
5210                 convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
5211                 convinfo[i].dobj.namespace =
5212                         findNamespace(fout,
5213                                                   atooid(PQgetvalue(res, i, i_connamespace)));
5214                 convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5215
5216                 /* Decide whether we want to dump it */
5217                 selectDumpableObject(&(convinfo[i].dobj), fout);
5218
5219                 /* Conversions do not currently have ACLs. */
5220                 convinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5221         }
5222
5223         PQclear(res);
5224
5225         destroyPQExpBuffer(query);
5226
5227         return convinfo;
5228 }
5229
5230 /*
5231  * getAccessMethods:
5232  *        read all user-defined access methods in the system catalogs and return
5233  *        them in the AccessMethodInfo* structure
5234  *
5235  *      numAccessMethods is set to the number of access methods read in
5236  */
5237 AccessMethodInfo *
5238 getAccessMethods(Archive *fout, int *numAccessMethods)
5239 {
5240         PGresult   *res;
5241         int                     ntups;
5242         int                     i;
5243         PQExpBuffer query;
5244         AccessMethodInfo *aminfo;
5245         int                     i_tableoid;
5246         int                     i_oid;
5247         int                     i_amname;
5248         int                     i_amhandler;
5249         int                     i_amtype;
5250
5251         /* Before 9.6, there are no user-defined access methods */
5252         if (fout->remoteVersion < 90600)
5253         {
5254                 *numAccessMethods = 0;
5255                 return NULL;
5256         }
5257
5258         query = createPQExpBuffer();
5259
5260         /* Select all access methods from pg_am table */
5261         appendPQExpBuffer(query, "SELECT tableoid, oid, amname, amtype, "
5262                                           "amhandler::pg_catalog.regproc AS amhandler "
5263                                           "FROM pg_am");
5264
5265         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5266
5267         ntups = PQntuples(res);
5268         *numAccessMethods = ntups;
5269
5270         aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
5271
5272         i_tableoid = PQfnumber(res, "tableoid");
5273         i_oid = PQfnumber(res, "oid");
5274         i_amname = PQfnumber(res, "amname");
5275         i_amhandler = PQfnumber(res, "amhandler");
5276         i_amtype = PQfnumber(res, "amtype");
5277
5278         for (i = 0; i < ntups; i++)
5279         {
5280                 aminfo[i].dobj.objType = DO_ACCESS_METHOD;
5281                 aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5282                 aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5283                 AssignDumpId(&aminfo[i].dobj);
5284                 aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
5285                 aminfo[i].dobj.namespace = NULL;
5286                 aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
5287                 aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
5288
5289                 /* Decide whether we want to dump it */
5290                 selectDumpableAccessMethod(&(aminfo[i]), fout);
5291
5292                 /* Access methods do not currently have ACLs. */
5293                 aminfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5294         }
5295
5296         PQclear(res);
5297
5298         destroyPQExpBuffer(query);
5299
5300         return aminfo;
5301 }
5302
5303
5304 /*
5305  * getOpclasses:
5306  *        read all opclasses in the system catalogs and return them in the
5307  * OpclassInfo* structure
5308  *
5309  *      numOpclasses is set to the number of opclasses read in
5310  */
5311 OpclassInfo *
5312 getOpclasses(Archive *fout, int *numOpclasses)
5313 {
5314         PGresult   *res;
5315         int                     ntups;
5316         int                     i;
5317         PQExpBuffer query = createPQExpBuffer();
5318         OpclassInfo *opcinfo;
5319         int                     i_tableoid;
5320         int                     i_oid;
5321         int                     i_opcname;
5322         int                     i_opcnamespace;
5323         int                     i_rolname;
5324
5325         /*
5326          * find all opclasses, including builtin opclasses; we filter out
5327          * system-defined opclasses at dump-out time.
5328          */
5329
5330         appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
5331                                           "opcnamespace, "
5332                                           "(%s opcowner) AS rolname "
5333                                           "FROM pg_opclass",
5334                                           username_subquery);
5335
5336         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5337
5338         ntups = PQntuples(res);
5339         *numOpclasses = ntups;
5340
5341         opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
5342
5343         i_tableoid = PQfnumber(res, "tableoid");
5344         i_oid = PQfnumber(res, "oid");
5345         i_opcname = PQfnumber(res, "opcname");
5346         i_opcnamespace = PQfnumber(res, "opcnamespace");
5347         i_rolname = PQfnumber(res, "rolname");
5348
5349         for (i = 0; i < ntups; i++)
5350         {
5351                 opcinfo[i].dobj.objType = DO_OPCLASS;
5352                 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5353                 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5354                 AssignDumpId(&opcinfo[i].dobj);
5355                 opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
5356                 opcinfo[i].dobj.namespace =
5357                         findNamespace(fout,
5358                                                   atooid(PQgetvalue(res, i, i_opcnamespace)));
5359                 opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5360
5361                 /* Decide whether we want to dump it */
5362                 selectDumpableObject(&(opcinfo[i].dobj), fout);
5363
5364                 /* Op Classes do not currently have ACLs. */
5365                 opcinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5366
5367                 if (strlen(opcinfo[i].rolname) == 0)
5368                         write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
5369                                           opcinfo[i].dobj.name);
5370         }
5371
5372         PQclear(res);
5373
5374         destroyPQExpBuffer(query);
5375
5376         return opcinfo;
5377 }
5378
5379 /*
5380  * getOpfamilies:
5381  *        read all opfamilies in the system catalogs and return them in the
5382  * OpfamilyInfo* structure
5383  *
5384  *      numOpfamilies is set to the number of opfamilies read in
5385  */
5386 OpfamilyInfo *
5387 getOpfamilies(Archive *fout, int *numOpfamilies)
5388 {
5389         PGresult   *res;
5390         int                     ntups;
5391         int                     i;
5392         PQExpBuffer query;
5393         OpfamilyInfo *opfinfo;
5394         int                     i_tableoid;
5395         int                     i_oid;
5396         int                     i_opfname;
5397         int                     i_opfnamespace;
5398         int                     i_rolname;
5399
5400         /* Before 8.3, there is no separate concept of opfamilies */
5401         if (fout->remoteVersion < 80300)
5402         {
5403                 *numOpfamilies = 0;
5404                 return NULL;
5405         }
5406
5407         query = createPQExpBuffer();
5408
5409         /*
5410          * find all opfamilies, including builtin opfamilies; we filter out
5411          * system-defined opfamilies at dump-out time.
5412          */
5413
5414         appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
5415                                           "opfnamespace, "
5416                                           "(%s opfowner) AS rolname "
5417                                           "FROM pg_opfamily",
5418                                           username_subquery);
5419
5420         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5421
5422         ntups = PQntuples(res);
5423         *numOpfamilies = ntups;
5424
5425         opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
5426
5427         i_tableoid = PQfnumber(res, "tableoid");
5428         i_oid = PQfnumber(res, "oid");
5429         i_opfname = PQfnumber(res, "opfname");
5430         i_opfnamespace = PQfnumber(res, "opfnamespace");
5431         i_rolname = PQfnumber(res, "rolname");
5432
5433         for (i = 0; i < ntups; i++)
5434         {
5435                 opfinfo[i].dobj.objType = DO_OPFAMILY;
5436                 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5437                 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5438                 AssignDumpId(&opfinfo[i].dobj);
5439                 opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
5440                 opfinfo[i].dobj.namespace =
5441                         findNamespace(fout,
5442                                                   atooid(PQgetvalue(res, i, i_opfnamespace)));
5443                 opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5444
5445                 /* Decide whether we want to dump it */
5446                 selectDumpableObject(&(opfinfo[i].dobj), fout);
5447
5448                 /* Extensions do not currently have ACLs. */
5449                 opfinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5450
5451                 if (strlen(opfinfo[i].rolname) == 0)
5452                         write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
5453                                           opfinfo[i].dobj.name);
5454         }
5455
5456         PQclear(res);
5457
5458         destroyPQExpBuffer(query);
5459
5460         return opfinfo;
5461 }
5462
5463 /*
5464  * getAggregates:
5465  *        read all the user-defined aggregates in the system catalogs and
5466  * return them in the AggInfo* structure
5467  *
5468  * numAggs is set to the number of aggregates read in
5469  */
5470 AggInfo *
5471 getAggregates(Archive *fout, int *numAggs)
5472 {
5473         DumpOptions *dopt = fout->dopt;
5474         PGresult   *res;
5475         int                     ntups;
5476         int                     i;
5477         PQExpBuffer query = createPQExpBuffer();
5478         AggInfo    *agginfo;
5479         int                     i_tableoid;
5480         int                     i_oid;
5481         int                     i_aggname;
5482         int                     i_aggnamespace;
5483         int                     i_pronargs;
5484         int                     i_proargtypes;
5485         int                     i_rolname;
5486         int                     i_aggacl;
5487         int                     i_raggacl;
5488         int                     i_initaggacl;
5489         int                     i_initraggacl;
5490
5491         /*
5492          * Find all interesting aggregates.  See comment in getFuncs() for the
5493          * rationale behind the filtering logic.
5494          */
5495         if (fout->remoteVersion >= 90600)
5496         {
5497                 PQExpBuffer acl_subquery = createPQExpBuffer();
5498                 PQExpBuffer racl_subquery = createPQExpBuffer();
5499                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5500                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5501                 const char *agg_check;
5502
5503                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5504                                                 initracl_subquery, "p.proacl", "p.proowner", "'f'",
5505                                                 dopt->binary_upgrade);
5506
5507                 agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
5508                                          : "p.proisagg");
5509
5510                 appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
5511                                                   "p.proname AS aggname, "
5512                                                   "p.pronamespace AS aggnamespace, "
5513                                                   "p.pronargs, p.proargtypes, "
5514                                                   "(%s p.proowner) AS rolname, "
5515                                                   "%s AS aggacl, "
5516                                                   "%s AS raggacl, "
5517                                                   "%s AS initaggacl, "
5518                                                   "%s AS initraggacl "
5519                                                   "FROM pg_proc p "
5520                                                   "LEFT JOIN pg_init_privs pip ON "
5521                                                   "(p.oid = pip.objoid "
5522                                                   "AND pip.classoid = 'pg_proc'::regclass "
5523                                                   "AND pip.objsubid = 0) "
5524                                                   "WHERE %s AND ("
5525                                                   "p.pronamespace != "
5526                                                   "(SELECT oid FROM pg_namespace "
5527                                                   "WHERE nspname = 'pg_catalog') OR "
5528                                                   "p.proacl IS DISTINCT FROM pip.initprivs",
5529                                                   username_subquery,
5530                                                   acl_subquery->data,
5531                                                   racl_subquery->data,
5532                                                   initacl_subquery->data,
5533                                                   initracl_subquery->data,
5534                                                   agg_check);
5535                 if (dopt->binary_upgrade)
5536                         appendPQExpBufferStr(query,
5537                                                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5538                                                                  "classid = 'pg_proc'::regclass AND "
5539                                                                  "objid = p.oid AND "
5540                                                                  "refclassid = 'pg_extension'::regclass AND "
5541                                                                  "deptype = 'e')");
5542                 appendPQExpBufferChar(query, ')');
5543
5544                 destroyPQExpBuffer(acl_subquery);
5545                 destroyPQExpBuffer(racl_subquery);
5546                 destroyPQExpBuffer(initacl_subquery);
5547                 destroyPQExpBuffer(initracl_subquery);
5548         }
5549         else if (fout->remoteVersion >= 80200)
5550         {
5551                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
5552                                                   "pronamespace AS aggnamespace, "
5553                                                   "pronargs, proargtypes, "
5554                                                   "(%s proowner) AS rolname, "
5555                                                   "proacl AS aggacl, "
5556                                                   "NULL AS raggacl, "
5557                                                   "NULL AS initaggacl, NULL AS initraggacl "
5558                                                   "FROM pg_proc p "
5559                                                   "WHERE proisagg AND ("
5560                                                   "pronamespace != "
5561                                                   "(SELECT oid FROM pg_namespace "
5562                                                   "WHERE nspname = 'pg_catalog')",
5563                                                   username_subquery);
5564                 if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
5565                         appendPQExpBufferStr(query,
5566                                                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5567                                                                  "classid = 'pg_proc'::regclass AND "
5568                                                                  "objid = p.oid AND "
5569                                                                  "refclassid = 'pg_extension'::regclass AND "
5570                                                                  "deptype = 'e')");
5571                 appendPQExpBufferChar(query, ')');
5572         }
5573         else
5574         {
5575                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
5576                                                   "pronamespace AS aggnamespace, "
5577                                                   "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
5578                                                   "proargtypes, "
5579                                                   "(%s proowner) AS rolname, "
5580                                                   "proacl AS aggacl, "
5581                                                   "NULL AS raggacl, "
5582                                                   "NULL AS initaggacl, NULL AS initraggacl "
5583                                                   "FROM pg_proc "
5584                                                   "WHERE proisagg "
5585                                                   "AND pronamespace != "
5586                                                   "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
5587                                                   username_subquery);
5588         }
5589
5590         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5591
5592         ntups = PQntuples(res);
5593         *numAggs = ntups;
5594
5595         agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
5596
5597         i_tableoid = PQfnumber(res, "tableoid");
5598         i_oid = PQfnumber(res, "oid");
5599         i_aggname = PQfnumber(res, "aggname");
5600         i_aggnamespace = PQfnumber(res, "aggnamespace");
5601         i_pronargs = PQfnumber(res, "pronargs");
5602         i_proargtypes = PQfnumber(res, "proargtypes");
5603         i_rolname = PQfnumber(res, "rolname");
5604         i_aggacl = PQfnumber(res, "aggacl");
5605         i_raggacl = PQfnumber(res, "raggacl");
5606         i_initaggacl = PQfnumber(res, "initaggacl");
5607         i_initraggacl = PQfnumber(res, "initraggacl");
5608
5609         for (i = 0; i < ntups; i++)
5610         {
5611                 agginfo[i].aggfn.dobj.objType = DO_AGG;
5612                 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5613                 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5614                 AssignDumpId(&agginfo[i].aggfn.dobj);
5615                 agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
5616                 agginfo[i].aggfn.dobj.namespace =
5617                         findNamespace(fout,
5618                                                   atooid(PQgetvalue(res, i, i_aggnamespace)));
5619                 agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5620                 if (strlen(agginfo[i].aggfn.rolname) == 0)
5621                         write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
5622                                           agginfo[i].aggfn.dobj.name);
5623                 agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
5624                 agginfo[i].aggfn.prorettype = InvalidOid;       /* not saved */
5625                 agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
5626                 agginfo[i].aggfn.rproacl = pg_strdup(PQgetvalue(res, i, i_raggacl));
5627                 agginfo[i].aggfn.initproacl = pg_strdup(PQgetvalue(res, i, i_initaggacl));
5628                 agginfo[i].aggfn.initrproacl = pg_strdup(PQgetvalue(res, i, i_initraggacl));
5629                 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
5630                 if (agginfo[i].aggfn.nargs == 0)
5631                         agginfo[i].aggfn.argtypes = NULL;
5632                 else
5633                 {
5634                         agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
5635                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
5636                                                   agginfo[i].aggfn.argtypes,
5637                                                   agginfo[i].aggfn.nargs);
5638                 }
5639
5640                 /* Decide whether we want to dump it */
5641                 selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
5642
5643                 /* Do not try to dump ACL if no ACL exists. */
5644                 if (PQgetisnull(res, i, i_aggacl) && PQgetisnull(res, i, i_raggacl) &&
5645                         PQgetisnull(res, i, i_initaggacl) &&
5646                         PQgetisnull(res, i, i_initraggacl))
5647                         agginfo[i].aggfn.dobj.dump &= ~DUMP_COMPONENT_ACL;
5648         }
5649
5650         PQclear(res);
5651
5652         destroyPQExpBuffer(query);
5653
5654         return agginfo;
5655 }
5656
5657 /*
5658  * getFuncs:
5659  *        read all the user-defined functions in the system catalogs and
5660  * return them in the FuncInfo* structure
5661  *
5662  * numFuncs is set to the number of functions read in
5663  */
5664 FuncInfo *
5665 getFuncs(Archive *fout, int *numFuncs)
5666 {
5667         DumpOptions *dopt = fout->dopt;
5668         PGresult   *res;
5669         int                     ntups;
5670         int                     i;
5671         PQExpBuffer query = createPQExpBuffer();
5672         FuncInfo   *finfo;
5673         int                     i_tableoid;
5674         int                     i_oid;
5675         int                     i_proname;
5676         int                     i_pronamespace;
5677         int                     i_rolname;
5678         int                     i_prolang;
5679         int                     i_pronargs;
5680         int                     i_proargtypes;
5681         int                     i_prorettype;
5682         int                     i_proacl;
5683         int                     i_rproacl;
5684         int                     i_initproacl;
5685         int                     i_initrproacl;
5686
5687         /*
5688          * Find all interesting functions.  This is a bit complicated:
5689          *
5690          * 1. Always exclude aggregates; those are handled elsewhere.
5691          *
5692          * 2. Always exclude functions that are internally dependent on something
5693          * else, since presumably those will be created as a result of creating
5694          * the something else.  This currently acts only to suppress constructor
5695          * functions for range types (so we only need it in 9.2 and up).  Note
5696          * this is OK only because the constructors don't have any dependencies
5697          * the range type doesn't have; otherwise we might not get creation
5698          * ordering correct.
5699          *
5700          * 3. Otherwise, we normally exclude functions in pg_catalog.  However, if
5701          * they're members of extensions and we are in binary-upgrade mode then
5702          * include them, since we want to dump extension members individually in
5703          * that mode.  Also, if they are used by casts or transforms then we need
5704          * to gather the information about them, though they won't be dumped if
5705          * they are built-in.  Also, in 9.6 and up, include functions in
5706          * pg_catalog if they have an ACL different from what's shown in
5707          * pg_init_privs.
5708          */
5709         if (fout->remoteVersion >= 90600)
5710         {
5711                 PQExpBuffer acl_subquery = createPQExpBuffer();
5712                 PQExpBuffer racl_subquery = createPQExpBuffer();
5713                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5714                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5715                 const char *not_agg_check;
5716
5717                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5718                                                 initracl_subquery, "p.proacl", "p.proowner", "'f'",
5719                                                 dopt->binary_upgrade);
5720
5721                 not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
5722                                                  : "NOT p.proisagg");
5723
5724                 appendPQExpBuffer(query,
5725                                                   "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
5726                                                   "p.pronargs, p.proargtypes, p.prorettype, "
5727                                                   "%s AS proacl, "
5728                                                   "%s AS rproacl, "
5729                                                   "%s AS initproacl, "
5730                                                   "%s AS initrproacl, "
5731                                                   "p.pronamespace, "
5732                                                   "(%s p.proowner) AS rolname "
5733                                                   "FROM pg_proc p "
5734                                                   "LEFT JOIN pg_init_privs pip ON "
5735                                                   "(p.oid = pip.objoid "
5736                                                   "AND pip.classoid = 'pg_proc'::regclass "
5737                                                   "AND pip.objsubid = 0) "
5738                                                   "WHERE %s"
5739                                                   "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
5740                                                   "WHERE classid = 'pg_proc'::regclass AND "
5741                                                   "objid = p.oid AND deptype = 'i')"
5742                                                   "\n  AND ("
5743                                                   "\n  pronamespace != "
5744                                                   "(SELECT oid FROM pg_namespace "
5745                                                   "WHERE nspname = 'pg_catalog')"
5746                                                   "\n  OR EXISTS (SELECT 1 FROM pg_cast"
5747                                                   "\n  WHERE pg_cast.oid > %u "
5748                                                   "\n  AND p.oid = pg_cast.castfunc)"
5749                                                   "\n  OR EXISTS (SELECT 1 FROM pg_transform"
5750                                                   "\n  WHERE pg_transform.oid > %u AND "
5751                                                   "\n  (p.oid = pg_transform.trffromsql"
5752                                                   "\n  OR p.oid = pg_transform.trftosql))",
5753                                                   acl_subquery->data,
5754                                                   racl_subquery->data,
5755                                                   initacl_subquery->data,
5756                                                   initracl_subquery->data,
5757                                                   username_subquery,
5758                                                   not_agg_check,
5759                                                   g_last_builtin_oid,
5760                                                   g_last_builtin_oid);
5761                 if (dopt->binary_upgrade)
5762                         appendPQExpBufferStr(query,
5763                                                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5764                                                                  "classid = 'pg_proc'::regclass AND "
5765                                                                  "objid = p.oid AND "
5766                                                                  "refclassid = 'pg_extension'::regclass AND "
5767                                                                  "deptype = 'e')");
5768                 appendPQExpBufferStr(query,
5769                                                          "\n  OR p.proacl IS DISTINCT FROM pip.initprivs");
5770                 appendPQExpBufferChar(query, ')');
5771
5772                 destroyPQExpBuffer(acl_subquery);
5773                 destroyPQExpBuffer(racl_subquery);
5774                 destroyPQExpBuffer(initacl_subquery);
5775                 destroyPQExpBuffer(initracl_subquery);
5776         }
5777         else
5778         {
5779                 appendPQExpBuffer(query,
5780                                                   "SELECT tableoid, oid, proname, prolang, "
5781                                                   "pronargs, proargtypes, prorettype, proacl, "
5782                                                   "NULL as rproacl, "
5783                                                   "NULL as initproacl, NULL AS initrproacl, "
5784                                                   "pronamespace, "
5785                                                   "(%s proowner) AS rolname "
5786                                                   "FROM pg_proc p "
5787                                                   "WHERE NOT proisagg",
5788                                                   username_subquery);
5789                 if (fout->remoteVersion >= 90200)
5790                         appendPQExpBufferStr(query,
5791                                                                  "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
5792                                                                  "WHERE classid = 'pg_proc'::regclass AND "
5793                                                                  "objid = p.oid AND deptype = 'i')");
5794                 appendPQExpBuffer(query,
5795                                                   "\n  AND ("
5796                                                   "\n  pronamespace != "
5797                                                   "(SELECT oid FROM pg_namespace "
5798                                                   "WHERE nspname = 'pg_catalog')"
5799                                                   "\n  OR EXISTS (SELECT 1 FROM pg_cast"
5800                                                   "\n  WHERE pg_cast.oid > '%u'::oid"
5801                                                   "\n  AND p.oid = pg_cast.castfunc)",
5802                                                   g_last_builtin_oid);
5803
5804                 if (fout->remoteVersion >= 90500)
5805                         appendPQExpBuffer(query,
5806                                                           "\n  OR EXISTS (SELECT 1 FROM pg_transform"
5807                                                           "\n  WHERE pg_transform.oid > '%u'::oid"
5808                                                           "\n  AND (p.oid = pg_transform.trffromsql"
5809                                                           "\n  OR p.oid = pg_transform.trftosql))",
5810                                                           g_last_builtin_oid);
5811
5812                 if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
5813                         appendPQExpBufferStr(query,
5814                                                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5815                                                                  "classid = 'pg_proc'::regclass AND "
5816                                                                  "objid = p.oid AND "
5817                                                                  "refclassid = 'pg_extension'::regclass AND "
5818                                                                  "deptype = 'e')");
5819                 appendPQExpBufferChar(query, ')');
5820         }
5821
5822         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5823
5824         ntups = PQntuples(res);
5825
5826         *numFuncs = ntups;
5827
5828         finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
5829
5830         i_tableoid = PQfnumber(res, "tableoid");
5831         i_oid = PQfnumber(res, "oid");
5832         i_proname = PQfnumber(res, "proname");
5833         i_pronamespace = PQfnumber(res, "pronamespace");
5834         i_rolname = PQfnumber(res, "rolname");
5835         i_prolang = PQfnumber(res, "prolang");
5836         i_pronargs = PQfnumber(res, "pronargs");
5837         i_proargtypes = PQfnumber(res, "proargtypes");
5838         i_prorettype = PQfnumber(res, "prorettype");
5839         i_proacl = PQfnumber(res, "proacl");
5840         i_rproacl = PQfnumber(res, "rproacl");
5841         i_initproacl = PQfnumber(res, "initproacl");
5842         i_initrproacl = PQfnumber(res, "initrproacl");
5843
5844         for (i = 0; i < ntups; i++)
5845         {
5846                 finfo[i].dobj.objType = DO_FUNC;
5847                 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5848                 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5849                 AssignDumpId(&finfo[i].dobj);
5850                 finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
5851                 finfo[i].dobj.namespace =
5852                         findNamespace(fout,
5853                                                   atooid(PQgetvalue(res, i, i_pronamespace)));
5854                 finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5855                 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
5856                 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
5857                 finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
5858                 finfo[i].rproacl = pg_strdup(PQgetvalue(res, i, i_rproacl));
5859                 finfo[i].initproacl = pg_strdup(PQgetvalue(res, i, i_initproacl));
5860                 finfo[i].initrproacl = pg_strdup(PQgetvalue(res, i, i_initrproacl));
5861                 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
5862                 if (finfo[i].nargs == 0)
5863                         finfo[i].argtypes = NULL;
5864                 else
5865                 {
5866                         finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
5867                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
5868                                                   finfo[i].argtypes, finfo[i].nargs);
5869                 }
5870
5871                 /* Decide whether we want to dump it */
5872                 selectDumpableObject(&(finfo[i].dobj), fout);
5873
5874                 /* Do not try to dump ACL if no ACL exists. */
5875                 if (PQgetisnull(res, i, i_proacl) && PQgetisnull(res, i, i_rproacl) &&
5876                         PQgetisnull(res, i, i_initproacl) &&
5877                         PQgetisnull(res, i, i_initrproacl))
5878                         finfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5879
5880                 if (strlen(finfo[i].rolname) == 0)
5881                         write_msg(NULL,
5882                                           "WARNING: owner of function \"%s\" appears to be invalid\n",
5883                                           finfo[i].dobj.name);
5884         }
5885
5886         PQclear(res);
5887
5888         destroyPQExpBuffer(query);
5889
5890         return finfo;
5891 }
5892
5893 /*
5894  * getTables
5895  *        read all the tables (no indexes)
5896  * in the system catalogs return them in the TableInfo* structure
5897  *
5898  * numTables is set to the number of tables read in
5899  */
5900 TableInfo *
5901 getTables(Archive *fout, int *numTables)
5902 {
5903         DumpOptions *dopt = fout->dopt;
5904         PGresult   *res;
5905         int                     ntups;
5906         int                     i;
5907         PQExpBuffer query = createPQExpBuffer();
5908         TableInfo  *tblinfo;
5909         int                     i_reltableoid;
5910         int                     i_reloid;
5911         int                     i_relname;
5912         int                     i_relnamespace;
5913         int                     i_relkind;
5914         int                     i_relacl;
5915         int                     i_rrelacl;
5916         int                     i_initrelacl;
5917         int                     i_initrrelacl;
5918         int                     i_rolname;
5919         int                     i_relchecks;
5920         int                     i_relhastriggers;
5921         int                     i_relhasindex;
5922         int                     i_relhasrules;
5923         int                     i_relrowsec;
5924         int                     i_relforcerowsec;
5925         int                     i_relhasoids;
5926         int                     i_relfrozenxid;
5927         int                     i_relminmxid;
5928         int                     i_toastoid;
5929         int                     i_toastfrozenxid;
5930         int                     i_toastminmxid;
5931         int                     i_relpersistence;
5932         int                     i_relispopulated;
5933         int                     i_relreplident;
5934         int                     i_owning_tab;
5935         int                     i_owning_col;
5936         int                     i_reltablespace;
5937         int                     i_reloptions;
5938         int                     i_checkoption;
5939         int                     i_toastreloptions;
5940         int                     i_reloftype;
5941         int                     i_relpages;
5942         int                     i_is_identity_sequence;
5943         int                     i_changed_acl;
5944         int                     i_partkeydef;
5945         int                     i_ispartition;
5946         int                     i_partbound;
5947         int                     i_amname;
5948
5949         /*
5950          * Find all the tables and table-like objects.
5951          *
5952          * We include system catalogs, so that we can work if a user table is
5953          * defined to inherit from a system catalog (pretty weird, but...)
5954          *
5955          * We ignore relations that are not ordinary tables, sequences, views,
5956          * materialized views, composite types, or foreign tables.
5957          *
5958          * Composite-type table entries won't be dumped as such, but we have to
5959          * make a DumpableObject for them so that we can track dependencies of the
5960          * composite type (pg_depend entries for columns of the composite type
5961          * link to the pg_class entry not the pg_type entry).
5962          *
5963          * Note: in this phase we should collect only a minimal amount of
5964          * information about each table, basically just enough to decide if it is
5965          * interesting. We must fetch all tables in this phase because otherwise
5966          * we cannot correctly identify inherited columns, owned sequences, etc.
5967          *
5968          * We purposefully ignore toast OIDs for partitioned tables; the reason is
5969          * that versions 10 and 11 have them, but 12 does not, so emitting them
5970          * causes the upgrade to fail.
5971          */
5972
5973         if (fout->remoteVersion >= 90600)
5974         {
5975                 char       *partkeydef = "NULL";
5976                 char       *ispartition = "false";
5977                 char       *partbound = "NULL";
5978                 char       *relhasoids = "c.relhasoids";
5979
5980                 PQExpBuffer acl_subquery = createPQExpBuffer();
5981                 PQExpBuffer racl_subquery = createPQExpBuffer();
5982                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5983                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5984
5985                 PQExpBuffer attacl_subquery = createPQExpBuffer();
5986                 PQExpBuffer attracl_subquery = createPQExpBuffer();
5987                 PQExpBuffer attinitacl_subquery = createPQExpBuffer();
5988                 PQExpBuffer attinitracl_subquery = createPQExpBuffer();
5989
5990                 /*
5991                  * Collect the information about any partitioned tables, which were
5992                  * added in PG10.
5993                  */
5994
5995                 if (fout->remoteVersion >= 100000)
5996                 {
5997                         partkeydef = "pg_get_partkeydef(c.oid)";
5998                         ispartition = "c.relispartition";
5999                         partbound = "pg_get_expr(c.relpartbound, c.oid)";
6000                 }
6001
6002                 /* In PG12 upwards WITH OIDS does not exist anymore. */
6003                 if (fout->remoteVersion >= 120000)
6004                         relhasoids = "'f'::bool";
6005
6006                 /*
6007                  * Left join to pick up dependency info linking sequences to their
6008                  * owning column, if any (note this dependency is AUTO as of 8.2)
6009                  *
6010                  * Left join to detect if any privileges are still as-set-at-init, in
6011                  * which case we won't dump out ACL commands for those.
6012                  */
6013
6014                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
6015                                                 initracl_subquery, "c.relacl", "c.relowner",
6016                                                 "CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
6017                                                 " THEN 's' ELSE 'r' END::\"char\"",
6018                                                 dopt->binary_upgrade);
6019
6020                 buildACLQueries(attacl_subquery, attracl_subquery, attinitacl_subquery,
6021                                                 attinitracl_subquery, "at.attacl", "c.relowner", "'c'",
6022                                                 dopt->binary_upgrade);
6023
6024                 appendPQExpBuffer(query,
6025                                                   "SELECT c.tableoid, c.oid, c.relname, "
6026                                                   "%s AS relacl, %s as rrelacl, "
6027                                                   "%s AS initrelacl, %s as initrrelacl, "
6028                                                   "c.relkind, c.relnamespace, "
6029                                                   "(%s c.relowner) AS rolname, "
6030                                                   "c.relchecks, c.relhastriggers, "
6031                                                   "c.relhasindex, c.relhasrules, %s AS relhasoids, "
6032                                                   "c.relrowsecurity, c.relforcerowsecurity, "
6033                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6034                                                   "tc.relfrozenxid AS tfrozenxid, "
6035                                                   "tc.relminmxid AS tminmxid, "
6036                                                   "c.relpersistence, c.relispopulated, "
6037                                                   "c.relreplident, c.relpages, am.amname, "
6038                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6039                                                   "d.refobjid AS owning_tab, "
6040                                                   "d.refobjsubid AS owning_col, "
6041                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6042                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6043                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6044                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6045                                                   "tc.reloptions AS toast_reloptions, "
6046                                                   "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, "
6047                                                   "EXISTS (SELECT 1 FROM pg_attribute at LEFT JOIN pg_init_privs pip ON "
6048                                                   "(c.oid = pip.objoid "
6049                                                   "AND pip.classoid = 'pg_class'::regclass "
6050                                                   "AND pip.objsubid = at.attnum)"
6051                                                   "WHERE at.attrelid = c.oid AND ("
6052                                                   "%s IS NOT NULL "
6053                                                   "OR %s IS NOT NULL "
6054                                                   "OR %s IS NOT NULL "
6055                                                   "OR %s IS NOT NULL"
6056                                                   "))"
6057                                                   "AS changed_acl, "
6058                                                   "%s AS partkeydef, "
6059                                                   "%s AS ispartition, "
6060                                                   "%s AS partbound "
6061                                                   "FROM pg_class c "
6062                                                   "LEFT JOIN pg_depend d ON "
6063                                                   "(c.relkind = '%c' AND "
6064                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6065                                                   "d.objsubid = 0 AND "
6066                                                   "d.refclassid = c.tableoid AND d.deptype IN ('a', 'i')) "
6067                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid AND c.relkind <> '%c') "
6068                                                   "LEFT JOIN pg_am am ON (c.relam = am.oid) "
6069                                                   "LEFT JOIN pg_init_privs pip ON "
6070                                                   "(c.oid = pip.objoid "
6071                                                   "AND pip.classoid = 'pg_class'::regclass "
6072                                                   "AND pip.objsubid = 0) "
6073                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c', '%c') "
6074                                                   "ORDER BY c.oid",
6075                                                   acl_subquery->data,
6076                                                   racl_subquery->data,
6077                                                   initacl_subquery->data,
6078                                                   initracl_subquery->data,
6079                                                   username_subquery,
6080                                                   relhasoids,
6081                                                   RELKIND_SEQUENCE,
6082                                                   attacl_subquery->data,
6083                                                   attracl_subquery->data,
6084                                                   attinitacl_subquery->data,
6085                                                   attinitracl_subquery->data,
6086                                                   partkeydef,
6087                                                   ispartition,
6088                                                   partbound,
6089                                                   RELKIND_SEQUENCE,
6090                                                   RELKIND_PARTITIONED_TABLE,
6091                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6092                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6093                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
6094                                                   RELKIND_PARTITIONED_TABLE);
6095
6096                 destroyPQExpBuffer(acl_subquery);
6097                 destroyPQExpBuffer(racl_subquery);
6098                 destroyPQExpBuffer(initacl_subquery);
6099                 destroyPQExpBuffer(initracl_subquery);
6100
6101                 destroyPQExpBuffer(attacl_subquery);
6102                 destroyPQExpBuffer(attracl_subquery);
6103                 destroyPQExpBuffer(attinitacl_subquery);
6104                 destroyPQExpBuffer(attinitracl_subquery);
6105         }
6106         else if (fout->remoteVersion >= 90500)
6107         {
6108                 /*
6109                  * Left join to pick up dependency info linking sequences to their
6110                  * owning column, if any (note this dependency is AUTO as of 8.2)
6111                  */
6112                 appendPQExpBuffer(query,
6113                                                   "SELECT c.tableoid, c.oid, c.relname, "
6114                                                   "c.relacl, NULL as rrelacl, "
6115                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6116                                                   "c.relkind, "
6117                                                   "c.relnamespace, "
6118                                                   "(%s c.relowner) AS rolname, "
6119                                                   "c.relchecks, c.relhastriggers, "
6120                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6121                                                   "c.relrowsecurity, c.relforcerowsecurity, "
6122                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6123                                                   "tc.relfrozenxid AS tfrozenxid, "
6124                                                   "tc.relminmxid AS tminmxid, "
6125                                                   "c.relpersistence, c.relispopulated, "
6126                                                   "c.relreplident, c.relpages, "
6127                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6128                                                   "d.refobjid AS owning_tab, "
6129                                                   "d.refobjsubid AS owning_col, "
6130                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6131                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6132                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6133                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6134                                                   "tc.reloptions AS toast_reloptions, "
6135                                                   "NULL AS changed_acl, "
6136                                                   "NULL AS partkeydef, "
6137                                                   "false AS ispartition, "
6138                                                   "NULL AS partbound "
6139                                                   "FROM pg_class c "
6140                                                   "LEFT JOIN pg_depend d ON "
6141                                                   "(c.relkind = '%c' AND "
6142                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6143                                                   "d.objsubid = 0 AND "
6144                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6145                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6146                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6147                                                   "ORDER BY c.oid",
6148                                                   username_subquery,
6149                                                   RELKIND_SEQUENCE,
6150                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6151                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6152                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6153         }
6154         else if (fout->remoteVersion >= 90400)
6155         {
6156                 /*
6157                  * Left join to pick up dependency info linking sequences to their
6158                  * owning column, if any (note this dependency is AUTO as of 8.2)
6159                  */
6160                 appendPQExpBuffer(query,
6161                                                   "SELECT c.tableoid, c.oid, c.relname, "
6162                                                   "c.relacl, NULL as rrelacl, "
6163                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6164                                                   "c.relkind, "
6165                                                   "c.relnamespace, "
6166                                                   "(%s c.relowner) AS rolname, "
6167                                                   "c.relchecks, c.relhastriggers, "
6168                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6169                                                   "'f'::bool AS relrowsecurity, "
6170                                                   "'f'::bool AS relforcerowsecurity, "
6171                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6172                                                   "tc.relfrozenxid AS tfrozenxid, "
6173                                                   "tc.relminmxid AS tminmxid, "
6174                                                   "c.relpersistence, c.relispopulated, "
6175                                                   "c.relreplident, c.relpages, "
6176                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6177                                                   "d.refobjid AS owning_tab, "
6178                                                   "d.refobjsubid AS owning_col, "
6179                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6180                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6181                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6182                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6183                                                   "tc.reloptions AS toast_reloptions, "
6184                                                   "NULL AS changed_acl, "
6185                                                   "NULL AS partkeydef, "
6186                                                   "false AS ispartition, "
6187                                                   "NULL AS partbound "
6188                                                   "FROM pg_class c "
6189                                                   "LEFT JOIN pg_depend d ON "
6190                                                   "(c.relkind = '%c' AND "
6191                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6192                                                   "d.objsubid = 0 AND "
6193                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6194                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6195                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6196                                                   "ORDER BY c.oid",
6197                                                   username_subquery,
6198                                                   RELKIND_SEQUENCE,
6199                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6200                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6201                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6202         }
6203         else if (fout->remoteVersion >= 90300)
6204         {
6205                 /*
6206                  * Left join to pick up dependency info linking sequences to their
6207                  * owning column, if any (note this dependency is AUTO as of 8.2)
6208                  */
6209                 appendPQExpBuffer(query,
6210                                                   "SELECT c.tableoid, c.oid, c.relname, "
6211                                                   "c.relacl, NULL as rrelacl, "
6212                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6213                                                   "c.relkind, "
6214                                                   "c.relnamespace, "
6215                                                   "(%s c.relowner) AS rolname, "
6216                                                   "c.relchecks, c.relhastriggers, "
6217                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6218                                                   "'f'::bool AS relrowsecurity, "
6219                                                   "'f'::bool AS relforcerowsecurity, "
6220                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6221                                                   "tc.relfrozenxid AS tfrozenxid, "
6222                                                   "tc.relminmxid AS tminmxid, "
6223                                                   "c.relpersistence, c.relispopulated, "
6224                                                   "'d' AS relreplident, c.relpages, "
6225                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6226                                                   "d.refobjid AS owning_tab, "
6227                                                   "d.refobjsubid AS owning_col, "
6228                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6229                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6230                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6231                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6232                                                   "tc.reloptions AS toast_reloptions, "
6233                                                   "NULL AS changed_acl, "
6234                                                   "NULL AS partkeydef, "
6235                                                   "false AS ispartition, "
6236                                                   "NULL AS partbound "
6237                                                   "FROM pg_class c "
6238                                                   "LEFT JOIN pg_depend d ON "
6239                                                   "(c.relkind = '%c' AND "
6240                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6241                                                   "d.objsubid = 0 AND "
6242                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6243                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6244                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6245                                                   "ORDER BY c.oid",
6246                                                   username_subquery,
6247                                                   RELKIND_SEQUENCE,
6248                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6249                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6250                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6251         }
6252         else if (fout->remoteVersion >= 90100)
6253         {
6254                 /*
6255                  * Left join to pick up dependency info linking sequences to their
6256                  * owning column, if any (note this dependency is AUTO as of 8.2)
6257                  */
6258                 appendPQExpBuffer(query,
6259                                                   "SELECT c.tableoid, c.oid, c.relname, "
6260                                                   "c.relacl, NULL as rrelacl, "
6261                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6262                                                   "c.relkind, "
6263                                                   "c.relnamespace, "
6264                                                   "(%s c.relowner) AS rolname, "
6265                                                   "c.relchecks, c.relhastriggers, "
6266                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6267                                                   "'f'::bool AS relrowsecurity, "
6268                                                   "'f'::bool AS relforcerowsecurity, "
6269                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6270                                                   "tc.relfrozenxid AS tfrozenxid, "
6271                                                   "0 AS tminmxid, "
6272                                                   "c.relpersistence, 't' as relispopulated, "
6273                                                   "'d' AS relreplident, c.relpages, "
6274                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6275                                                   "d.refobjid AS owning_tab, "
6276                                                   "d.refobjsubid AS owning_col, "
6277                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6278                                                   "c.reloptions AS reloptions, "
6279                                                   "tc.reloptions AS toast_reloptions, "
6280                                                   "NULL AS changed_acl, "
6281                                                   "NULL AS partkeydef, "
6282                                                   "false AS ispartition, "
6283                                                   "NULL AS partbound "
6284                                                   "FROM pg_class c "
6285                                                   "LEFT JOIN pg_depend d ON "
6286                                                   "(c.relkind = '%c' AND "
6287                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6288                                                   "d.objsubid = 0 AND "
6289                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6290                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6291                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6292                                                   "ORDER BY c.oid",
6293                                                   username_subquery,
6294                                                   RELKIND_SEQUENCE,
6295                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6296                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6297                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6298         }
6299         else if (fout->remoteVersion >= 90000)
6300         {
6301                 /*
6302                  * Left join to pick up dependency info linking sequences to their
6303                  * owning column, if any (note this dependency is AUTO as of 8.2)
6304                  */
6305                 appendPQExpBuffer(query,
6306                                                   "SELECT c.tableoid, c.oid, c.relname, "
6307                                                   "c.relacl, NULL as rrelacl, "
6308                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6309                                                   "c.relkind, "
6310                                                   "c.relnamespace, "
6311                                                   "(%s c.relowner) AS rolname, "
6312                                                   "c.relchecks, c.relhastriggers, "
6313                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6314                                                   "'f'::bool AS relrowsecurity, "
6315                                                   "'f'::bool AS relforcerowsecurity, "
6316                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6317                                                   "tc.relfrozenxid AS tfrozenxid, "
6318                                                   "0 AS tminmxid, "
6319                                                   "'p' AS relpersistence, 't' as relispopulated, "
6320                                                   "'d' AS relreplident, c.relpages, "
6321                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6322                                                   "d.refobjid AS owning_tab, "
6323                                                   "d.refobjsubid AS owning_col, "
6324                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6325                                                   "c.reloptions AS reloptions, "
6326                                                   "tc.reloptions AS toast_reloptions, "
6327                                                   "NULL AS changed_acl, "
6328                                                   "NULL AS partkeydef, "
6329                                                   "false AS ispartition, "
6330                                                   "NULL AS partbound "
6331                                                   "FROM pg_class c "
6332                                                   "LEFT JOIN pg_depend d ON "
6333                                                   "(c.relkind = '%c' AND "
6334                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6335                                                   "d.objsubid = 0 AND "
6336                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6337                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6338                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6339                                                   "ORDER BY c.oid",
6340                                                   username_subquery,
6341                                                   RELKIND_SEQUENCE,
6342                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6343                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6344         }
6345         else if (fout->remoteVersion >= 80400)
6346         {
6347                 /*
6348                  * Left join to pick up dependency info linking sequences to their
6349                  * owning column, if any (note this dependency is AUTO as of 8.2)
6350                  */
6351                 appendPQExpBuffer(query,
6352                                                   "SELECT c.tableoid, c.oid, c.relname, "
6353                                                   "c.relacl, NULL as rrelacl, "
6354                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6355                                                   "c.relkind, "
6356                                                   "c.relnamespace, "
6357                                                   "(%s c.relowner) AS rolname, "
6358                                                   "c.relchecks, c.relhastriggers, "
6359                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6360                                                   "'f'::bool AS relrowsecurity, "
6361                                                   "'f'::bool AS relforcerowsecurity, "
6362                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6363                                                   "tc.relfrozenxid AS tfrozenxid, "
6364                                                   "0 AS tminmxid, "
6365                                                   "'p' AS relpersistence, 't' as relispopulated, "
6366                                                   "'d' AS relreplident, c.relpages, "
6367                                                   "NULL AS reloftype, "
6368                                                   "d.refobjid AS owning_tab, "
6369                                                   "d.refobjsubid AS owning_col, "
6370                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6371                                                   "c.reloptions AS reloptions, "
6372                                                   "tc.reloptions AS toast_reloptions, "
6373                                                   "NULL AS changed_acl, "
6374                                                   "NULL AS partkeydef, "
6375                                                   "false AS ispartition, "
6376                                                   "NULL AS partbound "
6377                                                   "FROM pg_class c "
6378                                                   "LEFT JOIN pg_depend d ON "
6379                                                   "(c.relkind = '%c' AND "
6380                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6381                                                   "d.objsubid = 0 AND "
6382                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6383                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6384                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6385                                                   "ORDER BY c.oid",
6386                                                   username_subquery,
6387                                                   RELKIND_SEQUENCE,
6388                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6389                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6390         }
6391         else if (fout->remoteVersion >= 80200)
6392         {
6393                 /*
6394                  * Left join to pick up dependency info linking sequences to their
6395                  * owning column, if any (note this dependency is AUTO as of 8.2)
6396                  */
6397                 appendPQExpBuffer(query,
6398                                                   "SELECT c.tableoid, c.oid, c.relname, "
6399                                                   "c.relacl, NULL as rrelacl, "
6400                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6401                                                   "c.relkind, "
6402                                                   "c.relnamespace, "
6403                                                   "(%s c.relowner) AS rolname, "
6404                                                   "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
6405                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6406                                                   "'f'::bool AS relrowsecurity, "
6407                                                   "'f'::bool AS relforcerowsecurity, "
6408                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6409                                                   "tc.relfrozenxid AS tfrozenxid, "
6410                                                   "0 AS tminmxid, "
6411                                                   "'p' AS relpersistence, 't' as relispopulated, "
6412                                                   "'d' AS relreplident, c.relpages, "
6413                                                   "NULL AS reloftype, "
6414                                                   "d.refobjid AS owning_tab, "
6415                                                   "d.refobjsubid AS owning_col, "
6416                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6417                                                   "c.reloptions AS reloptions, "
6418                                                   "NULL AS toast_reloptions, "
6419                                                   "NULL AS changed_acl, "
6420                                                   "NULL AS partkeydef, "
6421                                                   "false AS ispartition, "
6422                                                   "NULL AS partbound "
6423                                                   "FROM pg_class c "
6424                                                   "LEFT JOIN pg_depend d ON "
6425                                                   "(c.relkind = '%c' AND "
6426                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6427                                                   "d.objsubid = 0 AND "
6428                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6429                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6430                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6431                                                   "ORDER BY c.oid",
6432                                                   username_subquery,
6433                                                   RELKIND_SEQUENCE,
6434                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6435                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6436         }
6437         else
6438         {
6439                 /*
6440                  * Left join to pick up dependency info linking sequences to their
6441                  * owning column, if any
6442                  */
6443                 appendPQExpBuffer(query,
6444                                                   "SELECT c.tableoid, c.oid, relname, "
6445                                                   "relacl, NULL as rrelacl, "
6446                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6447                                                   "relkind, relnamespace, "
6448                                                   "(%s relowner) AS rolname, "
6449                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
6450                                                   "relhasindex, relhasrules, relhasoids, "
6451                                                   "'f'::bool AS relrowsecurity, "
6452                                                   "'f'::bool AS relforcerowsecurity, "
6453                                                   "0 AS relfrozenxid, 0 AS relminmxid,"
6454                                                   "0 AS toid, "
6455                                                   "0 AS tfrozenxid, 0 AS tminmxid,"
6456                                                   "'p' AS relpersistence, 't' as relispopulated, "
6457                                                   "'d' AS relreplident, relpages, "
6458                                                   "NULL AS reloftype, "
6459                                                   "d.refobjid AS owning_tab, "
6460                                                   "d.refobjsubid AS owning_col, "
6461                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6462                                                   "NULL AS reloptions, "
6463                                                   "NULL AS toast_reloptions, "
6464                                                   "NULL AS changed_acl, "
6465                                                   "NULL AS partkeydef, "
6466                                                   "false AS ispartition, "
6467                                                   "NULL AS partbound "
6468                                                   "FROM pg_class c "
6469                                                   "LEFT JOIN pg_depend d ON "
6470                                                   "(c.relkind = '%c' AND "
6471                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6472                                                   "d.objsubid = 0 AND "
6473                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
6474                                                   "WHERE relkind in ('%c', '%c', '%c', '%c') "
6475                                                   "ORDER BY c.oid",
6476                                                   username_subquery,
6477                                                   RELKIND_SEQUENCE,
6478                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6479                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6480         }
6481
6482         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6483
6484         ntups = PQntuples(res);
6485
6486         *numTables = ntups;
6487
6488         /*
6489          * Extract data from result and lock dumpable tables.  We do the locking
6490          * before anything else, to minimize the window wherein a table could
6491          * disappear under us.
6492          *
6493          * Note that we have to save info about all tables here, even when dumping
6494          * only one, because we don't yet know which tables might be inheritance
6495          * ancestors of the target table.
6496          */
6497         tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
6498
6499         i_reltableoid = PQfnumber(res, "tableoid");
6500         i_reloid = PQfnumber(res, "oid");
6501         i_relname = PQfnumber(res, "relname");
6502         i_relnamespace = PQfnumber(res, "relnamespace");
6503         i_relacl = PQfnumber(res, "relacl");
6504         i_rrelacl = PQfnumber(res, "rrelacl");
6505         i_initrelacl = PQfnumber(res, "initrelacl");
6506         i_initrrelacl = PQfnumber(res, "initrrelacl");
6507         i_relkind = PQfnumber(res, "relkind");
6508         i_rolname = PQfnumber(res, "rolname");
6509         i_relchecks = PQfnumber(res, "relchecks");
6510         i_relhastriggers = PQfnumber(res, "relhastriggers");
6511         i_relhasindex = PQfnumber(res, "relhasindex");
6512         i_relhasrules = PQfnumber(res, "relhasrules");
6513         i_relrowsec = PQfnumber(res, "relrowsecurity");
6514         i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
6515         i_relhasoids = PQfnumber(res, "relhasoids");
6516         i_relfrozenxid = PQfnumber(res, "relfrozenxid");
6517         i_relminmxid = PQfnumber(res, "relminmxid");
6518         i_toastoid = PQfnumber(res, "toid");
6519         i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
6520         i_toastminmxid = PQfnumber(res, "tminmxid");
6521         i_relpersistence = PQfnumber(res, "relpersistence");
6522         i_relispopulated = PQfnumber(res, "relispopulated");
6523         i_relreplident = PQfnumber(res, "relreplident");
6524         i_relpages = PQfnumber(res, "relpages");
6525         i_owning_tab = PQfnumber(res, "owning_tab");
6526         i_owning_col = PQfnumber(res, "owning_col");
6527         i_reltablespace = PQfnumber(res, "reltablespace");
6528         i_reloptions = PQfnumber(res, "reloptions");
6529         i_checkoption = PQfnumber(res, "checkoption");
6530         i_toastreloptions = PQfnumber(res, "toast_reloptions");
6531         i_reloftype = PQfnumber(res, "reloftype");
6532         i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
6533         i_changed_acl = PQfnumber(res, "changed_acl");
6534         i_partkeydef = PQfnumber(res, "partkeydef");
6535         i_ispartition = PQfnumber(res, "ispartition");
6536         i_partbound = PQfnumber(res, "partbound");
6537         i_amname = PQfnumber(res, "amname");
6538
6539         if (dopt->lockWaitTimeout)
6540         {
6541                 /*
6542                  * Arrange to fail instead of waiting forever for a table lock.
6543                  *
6544                  * NB: this coding assumes that the only queries issued within the
6545                  * following loop are LOCK TABLEs; else the timeout may be undesirably
6546                  * applied to other things too.
6547                  */
6548                 resetPQExpBuffer(query);
6549                 appendPQExpBufferStr(query, "SET statement_timeout = ");
6550                 appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
6551                 ExecuteSqlStatement(fout, query->data);
6552         }
6553
6554         for (i = 0; i < ntups; i++)
6555         {
6556                 tblinfo[i].dobj.objType = DO_TABLE;
6557                 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
6558                 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
6559                 AssignDumpId(&tblinfo[i].dobj);
6560                 tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
6561                 tblinfo[i].dobj.namespace =
6562                         findNamespace(fout,
6563                                                   atooid(PQgetvalue(res, i, i_relnamespace)));
6564                 tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6565                 tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
6566                 tblinfo[i].rrelacl = pg_strdup(PQgetvalue(res, i, i_rrelacl));
6567                 tblinfo[i].initrelacl = pg_strdup(PQgetvalue(res, i, i_initrelacl));
6568                 tblinfo[i].initrrelacl = pg_strdup(PQgetvalue(res, i, i_initrrelacl));
6569                 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
6570                 tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
6571                 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
6572                 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
6573                 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
6574                 tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
6575                 tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
6576                 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
6577                 tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
6578                 tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
6579                 tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
6580                 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
6581                 tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
6582                 tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
6583                 tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
6584                 tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
6585                 if (PQgetisnull(res, i, i_reloftype))
6586                         tblinfo[i].reloftype = NULL;
6587                 else
6588                         tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
6589                 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
6590                 if (PQgetisnull(res, i, i_owning_tab))
6591                 {
6592                         tblinfo[i].owning_tab = InvalidOid;
6593                         tblinfo[i].owning_col = 0;
6594                 }
6595                 else
6596                 {
6597                         tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
6598                         tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
6599                 }
6600                 tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
6601                 tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
6602                 if (i_checkoption == -1 || PQgetisnull(res, i, i_checkoption))
6603                         tblinfo[i].checkoption = NULL;
6604                 else
6605                         tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
6606                 tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
6607                 if (PQgetisnull(res, i, i_amname))
6608                         tblinfo[i].amname = NULL;
6609                 else
6610                         tblinfo[i].amname = pg_strdup(PQgetvalue(res, i, i_amname));
6611
6612                 /* other fields were zeroed above */
6613
6614                 /*
6615                  * Decide whether we want to dump this table.
6616                  */
6617                 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
6618                         tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
6619                 else
6620                         selectDumpableTable(&tblinfo[i], fout);
6621
6622                 /*
6623                  * If the table-level and all column-level ACLs for this table are
6624                  * unchanged, then we don't need to worry about including the ACLs for
6625                  * this table.  If any column-level ACLs have been changed, the
6626                  * 'changed_acl' column from the query will indicate that.
6627                  *
6628                  * This can result in a significant performance improvement in cases
6629                  * where we are only looking to dump out the ACL (eg: pg_catalog).
6630                  */
6631                 if (PQgetisnull(res, i, i_relacl) && PQgetisnull(res, i, i_rrelacl) &&
6632                         PQgetisnull(res, i, i_initrelacl) &&
6633                         PQgetisnull(res, i, i_initrrelacl) &&
6634                         strcmp(PQgetvalue(res, i, i_changed_acl), "f") == 0)
6635                         tblinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
6636
6637                 tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
6638                 tblinfo[i].dummy_view = false;  /* might get set during sort */
6639                 tblinfo[i].postponed_def = false;       /* might get set during sort */
6640
6641                 tblinfo[i].is_identity_sequence = (i_is_identity_sequence >= 0 &&
6642                                                                                    strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
6643
6644                 /* Partition key string or NULL */
6645                 tblinfo[i].partkeydef = pg_strdup(PQgetvalue(res, i, i_partkeydef));
6646                 tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
6647                 tblinfo[i].partbound = pg_strdup(PQgetvalue(res, i, i_partbound));
6648
6649                 /*
6650                  * Read-lock target tables to make sure they aren't DROPPED or altered
6651                  * in schema before we get around to dumping them.
6652                  *
6653                  * Note that we don't explicitly lock parents of the target tables; we
6654                  * assume our lock on the child is enough to prevent schema
6655                  * alterations to parent tables.
6656                  *
6657                  * NOTE: it'd be kinda nice to lock other relations too, not only
6658                  * plain or partitioned tables, but the backend doesn't presently
6659                  * allow that.
6660                  *
6661                  * We only need to lock the table for certain components; see
6662                  * pg_dump.h
6663                  */
6664                 if (tblinfo[i].dobj.dump &&
6665                         (tblinfo[i].relkind == RELKIND_RELATION ||
6666                          tblinfo->relkind == RELKIND_PARTITIONED_TABLE) &&
6667                         (tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK))
6668                 {
6669                         resetPQExpBuffer(query);
6670                         appendPQExpBuffer(query,
6671                                                           "LOCK TABLE %s IN ACCESS SHARE MODE",
6672                                                           fmtQualifiedDumpable(&tblinfo[i]));
6673                         ExecuteSqlStatement(fout, query->data);
6674                 }
6675
6676                 /* Emit notice if join for owner failed */
6677                 if (strlen(tblinfo[i].rolname) == 0)
6678                         write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
6679                                           tblinfo[i].dobj.name);
6680         }
6681
6682         if (dopt->lockWaitTimeout)
6683         {
6684                 ExecuteSqlStatement(fout, "SET statement_timeout = 0");
6685         }
6686
6687         PQclear(res);
6688
6689         destroyPQExpBuffer(query);
6690
6691         return tblinfo;
6692 }
6693
6694 /*
6695  * getOwnedSeqs
6696  *        identify owned sequences and mark them as dumpable if owning table is
6697  *
6698  * We used to do this in getTables(), but it's better to do it after the
6699  * index used by findTableByOid() has been set up.
6700  */
6701 void
6702 getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
6703 {
6704         int                     i;
6705
6706         /*
6707          * Force sequences that are "owned" by table columns to be dumped whenever
6708          * their owning table is being dumped.
6709          */
6710         for (i = 0; i < numTables; i++)
6711         {
6712                 TableInfo  *seqinfo = &tblinfo[i];
6713                 TableInfo  *owning_tab;
6714
6715                 if (!OidIsValid(seqinfo->owning_tab))
6716                         continue;                       /* not an owned sequence */
6717
6718                 owning_tab = findTableByOid(seqinfo->owning_tab);
6719                 if (owning_tab == NULL)
6720                         exit_horribly(NULL, "failed sanity check, parent table with OID %u of sequence with OID %u not found\n",
6721                                                   seqinfo->owning_tab, seqinfo->dobj.catId.oid);
6722
6723                 /*
6724                  * Only dump identity sequences if we're going to dump the table that
6725                  * it belongs to.
6726                  */
6727                 if (owning_tab->dobj.dump == DUMP_COMPONENT_NONE &&
6728                         seqinfo->is_identity_sequence)
6729                 {
6730                         seqinfo->dobj.dump = DUMP_COMPONENT_NONE;
6731                         continue;
6732                 }
6733
6734                 /*
6735                  * Otherwise we need to dump the components that are being dumped for
6736                  * the table and any components which the sequence is explicitly
6737                  * marked with.
6738                  *
6739                  * We can't simply use the set of components which are being dumped
6740                  * for the table as the table might be in an extension (and only the
6741                  * non-extension components, eg: ACLs if changed, security labels, and
6742                  * policies, are being dumped) while the sequence is not (and
6743                  * therefore the definition and other components should also be
6744                  * dumped).
6745                  *
6746                  * If the sequence is part of the extension then it should be properly
6747                  * marked by checkExtensionMembership() and this will be a no-op as
6748                  * the table will be equivalently marked.
6749                  */
6750                 seqinfo->dobj.dump = seqinfo->dobj.dump | owning_tab->dobj.dump;
6751
6752                 if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
6753                         seqinfo->interesting = true;
6754         }
6755 }
6756
6757 /*
6758  * getInherits
6759  *        read all the inheritance information
6760  * from the system catalogs return them in the InhInfo* structure
6761  *
6762  * numInherits is set to the number of pairs read in
6763  */
6764 InhInfo *
6765 getInherits(Archive *fout, int *numInherits)
6766 {
6767         PGresult   *res;
6768         int                     ntups;
6769         int                     i;
6770         PQExpBuffer query = createPQExpBuffer();
6771         InhInfo    *inhinfo;
6772
6773         int                     i_inhrelid;
6774         int                     i_inhparent;
6775
6776         /*
6777          * Find all the inheritance information, excluding implicit inheritance
6778          * via partitioning.  We handle that case using getPartitions(), because
6779          * we want more information about partitions than just the parent-child
6780          * relationship.
6781          */
6782         appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
6783
6784         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6785
6786         ntups = PQntuples(res);
6787
6788         *numInherits = ntups;
6789
6790         inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
6791
6792         i_inhrelid = PQfnumber(res, "inhrelid");
6793         i_inhparent = PQfnumber(res, "inhparent");
6794
6795         for (i = 0; i < ntups; i++)
6796         {
6797                 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
6798                 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
6799         }
6800
6801         PQclear(res);
6802
6803         destroyPQExpBuffer(query);
6804
6805         return inhinfo;
6806 }
6807
6808 /*
6809  * getIndexes
6810  *        get information about every index on a dumpable table
6811  *
6812  * Note: index data is not returned directly to the caller, but it
6813  * does get entered into the DumpableObject tables.
6814  */
6815 void
6816 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
6817 {
6818         int                     i,
6819                                 j;
6820         PQExpBuffer query = createPQExpBuffer();
6821         PGresult   *res;
6822         IndxInfo   *indxinfo;
6823         ConstraintInfo *constrinfo;
6824         int                     i_tableoid,
6825                                 i_oid,
6826                                 i_indexname,
6827                                 i_parentidx,
6828                                 i_indexdef,
6829                                 i_indnkeyatts,
6830                                 i_indnatts,
6831                                 i_indkey,
6832                                 i_indisclustered,
6833                                 i_indisreplident,
6834                                 i_contype,
6835                                 i_conname,
6836                                 i_condeferrable,
6837                                 i_condeferred,
6838                                 i_contableoid,
6839                                 i_conoid,
6840                                 i_condef,
6841                                 i_tablespace,
6842                                 i_indreloptions,
6843                                 i_indstatcols,
6844                                 i_indstatvals;
6845         int                     ntups;
6846
6847         for (i = 0; i < numTables; i++)
6848         {
6849                 TableInfo  *tbinfo = &tblinfo[i];
6850
6851                 if (!tbinfo->hasindex)
6852                         continue;
6853
6854                 /*
6855                  * Ignore indexes of tables whose definitions are not to be dumped.
6856                  *
6857                  * We also need indexes on partitioned tables which have partitions to
6858                  * be dumped, in order to dump the indexes on the partitions.
6859                  */
6860                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION) &&
6861                         !tbinfo->interesting)
6862                         continue;
6863
6864                 if (g_verbose)
6865                         write_msg(NULL, "reading indexes for table \"%s.%s\"\n",
6866                                           tbinfo->dobj.namespace->dobj.name,
6867                                           tbinfo->dobj.name);
6868
6869                 /*
6870                  * The point of the messy-looking outer join is to find a constraint
6871                  * that is related by an internal dependency link to the index. If we
6872                  * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
6873                  * assume an index won't have more than one internal dependency.
6874                  *
6875                  * As of 9.0 we don't need to look at pg_depend but can check for a
6876                  * match to pg_constraint.conindid.  The check on conrelid is
6877                  * redundant but useful because that column is indexed while conindid
6878                  * is not.
6879                  */
6880                 resetPQExpBuffer(query);
6881                 if (fout->remoteVersion >= 110000)
6882                 {
6883                         appendPQExpBuffer(query,
6884                                                           "SELECT t.tableoid, t.oid, "
6885                                                           "t.relname AS indexname, "
6886                                                           "inh.inhparent AS parentidx, "
6887                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6888                                                           "i.indnkeyatts AS indnkeyatts, "
6889                                                           "i.indnatts AS indnatts, "
6890                                                           "i.indkey, i.indisclustered, "
6891                                                           "i.indisreplident, "
6892                                                           "c.contype, c.conname, "
6893                                                           "c.condeferrable, c.condeferred, "
6894                                                           "c.tableoid AS contableoid, "
6895                                                           "c.oid AS conoid, "
6896                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6897                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6898                                                           "t.reloptions AS indreloptions, "
6899                                                           "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
6900                                                           "  FROM pg_catalog.pg_attribute "
6901                                                           "  WHERE attrelid = i.indexrelid AND "
6902                                                           "    attstattarget >= 0) AS indstatcols,"
6903                                                           "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
6904                                                           "  FROM pg_catalog.pg_attribute "
6905                                                           "  WHERE attrelid = i.indexrelid AND "
6906                                                           "    attstattarget >= 0) AS indstatvals "
6907                                                           "FROM pg_catalog.pg_index i "
6908                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6909                                                           "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
6910                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6911                                                           "ON (i.indrelid = c.conrelid AND "
6912                                                           "i.indexrelid = c.conindid AND "
6913                                                           "c.contype IN ('p','u','x')) "
6914                                                           "LEFT JOIN pg_catalog.pg_inherits inh "
6915                                                           "ON (inh.inhrelid = indexrelid) "
6916                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6917                                                           "AND (i.indisvalid OR t2.relkind = 'p') "
6918                                                           "AND i.indisready "
6919                                                           "ORDER BY indexname",
6920                                                           tbinfo->dobj.catId.oid);
6921                 }
6922                 else if (fout->remoteVersion >= 90400)
6923                 {
6924                         /*
6925                          * the test on indisready is necessary in 9.2, and harmless in
6926                          * earlier/later versions
6927                          */
6928                         appendPQExpBuffer(query,
6929                                                           "SELECT t.tableoid, t.oid, "
6930                                                           "t.relname AS indexname, "
6931                                                           "0 AS parentidx, "
6932                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6933                                                           "i.indnatts AS indnkeyatts, "
6934                                                           "i.indnatts AS indnatts, "
6935                                                           "i.indkey, i.indisclustered, "
6936                                                           "i.indisreplident, "
6937                                                           "c.contype, c.conname, "
6938                                                           "c.condeferrable, c.condeferred, "
6939                                                           "c.tableoid AS contableoid, "
6940                                                           "c.oid AS conoid, "
6941                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6942                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6943                                                           "t.reloptions AS indreloptions, "
6944                                                           "'' AS indstatcols, "
6945                                                           "'' AS indstatvals "
6946                                                           "FROM pg_catalog.pg_index i "
6947                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6948                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6949                                                           "ON (i.indrelid = c.conrelid AND "
6950                                                           "i.indexrelid = c.conindid AND "
6951                                                           "c.contype IN ('p','u','x')) "
6952                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6953                                                           "AND i.indisvalid AND i.indisready "
6954                                                           "ORDER BY indexname",
6955                                                           tbinfo->dobj.catId.oid);
6956                 }
6957                 else if (fout->remoteVersion >= 90000)
6958                 {
6959                         /*
6960                          * the test on indisready is necessary in 9.2, and harmless in
6961                          * earlier/later versions
6962                          */
6963                         appendPQExpBuffer(query,
6964                                                           "SELECT t.tableoid, t.oid, "
6965                                                           "t.relname AS indexname, "
6966                                                           "0 AS parentidx, "
6967                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6968                                                           "i.indnatts AS indnkeyatts, "
6969                                                           "i.indnatts AS indnatts, "
6970                                                           "i.indkey, i.indisclustered, "
6971                                                           "false AS indisreplident, "
6972                                                           "c.contype, c.conname, "
6973                                                           "c.condeferrable, c.condeferred, "
6974                                                           "c.tableoid AS contableoid, "
6975                                                           "c.oid AS conoid, "
6976                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6977                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6978                                                           "t.reloptions AS indreloptions, "
6979                                                           "'' AS indstatcols, "
6980                                                           "'' AS indstatvals "
6981                                                           "FROM pg_catalog.pg_index i "
6982                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6983                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6984                                                           "ON (i.indrelid = c.conrelid AND "
6985                                                           "i.indexrelid = c.conindid AND "
6986                                                           "c.contype IN ('p','u','x')) "
6987                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6988                                                           "AND i.indisvalid AND i.indisready "
6989                                                           "ORDER BY indexname",
6990                                                           tbinfo->dobj.catId.oid);
6991                 }
6992                 else if (fout->remoteVersion >= 80200)
6993                 {
6994                         appendPQExpBuffer(query,
6995                                                           "SELECT t.tableoid, t.oid, "
6996                                                           "t.relname AS indexname, "
6997                                                           "0 AS parentidx, "
6998                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6999                                                           "i.indnatts AS indnkeyatts, "
7000                                                           "i.indnatts AS indnatts, "
7001                                                           "i.indkey, i.indisclustered, "
7002                                                           "false AS indisreplident, "
7003                                                           "c.contype, c.conname, "
7004                                                           "c.condeferrable, c.condeferred, "
7005                                                           "c.tableoid AS contableoid, "
7006                                                           "c.oid AS conoid, "
7007                                                           "null AS condef, "
7008                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
7009                                                           "t.reloptions AS indreloptions, "
7010                                                           "'' AS indstatcols, "
7011                                                           "'' AS indstatvals "
7012                                                           "FROM pg_catalog.pg_index i "
7013                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
7014                                                           "LEFT JOIN pg_catalog.pg_depend d "
7015                                                           "ON (d.classid = t.tableoid "
7016                                                           "AND d.objid = t.oid "
7017                                                           "AND d.deptype = 'i') "
7018                                                           "LEFT JOIN pg_catalog.pg_constraint c "
7019                                                           "ON (d.refclassid = c.tableoid "
7020                                                           "AND d.refobjid = c.oid) "
7021                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
7022                                                           "AND i.indisvalid "
7023                                                           "ORDER BY indexname",
7024                                                           tbinfo->dobj.catId.oid);
7025                 }
7026                 else
7027                 {
7028                         appendPQExpBuffer(query,
7029                                                           "SELECT t.tableoid, t.oid, "
7030                                                           "t.relname AS indexname, "
7031                                                           "0 AS parentidx, "
7032                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
7033                                                           "t.relnatts AS indnkeyatts, "
7034                                                           "t.relnatts AS indnatts, "
7035                                                           "i.indkey, i.indisclustered, "
7036                                                           "false AS indisreplident, "
7037                                                           "c.contype, c.conname, "
7038                                                           "c.condeferrable, c.condeferred, "
7039                                                           "c.tableoid AS contableoid, "
7040                                                           "c.oid AS conoid, "
7041                                                           "null AS condef, "
7042                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
7043                                                           "null AS indreloptions, "
7044                                                           "'' AS indstatcols, "
7045                                                           "'' AS indstatvals "
7046                                                           "FROM pg_catalog.pg_index i "
7047                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
7048                                                           "LEFT JOIN pg_catalog.pg_depend d "
7049                                                           "ON (d.classid = t.tableoid "
7050                                                           "AND d.objid = t.oid "
7051                                                           "AND d.deptype = 'i') "
7052                                                           "LEFT JOIN pg_catalog.pg_constraint c "
7053                                                           "ON (d.refclassid = c.tableoid "
7054                                                           "AND d.refobjid = c.oid) "
7055                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
7056                                                           "ORDER BY indexname",
7057                                                           tbinfo->dobj.catId.oid);
7058                 }
7059
7060                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7061
7062                 ntups = PQntuples(res);
7063
7064                 i_tableoid = PQfnumber(res, "tableoid");
7065                 i_oid = PQfnumber(res, "oid");
7066                 i_indexname = PQfnumber(res, "indexname");
7067                 i_parentidx = PQfnumber(res, "parentidx");
7068                 i_indexdef = PQfnumber(res, "indexdef");
7069                 i_indnkeyatts = PQfnumber(res, "indnkeyatts");
7070                 i_indnatts = PQfnumber(res, "indnatts");
7071                 i_indkey = PQfnumber(res, "indkey");
7072                 i_indisclustered = PQfnumber(res, "indisclustered");
7073                 i_indisreplident = PQfnumber(res, "indisreplident");
7074                 i_contype = PQfnumber(res, "contype");
7075                 i_conname = PQfnumber(res, "conname");
7076                 i_condeferrable = PQfnumber(res, "condeferrable");
7077                 i_condeferred = PQfnumber(res, "condeferred");
7078                 i_contableoid = PQfnumber(res, "contableoid");
7079                 i_conoid = PQfnumber(res, "conoid");
7080                 i_condef = PQfnumber(res, "condef");
7081                 i_tablespace = PQfnumber(res, "tablespace");
7082                 i_indreloptions = PQfnumber(res, "indreloptions");
7083                 i_indstatcols = PQfnumber(res, "indstatcols");
7084                 i_indstatvals = PQfnumber(res, "indstatvals");
7085
7086                 tbinfo->indexes = indxinfo =
7087                         (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
7088                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7089                 tbinfo->numIndexes = ntups;
7090
7091                 for (j = 0; j < ntups; j++)
7092                 {
7093                         char            contype;
7094
7095                         indxinfo[j].dobj.objType = DO_INDEX;
7096                         indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
7097                         indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7098                         AssignDumpId(&indxinfo[j].dobj);
7099                         indxinfo[j].dobj.dump = tbinfo->dobj.dump;
7100                         indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
7101                         indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7102                         indxinfo[j].indextable = tbinfo;
7103                         indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
7104                         indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
7105                         indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
7106                         indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
7107                         indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
7108                         indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
7109                         indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
7110                         indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
7111                         parseOidArray(PQgetvalue(res, j, i_indkey),
7112                                                   indxinfo[j].indkeys, indxinfo[j].indnattrs);
7113                         indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
7114                         indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
7115                         indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
7116                         contype = *(PQgetvalue(res, j, i_contype));
7117
7118                         if (contype == 'p' || contype == 'u' || contype == 'x')
7119                         {
7120                                 /*
7121                                  * If we found a constraint matching the index, create an
7122                                  * entry for it.
7123                                  */
7124                                 constrinfo[j].dobj.objType = DO_CONSTRAINT;
7125                                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7126                                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7127                                 AssignDumpId(&constrinfo[j].dobj);
7128                                 constrinfo[j].dobj.dump = tbinfo->dobj.dump;
7129                                 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7130                                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7131                                 constrinfo[j].contable = tbinfo;
7132                                 constrinfo[j].condomain = NULL;
7133                                 constrinfo[j].contype = contype;
7134                                 if (contype == 'x')
7135                                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
7136                                 else
7137                                         constrinfo[j].condef = NULL;
7138                                 constrinfo[j].confrelid = InvalidOid;
7139                                 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
7140                                 constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
7141                                 constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
7142                                 constrinfo[j].conislocal = true;
7143                                 constrinfo[j].separate = true;
7144
7145                                 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
7146                         }
7147                         else
7148                         {
7149                                 /* Plain secondary index */
7150                                 indxinfo[j].indexconstraint = 0;
7151                         }
7152                 }
7153
7154                 PQclear(res);
7155         }
7156
7157         destroyPQExpBuffer(query);
7158 }
7159
7160 /*
7161  * getExtendedStatistics
7162  *        get information about extended-statistics objects.
7163  *
7164  * Note: extended statistics data is not returned directly to the caller, but
7165  * it does get entered into the DumpableObject tables.
7166  */
7167 void
7168 getExtendedStatistics(Archive *fout)
7169 {
7170         PQExpBuffer query;
7171         PGresult   *res;
7172         StatsExtInfo *statsextinfo;
7173         int                     ntups;
7174         int                     i_tableoid;
7175         int                     i_oid;
7176         int                     i_stxname;
7177         int                     i_stxnamespace;
7178         int                     i_rolname;
7179         int                     i;
7180
7181         /* Extended statistics were new in v10 */
7182         if (fout->remoteVersion < 100000)
7183                 return;
7184
7185         query = createPQExpBuffer();
7186
7187         appendPQExpBuffer(query, "SELECT tableoid, oid, stxname, "
7188                                           "stxnamespace, (%s stxowner) AS rolname "
7189                                           "FROM pg_catalog.pg_statistic_ext",
7190                                           username_subquery);
7191
7192         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7193
7194         ntups = PQntuples(res);
7195
7196         i_tableoid = PQfnumber(res, "tableoid");
7197         i_oid = PQfnumber(res, "oid");
7198         i_stxname = PQfnumber(res, "stxname");
7199         i_stxnamespace = PQfnumber(res, "stxnamespace");
7200         i_rolname = PQfnumber(res, "rolname");
7201
7202         statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
7203
7204         for (i = 0; i < ntups; i++)
7205         {
7206                 statsextinfo[i].dobj.objType = DO_STATSEXT;
7207                 statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7208                 statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7209                 AssignDumpId(&statsextinfo[i].dobj);
7210                 statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
7211                 statsextinfo[i].dobj.namespace =
7212                         findNamespace(fout,
7213                                                   atooid(PQgetvalue(res, i, i_stxnamespace)));
7214                 statsextinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7215
7216                 /* Decide whether we want to dump it */
7217                 selectDumpableObject(&(statsextinfo[i].dobj), fout);
7218
7219                 /* Stats objects do not currently have ACLs. */
7220                 statsextinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7221         }
7222
7223         PQclear(res);
7224         destroyPQExpBuffer(query);
7225 }
7226
7227 /*
7228  * getConstraints
7229  *
7230  * Get info about constraints on dumpable tables.
7231  *
7232  * Currently handles foreign keys only.
7233  * Unique and primary key constraints are handled with indexes,
7234  * while check constraints are processed in getTableAttrs().
7235  */
7236 void
7237 getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
7238 {
7239         int                     i,
7240                                 j;
7241         ConstraintInfo *constrinfo;
7242         PQExpBuffer query;
7243         PGresult   *res;
7244         int                     i_contableoid,
7245                                 i_conoid,
7246                                 i_conname,
7247                                 i_confrelid,
7248                                 i_condef;
7249         int                     ntups;
7250
7251         query = createPQExpBuffer();
7252
7253         for (i = 0; i < numTables; i++)
7254         {
7255                 TableInfo  *tbinfo = &tblinfo[i];
7256
7257                 /*
7258                  * For partitioned tables, foreign keys have no triggers so they must
7259                  * be included anyway in case some foreign keys are defined.
7260                  */
7261                 if ((!tbinfo->hastriggers &&
7262                          tbinfo->relkind != RELKIND_PARTITIONED_TABLE) ||
7263                         !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7264                         continue;
7265
7266                 if (g_verbose)
7267                         write_msg(NULL, "reading foreign key constraints for table \"%s.%s\"\n",
7268                                           tbinfo->dobj.namespace->dobj.name,
7269                                           tbinfo->dobj.name);
7270
7271                 resetPQExpBuffer(query);
7272                 if (fout->remoteVersion >= 110000)
7273                         appendPQExpBuffer(query,
7274                                                           "SELECT tableoid, oid, conname, confrelid, "
7275                                                           "pg_catalog.pg_get_constraintdef(oid) AS condef "
7276                                                           "FROM pg_catalog.pg_constraint "
7277                                                           "WHERE conrelid = '%u'::pg_catalog.oid "
7278                                                           "AND conparentid = 0 "
7279                                                           "AND contype = 'f'",
7280                                                           tbinfo->dobj.catId.oid);
7281                 else
7282                         appendPQExpBuffer(query,
7283                                                           "SELECT tableoid, oid, conname, confrelid, "
7284                                                           "pg_catalog.pg_get_constraintdef(oid) AS condef "
7285                                                           "FROM pg_catalog.pg_constraint "
7286                                                           "WHERE conrelid = '%u'::pg_catalog.oid "
7287                                                           "AND contype = 'f'",
7288                                                           tbinfo->dobj.catId.oid);
7289                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7290
7291                 ntups = PQntuples(res);
7292
7293                 i_contableoid = PQfnumber(res, "tableoid");
7294                 i_conoid = PQfnumber(res, "oid");
7295                 i_conname = PQfnumber(res, "conname");
7296                 i_confrelid = PQfnumber(res, "confrelid");
7297                 i_condef = PQfnumber(res, "condef");
7298
7299                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7300
7301                 for (j = 0; j < ntups; j++)
7302                 {
7303                         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
7304                         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7305                         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7306                         AssignDumpId(&constrinfo[j].dobj);
7307                         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7308                         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7309                         constrinfo[j].contable = tbinfo;
7310                         constrinfo[j].condomain = NULL;
7311                         constrinfo[j].contype = 'f';
7312                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
7313                         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
7314                         constrinfo[j].conindex = 0;
7315                         constrinfo[j].condeferrable = false;
7316                         constrinfo[j].condeferred = false;
7317                         constrinfo[j].conislocal = true;
7318                         constrinfo[j].separate = true;
7319                 }
7320
7321                 PQclear(res);
7322         }
7323
7324         destroyPQExpBuffer(query);
7325 }
7326
7327 /*
7328  * getDomainConstraints
7329  *
7330  * Get info about constraints on a domain.
7331  */
7332 static void
7333 getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
7334 {
7335         int                     i;
7336         ConstraintInfo *constrinfo;
7337         PQExpBuffer query;
7338         PGresult   *res;
7339         int                     i_tableoid,
7340                                 i_oid,
7341                                 i_conname,
7342                                 i_consrc;
7343         int                     ntups;
7344
7345         query = createPQExpBuffer();
7346
7347         if (fout->remoteVersion >= 90100)
7348                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
7349                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7350                                                   "convalidated "
7351                                                   "FROM pg_catalog.pg_constraint "
7352                                                   "WHERE contypid = '%u'::pg_catalog.oid "
7353                                                   "ORDER BY conname",
7354                                                   tyinfo->dobj.catId.oid);
7355
7356         else
7357                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
7358                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7359                                                   "true as convalidated "
7360                                                   "FROM pg_catalog.pg_constraint "
7361                                                   "WHERE contypid = '%u'::pg_catalog.oid "
7362                                                   "ORDER BY conname",
7363                                                   tyinfo->dobj.catId.oid);
7364
7365         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7366
7367         ntups = PQntuples(res);
7368
7369         i_tableoid = PQfnumber(res, "tableoid");
7370         i_oid = PQfnumber(res, "oid");
7371         i_conname = PQfnumber(res, "conname");
7372         i_consrc = PQfnumber(res, "consrc");
7373
7374         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7375
7376         tyinfo->nDomChecks = ntups;
7377         tyinfo->domChecks = constrinfo;
7378
7379         for (i = 0; i < ntups; i++)
7380         {
7381                 bool            validated = PQgetvalue(res, i, 4)[0] == 't';
7382
7383                 constrinfo[i].dobj.objType = DO_CONSTRAINT;
7384                 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7385                 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7386                 AssignDumpId(&constrinfo[i].dobj);
7387                 constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
7388                 constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
7389                 constrinfo[i].contable = NULL;
7390                 constrinfo[i].condomain = tyinfo;
7391                 constrinfo[i].contype = 'c';
7392                 constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
7393                 constrinfo[i].confrelid = InvalidOid;
7394                 constrinfo[i].conindex = 0;
7395                 constrinfo[i].condeferrable = false;
7396                 constrinfo[i].condeferred = false;
7397                 constrinfo[i].conislocal = true;
7398
7399                 constrinfo[i].separate = !validated;
7400
7401                 /*
7402                  * Make the domain depend on the constraint, ensuring it won't be
7403                  * output till any constraint dependencies are OK.  If the constraint
7404                  * has not been validated, it's going to be dumped after the domain
7405                  * anyway, so this doesn't matter.
7406                  */
7407                 if (validated)
7408                         addObjectDependency(&tyinfo->dobj,
7409                                                                 constrinfo[i].dobj.dumpId);
7410         }
7411
7412         PQclear(res);
7413
7414         destroyPQExpBuffer(query);
7415 }
7416
7417 /*
7418  * getRules
7419  *        get basic information about every rule in the system
7420  *
7421  * numRules is set to the number of rules read in
7422  */
7423 RuleInfo *
7424 getRules(Archive *fout, int *numRules)
7425 {
7426         PGresult   *res;
7427         int                     ntups;
7428         int                     i;
7429         PQExpBuffer query = createPQExpBuffer();
7430         RuleInfo   *ruleinfo;
7431         int                     i_tableoid;
7432         int                     i_oid;
7433         int                     i_rulename;
7434         int                     i_ruletable;
7435         int                     i_ev_type;
7436         int                     i_is_instead;
7437         int                     i_ev_enabled;
7438
7439         if (fout->remoteVersion >= 80300)
7440         {
7441                 appendPQExpBufferStr(query, "SELECT "
7442                                                          "tableoid, oid, rulename, "
7443                                                          "ev_class AS ruletable, ev_type, is_instead, "
7444                                                          "ev_enabled "
7445                                                          "FROM pg_rewrite "
7446                                                          "ORDER BY oid");
7447         }
7448         else
7449         {
7450                 appendPQExpBufferStr(query, "SELECT "
7451                                                          "tableoid, oid, rulename, "
7452                                                          "ev_class AS ruletable, ev_type, is_instead, "
7453                                                          "'O'::char AS ev_enabled "
7454                                                          "FROM pg_rewrite "
7455                                                          "ORDER BY oid");
7456         }
7457
7458         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7459
7460         ntups = PQntuples(res);
7461
7462         *numRules = ntups;
7463
7464         ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
7465
7466         i_tableoid = PQfnumber(res, "tableoid");
7467         i_oid = PQfnumber(res, "oid");
7468         i_rulename = PQfnumber(res, "rulename");
7469         i_ruletable = PQfnumber(res, "ruletable");
7470         i_ev_type = PQfnumber(res, "ev_type");
7471         i_is_instead = PQfnumber(res, "is_instead");
7472         i_ev_enabled = PQfnumber(res, "ev_enabled");
7473
7474         for (i = 0; i < ntups; i++)
7475         {
7476                 Oid                     ruletableoid;
7477
7478                 ruleinfo[i].dobj.objType = DO_RULE;
7479                 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7480                 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7481                 AssignDumpId(&ruleinfo[i].dobj);
7482                 ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
7483                 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
7484                 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
7485                 if (ruleinfo[i].ruletable == NULL)
7486                         exit_horribly(NULL, "failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found\n",
7487                                                   ruletableoid, ruleinfo[i].dobj.catId.oid);
7488                 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
7489                 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
7490                 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
7491                 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
7492                 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
7493                 if (ruleinfo[i].ruletable)
7494                 {
7495                         /*
7496                          * If the table is a view or materialized view, force its ON
7497                          * SELECT rule to be sorted before the view itself --- this
7498                          * ensures that any dependencies for the rule affect the table's
7499                          * positioning. Other rules are forced to appear after their
7500                          * table.
7501                          */
7502                         if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
7503                                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
7504                                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
7505                         {
7506                                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
7507                                                                         ruleinfo[i].dobj.dumpId);
7508                                 /* We'll merge the rule into CREATE VIEW, if possible */
7509                                 ruleinfo[i].separate = false;
7510                         }
7511                         else
7512                         {
7513                                 addObjectDependency(&ruleinfo[i].dobj,
7514                                                                         ruleinfo[i].ruletable->dobj.dumpId);
7515                                 ruleinfo[i].separate = true;
7516                         }
7517                 }
7518                 else
7519                         ruleinfo[i].separate = true;
7520         }
7521
7522         PQclear(res);
7523
7524         destroyPQExpBuffer(query);
7525
7526         return ruleinfo;
7527 }
7528
7529 /*
7530  * getTriggers
7531  *        get information about every trigger on a dumpable table
7532  *
7533  * Note: trigger data is not returned directly to the caller, but it
7534  * does get entered into the DumpableObject tables.
7535  */
7536 void
7537 getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
7538 {
7539         int                     i,
7540                                 j;
7541         PQExpBuffer query = createPQExpBuffer();
7542         PGresult   *res;
7543         TriggerInfo *tginfo;
7544         int                     i_tableoid,
7545                                 i_oid,
7546                                 i_tgname,
7547                                 i_tgfname,
7548                                 i_tgtype,
7549                                 i_tgnargs,
7550                                 i_tgargs,
7551                                 i_tgisconstraint,
7552                                 i_tgconstrname,
7553                                 i_tgconstrrelid,
7554                                 i_tgconstrrelname,
7555                                 i_tgenabled,
7556                                 i_tgdeferrable,
7557                                 i_tginitdeferred,
7558                                 i_tgdef;
7559         int                     ntups;
7560
7561         for (i = 0; i < numTables; i++)
7562         {
7563                 TableInfo  *tbinfo = &tblinfo[i];
7564
7565                 if (!tbinfo->hastriggers ||
7566                         !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7567                         continue;
7568
7569                 if (g_verbose)
7570                         write_msg(NULL, "reading triggers for table \"%s.%s\"\n",
7571                                           tbinfo->dobj.namespace->dobj.name,
7572                                           tbinfo->dobj.name);
7573
7574                 resetPQExpBuffer(query);
7575                 if (fout->remoteVersion >= 90000)
7576                 {
7577                         /*
7578                          * NB: think not to use pretty=true in pg_get_triggerdef.  It
7579                          * could result in non-forward-compatible dumps of WHEN clauses
7580                          * due to under-parenthesization.
7581                          */
7582                         appendPQExpBuffer(query,
7583                                                           "SELECT tgname, "
7584                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7585                                                           "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
7586                                                           "tgenabled, tableoid, oid "
7587                                                           "FROM pg_catalog.pg_trigger t "
7588                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7589                                                           "AND NOT tgisinternal",
7590                                                           tbinfo->dobj.catId.oid);
7591                 }
7592                 else if (fout->remoteVersion >= 80300)
7593                 {
7594                         /*
7595                          * We ignore triggers that are tied to a foreign-key constraint
7596                          */
7597                         appendPQExpBuffer(query,
7598                                                           "SELECT tgname, "
7599                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7600                                                           "tgtype, tgnargs, tgargs, tgenabled, "
7601                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
7602                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
7603                                                           "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
7604                                                           "FROM pg_catalog.pg_trigger t "
7605                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7606                                                           "AND tgconstraint = 0",
7607                                                           tbinfo->dobj.catId.oid);
7608                 }
7609                 else
7610                 {
7611                         /*
7612                          * We ignore triggers that are tied to a foreign-key constraint,
7613                          * but in these versions we have to grovel through pg_constraint
7614                          * to find out
7615                          */
7616                         appendPQExpBuffer(query,
7617                                                           "SELECT tgname, "
7618                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7619                                                           "tgtype, tgnargs, tgargs, tgenabled, "
7620                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
7621                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
7622                                                           "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
7623                                                           "FROM pg_catalog.pg_trigger t "
7624                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7625                                                           "AND (NOT tgisconstraint "
7626                                                           " OR NOT EXISTS"
7627                                                           "  (SELECT 1 FROM pg_catalog.pg_depend d "
7628                                                           "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
7629                                                           "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
7630                                                           tbinfo->dobj.catId.oid);
7631                 }
7632
7633                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7634
7635                 ntups = PQntuples(res);
7636
7637                 i_tableoid = PQfnumber(res, "tableoid");
7638                 i_oid = PQfnumber(res, "oid");
7639                 i_tgname = PQfnumber(res, "tgname");
7640                 i_tgfname = PQfnumber(res, "tgfname");
7641                 i_tgtype = PQfnumber(res, "tgtype");
7642                 i_tgnargs = PQfnumber(res, "tgnargs");
7643                 i_tgargs = PQfnumber(res, "tgargs");
7644                 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
7645                 i_tgconstrname = PQfnumber(res, "tgconstrname");
7646                 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
7647                 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
7648                 i_tgenabled = PQfnumber(res, "tgenabled");
7649                 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
7650                 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
7651                 i_tgdef = PQfnumber(res, "tgdef");
7652
7653                 tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
7654
7655                 tbinfo->numTriggers = ntups;
7656                 tbinfo->triggers = tginfo;
7657
7658                 for (j = 0; j < ntups; j++)
7659                 {
7660                         tginfo[j].dobj.objType = DO_TRIGGER;
7661                         tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
7662                         tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7663                         AssignDumpId(&tginfo[j].dobj);
7664                         tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
7665                         tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
7666                         tginfo[j].tgtable = tbinfo;
7667                         tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
7668                         if (i_tgdef >= 0)
7669                         {
7670                                 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
7671
7672                                 /* remaining fields are not valid if we have tgdef */
7673                                 tginfo[j].tgfname = NULL;
7674                                 tginfo[j].tgtype = 0;
7675                                 tginfo[j].tgnargs = 0;
7676                                 tginfo[j].tgargs = NULL;
7677                                 tginfo[j].tgisconstraint = false;
7678                                 tginfo[j].tgdeferrable = false;
7679                                 tginfo[j].tginitdeferred = false;
7680                                 tginfo[j].tgconstrname = NULL;
7681                                 tginfo[j].tgconstrrelid = InvalidOid;
7682                                 tginfo[j].tgconstrrelname = NULL;
7683                         }
7684                         else
7685                         {
7686                                 tginfo[j].tgdef = NULL;
7687
7688                                 tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
7689                                 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
7690                                 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
7691                                 tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
7692                                 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
7693                                 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
7694                                 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
7695
7696                                 if (tginfo[j].tgisconstraint)
7697                                 {
7698                                         tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
7699                                         tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
7700                                         if (OidIsValid(tginfo[j].tgconstrrelid))
7701                                         {
7702                                                 if (PQgetisnull(res, j, i_tgconstrrelname))
7703                                                         exit_horribly(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
7704                                                                                   tginfo[j].dobj.name,
7705                                                                                   tbinfo->dobj.name,
7706                                                                                   tginfo[j].tgconstrrelid);
7707                                                 tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
7708                                         }
7709                                         else
7710                                                 tginfo[j].tgconstrrelname = NULL;
7711                                 }
7712                                 else
7713                                 {
7714                                         tginfo[j].tgconstrname = NULL;
7715                                         tginfo[j].tgconstrrelid = InvalidOid;
7716                                         tginfo[j].tgconstrrelname = NULL;
7717                                 }
7718                         }
7719                 }
7720
7721                 PQclear(res);
7722         }
7723
7724         destroyPQExpBuffer(query);
7725 }
7726
7727 /*
7728  * getEventTriggers
7729  *        get information about event triggers
7730  */
7731 EventTriggerInfo *
7732 getEventTriggers(Archive *fout, int *numEventTriggers)
7733 {
7734         int                     i;
7735         PQExpBuffer query;
7736         PGresult   *res;
7737         EventTriggerInfo *evtinfo;
7738         int                     i_tableoid,
7739                                 i_oid,
7740                                 i_evtname,
7741                                 i_evtevent,
7742                                 i_evtowner,
7743                                 i_evttags,
7744                                 i_evtfname,
7745                                 i_evtenabled;
7746         int                     ntups;
7747
7748         /* Before 9.3, there are no event triggers */
7749         if (fout->remoteVersion < 90300)
7750         {
7751                 *numEventTriggers = 0;
7752                 return NULL;
7753         }
7754
7755         query = createPQExpBuffer();
7756
7757         appendPQExpBuffer(query,
7758                                           "SELECT e.tableoid, e.oid, evtname, evtenabled, "
7759                                           "evtevent, (%s evtowner) AS evtowner, "
7760                                           "array_to_string(array("
7761                                           "select quote_literal(x) "
7762                                           " from unnest(evttags) as t(x)), ', ') as evttags, "
7763                                           "e.evtfoid::regproc as evtfname "
7764                                           "FROM pg_event_trigger e "
7765                                           "ORDER BY e.oid",
7766                                           username_subquery);
7767
7768         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7769
7770         ntups = PQntuples(res);
7771
7772         *numEventTriggers = ntups;
7773
7774         evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
7775
7776         i_tableoid = PQfnumber(res, "tableoid");
7777         i_oid = PQfnumber(res, "oid");
7778         i_evtname = PQfnumber(res, "evtname");
7779         i_evtevent = PQfnumber(res, "evtevent");
7780         i_evtowner = PQfnumber(res, "evtowner");
7781         i_evttags = PQfnumber(res, "evttags");
7782         i_evtfname = PQfnumber(res, "evtfname");
7783         i_evtenabled = PQfnumber(res, "evtenabled");
7784
7785         for (i = 0; i < ntups; i++)
7786         {
7787                 evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
7788                 evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7789                 evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7790                 AssignDumpId(&evtinfo[i].dobj);
7791                 evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
7792                 evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
7793                 evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
7794                 evtinfo[i].evtowner = pg_strdup(PQgetvalue(res, i, i_evtowner));
7795                 evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
7796                 evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
7797                 evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
7798
7799                 /* Decide whether we want to dump it */
7800                 selectDumpableObject(&(evtinfo[i].dobj), fout);
7801
7802                 /* Event Triggers do not currently have ACLs. */
7803                 evtinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7804         }
7805
7806         PQclear(res);
7807
7808         destroyPQExpBuffer(query);
7809
7810         return evtinfo;
7811 }
7812
7813 /*
7814  * getProcLangs
7815  *        get basic information about every procedural language in the system
7816  *
7817  * numProcLangs is set to the number of langs read in
7818  *
7819  * NB: this must run after getFuncs() because we assume we can do
7820  * findFuncByOid().
7821  */
7822 ProcLangInfo *
7823 getProcLangs(Archive *fout, int *numProcLangs)
7824 {
7825         DumpOptions *dopt = fout->dopt;
7826         PGresult   *res;
7827         int                     ntups;
7828         int                     i;
7829         PQExpBuffer query = createPQExpBuffer();
7830         ProcLangInfo *planginfo;
7831         int                     i_tableoid;
7832         int                     i_oid;
7833         int                     i_lanname;
7834         int                     i_lanpltrusted;
7835         int                     i_lanplcallfoid;
7836         int                     i_laninline;
7837         int                     i_lanvalidator;
7838         int                     i_lanacl;
7839         int                     i_rlanacl;
7840         int                     i_initlanacl;
7841         int                     i_initrlanacl;
7842         int                     i_lanowner;
7843
7844         if (fout->remoteVersion >= 90600)
7845         {
7846                 PQExpBuffer acl_subquery = createPQExpBuffer();
7847                 PQExpBuffer racl_subquery = createPQExpBuffer();
7848                 PQExpBuffer initacl_subquery = createPQExpBuffer();
7849                 PQExpBuffer initracl_subquery = createPQExpBuffer();
7850
7851                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
7852                                                 initracl_subquery, "l.lanacl", "l.lanowner", "'l'",
7853                                                 dopt->binary_upgrade);
7854
7855                 /* pg_language has a laninline column */
7856                 appendPQExpBuffer(query, "SELECT l.tableoid, l.oid, "
7857                                                   "l.lanname, l.lanpltrusted, l.lanplcallfoid, "
7858                                                   "l.laninline, l.lanvalidator, "
7859                                                   "%s AS lanacl, "
7860                                                   "%s AS rlanacl, "
7861                                                   "%s AS initlanacl, "
7862                                                   "%s AS initrlanacl, "
7863                                                   "(%s l.lanowner) AS lanowner "
7864                                                   "FROM pg_language l "
7865                                                   "LEFT JOIN pg_init_privs pip ON "
7866                                                   "(l.oid = pip.objoid "
7867                                                   "AND pip.classoid = 'pg_language'::regclass "
7868                                                   "AND pip.objsubid = 0) "
7869                                                   "WHERE l.lanispl "
7870                                                   "ORDER BY l.oid",
7871                                                   acl_subquery->data,
7872                                                   racl_subquery->data,
7873                                                   initacl_subquery->data,
7874                                                   initracl_subquery->data,
7875                                                   username_subquery);
7876
7877                 destroyPQExpBuffer(acl_subquery);
7878                 destroyPQExpBuffer(racl_subquery);
7879                 destroyPQExpBuffer(initacl_subquery);
7880                 destroyPQExpBuffer(initracl_subquery);
7881         }
7882         else if (fout->remoteVersion >= 90000)
7883         {
7884                 /* pg_language has a laninline column */
7885                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7886                                                   "lanname, lanpltrusted, lanplcallfoid, "
7887                                                   "laninline, lanvalidator, lanacl, NULL AS rlanacl, "
7888                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7889                                                   "(%s lanowner) AS lanowner "
7890                                                   "FROM pg_language "
7891                                                   "WHERE lanispl "
7892                                                   "ORDER BY oid",
7893                                                   username_subquery);
7894         }
7895         else if (fout->remoteVersion >= 80300)
7896         {
7897                 /* pg_language has a lanowner column */
7898                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7899                                                   "lanname, lanpltrusted, lanplcallfoid, "
7900                                                   "0 AS laninline, lanvalidator, lanacl, "
7901                                                   "NULL AS rlanacl, "
7902                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7903                                                   "(%s lanowner) AS lanowner "
7904                                                   "FROM pg_language "
7905                                                   "WHERE lanispl "
7906                                                   "ORDER BY oid",
7907                                                   username_subquery);
7908         }
7909         else if (fout->remoteVersion >= 80100)
7910         {
7911                 /* Languages are owned by the bootstrap superuser, OID 10 */
7912                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7913                                                   "lanname, lanpltrusted, lanplcallfoid, "
7914                                                   "0 AS laninline, lanvalidator, lanacl, "
7915                                                   "NULL AS rlanacl, "
7916                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7917                                                   "(%s '10') AS lanowner "
7918                                                   "FROM pg_language "
7919                                                   "WHERE lanispl "
7920                                                   "ORDER BY oid",
7921                                                   username_subquery);
7922         }
7923         else
7924         {
7925                 /* Languages are owned by the bootstrap superuser, sysid 1 */
7926                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7927                                                   "lanname, lanpltrusted, lanplcallfoid, "
7928                                                   "0 AS laninline, lanvalidator, lanacl, "
7929                                                   "NULL AS rlanacl, "
7930                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7931                                                   "(%s '1') AS lanowner "
7932                                                   "FROM pg_language "
7933                                                   "WHERE lanispl "
7934                                                   "ORDER BY oid",
7935                                                   username_subquery);
7936         }
7937
7938         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7939
7940         ntups = PQntuples(res);
7941
7942         *numProcLangs = ntups;
7943
7944         planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
7945
7946         i_tableoid = PQfnumber(res, "tableoid");
7947         i_oid = PQfnumber(res, "oid");
7948         i_lanname = PQfnumber(res, "lanname");
7949         i_lanpltrusted = PQfnumber(res, "lanpltrusted");
7950         i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
7951         i_laninline = PQfnumber(res, "laninline");
7952         i_lanvalidator = PQfnumber(res, "lanvalidator");
7953         i_lanacl = PQfnumber(res, "lanacl");
7954         i_rlanacl = PQfnumber(res, "rlanacl");
7955         i_initlanacl = PQfnumber(res, "initlanacl");
7956         i_initrlanacl = PQfnumber(res, "initrlanacl");
7957         i_lanowner = PQfnumber(res, "lanowner");
7958
7959         for (i = 0; i < ntups; i++)
7960         {
7961                 planginfo[i].dobj.objType = DO_PROCLANG;
7962                 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7963                 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7964                 AssignDumpId(&planginfo[i].dobj);
7965
7966                 planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
7967                 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
7968                 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
7969                 planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
7970                 planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
7971                 planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
7972                 planginfo[i].rlanacl = pg_strdup(PQgetvalue(res, i, i_rlanacl));
7973                 planginfo[i].initlanacl = pg_strdup(PQgetvalue(res, i, i_initlanacl));
7974                 planginfo[i].initrlanacl = pg_strdup(PQgetvalue(res, i, i_initrlanacl));
7975                 planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
7976
7977                 /* Decide whether we want to dump it */
7978                 selectDumpableProcLang(&(planginfo[i]), fout);
7979
7980                 /* Do not try to dump ACL if no ACL exists. */
7981                 if (PQgetisnull(res, i, i_lanacl) && PQgetisnull(res, i, i_rlanacl) &&
7982                         PQgetisnull(res, i, i_initlanacl) &&
7983                         PQgetisnull(res, i, i_initrlanacl))
7984                         planginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7985         }
7986
7987         PQclear(res);
7988
7989         destroyPQExpBuffer(query);
7990
7991         return planginfo;
7992 }
7993
7994 /*
7995  * getCasts
7996  *        get basic information about every cast in the system
7997  *
7998  * numCasts is set to the number of casts read in
7999  */
8000 CastInfo *
8001 getCasts(Archive *fout, int *numCasts)
8002 {
8003         PGresult   *res;
8004         int                     ntups;
8005         int                     i;
8006         PQExpBuffer query = createPQExpBuffer();
8007         CastInfo   *castinfo;
8008         int                     i_tableoid;
8009         int                     i_oid;
8010         int                     i_castsource;
8011         int                     i_casttarget;
8012         int                     i_castfunc;
8013         int                     i_castcontext;
8014         int                     i_castmethod;
8015
8016         if (fout->remoteVersion >= 80400)
8017         {
8018                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8019                                                          "castsource, casttarget, castfunc, castcontext, "
8020                                                          "castmethod "
8021                                                          "FROM pg_cast ORDER BY 3,4");
8022         }
8023         else
8024         {
8025                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8026                                                          "castsource, casttarget, castfunc, castcontext, "
8027                                                          "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
8028                                                          "FROM pg_cast ORDER BY 3,4");
8029         }
8030
8031         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8032
8033         ntups = PQntuples(res);
8034
8035         *numCasts = ntups;
8036
8037         castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
8038
8039         i_tableoid = PQfnumber(res, "tableoid");
8040         i_oid = PQfnumber(res, "oid");
8041         i_castsource = PQfnumber(res, "castsource");
8042         i_casttarget = PQfnumber(res, "casttarget");
8043         i_castfunc = PQfnumber(res, "castfunc");
8044         i_castcontext = PQfnumber(res, "castcontext");
8045         i_castmethod = PQfnumber(res, "castmethod");
8046
8047         for (i = 0; i < ntups; i++)
8048         {
8049                 PQExpBufferData namebuf;
8050                 TypeInfo   *sTypeInfo;
8051                 TypeInfo   *tTypeInfo;
8052
8053                 castinfo[i].dobj.objType = DO_CAST;
8054                 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8055                 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8056                 AssignDumpId(&castinfo[i].dobj);
8057                 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
8058                 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
8059                 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
8060                 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
8061                 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
8062
8063                 /*
8064                  * Try to name cast as concatenation of typnames.  This is only used
8065                  * for purposes of sorting.  If we fail to find either type, the name
8066                  * will be an empty string.
8067                  */
8068                 initPQExpBuffer(&namebuf);
8069                 sTypeInfo = findTypeByOid(castinfo[i].castsource);
8070                 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
8071                 if (sTypeInfo && tTypeInfo)
8072                         appendPQExpBuffer(&namebuf, "%s %s",
8073                                                           sTypeInfo->dobj.name, tTypeInfo->dobj.name);
8074                 castinfo[i].dobj.name = namebuf.data;
8075
8076                 /* Decide whether we want to dump it */
8077                 selectDumpableCast(&(castinfo[i]), fout);
8078
8079                 /* Casts do not currently have ACLs. */
8080                 castinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8081         }
8082
8083         PQclear(res);
8084
8085         destroyPQExpBuffer(query);
8086
8087         return castinfo;
8088 }
8089
8090 static char *
8091 get_language_name(Archive *fout, Oid langid)
8092 {
8093         PQExpBuffer query;
8094         PGresult   *res;
8095         char       *lanname;
8096
8097         query = createPQExpBuffer();
8098         appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
8099         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8100         lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
8101         destroyPQExpBuffer(query);
8102         PQclear(res);
8103
8104         return lanname;
8105 }
8106
8107 /*
8108  * getTransforms
8109  *        get basic information about every transform in the system
8110  *
8111  * numTransforms is set to the number of transforms read in
8112  */
8113 TransformInfo *
8114 getTransforms(Archive *fout, int *numTransforms)
8115 {
8116         PGresult   *res;
8117         int                     ntups;
8118         int                     i;
8119         PQExpBuffer query;
8120         TransformInfo *transforminfo;
8121         int                     i_tableoid;
8122         int                     i_oid;
8123         int                     i_trftype;
8124         int                     i_trflang;
8125         int                     i_trffromsql;
8126         int                     i_trftosql;
8127
8128         /* Transforms didn't exist pre-9.5 */
8129         if (fout->remoteVersion < 90500)
8130         {
8131                 *numTransforms = 0;
8132                 return NULL;
8133         }
8134
8135         query = createPQExpBuffer();
8136
8137         appendPQExpBuffer(query, "SELECT tableoid, oid, "
8138                                           "trftype, trflang, trffromsql::oid, trftosql::oid "
8139                                           "FROM pg_transform "
8140                                           "ORDER BY 3,4");
8141
8142         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8143
8144         ntups = PQntuples(res);
8145
8146         *numTransforms = ntups;
8147
8148         transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
8149
8150         i_tableoid = PQfnumber(res, "tableoid");
8151         i_oid = PQfnumber(res, "oid");
8152         i_trftype = PQfnumber(res, "trftype");
8153         i_trflang = PQfnumber(res, "trflang");
8154         i_trffromsql = PQfnumber(res, "trffromsql");
8155         i_trftosql = PQfnumber(res, "trftosql");
8156
8157         for (i = 0; i < ntups; i++)
8158         {
8159                 PQExpBufferData namebuf;
8160                 TypeInfo   *typeInfo;
8161                 char       *lanname;
8162
8163                 transforminfo[i].dobj.objType = DO_TRANSFORM;
8164                 transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8165                 transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8166                 AssignDumpId(&transforminfo[i].dobj);
8167                 transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
8168                 transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
8169                 transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
8170                 transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
8171
8172                 /*
8173                  * Try to name transform as concatenation of type and language name.
8174                  * This is only used for purposes of sorting.  If we fail to find
8175                  * either, the name will be an empty string.
8176                  */
8177                 initPQExpBuffer(&namebuf);
8178                 typeInfo = findTypeByOid(transforminfo[i].trftype);
8179                 lanname = get_language_name(fout, transforminfo[i].trflang);
8180                 if (typeInfo && lanname)
8181                         appendPQExpBuffer(&namebuf, "%s %s",
8182                                                           typeInfo->dobj.name, lanname);
8183                 transforminfo[i].dobj.name = namebuf.data;
8184                 free(lanname);
8185
8186                 /* Decide whether we want to dump it */
8187                 selectDumpableObject(&(transforminfo[i].dobj), fout);
8188         }
8189
8190         PQclear(res);
8191
8192         destroyPQExpBuffer(query);
8193
8194         return transforminfo;
8195 }
8196
8197 /*
8198  * getTableAttrs -
8199  *        for each interesting table, read info about its attributes
8200  *        (names, types, default values, CHECK constraints, etc)
8201  *
8202  * This is implemented in a very inefficient way right now, looping
8203  * through the tblinfo and doing a join per table to find the attrs and their
8204  * types.  However, because we want type names and so forth to be named
8205  * relative to the schema of each table, we couldn't do it in just one
8206  * query.  (Maybe one query per schema?)
8207  *
8208  *      modifies tblinfo
8209  */
8210 void
8211 getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
8212 {
8213         DumpOptions *dopt = fout->dopt;
8214         int                     i,
8215                                 j;
8216         PQExpBuffer q = createPQExpBuffer();
8217         int                     i_attnum;
8218         int                     i_attname;
8219         int                     i_atttypname;
8220         int                     i_atttypmod;
8221         int                     i_attstattarget;
8222         int                     i_attstorage;
8223         int                     i_typstorage;
8224         int                     i_attnotnull;
8225         int                     i_atthasdef;
8226         int                     i_attidentity;
8227         int                     i_attgenerated;
8228         int                     i_attisdropped;
8229         int                     i_attlen;
8230         int                     i_attalign;
8231         int                     i_attislocal;
8232         int                     i_attoptions;
8233         int                     i_attcollation;
8234         int                     i_attfdwoptions;
8235         int                     i_attmissingval;
8236         PGresult   *res;
8237         int                     ntups;
8238         bool            hasdefaults;
8239
8240         for (i = 0; i < numTables; i++)
8241         {
8242                 TableInfo  *tbinfo = &tblinfo[i];
8243
8244                 /* Don't bother to collect info for sequences */
8245                 if (tbinfo->relkind == RELKIND_SEQUENCE)
8246                         continue;
8247
8248                 /* Don't bother with uninteresting tables, either */
8249                 if (!tbinfo->interesting)
8250                         continue;
8251
8252                 /* find all the user attributes and their types */
8253
8254                 /*
8255                  * we must read the attribute names in attribute number order! because
8256                  * we will use the attnum to index into the attnames array later.
8257                  */
8258                 if (g_verbose)
8259                         write_msg(NULL, "finding the columns and types of table \"%s.%s\"\n",
8260                                           tbinfo->dobj.namespace->dobj.name,
8261                                           tbinfo->dobj.name);
8262
8263                 resetPQExpBuffer(q);
8264
8265                 appendPQExpBuffer(q,
8266                                                   "SELECT\n"
8267                                                   "a.attnum,\n"
8268                                                   "a.attname,\n"
8269                                                   "a.atttypmod,\n"
8270                                                   "a.attstattarget,\n"
8271                                                   "a.attstorage,\n"
8272                                                   "t.typstorage,\n"
8273                                                   "a.attnotnull,\n"
8274                                                   "a.atthasdef,\n"
8275                                                   "a.attisdropped,\n"
8276                                                   "a.attlen,\n"
8277                                                   "a.attalign,\n"
8278                                                   "a.attislocal,\n"
8279                                                   "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n");
8280
8281                 if (fout->remoteVersion >= 120000)
8282                         appendPQExpBuffer(q,
8283                                                           "a.attgenerated,\n");
8284                 else
8285                         appendPQExpBuffer(q,
8286                                                           "'' AS attgenerated,\n");
8287
8288                 if (fout->remoteVersion >= 110000)
8289                         appendPQExpBuffer(q,
8290                                                           "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
8291                                                           "THEN a.attmissingval ELSE null END AS attmissingval,\n");
8292                 else
8293                         appendPQExpBuffer(q,
8294                                                           "NULL AS attmissingval,\n");
8295
8296                 if (fout->remoteVersion >= 100000)
8297                         appendPQExpBuffer(q,
8298                                                           "a.attidentity,\n");
8299                 else
8300                         appendPQExpBuffer(q,
8301                                                           "'' AS attidentity,\n");
8302
8303                 if (fout->remoteVersion >= 90200)
8304                         appendPQExpBuffer(q,
8305                                                           "pg_catalog.array_to_string(ARRAY("
8306                                                           "SELECT pg_catalog.quote_ident(option_name) || "
8307                                                           "' ' || pg_catalog.quote_literal(option_value) "
8308                                                           "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
8309                                                           "ORDER BY option_name"
8310                                                           "), E',\n    ') AS attfdwoptions,\n");
8311                 else
8312                         appendPQExpBuffer(q,
8313                                                           "'' AS attfdwoptions,\n");
8314
8315                 if (fout->remoteVersion >= 90100)
8316                 {
8317                         /*
8318                          * Since we only want to dump COLLATE clauses for attributes whose
8319                          * collation is different from their type's default, we use a CASE
8320                          * here to suppress uninteresting attcollations cheaply.
8321                          */
8322                         appendPQExpBuffer(q,
8323                                                           "CASE WHEN a.attcollation <> t.typcollation "
8324                                                           "THEN a.attcollation ELSE 0 END AS attcollation,\n");
8325                 }
8326                 else
8327                         appendPQExpBuffer(q,
8328                                                           "0 AS attcollation,\n");
8329
8330                 if (fout->remoteVersion >= 90000)
8331                         appendPQExpBuffer(q,
8332                                                           "array_to_string(a.attoptions, ', ') AS attoptions\n");
8333                 else
8334                         appendPQExpBuffer(q,
8335                                                           "'' AS attoptions\n");
8336
8337                 /* need left join here to not fail on dropped columns ... */
8338                 appendPQExpBuffer(q,
8339                                                   "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
8340                                                   "ON a.atttypid = t.oid\n"
8341                                                   "WHERE a.attrelid = '%u'::pg_catalog.oid "
8342                                                   "AND a.attnum > 0::pg_catalog.int2\n"
8343                                                   "ORDER BY a.attnum",
8344                                                   tbinfo->dobj.catId.oid);
8345
8346                 res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8347
8348                 ntups = PQntuples(res);
8349
8350                 i_attnum = PQfnumber(res, "attnum");
8351                 i_attname = PQfnumber(res, "attname");
8352                 i_atttypname = PQfnumber(res, "atttypname");
8353                 i_atttypmod = PQfnumber(res, "atttypmod");
8354                 i_attstattarget = PQfnumber(res, "attstattarget");
8355                 i_attstorage = PQfnumber(res, "attstorage");
8356                 i_typstorage = PQfnumber(res, "typstorage");
8357                 i_attnotnull = PQfnumber(res, "attnotnull");
8358                 i_atthasdef = PQfnumber(res, "atthasdef");
8359                 i_attidentity = PQfnumber(res, "attidentity");
8360                 i_attgenerated = PQfnumber(res, "attgenerated");
8361                 i_attisdropped = PQfnumber(res, "attisdropped");
8362                 i_attlen = PQfnumber(res, "attlen");
8363                 i_attalign = PQfnumber(res, "attalign");
8364                 i_attislocal = PQfnumber(res, "attislocal");
8365                 i_attoptions = PQfnumber(res, "attoptions");
8366                 i_attcollation = PQfnumber(res, "attcollation");
8367                 i_attfdwoptions = PQfnumber(res, "attfdwoptions");
8368                 i_attmissingval = PQfnumber(res, "attmissingval");
8369
8370                 tbinfo->numatts = ntups;
8371                 tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
8372                 tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
8373                 tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
8374                 tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
8375                 tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
8376                 tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
8377                 tbinfo->attidentity = (char *) pg_malloc(ntups * sizeof(char));
8378                 tbinfo->attgenerated = (char *) pg_malloc(ntups * sizeof(char));
8379                 tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
8380                 tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
8381                 tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
8382                 tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
8383                 tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
8384                 tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
8385                 tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
8386                 tbinfo->attmissingval = (char **) pg_malloc(ntups * sizeof(char *));
8387                 tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
8388                 tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
8389                 tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
8390                 hasdefaults = false;
8391
8392                 for (j = 0; j < ntups; j++)
8393                 {
8394                         if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
8395                                 exit_horribly(NULL,
8396                                                           "invalid column numbering in table \"%s\"\n",
8397                                                           tbinfo->dobj.name);
8398                         tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
8399                         tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
8400                         tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
8401                         tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
8402                         tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
8403                         tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
8404                         tbinfo->attidentity[j] = *(PQgetvalue(res, j, i_attidentity));
8405                         tbinfo->attgenerated[j] = *(PQgetvalue(res, j, i_attgenerated));
8406                         tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
8407                         tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
8408                         tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
8409                         tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
8410                         tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
8411                         tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
8412                         tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
8413                         tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
8414                         tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
8415                         tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, j, i_attmissingval));
8416                         tbinfo->attrdefs[j] = NULL; /* fix below */
8417                         if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
8418                                 hasdefaults = true;
8419                         /* these flags will be set in flagInhAttrs() */
8420                         tbinfo->inhNotNull[j] = false;
8421                 }
8422
8423                 PQclear(res);
8424
8425                 /*
8426                  * Get info about column defaults
8427                  */
8428                 if (hasdefaults)
8429                 {
8430                         AttrDefInfo *attrdefs;
8431                         int                     numDefaults;
8432
8433                         if (g_verbose)
8434                                 write_msg(NULL, "finding default expressions of table \"%s.%s\"\n",
8435                                                   tbinfo->dobj.namespace->dobj.name,
8436                                                   tbinfo->dobj.name);
8437
8438                         printfPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
8439                                                           "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
8440                                                           "FROM pg_catalog.pg_attrdef "
8441                                                           "WHERE adrelid = '%u'::pg_catalog.oid",
8442                                                           tbinfo->dobj.catId.oid);
8443
8444                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8445
8446                         numDefaults = PQntuples(res);
8447                         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
8448
8449                         for (j = 0; j < numDefaults; j++)
8450                         {
8451                                 int                     adnum;
8452
8453                                 adnum = atoi(PQgetvalue(res, j, 2));
8454
8455                                 if (adnum <= 0 || adnum > ntups)
8456                                         exit_horribly(NULL,
8457                                                                   "invalid adnum value %d for table \"%s\"\n",
8458                                                                   adnum, tbinfo->dobj.name);
8459
8460                                 /*
8461                                  * dropped columns shouldn't have defaults, but just in case,
8462                                  * ignore 'em
8463                                  */
8464                                 if (tbinfo->attisdropped[adnum - 1])
8465                                         continue;
8466
8467                                 attrdefs[j].dobj.objType = DO_ATTRDEF;
8468                                 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
8469                                 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
8470                                 AssignDumpId(&attrdefs[j].dobj);
8471                                 attrdefs[j].adtable = tbinfo;
8472                                 attrdefs[j].adnum = adnum;
8473                                 attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
8474
8475                                 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
8476                                 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
8477
8478                                 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
8479
8480                                 /*
8481                                  * Defaults on a VIEW must always be dumped as separate ALTER
8482                                  * TABLE commands.  Defaults on regular tables are dumped as
8483                                  * part of the CREATE TABLE if possible, which it won't be if
8484                                  * the column is not going to be emitted explicitly.
8485                                  */
8486                                 if (tbinfo->relkind == RELKIND_VIEW)
8487                                 {
8488                                         attrdefs[j].separate = true;
8489                                 }
8490                                 else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
8491                                 {
8492                                         /* column will be suppressed, print default separately */
8493                                         attrdefs[j].separate = true;
8494                                 }
8495                                 else
8496                                 {
8497                                         attrdefs[j].separate = false;
8498
8499                                         /*
8500                                          * Mark the default as needing to appear before the table,
8501                                          * so that any dependencies it has must be emitted before
8502                                          * the CREATE TABLE.  If this is not possible, we'll
8503                                          * change to "separate" mode while sorting dependencies.
8504                                          */
8505                                         addObjectDependency(&tbinfo->dobj,
8506                                                                                 attrdefs[j].dobj.dumpId);
8507                                 }
8508
8509                                 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
8510                         }
8511                         PQclear(res);
8512                 }
8513
8514                 /*
8515                  * Get info about table CHECK constraints
8516                  */
8517                 if (tbinfo->ncheck > 0)
8518                 {
8519                         ConstraintInfo *constrs;
8520                         int                     numConstrs;
8521
8522                         if (g_verbose)
8523                                 write_msg(NULL, "finding check constraints for table \"%s.%s\"\n",
8524                                                   tbinfo->dobj.namespace->dobj.name,
8525                                                   tbinfo->dobj.name);
8526
8527                         resetPQExpBuffer(q);
8528                         if (fout->remoteVersion >= 90200)
8529                         {
8530                                 /*
8531                                  * convalidated is new in 9.2 (actually, it is there in 9.1,
8532                                  * but it wasn't ever false for check constraints until 9.2).
8533                                  */
8534                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8535                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8536                                                                   "conislocal, convalidated "
8537                                                                   "FROM pg_catalog.pg_constraint "
8538                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8539                                                                   "   AND contype = 'c' "
8540                                                                   "ORDER BY conname",
8541                                                                   tbinfo->dobj.catId.oid);
8542                         }
8543                         else if (fout->remoteVersion >= 80400)
8544                         {
8545                                 /* conislocal is new in 8.4 */
8546                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8547                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8548                                                                   "conislocal, true AS convalidated "
8549                                                                   "FROM pg_catalog.pg_constraint "
8550                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8551                                                                   "   AND contype = 'c' "
8552                                                                   "ORDER BY conname",
8553                                                                   tbinfo->dobj.catId.oid);
8554                         }
8555                         else
8556                         {
8557                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8558                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8559                                                                   "true AS conislocal, true AS convalidated "
8560                                                                   "FROM pg_catalog.pg_constraint "
8561                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8562                                                                   "   AND contype = 'c' "
8563                                                                   "ORDER BY conname",
8564                                                                   tbinfo->dobj.catId.oid);
8565                         }
8566
8567                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8568
8569                         numConstrs = PQntuples(res);
8570                         if (numConstrs != tbinfo->ncheck)
8571                         {
8572                                 write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
8573                                                                                  "expected %d check constraints on table \"%s\" but found %d\n",
8574                                                                                  tbinfo->ncheck),
8575                                                   tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
8576                                 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
8577                                 exit_nicely(1);
8578                         }
8579
8580                         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
8581                         tbinfo->checkexprs = constrs;
8582
8583                         for (j = 0; j < numConstrs; j++)
8584                         {
8585                                 bool            validated = PQgetvalue(res, j, 5)[0] == 't';
8586
8587                                 constrs[j].dobj.objType = DO_CONSTRAINT;
8588                                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
8589                                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
8590                                 AssignDumpId(&constrs[j].dobj);
8591                                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
8592                                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
8593                                 constrs[j].contable = tbinfo;
8594                                 constrs[j].condomain = NULL;
8595                                 constrs[j].contype = 'c';
8596                                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
8597                                 constrs[j].confrelid = InvalidOid;
8598                                 constrs[j].conindex = 0;
8599                                 constrs[j].condeferrable = false;
8600                                 constrs[j].condeferred = false;
8601                                 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
8602
8603                                 /*
8604                                  * An unvalidated constraint needs to be dumped separately, so
8605                                  * that potentially-violating existing data is loaded before
8606                                  * the constraint.
8607                                  */
8608                                 constrs[j].separate = !validated;
8609
8610                                 constrs[j].dobj.dump = tbinfo->dobj.dump;
8611
8612                                 /*
8613                                  * Mark the constraint as needing to appear before the table
8614                                  * --- this is so that any other dependencies of the
8615                                  * constraint will be emitted before we try to create the
8616                                  * table.  If the constraint is to be dumped separately, it
8617                                  * will be dumped after data is loaded anyway, so don't do it.
8618                                  * (There's an automatic dependency in the opposite direction
8619                                  * anyway, so don't need to add one manually here.)
8620                                  */
8621                                 if (!constrs[j].separate)
8622                                         addObjectDependency(&tbinfo->dobj,
8623                                                                                 constrs[j].dobj.dumpId);
8624
8625                                 /*
8626                                  * If the constraint is inherited, this will be detected later
8627                                  * (in pre-8.4 databases).  We also detect later if the
8628                                  * constraint must be split out from the table definition.
8629                                  */
8630                         }
8631                         PQclear(res);
8632                 }
8633         }
8634
8635         destroyPQExpBuffer(q);
8636 }
8637
8638 /*
8639  * Test whether a column should be printed as part of table's CREATE TABLE.
8640  * Column number is zero-based.
8641  *
8642  * Normally this is always true, but it's false for dropped columns, as well
8643  * as those that were inherited without any local definition.  (If we print
8644  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
8645  * However, in binary_upgrade mode, we must print all such columns anyway and
8646  * fix the attislocal/attisdropped state later, so as to keep control of the
8647  * physical column order.
8648  *
8649  * This function exists because there are scattered nonobvious places that
8650  * must be kept in sync with this decision.
8651  */
8652 bool
8653 shouldPrintColumn(DumpOptions *dopt, TableInfo *tbinfo, int colno)
8654 {
8655         if (dopt->binary_upgrade)
8656                 return true;
8657         return (tbinfo->attislocal[colno] && !tbinfo->attisdropped[colno]);
8658 }
8659
8660
8661 /*
8662  * getTSParsers:
8663  *        read all text search parsers in the system catalogs and return them
8664  *        in the TSParserInfo* structure
8665  *
8666  *      numTSParsers is set to the number of parsers read in
8667  */
8668 TSParserInfo *
8669 getTSParsers(Archive *fout, int *numTSParsers)
8670 {
8671         PGresult   *res;
8672         int                     ntups;
8673         int                     i;
8674         PQExpBuffer query;
8675         TSParserInfo *prsinfo;
8676         int                     i_tableoid;
8677         int                     i_oid;
8678         int                     i_prsname;
8679         int                     i_prsnamespace;
8680         int                     i_prsstart;
8681         int                     i_prstoken;
8682         int                     i_prsend;
8683         int                     i_prsheadline;
8684         int                     i_prslextype;
8685
8686         /* Before 8.3, there is no built-in text search support */
8687         if (fout->remoteVersion < 80300)
8688         {
8689                 *numTSParsers = 0;
8690                 return NULL;
8691         }
8692
8693         query = createPQExpBuffer();
8694
8695         /*
8696          * find all text search objects, including builtin ones; we filter out
8697          * system-defined objects at dump-out time.
8698          */
8699
8700         appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
8701                                                  "prsstart::oid, prstoken::oid, "
8702                                                  "prsend::oid, prsheadline::oid, prslextype::oid "
8703                                                  "FROM pg_ts_parser");
8704
8705         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8706
8707         ntups = PQntuples(res);
8708         *numTSParsers = ntups;
8709
8710         prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
8711
8712         i_tableoid = PQfnumber(res, "tableoid");
8713         i_oid = PQfnumber(res, "oid");
8714         i_prsname = PQfnumber(res, "prsname");
8715         i_prsnamespace = PQfnumber(res, "prsnamespace");
8716         i_prsstart = PQfnumber(res, "prsstart");
8717         i_prstoken = PQfnumber(res, "prstoken");
8718         i_prsend = PQfnumber(res, "prsend");
8719         i_prsheadline = PQfnumber(res, "prsheadline");
8720         i_prslextype = PQfnumber(res, "prslextype");
8721
8722         for (i = 0; i < ntups; i++)
8723         {
8724                 prsinfo[i].dobj.objType = DO_TSPARSER;
8725                 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8726                 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8727                 AssignDumpId(&prsinfo[i].dobj);
8728                 prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
8729                 prsinfo[i].dobj.namespace =
8730                         findNamespace(fout,
8731                                                   atooid(PQgetvalue(res, i, i_prsnamespace)));
8732                 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
8733                 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
8734                 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
8735                 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
8736                 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
8737
8738                 /* Decide whether we want to dump it */
8739                 selectDumpableObject(&(prsinfo[i].dobj), fout);
8740
8741                 /* Text Search Parsers do not currently have ACLs. */
8742                 prsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8743         }
8744
8745         PQclear(res);
8746
8747         destroyPQExpBuffer(query);
8748
8749         return prsinfo;
8750 }
8751
8752 /*
8753  * getTSDictionaries:
8754  *        read all text search dictionaries in the system catalogs and return them
8755  *        in the TSDictInfo* structure
8756  *
8757  *      numTSDicts is set to the number of dictionaries read in
8758  */
8759 TSDictInfo *
8760 getTSDictionaries(Archive *fout, int *numTSDicts)
8761 {
8762         PGresult   *res;
8763         int                     ntups;
8764         int                     i;
8765         PQExpBuffer query;
8766         TSDictInfo *dictinfo;
8767         int                     i_tableoid;
8768         int                     i_oid;
8769         int                     i_dictname;
8770         int                     i_dictnamespace;
8771         int                     i_rolname;
8772         int                     i_dicttemplate;
8773         int                     i_dictinitoption;
8774
8775         /* Before 8.3, there is no built-in text search support */
8776         if (fout->remoteVersion < 80300)
8777         {
8778                 *numTSDicts = 0;
8779                 return NULL;
8780         }
8781
8782         query = createPQExpBuffer();
8783
8784         appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
8785                                           "dictnamespace, (%s dictowner) AS rolname, "
8786                                           "dicttemplate, dictinitoption "
8787                                           "FROM pg_ts_dict",
8788                                           username_subquery);
8789
8790         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8791
8792         ntups = PQntuples(res);
8793         *numTSDicts = ntups;
8794
8795         dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
8796
8797         i_tableoid = PQfnumber(res, "tableoid");
8798         i_oid = PQfnumber(res, "oid");
8799         i_dictname = PQfnumber(res, "dictname");
8800         i_dictnamespace = PQfnumber(res, "dictnamespace");
8801         i_rolname = PQfnumber(res, "rolname");
8802         i_dictinitoption = PQfnumber(res, "dictinitoption");
8803         i_dicttemplate = PQfnumber(res, "dicttemplate");
8804
8805         for (i = 0; i < ntups; i++)
8806         {
8807                 dictinfo[i].dobj.objType = DO_TSDICT;
8808                 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8809                 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8810                 AssignDumpId(&dictinfo[i].dobj);
8811                 dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
8812                 dictinfo[i].dobj.namespace =
8813                         findNamespace(fout,
8814                                                   atooid(PQgetvalue(res, i, i_dictnamespace)));
8815                 dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8816                 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
8817                 if (PQgetisnull(res, i, i_dictinitoption))
8818                         dictinfo[i].dictinitoption = NULL;
8819                 else
8820                         dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
8821
8822                 /* Decide whether we want to dump it */
8823                 selectDumpableObject(&(dictinfo[i].dobj), fout);
8824
8825                 /* Text Search Dictionaries do not currently have ACLs. */
8826                 dictinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8827         }
8828
8829         PQclear(res);
8830
8831         destroyPQExpBuffer(query);
8832
8833         return dictinfo;
8834 }
8835
8836 /*
8837  * getTSTemplates:
8838  *        read all text search templates in the system catalogs and return them
8839  *        in the TSTemplateInfo* structure
8840  *
8841  *      numTSTemplates is set to the number of templates read in
8842  */
8843 TSTemplateInfo *
8844 getTSTemplates(Archive *fout, int *numTSTemplates)
8845 {
8846         PGresult   *res;
8847         int                     ntups;
8848         int                     i;
8849         PQExpBuffer query;
8850         TSTemplateInfo *tmplinfo;
8851         int                     i_tableoid;
8852         int                     i_oid;
8853         int                     i_tmplname;
8854         int                     i_tmplnamespace;
8855         int                     i_tmplinit;
8856         int                     i_tmpllexize;
8857
8858         /* Before 8.3, there is no built-in text search support */
8859         if (fout->remoteVersion < 80300)
8860         {
8861                 *numTSTemplates = 0;
8862                 return NULL;
8863         }
8864
8865         query = createPQExpBuffer();
8866
8867         appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
8868                                                  "tmplnamespace, tmplinit::oid, tmpllexize::oid "
8869                                                  "FROM pg_ts_template");
8870
8871         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8872
8873         ntups = PQntuples(res);
8874         *numTSTemplates = ntups;
8875
8876         tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
8877
8878         i_tableoid = PQfnumber(res, "tableoid");
8879         i_oid = PQfnumber(res, "oid");
8880         i_tmplname = PQfnumber(res, "tmplname");
8881         i_tmplnamespace = PQfnumber(res, "tmplnamespace");
8882         i_tmplinit = PQfnumber(res, "tmplinit");
8883         i_tmpllexize = PQfnumber(res, "tmpllexize");
8884
8885         for (i = 0; i < ntups; i++)
8886         {
8887                 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
8888                 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8889                 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8890                 AssignDumpId(&tmplinfo[i].dobj);
8891                 tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
8892                 tmplinfo[i].dobj.namespace =
8893                         findNamespace(fout,
8894                                                   atooid(PQgetvalue(res, i, i_tmplnamespace)));
8895                 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
8896                 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
8897
8898                 /* Decide whether we want to dump it */
8899                 selectDumpableObject(&(tmplinfo[i].dobj), fout);
8900
8901                 /* Text Search Templates do not currently have ACLs. */
8902                 tmplinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8903         }
8904
8905         PQclear(res);
8906
8907         destroyPQExpBuffer(query);
8908
8909         return tmplinfo;
8910 }
8911
8912 /*
8913  * getTSConfigurations:
8914  *        read all text search configurations in the system catalogs and return
8915  *        them in the TSConfigInfo* structure
8916  *
8917  *      numTSConfigs is set to the number of configurations read in
8918  */
8919 TSConfigInfo *
8920 getTSConfigurations(Archive *fout, int *numTSConfigs)
8921 {
8922         PGresult   *res;
8923         int                     ntups;
8924         int                     i;
8925         PQExpBuffer query;
8926         TSConfigInfo *cfginfo;
8927         int                     i_tableoid;
8928         int                     i_oid;
8929         int                     i_cfgname;
8930         int                     i_cfgnamespace;
8931         int                     i_rolname;
8932         int                     i_cfgparser;
8933
8934         /* Before 8.3, there is no built-in text search support */
8935         if (fout->remoteVersion < 80300)
8936         {
8937                 *numTSConfigs = 0;
8938                 return NULL;
8939         }
8940
8941         query = createPQExpBuffer();
8942
8943         appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
8944                                           "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
8945                                           "FROM pg_ts_config",
8946                                           username_subquery);
8947
8948         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8949
8950         ntups = PQntuples(res);
8951         *numTSConfigs = ntups;
8952
8953         cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
8954
8955         i_tableoid = PQfnumber(res, "tableoid");
8956         i_oid = PQfnumber(res, "oid");
8957         i_cfgname = PQfnumber(res, "cfgname");
8958         i_cfgnamespace = PQfnumber(res, "cfgnamespace");
8959         i_rolname = PQfnumber(res, "rolname");
8960         i_cfgparser = PQfnumber(res, "cfgparser");
8961
8962         for (i = 0; i < ntups; i++)
8963         {
8964                 cfginfo[i].dobj.objType = DO_TSCONFIG;
8965                 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8966                 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8967                 AssignDumpId(&cfginfo[i].dobj);
8968                 cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
8969                 cfginfo[i].dobj.namespace =
8970                         findNamespace(fout,
8971                                                   atooid(PQgetvalue(res, i, i_cfgnamespace)));
8972                 cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8973                 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
8974
8975                 /* Decide whether we want to dump it */
8976                 selectDumpableObject(&(cfginfo[i].dobj), fout);
8977
8978                 /* Text Search Configurations do not currently have ACLs. */
8979                 cfginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8980         }
8981
8982         PQclear(res);
8983
8984         destroyPQExpBuffer(query);
8985
8986         return cfginfo;
8987 }
8988
8989 /*
8990  * getForeignDataWrappers:
8991  *        read all foreign-data wrappers in the system catalogs and return
8992  *        them in the FdwInfo* structure
8993  *
8994  *      numForeignDataWrappers is set to the number of fdws read in
8995  */
8996 FdwInfo *
8997 getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
8998 {
8999         DumpOptions *dopt = fout->dopt;
9000         PGresult   *res;
9001         int                     ntups;
9002         int                     i;
9003         PQExpBuffer query;
9004         FdwInfo    *fdwinfo;
9005         int                     i_tableoid;
9006         int                     i_oid;
9007         int                     i_fdwname;
9008         int                     i_rolname;
9009         int                     i_fdwhandler;
9010         int                     i_fdwvalidator;
9011         int                     i_fdwacl;
9012         int                     i_rfdwacl;
9013         int                     i_initfdwacl;
9014         int                     i_initrfdwacl;
9015         int                     i_fdwoptions;
9016
9017         /* Before 8.4, there are no foreign-data wrappers */
9018         if (fout->remoteVersion < 80400)
9019         {
9020                 *numForeignDataWrappers = 0;
9021                 return NULL;
9022         }
9023
9024         query = createPQExpBuffer();
9025
9026         if (fout->remoteVersion >= 90600)
9027         {
9028                 PQExpBuffer acl_subquery = createPQExpBuffer();
9029                 PQExpBuffer racl_subquery = createPQExpBuffer();
9030                 PQExpBuffer initacl_subquery = createPQExpBuffer();
9031                 PQExpBuffer initracl_subquery = createPQExpBuffer();
9032
9033                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9034                                                 initracl_subquery, "f.fdwacl", "f.fdwowner", "'F'",
9035                                                 dopt->binary_upgrade);
9036
9037                 appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.fdwname, "
9038                                                   "(%s f.fdwowner) AS rolname, "
9039                                                   "f.fdwhandler::pg_catalog.regproc, "
9040                                                   "f.fdwvalidator::pg_catalog.regproc, "
9041                                                   "%s AS fdwacl, "
9042                                                   "%s AS rfdwacl, "
9043                                                   "%s AS initfdwacl, "
9044                                                   "%s AS initrfdwacl, "
9045                                                   "array_to_string(ARRAY("
9046                                                   "SELECT quote_ident(option_name) || ' ' || "
9047                                                   "quote_literal(option_value) "
9048                                                   "FROM pg_options_to_table(f.fdwoptions) "
9049                                                   "ORDER BY option_name"
9050                                                   "), E',\n    ') AS fdwoptions "
9051                                                   "FROM pg_foreign_data_wrapper f "
9052                                                   "LEFT JOIN pg_init_privs pip ON "
9053                                                   "(f.oid = pip.objoid "
9054                                                   "AND pip.classoid = 'pg_foreign_data_wrapper'::regclass "
9055                                                   "AND pip.objsubid = 0) ",
9056                                                   username_subquery,
9057                                                   acl_subquery->data,
9058                                                   racl_subquery->data,
9059                                                   initacl_subquery->data,
9060                                                   initracl_subquery->data);
9061
9062                 destroyPQExpBuffer(acl_subquery);
9063                 destroyPQExpBuffer(racl_subquery);
9064                 destroyPQExpBuffer(initacl_subquery);
9065                 destroyPQExpBuffer(initracl_subquery);
9066         }
9067         else if (fout->remoteVersion >= 90100)
9068         {
9069                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
9070                                                   "(%s fdwowner) AS rolname, "
9071                                                   "fdwhandler::pg_catalog.regproc, "
9072                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
9073                                                   "NULL as rfdwacl, "
9074                                                   "NULL as initfdwacl, NULL AS initrfdwacl, "
9075                                                   "array_to_string(ARRAY("
9076                                                   "SELECT quote_ident(option_name) || ' ' || "
9077                                                   "quote_literal(option_value) "
9078                                                   "FROM pg_options_to_table(fdwoptions) "
9079                                                   "ORDER BY option_name"
9080                                                   "), E',\n    ') AS fdwoptions "
9081                                                   "FROM pg_foreign_data_wrapper",
9082                                                   username_subquery);
9083         }
9084         else
9085         {
9086                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
9087                                                   "(%s fdwowner) AS rolname, "
9088                                                   "'-' AS fdwhandler, "
9089                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
9090                                                   "NULL as rfdwacl, "
9091                                                   "NULL as initfdwacl, NULL AS initrfdwacl, "
9092                                                   "array_to_string(ARRAY("
9093                                                   "SELECT quote_ident(option_name) || ' ' || "
9094                                                   "quote_literal(option_value) "
9095                                                   "FROM pg_options_to_table(fdwoptions) "
9096                                                   "ORDER BY option_name"
9097                                                   "), E',\n    ') AS fdwoptions "
9098                                                   "FROM pg_foreign_data_wrapper",
9099                                                   username_subquery);
9100         }
9101
9102         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9103
9104         ntups = PQntuples(res);
9105         *numForeignDataWrappers = ntups;
9106
9107         fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
9108
9109         i_tableoid = PQfnumber(res, "tableoid");
9110         i_oid = PQfnumber(res, "oid");
9111         i_fdwname = PQfnumber(res, "fdwname");
9112         i_rolname = PQfnumber(res, "rolname");
9113         i_fdwhandler = PQfnumber(res, "fdwhandler");
9114         i_fdwvalidator = PQfnumber(res, "fdwvalidator");
9115         i_fdwacl = PQfnumber(res, "fdwacl");
9116         i_rfdwacl = PQfnumber(res, "rfdwacl");
9117         i_initfdwacl = PQfnumber(res, "initfdwacl");
9118         i_initrfdwacl = PQfnumber(res, "initrfdwacl");
9119         i_fdwoptions = PQfnumber(res, "fdwoptions");
9120
9121         for (i = 0; i < ntups; i++)
9122         {
9123                 fdwinfo[i].dobj.objType = DO_FDW;
9124                 fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9125                 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9126                 AssignDumpId(&fdwinfo[i].dobj);
9127                 fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
9128                 fdwinfo[i].dobj.namespace = NULL;
9129                 fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
9130                 fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
9131                 fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
9132                 fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
9133                 fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
9134                 fdwinfo[i].rfdwacl = pg_strdup(PQgetvalue(res, i, i_rfdwacl));
9135                 fdwinfo[i].initfdwacl = pg_strdup(PQgetvalue(res, i, i_initfdwacl));
9136                 fdwinfo[i].initrfdwacl = pg_strdup(PQgetvalue(res, i, i_initrfdwacl));
9137
9138                 /* Decide whether we want to dump it */
9139                 selectDumpableObject(&(fdwinfo[i].dobj), fout);
9140
9141                 /* Do not try to dump ACL if no ACL exists. */
9142                 if (PQgetisnull(res, i, i_fdwacl) && PQgetisnull(res, i, i_rfdwacl) &&
9143                         PQgetisnull(res, i, i_initfdwacl) &&
9144                         PQgetisnull(res, i, i_initrfdwacl))
9145                         fdwinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
9146         }
9147
9148         PQclear(res);
9149
9150         destroyPQExpBuffer(query);
9151
9152         return fdwinfo;
9153 }
9154
9155 /*
9156  * getForeignServers:
9157  *        read all foreign servers in the system catalogs and return
9158  *        them in the ForeignServerInfo * structure
9159  *
9160  *      numForeignServers is set to the number of servers read in
9161  */
9162 ForeignServerInfo *
9163 getForeignServers(Archive *fout, int *numForeignServers)
9164 {
9165         DumpOptions *dopt = fout->dopt;
9166         PGresult   *res;
9167         int                     ntups;
9168         int                     i;
9169         PQExpBuffer query;
9170         ForeignServerInfo *srvinfo;
9171         int                     i_tableoid;
9172         int                     i_oid;
9173         int                     i_srvname;
9174         int                     i_rolname;
9175         int                     i_srvfdw;
9176         int                     i_srvtype;
9177         int                     i_srvversion;
9178         int                     i_srvacl;
9179         int                     i_rsrvacl;
9180         int                     i_initsrvacl;
9181         int                     i_initrsrvacl;
9182         int                     i_srvoptions;
9183
9184         /* Before 8.4, there are no foreign servers */
9185         if (fout->remoteVersion < 80400)
9186         {
9187                 *numForeignServers = 0;
9188                 return NULL;
9189         }
9190
9191         query = createPQExpBuffer();
9192
9193         if (fout->remoteVersion >= 90600)
9194         {
9195                 PQExpBuffer acl_subquery = createPQExpBuffer();
9196                 PQExpBuffer racl_subquery = createPQExpBuffer();
9197                 PQExpBuffer initacl_subquery = createPQExpBuffer();
9198                 PQExpBuffer initracl_subquery = createPQExpBuffer();
9199
9200                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9201                                                 initracl_subquery, "f.srvacl", "f.srvowner", "'S'",
9202                                                 dopt->binary_upgrade);
9203
9204                 appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.srvname, "
9205                                                   "(%s f.srvowner) AS rolname, "
9206                                                   "f.srvfdw, f.srvtype, f.srvversion, "
9207                                                   "%s AS srvacl, "
9208                                                   "%s AS rsrvacl, "
9209                                                   "%s AS initsrvacl, "
9210                                                   "%s AS initrsrvacl, "
9211                                                   "array_to_string(ARRAY("
9212                                                   "SELECT quote_ident(option_name) || ' ' || "
9213                                                   "quote_literal(option_value) "
9214                                                   "FROM pg_options_to_table(f.srvoptions) "
9215                                                   "ORDER BY option_name"
9216                                                   "), E',\n    ') AS srvoptions "
9217                                                   "FROM pg_foreign_server f "
9218                                                   "LEFT JOIN pg_init_privs pip "
9219                                                   "ON (f.oid = pip.objoid "
9220                                                   "AND pip.classoid = 'pg_foreign_server'::regclass "
9221                                                   "AND pip.objsubid = 0) ",
9222                                                   username_subquery,
9223                                                   acl_subquery->data,
9224                                                   racl_subquery->data,
9225                                                   initacl_subquery->data,
9226                                                   initracl_subquery->data);
9227
9228                 destroyPQExpBuffer(acl_subquery);
9229                 destroyPQExpBuffer(racl_subquery);
9230                 destroyPQExpBuffer(initacl_subquery);
9231                 destroyPQExpBuffer(initracl_subquery);
9232         }
9233         else
9234         {
9235                 appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
9236                                                   "(%s srvowner) AS rolname, "
9237                                                   "srvfdw, srvtype, srvversion, srvacl, "
9238                                                   "NULL AS rsrvacl, "
9239                                                   "NULL AS initsrvacl, NULL AS initrsrvacl, "
9240                                                   "array_to_string(ARRAY("
9241                                                   "SELECT quote_ident(option_name) || ' ' || "
9242                                                   "quote_literal(option_value) "
9243                                                   "FROM pg_options_to_table(srvoptions) "
9244                                                   "ORDER BY option_name"
9245                                                   "), E',\n    ') AS srvoptions "
9246                                                   "FROM pg_foreign_server",
9247                                                   username_subquery);
9248         }
9249
9250         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9251
9252         ntups = PQntuples(res);
9253         *numForeignServers = ntups;
9254
9255         srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
9256
9257         i_tableoid = PQfnumber(res, "tableoid");
9258         i_oid = PQfnumber(res, "oid");
9259         i_srvname = PQfnumber(res, "srvname");
9260         i_rolname = PQfnumber(res, "rolname");
9261         i_srvfdw = PQfnumber(res, "srvfdw");
9262         i_srvtype = PQfnumber(res, "srvtype");
9263         i_srvversion = PQfnumber(res, "srvversion");
9264         i_srvacl = PQfnumber(res, "srvacl");
9265         i_rsrvacl = PQfnumber(res, "rsrvacl");
9266         i_initsrvacl = PQfnumber(res, "initsrvacl");
9267         i_initrsrvacl = PQfnumber(res, "initrsrvacl");
9268         i_srvoptions = PQfnumber(res, "srvoptions");
9269
9270         for (i = 0; i < ntups; i++)
9271         {
9272                 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
9273                 srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9274                 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9275                 AssignDumpId(&srvinfo[i].dobj);
9276                 srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
9277                 srvinfo[i].dobj.namespace = NULL;
9278                 srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
9279                 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
9280                 srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
9281                 srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
9282                 srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
9283                 srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
9284                 srvinfo[i].rsrvacl = pg_strdup(PQgetvalue(res, i, i_rsrvacl));
9285                 srvinfo[i].initsrvacl = pg_strdup(PQgetvalue(res, i, i_initsrvacl));
9286                 srvinfo[i].initrsrvacl = pg_strdup(PQgetvalue(res, i, i_initrsrvacl));
9287
9288                 /* Decide whether we want to dump it */
9289                 selectDumpableObject(&(srvinfo[i].dobj), fout);
9290
9291                 /* Do not try to dump ACL if no ACL exists. */
9292                 if (PQgetisnull(res, i, i_srvacl) && PQgetisnull(res, i, i_rsrvacl) &&
9293                         PQgetisnull(res, i, i_initsrvacl) &&
9294                         PQgetisnull(res, i, i_initrsrvacl))
9295                         srvinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
9296         }
9297
9298         PQclear(res);
9299
9300         destroyPQExpBuffer(query);
9301
9302         return srvinfo;
9303 }
9304
9305 /*
9306  * getDefaultACLs:
9307  *        read all default ACL information in the system catalogs and return
9308  *        them in the DefaultACLInfo structure
9309  *
9310  *      numDefaultACLs is set to the number of ACLs read in
9311  */
9312 DefaultACLInfo *
9313 getDefaultACLs(Archive *fout, int *numDefaultACLs)
9314 {
9315         DumpOptions *dopt = fout->dopt;
9316         DefaultACLInfo *daclinfo;
9317         PQExpBuffer query;
9318         PGresult   *res;
9319         int                     i_oid;
9320         int                     i_tableoid;
9321         int                     i_defaclrole;
9322         int                     i_defaclnamespace;
9323         int                     i_defaclobjtype;
9324         int                     i_defaclacl;
9325         int                     i_rdefaclacl;
9326         int                     i_initdefaclacl;
9327         int                     i_initrdefaclacl;
9328         int                     i,
9329                                 ntups;
9330
9331         if (fout->remoteVersion < 90000)
9332         {
9333                 *numDefaultACLs = 0;
9334                 return NULL;
9335         }
9336
9337         query = createPQExpBuffer();
9338
9339         if (fout->remoteVersion >= 90600)
9340         {
9341                 PQExpBuffer acl_subquery = createPQExpBuffer();
9342                 PQExpBuffer racl_subquery = createPQExpBuffer();
9343                 PQExpBuffer initacl_subquery = createPQExpBuffer();
9344                 PQExpBuffer initracl_subquery = createPQExpBuffer();
9345
9346                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9347                                                 initracl_subquery, "defaclacl", "defaclrole",
9348                                                 "CASE WHEN defaclobjtype = 'S' THEN 's' ELSE defaclobjtype END::\"char\"",
9349                                                 dopt->binary_upgrade);
9350
9351                 appendPQExpBuffer(query, "SELECT d.oid, d.tableoid, "
9352                                                   "(%s d.defaclrole) AS defaclrole, "
9353                                                   "d.defaclnamespace, "
9354                                                   "d.defaclobjtype, "
9355                                                   "%s AS defaclacl, "
9356                                                   "%s AS rdefaclacl, "
9357                                                   "%s AS initdefaclacl, "
9358                                                   "%s AS initrdefaclacl "
9359                                                   "FROM pg_default_acl d "
9360                                                   "LEFT JOIN pg_init_privs pip ON "
9361                                                   "(d.oid = pip.objoid "
9362                                                   "AND pip.classoid = 'pg_default_acl'::regclass "
9363                                                   "AND pip.objsubid = 0) ",
9364                                                   username_subquery,
9365                                                   acl_subquery->data,
9366                                                   racl_subquery->data,
9367                                                   initacl_subquery->data,
9368                                                   initracl_subquery->data);
9369         }
9370         else
9371         {
9372                 appendPQExpBuffer(query, "SELECT oid, tableoid, "
9373                                                   "(%s defaclrole) AS defaclrole, "
9374                                                   "defaclnamespace, "
9375                                                   "defaclobjtype, "
9376                                                   "defaclacl, "
9377                                                   "NULL AS rdefaclacl, "
9378                                                   "NULL AS initdefaclacl, "
9379                                                   "NULL AS initrdefaclacl "
9380                                                   "FROM pg_default_acl",
9381                                                   username_subquery);
9382         }
9383
9384         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9385
9386         ntups = PQntuples(res);
9387         *numDefaultACLs = ntups;
9388
9389         daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
9390
9391         i_oid = PQfnumber(res, "oid");
9392         i_tableoid = PQfnumber(res, "tableoid");
9393         i_defaclrole = PQfnumber(res, "defaclrole");
9394         i_defaclnamespace = PQfnumber(res, "defaclnamespace");
9395         i_defaclobjtype = PQfnumber(res, "defaclobjtype");
9396         i_defaclacl = PQfnumber(res, "defaclacl");
9397         i_rdefaclacl = PQfnumber(res, "rdefaclacl");
9398         i_initdefaclacl = PQfnumber(res, "initdefaclacl");
9399         i_initrdefaclacl = PQfnumber(res, "initrdefaclacl");
9400
9401         for (i = 0; i < ntups; i++)
9402         {
9403                 Oid                     nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
9404
9405                 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
9406                 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9407                 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9408                 AssignDumpId(&daclinfo[i].dobj);
9409                 /* cheesy ... is it worth coming up with a better object name? */
9410                 daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
9411
9412                 if (nspid != InvalidOid)
9413                         daclinfo[i].dobj.namespace = findNamespace(fout, nspid);
9414                 else
9415                         daclinfo[i].dobj.namespace = NULL;
9416
9417                 daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
9418                 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
9419                 daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
9420                 daclinfo[i].rdefaclacl = pg_strdup(PQgetvalue(res, i, i_rdefaclacl));
9421                 daclinfo[i].initdefaclacl = pg_strdup(PQgetvalue(res, i, i_initdefaclacl));
9422                 daclinfo[i].initrdefaclacl = pg_strdup(PQgetvalue(res, i, i_initrdefaclacl));
9423
9424                 /* Decide whether we want to dump it */
9425                 selectDumpableDefaultACL(&(daclinfo[i]), dopt);
9426         }
9427
9428         PQclear(res);
9429
9430         destroyPQExpBuffer(query);
9431
9432         return daclinfo;
9433 }
9434
9435 /*
9436  * dumpComment --
9437  *
9438  * This routine is used to dump any comments associated with the
9439  * object handed to this routine. The routine takes the object type
9440  * and object name (ready to print, except for schema decoration), plus
9441  * the namespace and owner of the object (for labeling the ArchiveEntry),
9442  * plus catalog ID and subid which are the lookup key for pg_description,
9443  * plus the dump ID for the object (for setting a dependency).
9444  * If a matching pg_description entry is found, it is dumped.
9445  *
9446  * Note: in some cases, such as comments for triggers and rules, the "type"
9447  * string really looks like, e.g., "TRIGGER name ON".  This is a bit of a hack
9448  * but it doesn't seem worth complicating the API for all callers to make
9449  * it cleaner.
9450  *
9451  * Note: although this routine takes a dumpId for dependency purposes,
9452  * that purpose is just to mark the dependency in the emitted dump file
9453  * for possible future use by pg_restore.  We do NOT use it for determining
9454  * ordering of the comment in the dump file, because this routine is called
9455  * after dependency sorting occurs.  This routine should be called just after
9456  * calling ArchiveEntry() for the specified object.
9457  */
9458 static void
9459 dumpComment(Archive *fout, const char *type, const char *name,
9460                         const char *namespace, const char *owner,
9461                         CatalogId catalogId, int subid, DumpId dumpId)
9462 {
9463         DumpOptions *dopt = fout->dopt;
9464         CommentItem *comments;
9465         int                     ncomments;
9466
9467         /* do nothing, if --no-comments is supplied */
9468         if (dopt->no_comments)
9469                 return;
9470
9471         /* Comments are schema not data ... except blob comments are data */
9472         if (strcmp(type, "LARGE OBJECT") != 0)
9473         {
9474                 if (dopt->dataOnly)
9475                         return;
9476         }
9477         else
9478         {
9479                 /* We do dump blob comments in binary-upgrade mode */
9480                 if (dopt->schemaOnly && !dopt->binary_upgrade)
9481                         return;
9482         }
9483
9484         /* Search for comments associated with catalogId, using table */
9485         ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
9486                                                          &comments);
9487
9488         /* Is there one matching the subid? */
9489         while (ncomments > 0)
9490         {
9491                 if (comments->objsubid == subid)
9492                         break;
9493                 comments++;
9494                 ncomments--;
9495         }
9496
9497         /* If a comment exists, build COMMENT ON statement */
9498         if (ncomments > 0)
9499         {
9500                 PQExpBuffer query = createPQExpBuffer();
9501                 PQExpBuffer tag = createPQExpBuffer();
9502
9503                 appendPQExpBuffer(query, "COMMENT ON %s ", type);
9504                 if (namespace && *namespace)
9505                         appendPQExpBuffer(query, "%s.", fmtId(namespace));
9506                 appendPQExpBuffer(query, "%s IS ", name);
9507                 appendStringLiteralAH(query, comments->descr, fout);
9508                 appendPQExpBufferStr(query, ";\n");
9509
9510                 appendPQExpBuffer(tag, "%s %s", type, name);
9511
9512                 /*
9513                  * We mark comments as SECTION_NONE because they really belong in the
9514                  * same section as their parent, whether that is pre-data or
9515                  * post-data.
9516                  */
9517                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
9518                                          ARCHIVE_OPTS(.tag = tag->data,
9519                                                                   .namespace = namespace,
9520                                                                   .owner = owner,
9521                                                                   .description = "COMMENT",
9522                                                                   .section = SECTION_NONE,
9523                                                                   .createStmt = query->data,
9524                                                                   .dropStmt = "",
9525                                                                   .deps = &dumpId,
9526                                                                   .nDeps = 1));
9527
9528                 destroyPQExpBuffer(query);
9529                 destroyPQExpBuffer(tag);
9530         }
9531 }
9532
9533 /*
9534  * dumpTableComment --
9535  *
9536  * As above, but dump comments for both the specified table (or view)
9537  * and its columns.
9538  */
9539 static void
9540 dumpTableComment(Archive *fout, TableInfo *tbinfo,
9541                                  const char *reltypename)
9542 {
9543         DumpOptions *dopt = fout->dopt;
9544         CommentItem *comments;
9545         int                     ncomments;
9546         PQExpBuffer query;
9547         PQExpBuffer tag;
9548
9549         /* do nothing, if --no-comments is supplied */
9550         if (dopt->no_comments)
9551                 return;
9552
9553         /* Comments are SCHEMA not data */
9554         if (dopt->dataOnly)
9555                 return;
9556
9557         /* Search for comments associated with relation, using table */
9558         ncomments = findComments(fout,
9559                                                          tbinfo->dobj.catId.tableoid,
9560                                                          tbinfo->dobj.catId.oid,
9561                                                          &comments);
9562
9563         /* If comments exist, build COMMENT ON statements */
9564         if (ncomments <= 0)
9565                 return;
9566
9567         query = createPQExpBuffer();
9568         tag = createPQExpBuffer();
9569
9570         while (ncomments > 0)
9571         {
9572                 const char *descr = comments->descr;
9573                 int                     objsubid = comments->objsubid;
9574
9575                 if (objsubid == 0)
9576                 {
9577                         resetPQExpBuffer(tag);
9578                         appendPQExpBuffer(tag, "%s %s", reltypename,
9579                                                           fmtId(tbinfo->dobj.name));
9580
9581                         resetPQExpBuffer(query);
9582                         appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
9583                                                           fmtQualifiedDumpable(tbinfo));
9584                         appendStringLiteralAH(query, descr, fout);
9585                         appendPQExpBufferStr(query, ";\n");
9586
9587                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
9588                                                  ARCHIVE_OPTS(.tag = tag->data,
9589                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
9590                                                                           .owner = tbinfo->rolname,
9591                                                                           .description = "COMMENT",
9592                                                                           .section = SECTION_NONE,
9593                                                                           .createStmt = query->data,
9594                                                                           .dropStmt = "",
9595                                                                           .deps = &(tbinfo->dobj.dumpId),
9596                                                                           .nDeps = 1));
9597                 }
9598                 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
9599                 {
9600                         resetPQExpBuffer(tag);
9601                         appendPQExpBuffer(tag, "COLUMN %s.",
9602                                                           fmtId(tbinfo->dobj.name));
9603                         appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
9604
9605                         resetPQExpBuffer(query);
9606                         appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
9607                                                           fmtQualifiedDumpable(tbinfo));
9608                         appendPQExpBuffer(query, "%s IS ",
9609                                                           fmtId(tbinfo->attnames[objsubid - 1]));
9610                         appendStringLiteralAH(query, descr, fout);
9611                         appendPQExpBufferStr(query, ";\n");
9612
9613                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
9614                                                  ARCHIVE_OPTS(.tag = tag->data,
9615                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
9616                                                                           .owner = tbinfo->rolname,
9617                                                                           .description = "COMMENT",
9618                                                                           .section = SECTION_NONE,
9619                                                                           .createStmt = query->data,
9620                                                                           .dropStmt = "",
9621                                                                           .deps = &(tbinfo->dobj.dumpId),
9622                                                                           .nDeps = 1));
9623                 }
9624
9625                 comments++;
9626                 ncomments--;
9627         }
9628
9629         destroyPQExpBuffer(query);
9630         destroyPQExpBuffer(tag);
9631 }
9632
9633 /*
9634  * findComments --
9635  *
9636  * Find the comment(s), if any, associated with the given object.  All the
9637  * objsubid values associated with the given classoid/objoid are found with
9638  * one search.
9639  */
9640 static int
9641 findComments(Archive *fout, Oid classoid, Oid objoid,
9642                          CommentItem **items)
9643 {
9644         /* static storage for table of comments */
9645         static CommentItem *comments = NULL;
9646         static int      ncomments = -1;
9647
9648         CommentItem *middle = NULL;
9649         CommentItem *low;
9650         CommentItem *high;
9651         int                     nmatch;
9652
9653         /* Get comments if we didn't already */
9654         if (ncomments < 0)
9655                 ncomments = collectComments(fout, &comments);
9656
9657         /*
9658          * Do binary search to find some item matching the object.
9659          */
9660         low = &comments[0];
9661         high = &comments[ncomments - 1];
9662         while (low <= high)
9663         {
9664                 middle = low + (high - low) / 2;
9665
9666                 if (classoid < middle->classoid)
9667                         high = middle - 1;
9668                 else if (classoid > middle->classoid)
9669                         low = middle + 1;
9670                 else if (objoid < middle->objoid)
9671                         high = middle - 1;
9672                 else if (objoid > middle->objoid)
9673                         low = middle + 1;
9674                 else
9675                         break;                          /* found a match */
9676         }
9677
9678         if (low > high)                         /* no matches */
9679         {
9680                 *items = NULL;
9681                 return 0;
9682         }
9683
9684         /*
9685          * Now determine how many items match the object.  The search loop
9686          * invariant still holds: only items between low and high inclusive could
9687          * match.
9688          */
9689         nmatch = 1;
9690         while (middle > low)
9691         {
9692                 if (classoid != middle[-1].classoid ||
9693                         objoid != middle[-1].objoid)
9694                         break;
9695                 middle--;
9696                 nmatch++;
9697         }
9698
9699         *items = middle;
9700
9701         middle += nmatch;
9702         while (middle <= high)
9703         {
9704                 if (classoid != middle->classoid ||
9705                         objoid != middle->objoid)
9706                         break;
9707                 middle++;
9708                 nmatch++;
9709         }
9710
9711         return nmatch;
9712 }
9713
9714 /*
9715  * collectComments --
9716  *
9717  * Construct a table of all comments available for database objects.
9718  * We used to do per-object queries for the comments, but it's much faster
9719  * to pull them all over at once, and on most databases the memory cost
9720  * isn't high.
9721  *
9722  * The table is sorted by classoid/objid/objsubid for speed in lookup.
9723  */
9724 static int
9725 collectComments(Archive *fout, CommentItem **items)
9726 {
9727         PGresult   *res;
9728         PQExpBuffer query;
9729         int                     i_description;
9730         int                     i_classoid;
9731         int                     i_objoid;
9732         int                     i_objsubid;
9733         int                     ntups;
9734         int                     i;
9735         CommentItem *comments;
9736
9737         query = createPQExpBuffer();
9738
9739         appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
9740                                                  "FROM pg_catalog.pg_description "
9741                                                  "ORDER BY classoid, objoid, objsubid");
9742
9743         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9744
9745         /* Construct lookup table containing OIDs in numeric form */
9746
9747         i_description = PQfnumber(res, "description");
9748         i_classoid = PQfnumber(res, "classoid");
9749         i_objoid = PQfnumber(res, "objoid");
9750         i_objsubid = PQfnumber(res, "objsubid");
9751
9752         ntups = PQntuples(res);
9753
9754         comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
9755
9756         for (i = 0; i < ntups; i++)
9757         {
9758                 comments[i].descr = PQgetvalue(res, i, i_description);
9759                 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
9760                 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
9761                 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
9762         }
9763
9764         /* Do NOT free the PGresult since we are keeping pointers into it */
9765         destroyPQExpBuffer(query);
9766
9767         *items = comments;
9768         return ntups;
9769 }
9770
9771 /*
9772  * dumpDumpableObject
9773  *
9774  * This routine and its subsidiaries are responsible for creating
9775  * ArchiveEntries (TOC objects) for each object to be dumped.
9776  */
9777 static void
9778 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
9779 {
9780         switch (dobj->objType)
9781         {
9782                 case DO_NAMESPACE:
9783                         dumpNamespace(fout, (NamespaceInfo *) dobj);
9784                         break;
9785                 case DO_EXTENSION:
9786                         dumpExtension(fout, (ExtensionInfo *) dobj);
9787                         break;
9788                 case DO_TYPE:
9789                         dumpType(fout, (TypeInfo *) dobj);
9790                         break;
9791                 case DO_SHELL_TYPE:
9792                         dumpShellType(fout, (ShellTypeInfo *) dobj);
9793                         break;
9794                 case DO_FUNC:
9795                         dumpFunc(fout, (FuncInfo *) dobj);
9796                         break;
9797                 case DO_AGG:
9798                         dumpAgg(fout, (AggInfo *) dobj);
9799                         break;
9800                 case DO_OPERATOR:
9801                         dumpOpr(fout, (OprInfo *) dobj);
9802                         break;
9803                 case DO_ACCESS_METHOD:
9804                         dumpAccessMethod(fout, (AccessMethodInfo *) dobj);
9805                         break;
9806                 case DO_OPCLASS:
9807                         dumpOpclass(fout, (OpclassInfo *) dobj);
9808                         break;
9809                 case DO_OPFAMILY:
9810                         dumpOpfamily(fout, (OpfamilyInfo *) dobj);
9811                         break;
9812                 case DO_COLLATION:
9813                         dumpCollation(fout, (CollInfo *) dobj);
9814                         break;
9815                 case DO_CONVERSION:
9816                         dumpConversion(fout, (ConvInfo *) dobj);
9817                         break;
9818                 case DO_TABLE:
9819                         dumpTable(fout, (TableInfo *) dobj);
9820                         break;
9821                 case DO_ATTRDEF:
9822                         dumpAttrDef(fout, (AttrDefInfo *) dobj);
9823                         break;
9824                 case DO_INDEX:
9825                         dumpIndex(fout, (IndxInfo *) dobj);
9826                         break;
9827                 case DO_INDEX_ATTACH:
9828                         dumpIndexAttach(fout, (IndexAttachInfo *) dobj);
9829                         break;
9830                 case DO_STATSEXT:
9831                         dumpStatisticsExt(fout, (StatsExtInfo *) dobj);
9832                         break;
9833                 case DO_REFRESH_MATVIEW:
9834                         refreshMatViewData(fout, (TableDataInfo *) dobj);
9835                         break;
9836                 case DO_RULE:
9837                         dumpRule(fout, (RuleInfo *) dobj);
9838                         break;
9839                 case DO_TRIGGER:
9840                         dumpTrigger(fout, (TriggerInfo *) dobj);
9841                         break;
9842                 case DO_EVENT_TRIGGER:
9843                         dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
9844                         break;
9845                 case DO_CONSTRAINT:
9846                         dumpConstraint(fout, (ConstraintInfo *) dobj);
9847                         break;
9848                 case DO_FK_CONSTRAINT:
9849                         dumpConstraint(fout, (ConstraintInfo *) dobj);
9850                         break;
9851                 case DO_PROCLANG:
9852                         dumpProcLang(fout, (ProcLangInfo *) dobj);
9853                         break;
9854                 case DO_CAST:
9855                         dumpCast(fout, (CastInfo *) dobj);
9856                         break;
9857                 case DO_TRANSFORM:
9858                         dumpTransform(fout, (TransformInfo *) dobj);
9859                         break;
9860                 case DO_SEQUENCE_SET:
9861                         dumpSequenceData(fout, (TableDataInfo *) dobj);
9862                         break;
9863                 case DO_TABLE_DATA:
9864                         dumpTableData(fout, (TableDataInfo *) dobj);
9865                         break;
9866                 case DO_DUMMY_TYPE:
9867                         /* table rowtypes and array types are never dumped separately */
9868                         break;
9869                 case DO_TSPARSER:
9870                         dumpTSParser(fout, (TSParserInfo *) dobj);
9871                         break;
9872                 case DO_TSDICT:
9873                         dumpTSDictionary(fout, (TSDictInfo *) dobj);
9874                         break;
9875                 case DO_TSTEMPLATE:
9876                         dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
9877                         break;
9878                 case DO_TSCONFIG:
9879                         dumpTSConfig(fout, (TSConfigInfo *) dobj);
9880                         break;
9881                 case DO_FDW:
9882                         dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
9883                         break;
9884                 case DO_FOREIGN_SERVER:
9885                         dumpForeignServer(fout, (ForeignServerInfo *) dobj);
9886                         break;
9887                 case DO_DEFAULT_ACL:
9888                         dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
9889                         break;
9890                 case DO_BLOB:
9891                         dumpBlob(fout, (BlobInfo *) dobj);
9892                         break;
9893                 case DO_BLOB_DATA:
9894                         if (dobj->dump & DUMP_COMPONENT_DATA)
9895                         {
9896                                 TocEntry   *te;
9897
9898                                 te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
9899                                                                   ARCHIVE_OPTS(.tag = dobj->name,
9900                                                                                            .description = "BLOBS",
9901                                                                                            .owner = "",
9902                                                                                            .section = SECTION_DATA,
9903                                                                                            .dumpFn = dumpBlobs,
9904                                                                                            .createStmt = "",
9905                                                                                            .dropStmt = ""));
9906
9907                                 /*
9908                                  * Set the TocEntry's dataLength in case we are doing a
9909                                  * parallel dump and want to order dump jobs by table size.
9910                                  * (We need some size estimate for every TocEntry with a
9911                                  * DataDumper function.)  We don't currently have any cheap
9912                                  * way to estimate the size of blobs, but it doesn't matter;
9913                                  * let's just set the size to a large value so parallel dumps
9914                                  * will launch this job first.  If there's lots of blobs, we
9915                                  * win, and if there aren't, we don't lose much.  (If you want
9916                                  * to improve on this, really what you should be thinking
9917                                  * about is allowing blob dumping to be parallelized, not just
9918                                  * getting a smarter estimate for the single TOC entry.)
9919                                  */
9920                                 te->dataLength = MaxBlockNumber;
9921                         }
9922                         break;
9923                 case DO_POLICY:
9924                         dumpPolicy(fout, (PolicyInfo *) dobj);
9925                         break;
9926                 case DO_PUBLICATION:
9927                         dumpPublication(fout, (PublicationInfo *) dobj);
9928                         break;
9929                 case DO_PUBLICATION_REL:
9930                         dumpPublicationTable(fout, (PublicationRelInfo *) dobj);
9931                         break;
9932                 case DO_SUBSCRIPTION:
9933                         dumpSubscription(fout, (SubscriptionInfo *) dobj);
9934                         break;
9935                 case DO_PRE_DATA_BOUNDARY:
9936                 case DO_POST_DATA_BOUNDARY:
9937                         /* never dumped, nothing to do */
9938                         break;
9939         }
9940 }
9941
9942 /*
9943  * dumpNamespace
9944  *        writes out to fout the queries to recreate a user-defined namespace
9945  */
9946 static void
9947 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
9948 {
9949         DumpOptions *dopt = fout->dopt;
9950         PQExpBuffer q;
9951         PQExpBuffer delq;
9952         char       *qnspname;
9953
9954         /* Skip if not to be dumped */
9955         if (!nspinfo->dobj.dump || dopt->dataOnly)
9956                 return;
9957
9958         q = createPQExpBuffer();
9959         delq = createPQExpBuffer();
9960
9961         qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
9962
9963         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
9964
9965         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
9966
9967         if (dopt->binary_upgrade)
9968                 binary_upgrade_extension_member(q, &nspinfo->dobj,
9969                                                                                 "SCHEMA", qnspname, NULL);
9970
9971         if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
9972                 ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
9973                                          ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
9974                                                                   .owner = nspinfo->rolname,
9975                                                                   .description = "SCHEMA",
9976                                                                   .section = SECTION_PRE_DATA,
9977                                                                   .createStmt = q->data,
9978                                                                   .dropStmt = delq->data));
9979
9980         /* Dump Schema Comments and Security Labels */
9981         if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
9982                 dumpComment(fout, "SCHEMA", qnspname,
9983                                         NULL, nspinfo->rolname,
9984                                         nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
9985
9986         if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
9987                 dumpSecLabel(fout, "SCHEMA", qnspname,
9988                                          NULL, nspinfo->rolname,
9989                                          nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
9990
9991         if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
9992                 dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
9993                                 qnspname, NULL, NULL,
9994                                 nspinfo->rolname, nspinfo->nspacl, nspinfo->rnspacl,
9995                                 nspinfo->initnspacl, nspinfo->initrnspacl);
9996
9997         free(qnspname);
9998
9999         destroyPQExpBuffer(q);
10000         destroyPQExpBuffer(delq);
10001 }
10002
10003 /*
10004  * dumpExtension
10005  *        writes out to fout the queries to recreate an extension
10006  */
10007 static void
10008 dumpExtension(Archive *fout, ExtensionInfo *extinfo)
10009 {
10010         DumpOptions *dopt = fout->dopt;
10011         PQExpBuffer q;
10012         PQExpBuffer delq;
10013         char       *qextname;
10014
10015         /* Skip if not to be dumped */
10016         if (!extinfo->dobj.dump || dopt->dataOnly)
10017                 return;
10018
10019         q = createPQExpBuffer();
10020         delq = createPQExpBuffer();
10021
10022         qextname = pg_strdup(fmtId(extinfo->dobj.name));
10023
10024         appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
10025
10026         if (!dopt->binary_upgrade)
10027         {
10028                 /*
10029                  * In a regular dump, we simply create the extension, intentionally
10030                  * not specifying a version, so that the destination installation's
10031                  * default version is used.
10032                  *
10033                  * Use of IF NOT EXISTS here is unlike our behavior for other object
10034                  * types; but there are various scenarios in which it's convenient to
10035                  * manually create the desired extension before restoring, so we
10036                  * prefer to allow it to exist already.
10037                  */
10038                 appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
10039                                                   qextname, fmtId(extinfo->namespace));
10040         }
10041         else
10042         {
10043                 /*
10044                  * In binary-upgrade mode, it's critical to reproduce the state of the
10045                  * database exactly, so our procedure is to create an empty extension,
10046                  * restore all the contained objects normally, and add them to the
10047                  * extension one by one.  This function performs just the first of
10048                  * those steps.  binary_upgrade_extension_member() takes care of
10049                  * adding member objects as they're created.
10050                  */
10051                 int                     i;
10052                 int                     n;
10053
10054                 appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
10055
10056                 /*
10057                  * We unconditionally create the extension, so we must drop it if it
10058                  * exists.  This could happen if the user deleted 'plpgsql' and then
10059                  * readded it, causing its oid to be greater than g_last_builtin_oid.
10060                  */
10061                 appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
10062
10063                 appendPQExpBufferStr(q,
10064                                                          "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
10065                 appendStringLiteralAH(q, extinfo->dobj.name, fout);
10066                 appendPQExpBufferStr(q, ", ");
10067                 appendStringLiteralAH(q, extinfo->namespace, fout);
10068                 appendPQExpBufferStr(q, ", ");
10069                 appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
10070                 appendStringLiteralAH(q, extinfo->extversion, fout);
10071                 appendPQExpBufferStr(q, ", ");
10072
10073                 /*
10074                  * Note that we're pushing extconfig (an OID array) back into
10075                  * pg_extension exactly as-is.  This is OK because pg_class OIDs are
10076                  * preserved in binary upgrade.
10077                  */
10078                 if (strlen(extinfo->extconfig) > 2)
10079                         appendStringLiteralAH(q, extinfo->extconfig, fout);
10080                 else
10081                         appendPQExpBufferStr(q, "NULL");
10082                 appendPQExpBufferStr(q, ", ");
10083                 if (strlen(extinfo->extcondition) > 2)
10084                         appendStringLiteralAH(q, extinfo->extcondition, fout);
10085                 else
10086                         appendPQExpBufferStr(q, "NULL");
10087                 appendPQExpBufferStr(q, ", ");
10088                 appendPQExpBufferStr(q, "ARRAY[");
10089                 n = 0;
10090                 for (i = 0; i < extinfo->dobj.nDeps; i++)
10091                 {
10092                         DumpableObject *extobj;
10093
10094                         extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
10095                         if (extobj && extobj->objType == DO_EXTENSION)
10096                         {
10097                                 if (n++ > 0)
10098                                         appendPQExpBufferChar(q, ',');
10099                                 appendStringLiteralAH(q, extobj->name, fout);
10100                         }
10101                 }
10102                 appendPQExpBufferStr(q, "]::pg_catalog.text[]");
10103                 appendPQExpBufferStr(q, ");\n");
10104         }
10105
10106         if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10107                 ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
10108                                          ARCHIVE_OPTS(.tag = extinfo->dobj.name,
10109                                                                   .description = "EXTENSION",
10110                                                                   .owner = "",
10111                                                                   .section = SECTION_PRE_DATA,
10112                                                                   .createStmt = q->data,
10113                                                                   .dropStmt = delq->data));
10114
10115         /* Dump Extension Comments and Security Labels */
10116         if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10117                 dumpComment(fout, "EXTENSION", qextname,
10118                                         NULL, "",
10119                                         extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
10120
10121         if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10122                 dumpSecLabel(fout, "EXTENSION", qextname,
10123                                          NULL, "",
10124                                          extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
10125
10126         free(qextname);
10127
10128         destroyPQExpBuffer(q);
10129         destroyPQExpBuffer(delq);
10130 }
10131
10132 /*
10133  * dumpType
10134  *        writes out to fout the queries to recreate a user-defined type
10135  */
10136 static void
10137 dumpType(Archive *fout, TypeInfo *tyinfo)
10138 {
10139         DumpOptions *dopt = fout->dopt;
10140
10141         /* Skip if not to be dumped */
10142         if (!tyinfo->dobj.dump || dopt->dataOnly)
10143                 return;
10144
10145         /* Dump out in proper style */
10146         if (tyinfo->typtype == TYPTYPE_BASE)
10147                 dumpBaseType(fout, tyinfo);
10148         else if (tyinfo->typtype == TYPTYPE_DOMAIN)
10149                 dumpDomain(fout, tyinfo);
10150         else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
10151                 dumpCompositeType(fout, tyinfo);
10152         else if (tyinfo->typtype == TYPTYPE_ENUM)
10153                 dumpEnumType(fout, tyinfo);
10154         else if (tyinfo->typtype == TYPTYPE_RANGE)
10155                 dumpRangeType(fout, tyinfo);
10156         else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
10157                 dumpUndefinedType(fout, tyinfo);
10158         else
10159                 write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
10160                                   tyinfo->dobj.name);
10161 }
10162
10163 /*
10164  * dumpEnumType
10165  *        writes out to fout the queries to recreate a user-defined enum type
10166  */
10167 static void
10168 dumpEnumType(Archive *fout, TypeInfo *tyinfo)
10169 {
10170         DumpOptions *dopt = fout->dopt;
10171         PQExpBuffer q = createPQExpBuffer();
10172         PQExpBuffer delq = createPQExpBuffer();
10173         PQExpBuffer query = createPQExpBuffer();
10174         PGresult   *res;
10175         int                     num,
10176                                 i;
10177         Oid                     enum_oid;
10178         char       *qtypname;
10179         char       *qualtypname;
10180         char       *label;
10181
10182         if (fout->remoteVersion >= 90100)
10183                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
10184                                                   "FROM pg_catalog.pg_enum "
10185                                                   "WHERE enumtypid = '%u'"
10186                                                   "ORDER BY enumsortorder",
10187                                                   tyinfo->dobj.catId.oid);
10188         else
10189                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
10190                                                   "FROM pg_catalog.pg_enum "
10191                                                   "WHERE enumtypid = '%u'"
10192                                                   "ORDER BY oid",
10193                                                   tyinfo->dobj.catId.oid);
10194
10195         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10196
10197         num = PQntuples(res);
10198
10199         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10200         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10201
10202         /*
10203          * CASCADE shouldn't be required here as for normal types since the I/O
10204          * functions are generic and do not get dropped.
10205          */
10206         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10207
10208         if (dopt->binary_upgrade)
10209                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10210                                                                                                  tyinfo->dobj.catId.oid,
10211                                                                                                  false);
10212
10213         appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
10214                                           qualtypname);
10215
10216         if (!dopt->binary_upgrade)
10217         {
10218                 /* Labels with server-assigned oids */
10219                 for (i = 0; i < num; i++)
10220                 {
10221                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
10222                         if (i > 0)
10223                                 appendPQExpBufferChar(q, ',');
10224                         appendPQExpBufferStr(q, "\n    ");
10225                         appendStringLiteralAH(q, label, fout);
10226                 }
10227         }
10228
10229         appendPQExpBufferStr(q, "\n);\n");
10230
10231         if (dopt->binary_upgrade)
10232         {
10233                 /* Labels with dump-assigned (preserved) oids */
10234                 for (i = 0; i < num; i++)
10235                 {
10236                         enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
10237                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
10238
10239                         if (i == 0)
10240                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
10241                         appendPQExpBuffer(q,
10242                                                           "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
10243                                                           enum_oid);
10244                         appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
10245                         appendStringLiteralAH(q, label, fout);
10246                         appendPQExpBufferStr(q, ";\n\n");
10247                 }
10248         }
10249
10250         if (dopt->binary_upgrade)
10251                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10252                                                                                 "TYPE", qtypname,
10253                                                                                 tyinfo->dobj.namespace->dobj.name);
10254
10255         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10256                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10257                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10258                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10259                                                                   .owner = tyinfo->rolname,
10260                                                                   .description = "TYPE",
10261                                                                   .section = SECTION_PRE_DATA,
10262                                                                   .createStmt = q->data,
10263                                                                   .dropStmt = delq->data));
10264
10265         /* Dump Type Comments and Security Labels */
10266         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10267                 dumpComment(fout, "TYPE", qtypname,
10268                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10269                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10270
10271         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10272                 dumpSecLabel(fout, "TYPE", qtypname,
10273                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10274                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10275
10276         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10277                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10278                                 qtypname, NULL,
10279                                 tyinfo->dobj.namespace->dobj.name,
10280                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10281                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10282
10283         PQclear(res);
10284         destroyPQExpBuffer(q);
10285         destroyPQExpBuffer(delq);
10286         destroyPQExpBuffer(query);
10287         free(qtypname);
10288         free(qualtypname);
10289 }
10290
10291 /*
10292  * dumpRangeType
10293  *        writes out to fout the queries to recreate a user-defined range type
10294  */
10295 static void
10296 dumpRangeType(Archive *fout, TypeInfo *tyinfo)
10297 {
10298         DumpOptions *dopt = fout->dopt;
10299         PQExpBuffer q = createPQExpBuffer();
10300         PQExpBuffer delq = createPQExpBuffer();
10301         PQExpBuffer query = createPQExpBuffer();
10302         PGresult   *res;
10303         Oid                     collationOid;
10304         char       *qtypname;
10305         char       *qualtypname;
10306         char       *procname;
10307
10308         appendPQExpBuffer(query,
10309                                           "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
10310                                           "opc.opcname AS opcname, "
10311                                           "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
10312                                           "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
10313                                           "opc.opcdefault, "
10314                                           "CASE WHEN rngcollation = st.typcollation THEN 0 "
10315                                           "     ELSE rngcollation END AS collation, "
10316                                           "rngcanonical, rngsubdiff "
10317                                           "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
10318                                           "     pg_catalog.pg_opclass opc "
10319                                           "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
10320                                           "rngtypid = '%u'",
10321                                           tyinfo->dobj.catId.oid);
10322
10323         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10324
10325         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10326         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10327
10328         /*
10329          * CASCADE shouldn't be required here as for normal types since the I/O
10330          * functions are generic and do not get dropped.
10331          */
10332         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10333
10334         if (dopt->binary_upgrade)
10335                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10336                                                                                                  tyinfo->dobj.catId.oid,
10337                                                                                                  false);
10338
10339         appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
10340                                           qualtypname);
10341
10342         appendPQExpBuffer(q, "\n    subtype = %s",
10343                                           PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
10344
10345         /* print subtype_opclass only if not default for subtype */
10346         if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
10347         {
10348                 char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
10349                 char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
10350
10351                 appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
10352                                                   fmtId(nspname));
10353                 appendPQExpBufferStr(q, fmtId(opcname));
10354         }
10355
10356         collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
10357         if (OidIsValid(collationOid))
10358         {
10359                 CollInfo   *coll = findCollationByOid(collationOid);
10360
10361                 if (coll)
10362                         appendPQExpBuffer(q, ",\n    collation = %s",
10363                                                           fmtQualifiedDumpable(coll));
10364         }
10365
10366         procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
10367         if (strcmp(procname, "-") != 0)
10368                 appendPQExpBuffer(q, ",\n    canonical = %s", procname);
10369
10370         procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
10371         if (strcmp(procname, "-") != 0)
10372                 appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
10373
10374         appendPQExpBufferStr(q, "\n);\n");
10375
10376         if (dopt->binary_upgrade)
10377                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10378                                                                                 "TYPE", qtypname,
10379                                                                                 tyinfo->dobj.namespace->dobj.name);
10380
10381         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10382                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10383                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10384                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10385                                                                   .owner = tyinfo->rolname,
10386                                                                   .description = "TYPE",
10387                                                                   .section = SECTION_PRE_DATA,
10388                                                                   .createStmt = q->data,
10389                                                                   .dropStmt = delq->data));
10390
10391         /* Dump Type Comments and Security Labels */
10392         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10393                 dumpComment(fout, "TYPE", qtypname,
10394                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10395                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10396
10397         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10398                 dumpSecLabel(fout, "TYPE", qtypname,
10399                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10400                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10401
10402         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10403                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10404                                 qtypname, NULL,
10405                                 tyinfo->dobj.namespace->dobj.name,
10406                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10407                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10408
10409         PQclear(res);
10410         destroyPQExpBuffer(q);
10411         destroyPQExpBuffer(delq);
10412         destroyPQExpBuffer(query);
10413         free(qtypname);
10414         free(qualtypname);
10415 }
10416
10417 /*
10418  * dumpUndefinedType
10419  *        writes out to fout the queries to recreate a !typisdefined type
10420  *
10421  * This is a shell type, but we use different terminology to distinguish
10422  * this case from where we have to emit a shell type definition to break
10423  * circular dependencies.  An undefined type shouldn't ever have anything
10424  * depending on it.
10425  */
10426 static void
10427 dumpUndefinedType(Archive *fout, TypeInfo *tyinfo)
10428 {
10429         DumpOptions *dopt = fout->dopt;
10430         PQExpBuffer q = createPQExpBuffer();
10431         PQExpBuffer delq = createPQExpBuffer();
10432         char       *qtypname;
10433         char       *qualtypname;
10434
10435         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10436         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10437
10438         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10439
10440         if (dopt->binary_upgrade)
10441                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10442                                                                                                  tyinfo->dobj.catId.oid,
10443                                                                                                  false);
10444
10445         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
10446                                           qualtypname);
10447
10448         if (dopt->binary_upgrade)
10449                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10450                                                                                 "TYPE", qtypname,
10451                                                                                 tyinfo->dobj.namespace->dobj.name);
10452
10453         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10454                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10455                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10456                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10457                                                                   .owner = tyinfo->rolname,
10458                                                                   .description = "TYPE",
10459                                                                   .section = SECTION_PRE_DATA,
10460                                                                   .createStmt = q->data,
10461                                                                   .dropStmt = delq->data));
10462
10463         /* Dump Type Comments and Security Labels */
10464         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10465                 dumpComment(fout, "TYPE", qtypname,
10466                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10467                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10468
10469         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10470                 dumpSecLabel(fout, "TYPE", qtypname,
10471                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10472                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10473
10474         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10475                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10476                                 qtypname, NULL,
10477                                 tyinfo->dobj.namespace->dobj.name,
10478                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10479                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10480
10481         destroyPQExpBuffer(q);
10482         destroyPQExpBuffer(delq);
10483         free(qtypname);
10484         free(qualtypname);
10485 }
10486
10487 /*
10488  * dumpBaseType
10489  *        writes out to fout the queries to recreate a user-defined base type
10490  */
10491 static void
10492 dumpBaseType(Archive *fout, TypeInfo *tyinfo)
10493 {
10494         DumpOptions *dopt = fout->dopt;
10495         PQExpBuffer q = createPQExpBuffer();
10496         PQExpBuffer delq = createPQExpBuffer();
10497         PQExpBuffer query = createPQExpBuffer();
10498         PGresult   *res;
10499         char       *qtypname;
10500         char       *qualtypname;
10501         char       *typlen;
10502         char       *typinput;
10503         char       *typoutput;
10504         char       *typreceive;
10505         char       *typsend;
10506         char       *typmodin;
10507         char       *typmodout;
10508         char       *typanalyze;
10509         Oid                     typreceiveoid;
10510         Oid                     typsendoid;
10511         Oid                     typmodinoid;
10512         Oid                     typmodoutoid;
10513         Oid                     typanalyzeoid;
10514         char       *typcategory;
10515         char       *typispreferred;
10516         char       *typdelim;
10517         char       *typbyval;
10518         char       *typalign;
10519         char       *typstorage;
10520         char       *typcollatable;
10521         char       *typdefault;
10522         bool            typdefault_is_literal = false;
10523
10524         /* Fetch type-specific details */
10525         if (fout->remoteVersion >= 90100)
10526         {
10527                 appendPQExpBuffer(query, "SELECT typlen, "
10528                                                   "typinput, typoutput, typreceive, typsend, "
10529                                                   "typmodin, typmodout, typanalyze, "
10530                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10531                                                   "typsend::pg_catalog.oid AS typsendoid, "
10532                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10533                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10534                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10535                                                   "typcategory, typispreferred, "
10536                                                   "typdelim, typbyval, typalign, typstorage, "
10537                                                   "(typcollation <> 0) AS typcollatable, "
10538                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
10539                                                   "FROM pg_catalog.pg_type "
10540                                                   "WHERE oid = '%u'::pg_catalog.oid",
10541                                                   tyinfo->dobj.catId.oid);
10542         }
10543         else if (fout->remoteVersion >= 80400)
10544         {
10545                 appendPQExpBuffer(query, "SELECT typlen, "
10546                                                   "typinput, typoutput, typreceive, typsend, "
10547                                                   "typmodin, typmodout, typanalyze, "
10548                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10549                                                   "typsend::pg_catalog.oid AS typsendoid, "
10550                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10551                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10552                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10553                                                   "typcategory, typispreferred, "
10554                                                   "typdelim, typbyval, typalign, typstorage, "
10555                                                   "false AS typcollatable, "
10556                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
10557                                                   "FROM pg_catalog.pg_type "
10558                                                   "WHERE oid = '%u'::pg_catalog.oid",
10559                                                   tyinfo->dobj.catId.oid);
10560         }
10561         else if (fout->remoteVersion >= 80300)
10562         {
10563                 /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
10564                 appendPQExpBuffer(query, "SELECT typlen, "
10565                                                   "typinput, typoutput, typreceive, typsend, "
10566                                                   "typmodin, typmodout, typanalyze, "
10567                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10568                                                   "typsend::pg_catalog.oid AS typsendoid, "
10569                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10570                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10571                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10572                                                   "'U' AS typcategory, false AS typispreferred, "
10573                                                   "typdelim, typbyval, typalign, typstorage, "
10574                                                   "false AS typcollatable, "
10575                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10576                                                   "FROM pg_catalog.pg_type "
10577                                                   "WHERE oid = '%u'::pg_catalog.oid",
10578                                                   tyinfo->dobj.catId.oid);
10579         }
10580         else
10581         {
10582                 appendPQExpBuffer(query, "SELECT typlen, "
10583                                                   "typinput, typoutput, typreceive, typsend, "
10584                                                   "'-' AS typmodin, '-' AS typmodout, "
10585                                                   "typanalyze, "
10586                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10587                                                   "typsend::pg_catalog.oid AS typsendoid, "
10588                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
10589                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10590                                                   "'U' AS typcategory, false AS typispreferred, "
10591                                                   "typdelim, typbyval, typalign, typstorage, "
10592                                                   "false AS typcollatable, "
10593                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10594                                                   "FROM pg_catalog.pg_type "
10595                                                   "WHERE oid = '%u'::pg_catalog.oid",
10596                                                   tyinfo->dobj.catId.oid);
10597         }
10598
10599         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10600
10601         typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
10602         typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
10603         typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
10604         typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
10605         typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
10606         typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
10607         typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
10608         typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
10609         typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
10610         typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
10611         typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
10612         typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
10613         typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
10614         typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
10615         typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
10616         typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
10617         typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
10618         typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
10619         typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
10620         typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
10621         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
10622                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
10623         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
10624         {
10625                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
10626                 typdefault_is_literal = true;   /* it needs quotes */
10627         }
10628         else
10629                 typdefault = NULL;
10630
10631         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10632         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10633
10634         /*
10635          * The reason we include CASCADE is that the circular dependency between
10636          * the type and its I/O functions makes it impossible to drop the type any
10637          * other way.
10638          */
10639         appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
10640
10641         /*
10642          * We might already have a shell type, but setting pg_type_oid is
10643          * harmless, and in any case we'd better set the array type OID.
10644          */
10645         if (dopt->binary_upgrade)
10646                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10647                                                                                                  tyinfo->dobj.catId.oid,
10648                                                                                                  false);
10649
10650         appendPQExpBuffer(q,
10651                                           "CREATE TYPE %s (\n"
10652                                           "    INTERNALLENGTH = %s",
10653                                           qualtypname,
10654                                           (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
10655
10656         /* regproc result is sufficiently quoted already */
10657         appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
10658         appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
10659         if (OidIsValid(typreceiveoid))
10660                 appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
10661         if (OidIsValid(typsendoid))
10662                 appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
10663         if (OidIsValid(typmodinoid))
10664                 appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
10665         if (OidIsValid(typmodoutoid))
10666                 appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
10667         if (OidIsValid(typanalyzeoid))
10668                 appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
10669
10670         if (strcmp(typcollatable, "t") == 0)
10671                 appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
10672
10673         if (typdefault != NULL)
10674         {
10675                 appendPQExpBufferStr(q, ",\n    DEFAULT = ");
10676                 if (typdefault_is_literal)
10677                         appendStringLiteralAH(q, typdefault, fout);
10678                 else
10679                         appendPQExpBufferStr(q, typdefault);
10680         }
10681
10682         if (OidIsValid(tyinfo->typelem))
10683         {
10684                 char       *elemType;
10685
10686                 elemType = getFormattedTypeName(fout, tyinfo->typelem, zeroAsOpaque);
10687                 appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
10688                 free(elemType);
10689         }
10690
10691         if (strcmp(typcategory, "U") != 0)
10692         {
10693                 appendPQExpBufferStr(q, ",\n    CATEGORY = ");
10694                 appendStringLiteralAH(q, typcategory, fout);
10695         }
10696
10697         if (strcmp(typispreferred, "t") == 0)
10698                 appendPQExpBufferStr(q, ",\n    PREFERRED = true");
10699
10700         if (typdelim && strcmp(typdelim, ",") != 0)
10701         {
10702                 appendPQExpBufferStr(q, ",\n    DELIMITER = ");
10703                 appendStringLiteralAH(q, typdelim, fout);
10704         }
10705
10706         if (strcmp(typalign, "c") == 0)
10707                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
10708         else if (strcmp(typalign, "s") == 0)
10709                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
10710         else if (strcmp(typalign, "i") == 0)
10711                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
10712         else if (strcmp(typalign, "d") == 0)
10713                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
10714
10715         if (strcmp(typstorage, "p") == 0)
10716                 appendPQExpBufferStr(q, ",\n    STORAGE = plain");
10717         else if (strcmp(typstorage, "e") == 0)
10718                 appendPQExpBufferStr(q, ",\n    STORAGE = external");
10719         else if (strcmp(typstorage, "x") == 0)
10720                 appendPQExpBufferStr(q, ",\n    STORAGE = extended");
10721         else if (strcmp(typstorage, "m") == 0)
10722                 appendPQExpBufferStr(q, ",\n    STORAGE = main");
10723
10724         if (strcmp(typbyval, "t") == 0)
10725                 appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
10726
10727         appendPQExpBufferStr(q, "\n);\n");
10728
10729         if (dopt->binary_upgrade)
10730                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10731                                                                                 "TYPE", qtypname,
10732                                                                                 tyinfo->dobj.namespace->dobj.name);
10733
10734         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10735                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10736                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10737                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10738                                                                   .owner = tyinfo->rolname,
10739                                                                   .description = "TYPE",
10740                                                                   .section = SECTION_PRE_DATA,
10741                                                                   .createStmt = q->data,
10742                                                                   .dropStmt = delq->data));
10743
10744         /* Dump Type Comments and Security Labels */
10745         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10746                 dumpComment(fout, "TYPE", qtypname,
10747                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10748                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10749
10750         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10751                 dumpSecLabel(fout, "TYPE", qtypname,
10752                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10753                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10754
10755         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10756                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10757                                 qtypname, NULL,
10758                                 tyinfo->dobj.namespace->dobj.name,
10759                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10760                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10761
10762         PQclear(res);
10763         destroyPQExpBuffer(q);
10764         destroyPQExpBuffer(delq);
10765         destroyPQExpBuffer(query);
10766         free(qtypname);
10767         free(qualtypname);
10768 }
10769
10770 /*
10771  * dumpDomain
10772  *        writes out to fout the queries to recreate a user-defined domain
10773  */
10774 static void
10775 dumpDomain(Archive *fout, TypeInfo *tyinfo)
10776 {
10777         DumpOptions *dopt = fout->dopt;
10778         PQExpBuffer q = createPQExpBuffer();
10779         PQExpBuffer delq = createPQExpBuffer();
10780         PQExpBuffer query = createPQExpBuffer();
10781         PGresult   *res;
10782         int                     i;
10783         char       *qtypname;
10784         char       *qualtypname;
10785         char       *typnotnull;
10786         char       *typdefn;
10787         char       *typdefault;
10788         Oid                     typcollation;
10789         bool            typdefault_is_literal = false;
10790
10791         /* Fetch domain specific details */
10792         if (fout->remoteVersion >= 90100)
10793         {
10794                 /* typcollation is new in 9.1 */
10795                 appendPQExpBuffer(query, "SELECT t.typnotnull, "
10796                                                   "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
10797                                                   "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
10798                                                   "t.typdefault, "
10799                                                   "CASE WHEN t.typcollation <> u.typcollation "
10800                                                   "THEN t.typcollation ELSE 0 END AS typcollation "
10801                                                   "FROM pg_catalog.pg_type t "
10802                                                   "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
10803                                                   "WHERE t.oid = '%u'::pg_catalog.oid",
10804                                                   tyinfo->dobj.catId.oid);
10805         }
10806         else
10807         {
10808                 appendPQExpBuffer(query, "SELECT typnotnull, "
10809                                                   "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
10810                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
10811                                                   "typdefault, 0 AS typcollation "
10812                                                   "FROM pg_catalog.pg_type "
10813                                                   "WHERE oid = '%u'::pg_catalog.oid",
10814                                                   tyinfo->dobj.catId.oid);
10815         }
10816
10817         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10818
10819         typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
10820         typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
10821         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
10822                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
10823         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
10824         {
10825                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
10826                 typdefault_is_literal = true;   /* it needs quotes */
10827         }
10828         else
10829                 typdefault = NULL;
10830         typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
10831
10832         if (dopt->binary_upgrade)
10833                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10834                                                                                                  tyinfo->dobj.catId.oid,
10835                                                                                                  true); /* force array type */
10836
10837         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10838         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10839
10840         appendPQExpBuffer(q,
10841                                           "CREATE DOMAIN %s AS %s",
10842                                           qualtypname,
10843                                           typdefn);
10844
10845         /* Print collation only if different from base type's collation */
10846         if (OidIsValid(typcollation))
10847         {
10848                 CollInfo   *coll;
10849
10850                 coll = findCollationByOid(typcollation);
10851                 if (coll)
10852                         appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
10853         }
10854
10855         if (typnotnull[0] == 't')
10856                 appendPQExpBufferStr(q, " NOT NULL");
10857
10858         if (typdefault != NULL)
10859         {
10860                 appendPQExpBufferStr(q, " DEFAULT ");
10861                 if (typdefault_is_literal)
10862                         appendStringLiteralAH(q, typdefault, fout);
10863                 else
10864                         appendPQExpBufferStr(q, typdefault);
10865         }
10866
10867         PQclear(res);
10868
10869         /*
10870          * Add any CHECK constraints for the domain
10871          */
10872         for (i = 0; i < tyinfo->nDomChecks; i++)
10873         {
10874                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
10875
10876                 if (!domcheck->separate)
10877                         appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
10878                                                           fmtId(domcheck->dobj.name), domcheck->condef);
10879         }
10880
10881         appendPQExpBufferStr(q, ";\n");
10882
10883         appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
10884
10885         if (dopt->binary_upgrade)
10886                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10887                                                                                 "DOMAIN", qtypname,
10888                                                                                 tyinfo->dobj.namespace->dobj.name);
10889
10890         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10891                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10892                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10893                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10894                                                                   .owner = tyinfo->rolname,
10895                                                                   .description = "DOMAIN",
10896                                                                   .section = SECTION_PRE_DATA,
10897                                                                   .createStmt = q->data,
10898                                                                   .dropStmt = delq->data));
10899
10900         /* Dump Domain Comments and Security Labels */
10901         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10902                 dumpComment(fout, "DOMAIN", qtypname,
10903                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10904                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10905
10906         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10907                 dumpSecLabel(fout, "DOMAIN", qtypname,
10908                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10909                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10910
10911         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10912                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10913                                 qtypname, NULL,
10914                                 tyinfo->dobj.namespace->dobj.name,
10915                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10916                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10917
10918         /* Dump any per-constraint comments */
10919         for (i = 0; i < tyinfo->nDomChecks; i++)
10920         {
10921                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
10922                 PQExpBuffer conprefix = createPQExpBuffer();
10923
10924                 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
10925                                                   fmtId(domcheck->dobj.name));
10926
10927                 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10928                         dumpComment(fout, conprefix->data, qtypname,
10929                                                 tyinfo->dobj.namespace->dobj.name,
10930                                                 tyinfo->rolname,
10931                                                 domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
10932
10933                 destroyPQExpBuffer(conprefix);
10934         }
10935
10936         destroyPQExpBuffer(q);
10937         destroyPQExpBuffer(delq);
10938         destroyPQExpBuffer(query);
10939         free(qtypname);
10940         free(qualtypname);
10941 }
10942
10943 /*
10944  * dumpCompositeType
10945  *        writes out to fout the queries to recreate a user-defined stand-alone
10946  *        composite type
10947  */
10948 static void
10949 dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
10950 {
10951         DumpOptions *dopt = fout->dopt;
10952         PQExpBuffer q = createPQExpBuffer();
10953         PQExpBuffer dropped = createPQExpBuffer();
10954         PQExpBuffer delq = createPQExpBuffer();
10955         PQExpBuffer query = createPQExpBuffer();
10956         PGresult   *res;
10957         char       *qtypname;
10958         char       *qualtypname;
10959         int                     ntups;
10960         int                     i_attname;
10961         int                     i_atttypdefn;
10962         int                     i_attlen;
10963         int                     i_attalign;
10964         int                     i_attisdropped;
10965         int                     i_attcollation;
10966         int                     i;
10967         int                     actual_atts;
10968
10969         /* Fetch type specific details */
10970         if (fout->remoteVersion >= 90100)
10971         {
10972                 /*
10973                  * attcollation is new in 9.1.  Since we only want to dump COLLATE
10974                  * clauses for attributes whose collation is different from their
10975                  * type's default, we use a CASE here to suppress uninteresting
10976                  * attcollations cheaply.  atttypid will be 0 for dropped columns;
10977                  * collation does not matter for those.
10978                  */
10979                 appendPQExpBuffer(query, "SELECT a.attname, "
10980                                                   "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
10981                                                   "a.attlen, a.attalign, a.attisdropped, "
10982                                                   "CASE WHEN a.attcollation <> at.typcollation "
10983                                                   "THEN a.attcollation ELSE 0 END AS attcollation "
10984                                                   "FROM pg_catalog.pg_type ct "
10985                                                   "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
10986                                                   "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
10987                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
10988                                                   "ORDER BY a.attnum ",
10989                                                   tyinfo->dobj.catId.oid);
10990         }
10991         else
10992         {
10993                 /*
10994                  * Since ALTER TYPE could not drop columns until 9.1, attisdropped
10995                  * should always be false.
10996                  */
10997                 appendPQExpBuffer(query, "SELECT a.attname, "
10998                                                   "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
10999                                                   "a.attlen, a.attalign, a.attisdropped, "
11000                                                   "0 AS attcollation "
11001                                                   "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
11002                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
11003                                                   "AND a.attrelid = ct.typrelid "
11004                                                   "ORDER BY a.attnum ",
11005                                                   tyinfo->dobj.catId.oid);
11006         }
11007
11008         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11009
11010         ntups = PQntuples(res);
11011
11012         i_attname = PQfnumber(res, "attname");
11013         i_atttypdefn = PQfnumber(res, "atttypdefn");
11014         i_attlen = PQfnumber(res, "attlen");
11015         i_attalign = PQfnumber(res, "attalign");
11016         i_attisdropped = PQfnumber(res, "attisdropped");
11017         i_attcollation = PQfnumber(res, "attcollation");
11018
11019         if (dopt->binary_upgrade)
11020         {
11021                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
11022                                                                                                  tyinfo->dobj.catId.oid,
11023                                                                                                  false);
11024                 binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid, false);
11025         }
11026
11027         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
11028         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
11029
11030         appendPQExpBuffer(q, "CREATE TYPE %s AS (",
11031                                           qualtypname);
11032
11033         actual_atts = 0;
11034         for (i = 0; i < ntups; i++)
11035         {
11036                 char       *attname;
11037                 char       *atttypdefn;
11038                 char       *attlen;
11039                 char       *attalign;
11040                 bool            attisdropped;
11041                 Oid                     attcollation;
11042
11043                 attname = PQgetvalue(res, i, i_attname);
11044                 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
11045                 attlen = PQgetvalue(res, i, i_attlen);
11046                 attalign = PQgetvalue(res, i, i_attalign);
11047                 attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
11048                 attcollation = atooid(PQgetvalue(res, i, i_attcollation));
11049
11050                 if (attisdropped && !dopt->binary_upgrade)
11051                         continue;
11052
11053                 /* Format properly if not first attr */
11054                 if (actual_atts++ > 0)
11055                         appendPQExpBufferChar(q, ',');
11056                 appendPQExpBufferStr(q, "\n\t");
11057
11058                 if (!attisdropped)
11059                 {
11060                         appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
11061
11062                         /* Add collation if not default for the column type */
11063                         if (OidIsValid(attcollation))
11064                         {
11065                                 CollInfo   *coll;
11066
11067                                 coll = findCollationByOid(attcollation);
11068                                 if (coll)
11069                                         appendPQExpBuffer(q, " COLLATE %s",
11070                                                                           fmtQualifiedDumpable(coll));
11071                         }
11072                 }
11073                 else
11074                 {
11075                         /*
11076                          * This is a dropped attribute and we're in binary_upgrade mode.
11077                          * Insert a placeholder for it in the CREATE TYPE command, and set
11078                          * length and alignment with direct UPDATE to the catalogs
11079                          * afterwards. See similar code in dumpTableSchema().
11080                          */
11081                         appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
11082
11083                         /* stash separately for insertion after the CREATE TYPE */
11084                         appendPQExpBufferStr(dropped,
11085                                                                  "\n-- For binary upgrade, recreate dropped column.\n");
11086                         appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
11087                                                           "SET attlen = %s, "
11088                                                           "attalign = '%s', attbyval = false\n"
11089                                                           "WHERE attname = ", attlen, attalign);
11090                         appendStringLiteralAH(dropped, attname, fout);
11091                         appendPQExpBufferStr(dropped, "\n  AND attrelid = ");
11092                         appendStringLiteralAH(dropped, qualtypname, fout);
11093                         appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
11094
11095                         appendPQExpBuffer(dropped, "ALTER TYPE %s ",
11096                                                           qualtypname);
11097                         appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
11098                                                           fmtId(attname));
11099                 }
11100         }
11101         appendPQExpBufferStr(q, "\n);\n");
11102         appendPQExpBufferStr(q, dropped->data);
11103
11104         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
11105
11106         if (dopt->binary_upgrade)
11107                 binary_upgrade_extension_member(q, &tyinfo->dobj,
11108                                                                                 "TYPE", qtypname,
11109                                                                                 tyinfo->dobj.namespace->dobj.name);
11110
11111         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11112                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
11113                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
11114                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
11115                                                                   .owner = tyinfo->rolname,
11116                                                                   .description = "TYPE",
11117                                                                   .section = SECTION_PRE_DATA,
11118                                                                   .createStmt = q->data,
11119                                                                   .dropStmt = delq->data));
11120
11121
11122         /* Dump Type Comments and Security Labels */
11123         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11124                 dumpComment(fout, "TYPE", qtypname,
11125                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11126                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11127
11128         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11129                 dumpSecLabel(fout, "TYPE", qtypname,
11130                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11131                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11132
11133         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
11134                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
11135                                 qtypname, NULL,
11136                                 tyinfo->dobj.namespace->dobj.name,
11137                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
11138                                 tyinfo->inittypacl, tyinfo->initrtypacl);
11139
11140         PQclear(res);
11141         destroyPQExpBuffer(q);
11142         destroyPQExpBuffer(dropped);
11143         destroyPQExpBuffer(delq);
11144         destroyPQExpBuffer(query);
11145         free(qtypname);
11146         free(qualtypname);
11147
11148         /* Dump any per-column comments */
11149         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11150                 dumpCompositeTypeColComments(fout, tyinfo);
11151 }
11152
11153 /*
11154  * dumpCompositeTypeColComments
11155  *        writes out to fout the queries to recreate comments on the columns of
11156  *        a user-defined stand-alone composite type
11157  */
11158 static void
11159 dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
11160 {
11161         CommentItem *comments;
11162         int                     ncomments;
11163         PGresult   *res;
11164         PQExpBuffer query;
11165         PQExpBuffer target;
11166         Oid                     pgClassOid;
11167         int                     i;
11168         int                     ntups;
11169         int                     i_attname;
11170         int                     i_attnum;
11171
11172         /* do nothing, if --no-comments is supplied */
11173         if (fout->dopt->no_comments)
11174                 return;
11175
11176         query = createPQExpBuffer();
11177
11178         appendPQExpBuffer(query,
11179                                           "SELECT c.tableoid, a.attname, a.attnum "
11180                                           "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
11181                                           "WHERE c.oid = '%u' AND c.oid = a.attrelid "
11182                                           "  AND NOT a.attisdropped "
11183                                           "ORDER BY a.attnum ",
11184                                           tyinfo->typrelid);
11185
11186         /* Fetch column attnames */
11187         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11188
11189         ntups = PQntuples(res);
11190         if (ntups < 1)
11191         {
11192                 PQclear(res);
11193                 destroyPQExpBuffer(query);
11194                 return;
11195         }
11196
11197         pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
11198
11199         /* Search for comments associated with type's pg_class OID */
11200         ncomments = findComments(fout,
11201                                                          pgClassOid,
11202                                                          tyinfo->typrelid,
11203                                                          &comments);
11204
11205         /* If no comments exist, we're done */
11206         if (ncomments <= 0)
11207         {
11208                 PQclear(res);
11209                 destroyPQExpBuffer(query);
11210                 return;
11211         }
11212
11213         /* Build COMMENT ON statements */
11214         target = createPQExpBuffer();
11215
11216         i_attnum = PQfnumber(res, "attnum");
11217         i_attname = PQfnumber(res, "attname");
11218         while (ncomments > 0)
11219         {
11220                 const char *attname;
11221
11222                 attname = NULL;
11223                 for (i = 0; i < ntups; i++)
11224                 {
11225                         if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
11226                         {
11227                                 attname = PQgetvalue(res, i, i_attname);
11228                                 break;
11229                         }
11230                 }
11231                 if (attname)                    /* just in case we don't find it */
11232                 {
11233                         const char *descr = comments->descr;
11234
11235                         resetPQExpBuffer(target);
11236                         appendPQExpBuffer(target, "COLUMN %s.",
11237                                                           fmtId(tyinfo->dobj.name));
11238                         appendPQExpBufferStr(target, fmtId(attname));
11239
11240                         resetPQExpBuffer(query);
11241                         appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
11242                                                           fmtQualifiedDumpable(tyinfo));
11243                         appendPQExpBuffer(query, "%s IS ", fmtId(attname));
11244                         appendStringLiteralAH(query, descr, fout);
11245                         appendPQExpBufferStr(query, ";\n");
11246
11247                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
11248                                                  ARCHIVE_OPTS(.tag = target->data,
11249                                                                           .namespace = tyinfo->dobj.namespace->dobj.name,
11250                                                                           .owner = tyinfo->rolname,
11251                                                                           .description = "COMMENT",
11252                                                                           .section = SECTION_NONE,
11253                                                                           .createStmt = query->data,
11254                                                                           .dropStmt = "",
11255                                                                           .deps = &(tyinfo->dobj.dumpId),
11256                                                                           .nDeps = 1));
11257                 }
11258
11259                 comments++;
11260                 ncomments--;
11261         }
11262
11263         PQclear(res);
11264         destroyPQExpBuffer(query);
11265         destroyPQExpBuffer(target);
11266 }
11267
11268 /*
11269  * dumpShellType
11270  *        writes out to fout the queries to create a shell type
11271  *
11272  * We dump a shell definition in advance of the I/O functions for the type.
11273  */
11274 static void
11275 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
11276 {
11277         DumpOptions *dopt = fout->dopt;
11278         PQExpBuffer q;
11279
11280         /* Skip if not to be dumped */
11281         if (!stinfo->dobj.dump || dopt->dataOnly)
11282                 return;
11283
11284         q = createPQExpBuffer();
11285
11286         /*
11287          * Note the lack of a DROP command for the shell type; any required DROP
11288          * is driven off the base type entry, instead.  This interacts with
11289          * _printTocEntry()'s use of the presence of a DROP command to decide
11290          * whether an entry needs an ALTER OWNER command.  We don't want to alter
11291          * the shell type's owner immediately on creation; that should happen only
11292          * after it's filled in, otherwise the backend complains.
11293          */
11294
11295         if (dopt->binary_upgrade)
11296                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
11297                                                                                                  stinfo->baseType->dobj.catId.oid,
11298                                                                                                  false);
11299
11300         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
11301                                           fmtQualifiedDumpable(stinfo));
11302
11303         if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11304                 ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
11305                                          ARCHIVE_OPTS(.tag = stinfo->dobj.name,
11306                                                                   .namespace = stinfo->dobj.namespace->dobj.name,
11307                                                                   .owner = stinfo->baseType->rolname,
11308                                                                   .description = "SHELL TYPE",
11309                                                                   .section = SECTION_PRE_DATA,
11310                                                                   .createStmt = q->data,
11311                                                                   .dropStmt = ""));
11312
11313         destroyPQExpBuffer(q);
11314 }
11315
11316 /*
11317  * dumpProcLang
11318  *                writes out to fout the queries to recreate a user-defined
11319  *                procedural language
11320  */
11321 static void
11322 dumpProcLang(Archive *fout, ProcLangInfo *plang)
11323 {
11324         DumpOptions *dopt = fout->dopt;
11325         PQExpBuffer defqry;
11326         PQExpBuffer delqry;
11327         bool            useParams;
11328         char       *qlanname;
11329         FuncInfo   *funcInfo;
11330         FuncInfo   *inlineInfo = NULL;
11331         FuncInfo   *validatorInfo = NULL;
11332
11333         /* Skip if not to be dumped */
11334         if (!plang->dobj.dump || dopt->dataOnly)
11335                 return;
11336
11337         /*
11338          * Try to find the support function(s).  It is not an error if we don't
11339          * find them --- if the functions are in the pg_catalog schema, as is
11340          * standard in 8.1 and up, then we won't have loaded them. (In this case
11341          * we will emit a parameterless CREATE LANGUAGE command, which will
11342          * require PL template knowledge in the backend to reload.)
11343          */
11344
11345         funcInfo = findFuncByOid(plang->lanplcallfoid);
11346         if (funcInfo != NULL && !funcInfo->dobj.dump)
11347                 funcInfo = NULL;                /* treat not-dumped same as not-found */
11348
11349         if (OidIsValid(plang->laninline))
11350         {
11351                 inlineInfo = findFuncByOid(plang->laninline);
11352                 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
11353                         inlineInfo = NULL;
11354         }
11355
11356         if (OidIsValid(plang->lanvalidator))
11357         {
11358                 validatorInfo = findFuncByOid(plang->lanvalidator);
11359                 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
11360                         validatorInfo = NULL;
11361         }
11362
11363         /*
11364          * If the functions are dumpable then emit a traditional CREATE LANGUAGE
11365          * with parameters.  Otherwise, we'll write a parameterless command, which
11366          * will rely on data from pg_pltemplate.
11367          */
11368         useParams = (funcInfo != NULL &&
11369                                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
11370                                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
11371
11372         defqry = createPQExpBuffer();
11373         delqry = createPQExpBuffer();
11374
11375         qlanname = pg_strdup(fmtId(plang->dobj.name));
11376
11377         appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
11378                                           qlanname);
11379
11380         if (useParams)
11381         {
11382                 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
11383                                                   plang->lanpltrusted ? "TRUSTED " : "",
11384                                                   qlanname);
11385                 appendPQExpBuffer(defqry, " HANDLER %s",
11386                                                   fmtQualifiedDumpable(funcInfo));
11387                 if (OidIsValid(plang->laninline))
11388                         appendPQExpBuffer(defqry, " INLINE %s",
11389                                                           fmtQualifiedDumpable(inlineInfo));
11390                 if (OidIsValid(plang->lanvalidator))
11391                         appendPQExpBuffer(defqry, " VALIDATOR %s",
11392                                                           fmtQualifiedDumpable(validatorInfo));
11393         }
11394         else
11395         {
11396                 /*
11397                  * If not dumping parameters, then use CREATE OR REPLACE so that the
11398                  * command will not fail if the language is preinstalled in the target
11399                  * database.  We restrict the use of REPLACE to this case so as to
11400                  * eliminate the risk of replacing a language with incompatible
11401                  * parameter settings: this command will only succeed at all if there
11402                  * is a pg_pltemplate entry, and if there is one, the existing entry
11403                  * must match it too.
11404                  */
11405                 appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
11406                                                   qlanname);
11407         }
11408         appendPQExpBufferStr(defqry, ";\n");
11409
11410         if (dopt->binary_upgrade)
11411                 binary_upgrade_extension_member(defqry, &plang->dobj,
11412                                                                                 "LANGUAGE", qlanname, NULL);
11413
11414         if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
11415                 ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
11416                                          ARCHIVE_OPTS(.tag = plang->dobj.name,
11417                                                                   .owner = plang->lanowner,
11418                                                                   .description = "PROCEDURAL LANGUAGE",
11419                                                                   .section = SECTION_PRE_DATA,
11420                                                                   .createStmt = defqry->data,
11421                                                                   .dropStmt = delqry->data,
11422                                                                   ));
11423
11424         /* Dump Proc Lang Comments and Security Labels */
11425         if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
11426                 dumpComment(fout, "LANGUAGE", qlanname,
11427                                         NULL, plang->lanowner,
11428                                         plang->dobj.catId, 0, plang->dobj.dumpId);
11429
11430         if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
11431                 dumpSecLabel(fout, "LANGUAGE", qlanname,
11432                                          NULL, plang->lanowner,
11433                                          plang->dobj.catId, 0, plang->dobj.dumpId);
11434
11435         if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
11436                 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
11437                                 qlanname, NULL, NULL,
11438                                 plang->lanowner, plang->lanacl, plang->rlanacl,
11439                                 plang->initlanacl, plang->initrlanacl);
11440
11441         free(qlanname);
11442
11443         destroyPQExpBuffer(defqry);
11444         destroyPQExpBuffer(delqry);
11445 }
11446
11447 /*
11448  * format_function_arguments: generate function name and argument list
11449  *
11450  * This is used when we can rely on pg_get_function_arguments to format
11451  * the argument list.  Note, however, that pg_get_function_arguments
11452  * does not special-case zero-argument aggregates.
11453  */
11454 static char *
11455 format_function_arguments(FuncInfo *finfo, char *funcargs, bool is_agg)
11456 {
11457         PQExpBufferData fn;
11458
11459         initPQExpBuffer(&fn);
11460         appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
11461         if (is_agg && finfo->nargs == 0)
11462                 appendPQExpBufferStr(&fn, "(*)");
11463         else
11464                 appendPQExpBuffer(&fn, "(%s)", funcargs);
11465         return fn.data;
11466 }
11467
11468 /*
11469  * format_function_arguments_old: generate function name and argument list
11470  *
11471  * The argument type names are qualified if needed.  The function name
11472  * is never qualified.
11473  *
11474  * This is used only with pre-8.4 servers, so we aren't expecting to see
11475  * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
11476  *
11477  * Any or all of allargtypes, argmodes, argnames may be NULL.
11478  */
11479 static char *
11480 format_function_arguments_old(Archive *fout,
11481                                                           FuncInfo *finfo, int nallargs,
11482                                                           char **allargtypes,
11483                                                           char **argmodes,
11484                                                           char **argnames)
11485 {
11486         PQExpBufferData fn;
11487         int                     j;
11488
11489         initPQExpBuffer(&fn);
11490         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11491         for (j = 0; j < nallargs; j++)
11492         {
11493                 Oid                     typid;
11494                 char       *typname;
11495                 const char *argmode;
11496                 const char *argname;
11497
11498                 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
11499                 typname = getFormattedTypeName(fout, typid, zeroAsOpaque);
11500
11501                 if (argmodes)
11502                 {
11503                         switch (argmodes[j][0])
11504                         {
11505                                 case PROARGMODE_IN:
11506                                         argmode = "";
11507                                         break;
11508                                 case PROARGMODE_OUT:
11509                                         argmode = "OUT ";
11510                                         break;
11511                                 case PROARGMODE_INOUT:
11512                                         argmode = "INOUT ";
11513                                         break;
11514                                 default:
11515                                         write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
11516                                         argmode = "";
11517                                         break;
11518                         }
11519                 }
11520                 else
11521                         argmode = "";
11522
11523                 argname = argnames ? argnames[j] : (char *) NULL;
11524                 if (argname && argname[0] == '\0')
11525                         argname = NULL;
11526
11527                 appendPQExpBuffer(&fn, "%s%s%s%s%s",
11528                                                   (j > 0) ? ", " : "",
11529                                                   argmode,
11530                                                   argname ? fmtId(argname) : "",
11531                                                   argname ? " " : "",
11532                                                   typname);
11533                 free(typname);
11534         }
11535         appendPQExpBufferChar(&fn, ')');
11536         return fn.data;
11537 }
11538
11539 /*
11540  * format_function_signature: generate function name and argument list
11541  *
11542  * This is like format_function_arguments_old except that only a minimal
11543  * list of input argument types is generated; this is sufficient to
11544  * reference the function, but not to define it.
11545  *
11546  * If honor_quotes is false then the function name is never quoted.
11547  * This is appropriate for use in TOC tags, but not in SQL commands.
11548  */
11549 static char *
11550 format_function_signature(Archive *fout, FuncInfo *finfo, bool honor_quotes)
11551 {
11552         PQExpBufferData fn;
11553         int                     j;
11554
11555         initPQExpBuffer(&fn);
11556         if (honor_quotes)
11557                 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11558         else
11559                 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
11560         for (j = 0; j < finfo->nargs; j++)
11561         {
11562                 char       *typname;
11563
11564                 if (j > 0)
11565                         appendPQExpBufferStr(&fn, ", ");
11566
11567                 typname = getFormattedTypeName(fout, finfo->argtypes[j],
11568                                                                            zeroAsOpaque);
11569                 appendPQExpBufferStr(&fn, typname);
11570                 free(typname);
11571         }
11572         appendPQExpBufferChar(&fn, ')');
11573         return fn.data;
11574 }
11575
11576
11577 /*
11578  * dumpFunc:
11579  *        dump out one function
11580  */
11581 static void
11582 dumpFunc(Archive *fout, FuncInfo *finfo)
11583 {
11584         DumpOptions *dopt = fout->dopt;
11585         PQExpBuffer query;
11586         PQExpBuffer q;
11587         PQExpBuffer delqry;
11588         PQExpBuffer asPart;
11589         PGresult   *res;
11590         char       *funcsig;            /* identity signature */
11591         char       *funcfullsig = NULL; /* full signature */
11592         char       *funcsig_tag;
11593         char       *proretset;
11594         char       *prosrc;
11595         char       *probin;
11596         char       *funcargs;
11597         char       *funciargs;
11598         char       *funcresult;
11599         char       *proallargtypes;
11600         char       *proargmodes;
11601         char       *proargnames;
11602         char       *protrftypes;
11603         char       *prokind;
11604         char       *provolatile;
11605         char       *proisstrict;
11606         char       *prosecdef;
11607         char       *proleakproof;
11608         char       *proconfig;
11609         char       *procost;
11610         char       *prorows;
11611         char       *prosupport;
11612         char       *proparallel;
11613         char       *lanname;
11614         char       *rettypename;
11615         int                     nallargs;
11616         char      **allargtypes = NULL;
11617         char      **argmodes = NULL;
11618         char      **argnames = NULL;
11619         char      **configitems = NULL;
11620         int                     nconfigitems = 0;
11621         const char *keyword;
11622         int                     i;
11623
11624         /* Skip if not to be dumped */
11625         if (!finfo->dobj.dump || dopt->dataOnly)
11626                 return;
11627
11628         query = createPQExpBuffer();
11629         q = createPQExpBuffer();
11630         delqry = createPQExpBuffer();
11631         asPart = createPQExpBuffer();
11632
11633         /* Fetch function-specific details */
11634         if (fout->remoteVersion >= 120000)
11635         {
11636                 /*
11637                  * prosupport was added in 12
11638                  */
11639                 appendPQExpBuffer(query,
11640                                                   "SELECT proretset, prosrc, probin, "
11641                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11642                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11643                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11644                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11645                                                   "prokind, provolatile, proisstrict, prosecdef, "
11646                                                   "proleakproof, proconfig, procost, prorows, "
11647                                                   "prosupport, proparallel, "
11648                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11649                                                   "FROM pg_catalog.pg_proc "
11650                                                   "WHERE oid = '%u'::pg_catalog.oid",
11651                                                   finfo->dobj.catId.oid);
11652         }
11653         else if (fout->remoteVersion >= 110000)
11654         {
11655                 /*
11656                  * prokind was added in 11
11657                  */
11658                 appendPQExpBuffer(query,
11659                                                   "SELECT proretset, prosrc, probin, "
11660                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11661                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11662                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11663                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11664                                                   "prokind, provolatile, proisstrict, prosecdef, "
11665                                                   "proleakproof, proconfig, procost, prorows, "
11666                                                   "'-' AS prosupport, proparallel, "
11667                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11668                                                   "FROM pg_catalog.pg_proc "
11669                                                   "WHERE oid = '%u'::pg_catalog.oid",
11670                                                   finfo->dobj.catId.oid);
11671         }
11672         else if (fout->remoteVersion >= 90600)
11673         {
11674                 /*
11675                  * proparallel was added in 9.6
11676                  */
11677                 appendPQExpBuffer(query,
11678                                                   "SELECT proretset, prosrc, probin, "
11679                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11680                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11681                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11682                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11683                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11684                                                   "provolatile, proisstrict, prosecdef, "
11685                                                   "proleakproof, proconfig, procost, prorows, "
11686                                                   "'-' AS prosupport, proparallel, "
11687                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11688                                                   "FROM pg_catalog.pg_proc "
11689                                                   "WHERE oid = '%u'::pg_catalog.oid",
11690                                                   finfo->dobj.catId.oid);
11691         }
11692         else if (fout->remoteVersion >= 90500)
11693         {
11694                 /*
11695                  * protrftypes was added in 9.5
11696                  */
11697                 appendPQExpBuffer(query,
11698                                                   "SELECT proretset, prosrc, probin, "
11699                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11700                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11701                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11702                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11703                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11704                                                   "provolatile, proisstrict, prosecdef, "
11705                                                   "proleakproof, proconfig, procost, prorows, "
11706                                                   "'-' AS prosupport, "
11707                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11708                                                   "FROM pg_catalog.pg_proc "
11709                                                   "WHERE oid = '%u'::pg_catalog.oid",
11710                                                   finfo->dobj.catId.oid);
11711         }
11712         else if (fout->remoteVersion >= 90200)
11713         {
11714                 /*
11715                  * proleakproof was added in 9.2
11716                  */
11717                 appendPQExpBuffer(query,
11718                                                   "SELECT proretset, prosrc, probin, "
11719                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11720                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11721                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11722                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11723                                                   "provolatile, proisstrict, prosecdef, "
11724                                                   "proleakproof, proconfig, procost, prorows, "
11725                                                   "'-' AS prosupport, "
11726                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11727                                                   "FROM pg_catalog.pg_proc "
11728                                                   "WHERE oid = '%u'::pg_catalog.oid",
11729                                                   finfo->dobj.catId.oid);
11730         }
11731         else if (fout->remoteVersion >= 80400)
11732         {
11733                 /*
11734                  * In 8.4 and up we rely on pg_get_function_arguments and
11735                  * pg_get_function_result instead of examining proallargtypes etc.
11736                  */
11737                 appendPQExpBuffer(query,
11738                                                   "SELECT proretset, prosrc, probin, "
11739                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11740                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11741                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11742                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11743                                                   "provolatile, proisstrict, prosecdef, "
11744                                                   "false AS proleakproof, "
11745                                                   " proconfig, procost, prorows, "
11746                                                   "'-' AS prosupport, "
11747                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11748                                                   "FROM pg_catalog.pg_proc "
11749                                                   "WHERE oid = '%u'::pg_catalog.oid",
11750                                                   finfo->dobj.catId.oid);
11751         }
11752         else if (fout->remoteVersion >= 80300)
11753         {
11754                 appendPQExpBuffer(query,
11755                                                   "SELECT proretset, prosrc, probin, "
11756                                                   "proallargtypes, proargmodes, proargnames, "
11757                                                   "'f' AS prokind, "
11758                                                   "provolatile, proisstrict, prosecdef, "
11759                                                   "false AS proleakproof, "
11760                                                   "proconfig, procost, prorows, "
11761                                                   "'-' AS prosupport, "
11762                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11763                                                   "FROM pg_catalog.pg_proc "
11764                                                   "WHERE oid = '%u'::pg_catalog.oid",
11765                                                   finfo->dobj.catId.oid);
11766         }
11767         else if (fout->remoteVersion >= 80100)
11768         {
11769                 appendPQExpBuffer(query,
11770                                                   "SELECT proretset, prosrc, probin, "
11771                                                   "proallargtypes, proargmodes, proargnames, "
11772                                                   "'f' AS prokind, "
11773                                                   "provolatile, proisstrict, prosecdef, "
11774                                                   "false AS proleakproof, "
11775                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
11776                                                   "'-' AS prosupport, "
11777                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11778                                                   "FROM pg_catalog.pg_proc "
11779                                                   "WHERE oid = '%u'::pg_catalog.oid",
11780                                                   finfo->dobj.catId.oid);
11781         }
11782         else
11783         {
11784                 appendPQExpBuffer(query,
11785                                                   "SELECT proretset, prosrc, probin, "
11786                                                   "null AS proallargtypes, "
11787                                                   "null AS proargmodes, "
11788                                                   "proargnames, "
11789                                                   "'f' AS prokind, "
11790                                                   "provolatile, proisstrict, prosecdef, "
11791                                                   "false AS proleakproof, "
11792                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
11793                                                   "'-' AS prosupport, "
11794                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11795                                                   "FROM pg_catalog.pg_proc "
11796                                                   "WHERE oid = '%u'::pg_catalog.oid",
11797                                                   finfo->dobj.catId.oid);
11798         }
11799
11800         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11801
11802         proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
11803         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
11804         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
11805         if (fout->remoteVersion >= 80400)
11806         {
11807                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
11808                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
11809                 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
11810                 proallargtypes = proargmodes = proargnames = NULL;
11811         }
11812         else
11813         {
11814                 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
11815                 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
11816                 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
11817                 funcargs = funciargs = funcresult = NULL;
11818         }
11819         if (PQfnumber(res, "protrftypes") != -1)
11820                 protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
11821         else
11822                 protrftypes = NULL;
11823         prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
11824         provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
11825         proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
11826         prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
11827         proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
11828         proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
11829         procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
11830         prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
11831         prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
11832
11833         if (PQfnumber(res, "proparallel") != -1)
11834                 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
11835         else
11836                 proparallel = NULL;
11837
11838         lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
11839
11840         /*
11841          * See backend/commands/functioncmds.c for details of how the 'AS' clause
11842          * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
11843          * versions would set it to "-".  There are no known cases in which prosrc
11844          * is unused, so the tests below for "-" are probably useless.
11845          */
11846         if (probin[0] != '\0' && strcmp(probin, "-") != 0)
11847         {
11848                 appendPQExpBufferStr(asPart, "AS ");
11849                 appendStringLiteralAH(asPart, probin, fout);
11850                 if (strcmp(prosrc, "-") != 0)
11851                 {
11852                         appendPQExpBufferStr(asPart, ", ");
11853
11854                         /*
11855                          * where we have bin, use dollar quoting if allowed and src
11856                          * contains quote or backslash; else use regular quoting.
11857                          */
11858                         if (dopt->disable_dollar_quoting ||
11859                                 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
11860                                 appendStringLiteralAH(asPart, prosrc, fout);
11861                         else
11862                                 appendStringLiteralDQ(asPart, prosrc, NULL);
11863                 }
11864         }
11865         else
11866         {
11867                 if (strcmp(prosrc, "-") != 0)
11868                 {
11869                         appendPQExpBufferStr(asPart, "AS ");
11870                         /* with no bin, dollar quote src unconditionally if allowed */
11871                         if (dopt->disable_dollar_quoting)
11872                                 appendStringLiteralAH(asPart, prosrc, fout);
11873                         else
11874                                 appendStringLiteralDQ(asPart, prosrc, NULL);
11875                 }
11876         }
11877
11878         nallargs = finfo->nargs;        /* unless we learn different from allargs */
11879
11880         if (proallargtypes && *proallargtypes)
11881         {
11882                 int                     nitems = 0;
11883
11884                 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
11885                         nitems < finfo->nargs)
11886                 {
11887                         write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
11888                         if (allargtypes)
11889                                 free(allargtypes);
11890                         allargtypes = NULL;
11891                 }
11892                 else
11893                         nallargs = nitems;
11894         }
11895
11896         if (proargmodes && *proargmodes)
11897         {
11898                 int                     nitems = 0;
11899
11900                 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
11901                         nitems != nallargs)
11902                 {
11903                         write_msg(NULL, "WARNING: could not parse proargmodes array\n");
11904                         if (argmodes)
11905                                 free(argmodes);
11906                         argmodes = NULL;
11907                 }
11908         }
11909
11910         if (proargnames && *proargnames)
11911         {
11912                 int                     nitems = 0;
11913
11914                 if (!parsePGArray(proargnames, &argnames, &nitems) ||
11915                         nitems != nallargs)
11916                 {
11917                         write_msg(NULL, "WARNING: could not parse proargnames array\n");
11918                         if (argnames)
11919                                 free(argnames);
11920                         argnames = NULL;
11921                 }
11922         }
11923
11924         if (proconfig && *proconfig)
11925         {
11926                 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
11927                 {
11928                         write_msg(NULL, "WARNING: could not parse proconfig array\n");
11929                         if (configitems)
11930                                 free(configitems);
11931                         configitems = NULL;
11932                         nconfigitems = 0;
11933                 }
11934         }
11935
11936         if (funcargs)
11937         {
11938                 /* 8.4 or later; we rely on server-side code for most of the work */
11939                 funcfullsig = format_function_arguments(finfo, funcargs, false);
11940                 funcsig = format_function_arguments(finfo, funciargs, false);
11941         }
11942         else
11943                 /* pre-8.4, do it ourselves */
11944                 funcsig = format_function_arguments_old(fout,
11945                                                                                                 finfo, nallargs, allargtypes,
11946                                                                                                 argmodes, argnames);
11947
11948         funcsig_tag = format_function_signature(fout, finfo, false);
11949
11950         if (prokind[0] == PROKIND_PROCEDURE)
11951                 keyword = "PROCEDURE";
11952         else
11953                 keyword = "FUNCTION";   /* works for window functions too */
11954
11955         appendPQExpBuffer(delqry, "DROP %s %s.%s;\n",
11956                                           keyword,
11957                                           fmtId(finfo->dobj.namespace->dobj.name),
11958                                           funcsig);
11959
11960         appendPQExpBuffer(q, "CREATE %s %s.%s",
11961                                           keyword,
11962                                           fmtId(finfo->dobj.namespace->dobj.name),
11963                                           funcfullsig ? funcfullsig :
11964                                           funcsig);
11965
11966         if (prokind[0] == PROKIND_PROCEDURE)
11967                  /* no result type to output */ ;
11968         else if (funcresult)
11969                 appendPQExpBuffer(q, " RETURNS %s", funcresult);
11970         else
11971         {
11972                 rettypename = getFormattedTypeName(fout, finfo->prorettype,
11973                                                                                    zeroAsOpaque);
11974                 appendPQExpBuffer(q, " RETURNS %s%s",
11975                                                   (proretset[0] == 't') ? "SETOF " : "",
11976                                                   rettypename);
11977                 free(rettypename);
11978         }
11979
11980         appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
11981
11982         if (protrftypes != NULL && strcmp(protrftypes, "") != 0)
11983         {
11984                 Oid                *typeids = palloc(FUNC_MAX_ARGS * sizeof(Oid));
11985                 int                     i;
11986
11987                 appendPQExpBufferStr(q, " TRANSFORM ");
11988                 parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
11989                 for (i = 0; typeids[i]; i++)
11990                 {
11991                         if (i != 0)
11992                                 appendPQExpBufferStr(q, ", ");
11993                         appendPQExpBuffer(q, "FOR TYPE %s",
11994                                                           getFormattedTypeName(fout, typeids[i], zeroAsNone));
11995                 }
11996         }
11997
11998         if (prokind[0] == PROKIND_WINDOW)
11999                 appendPQExpBufferStr(q, " WINDOW");
12000
12001         if (provolatile[0] != PROVOLATILE_VOLATILE)
12002         {
12003                 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
12004                         appendPQExpBufferStr(q, " IMMUTABLE");
12005                 else if (provolatile[0] == PROVOLATILE_STABLE)
12006                         appendPQExpBufferStr(q, " STABLE");
12007                 else if (provolatile[0] != PROVOLATILE_VOLATILE)
12008                         exit_horribly(NULL, "unrecognized provolatile value for function \"%s\"\n",
12009                                                   finfo->dobj.name);
12010         }
12011
12012         if (proisstrict[0] == 't')
12013                 appendPQExpBufferStr(q, " STRICT");
12014
12015         if (prosecdef[0] == 't')
12016                 appendPQExpBufferStr(q, " SECURITY DEFINER");
12017
12018         if (proleakproof[0] == 't')
12019                 appendPQExpBufferStr(q, " LEAKPROOF");
12020
12021         /*
12022          * COST and ROWS are emitted only if present and not default, so as not to
12023          * break backwards-compatibility of the dump without need.  Keep this code
12024          * in sync with the defaults in functioncmds.c.
12025          */
12026         if (strcmp(procost, "0") != 0)
12027         {
12028                 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
12029                 {
12030                         /* default cost is 1 */
12031                         if (strcmp(procost, "1") != 0)
12032                                 appendPQExpBuffer(q, " COST %s", procost);
12033                 }
12034                 else
12035                 {
12036                         /* default cost is 100 */
12037                         if (strcmp(procost, "100") != 0)
12038                                 appendPQExpBuffer(q, " COST %s", procost);
12039                 }
12040         }
12041         if (proretset[0] == 't' &&
12042                 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
12043                 appendPQExpBuffer(q, " ROWS %s", prorows);
12044
12045         if (strcmp(prosupport, "-") != 0)
12046         {
12047                 /* We rely on regprocout to provide quoting and qualification */
12048                 appendPQExpBuffer(q, " SUPPORT %s", prosupport);
12049         }
12050
12051         if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
12052         {
12053                 if (proparallel[0] == PROPARALLEL_SAFE)
12054                         appendPQExpBufferStr(q, " PARALLEL SAFE");
12055                 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
12056                         appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
12057                 else if (proparallel[0] != PROPARALLEL_UNSAFE)
12058                         exit_horribly(NULL, "unrecognized proparallel value for function \"%s\"\n",
12059                                                   finfo->dobj.name);
12060         }
12061
12062         for (i = 0; i < nconfigitems; i++)
12063         {
12064                 /* we feel free to scribble on configitems[] here */
12065                 char       *configitem = configitems[i];
12066                 char       *pos;
12067
12068                 pos = strchr(configitem, '=');
12069                 if (pos == NULL)
12070                         continue;
12071                 *pos++ = '\0';
12072                 appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
12073
12074                 /*
12075                  * Variables that are marked GUC_LIST_QUOTE were already fully quoted
12076                  * by flatten_set_variable_args() before they were put into the
12077                  * proconfig array.  However, because the quoting rules used there
12078                  * aren't exactly like SQL's, we have to break the list value apart
12079                  * and then quote the elements as string literals.  (The elements may
12080                  * be double-quoted as-is, but we can't just feed them to the SQL
12081                  * parser; it would do the wrong thing with elements that are
12082                  * zero-length or longer than NAMEDATALEN.)
12083                  *
12084                  * Variables that are not so marked should just be emitted as simple
12085                  * string literals.  If the variable is not known to
12086                  * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
12087                  * to use GUC_LIST_QUOTE for extension variables.
12088                  */
12089                 if (variable_is_guc_list_quote(configitem))
12090                 {
12091                         char      **namelist;
12092                         char      **nameptr;
12093
12094                         /* Parse string into list of identifiers */
12095                         /* this shouldn't fail really */
12096                         if (SplitGUCList(pos, ',', &namelist))
12097                         {
12098                                 for (nameptr = namelist; *nameptr; nameptr++)
12099                                 {
12100                                         if (nameptr != namelist)
12101                                                 appendPQExpBufferStr(q, ", ");
12102                                         appendStringLiteralAH(q, *nameptr, fout);
12103                                 }
12104                         }
12105                         pg_free(namelist);
12106                 }
12107                 else
12108                         appendStringLiteralAH(q, pos, fout);
12109         }
12110
12111         appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
12112
12113         if (dopt->binary_upgrade)
12114                 binary_upgrade_extension_member(q, &finfo->dobj,
12115                                                                                 keyword, funcsig,
12116                                                                                 finfo->dobj.namespace->dobj.name);
12117
12118         if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12119                 ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
12120                                          ARCHIVE_OPTS(.tag = funcsig_tag,
12121                                                                   .namespace = finfo->dobj.namespace->dobj.name,
12122                                                                   .owner = finfo->rolname,
12123                                                                   .description = keyword,
12124                                                                   .section = SECTION_PRE_DATA,
12125                                                                   .createStmt = q->data,
12126                                                                   .dropStmt = delqry->data));
12127
12128         /* Dump Function Comments and Security Labels */
12129         if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12130                 dumpComment(fout, keyword, funcsig,
12131                                         finfo->dobj.namespace->dobj.name, finfo->rolname,
12132                                         finfo->dobj.catId, 0, finfo->dobj.dumpId);
12133
12134         if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
12135                 dumpSecLabel(fout, keyword, funcsig,
12136                                          finfo->dobj.namespace->dobj.name, finfo->rolname,
12137                                          finfo->dobj.catId, 0, finfo->dobj.dumpId);
12138
12139         if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
12140                 dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, keyword,
12141                                 funcsig, NULL,
12142                                 finfo->dobj.namespace->dobj.name,
12143                                 finfo->rolname, finfo->proacl, finfo->rproacl,
12144                                 finfo->initproacl, finfo->initrproacl);
12145
12146         PQclear(res);
12147
12148         destroyPQExpBuffer(query);
12149         destroyPQExpBuffer(q);
12150         destroyPQExpBuffer(delqry);
12151         destroyPQExpBuffer(asPart);
12152         free(funcsig);
12153         if (funcfullsig)
12154                 free(funcfullsig);
12155         free(funcsig_tag);
12156         if (allargtypes)
12157                 free(allargtypes);
12158         if (argmodes)
12159                 free(argmodes);
12160         if (argnames)
12161                 free(argnames);
12162         if (configitems)
12163                 free(configitems);
12164 }
12165
12166
12167 /*
12168  * Dump a user-defined cast
12169  */
12170 static void
12171 dumpCast(Archive *fout, CastInfo *cast)
12172 {
12173         DumpOptions *dopt = fout->dopt;
12174         PQExpBuffer defqry;
12175         PQExpBuffer delqry;
12176         PQExpBuffer labelq;
12177         PQExpBuffer castargs;
12178         FuncInfo   *funcInfo = NULL;
12179         char       *sourceType;
12180         char       *targetType;
12181
12182         /* Skip if not to be dumped */
12183         if (!cast->dobj.dump || dopt->dataOnly)
12184                 return;
12185
12186         /* Cannot dump if we don't have the cast function's info */
12187         if (OidIsValid(cast->castfunc))
12188         {
12189                 funcInfo = findFuncByOid(cast->castfunc);
12190                 if (funcInfo == NULL)
12191                         exit_horribly(NULL, "could not find function definition for function with OID %u\n",
12192                                                   cast->castfunc);
12193         }
12194
12195         defqry = createPQExpBuffer();
12196         delqry = createPQExpBuffer();
12197         labelq = createPQExpBuffer();
12198         castargs = createPQExpBuffer();
12199
12200         sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
12201         targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
12202         appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
12203                                           sourceType, targetType);
12204
12205         appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
12206                                           sourceType, targetType);
12207
12208         switch (cast->castmethod)
12209         {
12210                 case COERCION_METHOD_BINARY:
12211                         appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
12212                         break;
12213                 case COERCION_METHOD_INOUT:
12214                         appendPQExpBufferStr(defqry, "WITH INOUT");
12215                         break;
12216                 case COERCION_METHOD_FUNCTION:
12217                         if (funcInfo)
12218                         {
12219                                 char       *fsig = format_function_signature(fout, funcInfo, true);
12220
12221                                 /*
12222                                  * Always qualify the function name (format_function_signature
12223                                  * won't qualify it).
12224                                  */
12225                                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
12226                                                                   fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
12227                                 free(fsig);
12228                         }
12229                         else
12230                                 write_msg(NULL, "WARNING: bogus value in pg_cast.castfunc or pg_cast.castmethod field\n");
12231                         break;
12232                 default:
12233                         write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
12234         }
12235
12236         if (cast->castcontext == 'a')
12237                 appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
12238         else if (cast->castcontext == 'i')
12239                 appendPQExpBufferStr(defqry, " AS IMPLICIT");
12240         appendPQExpBufferStr(defqry, ";\n");
12241
12242         appendPQExpBuffer(labelq, "CAST (%s AS %s)",
12243                                           sourceType, targetType);
12244
12245         appendPQExpBuffer(castargs, "(%s AS %s)",
12246                                           sourceType, targetType);
12247
12248         if (dopt->binary_upgrade)
12249                 binary_upgrade_extension_member(defqry, &cast->dobj,
12250                                                                                 "CAST", castargs->data, NULL);
12251
12252         if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
12253                 ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
12254                                          ARCHIVE_OPTS(.tag = labelq->data,
12255                                                                   .description = "CAST",
12256                                                                   .owner = "",
12257                                                                   .section = SECTION_PRE_DATA,
12258                                                                   .createStmt = defqry->data,
12259                                                                   .dropStmt = delqry->data));
12260
12261         /* Dump Cast Comments */
12262         if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
12263                 dumpComment(fout, "CAST", castargs->data,
12264                                         NULL, "",
12265                                         cast->dobj.catId, 0, cast->dobj.dumpId);
12266
12267         free(sourceType);
12268         free(targetType);
12269
12270         destroyPQExpBuffer(defqry);
12271         destroyPQExpBuffer(delqry);
12272         destroyPQExpBuffer(labelq);
12273         destroyPQExpBuffer(castargs);
12274 }
12275
12276 /*
12277  * Dump a transform
12278  */
12279 static void
12280 dumpTransform(Archive *fout, TransformInfo *transform)
12281 {
12282         DumpOptions *dopt = fout->dopt;
12283         PQExpBuffer defqry;
12284         PQExpBuffer delqry;
12285         PQExpBuffer labelq;
12286         PQExpBuffer transformargs;
12287         FuncInfo   *fromsqlFuncInfo = NULL;
12288         FuncInfo   *tosqlFuncInfo = NULL;
12289         char       *lanname;
12290         char       *transformType;
12291
12292         /* Skip if not to be dumped */
12293         if (!transform->dobj.dump || dopt->dataOnly)
12294                 return;
12295
12296         /* Cannot dump if we don't have the transform functions' info */
12297         if (OidIsValid(transform->trffromsql))
12298         {
12299                 fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
12300                 if (fromsqlFuncInfo == NULL)
12301                         exit_horribly(NULL, "could not find function definition for function with OID %u\n",
12302                                                   transform->trffromsql);
12303         }
12304         if (OidIsValid(transform->trftosql))
12305         {
12306                 tosqlFuncInfo = findFuncByOid(transform->trftosql);
12307                 if (tosqlFuncInfo == NULL)
12308                         exit_horribly(NULL, "could not find function definition for function with OID %u\n",
12309                                                   transform->trftosql);
12310         }
12311
12312         defqry = createPQExpBuffer();
12313         delqry = createPQExpBuffer();
12314         labelq = createPQExpBuffer();
12315         transformargs = createPQExpBuffer();
12316
12317         lanname = get_language_name(fout, transform->trflang);
12318         transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
12319
12320         appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
12321                                           transformType, lanname);
12322
12323         appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
12324                                           transformType, lanname);
12325
12326         if (!transform->trffromsql && !transform->trftosql)
12327                 write_msg(NULL, "WARNING: bogus transform definition, at least one of trffromsql and trftosql should be nonzero\n");
12328
12329         if (transform->trffromsql)
12330         {
12331                 if (fromsqlFuncInfo)
12332                 {
12333                         char       *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
12334
12335                         /*
12336                          * Always qualify the function name (format_function_signature
12337                          * won't qualify it).
12338                          */
12339                         appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
12340                                                           fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
12341                         free(fsig);
12342                 }
12343                 else
12344                         write_msg(NULL, "WARNING: bogus value in pg_transform.trffromsql field\n");
12345         }
12346
12347         if (transform->trftosql)
12348         {
12349                 if (transform->trffromsql)
12350                         appendPQExpBuffer(defqry, ", ");
12351
12352                 if (tosqlFuncInfo)
12353                 {
12354                         char       *fsig = format_function_signature(fout, tosqlFuncInfo, true);
12355
12356                         /*
12357                          * Always qualify the function name (format_function_signature
12358                          * won't qualify it).
12359                          */
12360                         appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
12361                                                           fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
12362                         free(fsig);
12363                 }
12364                 else
12365                         write_msg(NULL, "WARNING: bogus value in pg_transform.trftosql field\n");
12366         }
12367
12368         appendPQExpBuffer(defqry, ");\n");
12369
12370         appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
12371                                           transformType, lanname);
12372
12373         appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
12374                                           transformType, lanname);
12375
12376         if (dopt->binary_upgrade)
12377                 binary_upgrade_extension_member(defqry, &transform->dobj,
12378                                                                                 "TRANSFORM", transformargs->data, NULL);
12379
12380         if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
12381                 ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
12382                                          ARCHIVE_OPTS(.tag = labelq->data,
12383                                                                   .description = "TRANSFORM",
12384                                                                   .owner = "",
12385                                                                   .section = SECTION_PRE_DATA,
12386                                                                   .createStmt = defqry->data,
12387                                                                   .dropStmt = delqry->data,
12388                                                                   .deps = transform->dobj.dependencies,
12389                                                                   .nDeps = transform->dobj.nDeps));
12390
12391         /* Dump Transform Comments */
12392         if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
12393                 dumpComment(fout, "TRANSFORM", transformargs->data,
12394                                         NULL, "",
12395                                         transform->dobj.catId, 0, transform->dobj.dumpId);
12396
12397         free(lanname);
12398         free(transformType);
12399         destroyPQExpBuffer(defqry);
12400         destroyPQExpBuffer(delqry);
12401         destroyPQExpBuffer(labelq);
12402         destroyPQExpBuffer(transformargs);
12403 }
12404
12405
12406 /*
12407  * dumpOpr
12408  *        write out a single operator definition
12409  */
12410 static void
12411 dumpOpr(Archive *fout, OprInfo *oprinfo)
12412 {
12413         DumpOptions *dopt = fout->dopt;
12414         PQExpBuffer query;
12415         PQExpBuffer q;
12416         PQExpBuffer delq;
12417         PQExpBuffer oprid;
12418         PQExpBuffer details;
12419         PGresult   *res;
12420         int                     i_oprkind;
12421         int                     i_oprcode;
12422         int                     i_oprleft;
12423         int                     i_oprright;
12424         int                     i_oprcom;
12425         int                     i_oprnegate;
12426         int                     i_oprrest;
12427         int                     i_oprjoin;
12428         int                     i_oprcanmerge;
12429         int                     i_oprcanhash;
12430         char       *oprkind;
12431         char       *oprcode;
12432         char       *oprleft;
12433         char       *oprright;
12434         char       *oprcom;
12435         char       *oprnegate;
12436         char       *oprrest;
12437         char       *oprjoin;
12438         char       *oprcanmerge;
12439         char       *oprcanhash;
12440         char       *oprregproc;
12441         char       *oprref;
12442
12443         /* Skip if not to be dumped */
12444         if (!oprinfo->dobj.dump || dopt->dataOnly)
12445                 return;
12446
12447         /*
12448          * some operators are invalid because they were the result of user
12449          * defining operators before commutators exist
12450          */
12451         if (!OidIsValid(oprinfo->oprcode))
12452                 return;
12453
12454         query = createPQExpBuffer();
12455         q = createPQExpBuffer();
12456         delq = createPQExpBuffer();
12457         oprid = createPQExpBuffer();
12458         details = createPQExpBuffer();
12459
12460         if (fout->remoteVersion >= 80300)
12461         {
12462                 appendPQExpBuffer(query, "SELECT oprkind, "
12463                                                   "oprcode::pg_catalog.regprocedure, "
12464                                                   "oprleft::pg_catalog.regtype, "
12465                                                   "oprright::pg_catalog.regtype, "
12466                                                   "oprcom, "
12467                                                   "oprnegate, "
12468                                                   "oprrest::pg_catalog.regprocedure, "
12469                                                   "oprjoin::pg_catalog.regprocedure, "
12470                                                   "oprcanmerge, oprcanhash "
12471                                                   "FROM pg_catalog.pg_operator "
12472                                                   "WHERE oid = '%u'::pg_catalog.oid",
12473                                                   oprinfo->dobj.catId.oid);
12474         }
12475         else
12476         {
12477                 appendPQExpBuffer(query, "SELECT oprkind, "
12478                                                   "oprcode::pg_catalog.regprocedure, "
12479                                                   "oprleft::pg_catalog.regtype, "
12480                                                   "oprright::pg_catalog.regtype, "
12481                                                   "oprcom, "
12482                                                   "oprnegate, "
12483                                                   "oprrest::pg_catalog.regprocedure, "
12484                                                   "oprjoin::pg_catalog.regprocedure, "
12485                                                   "(oprlsortop != 0) AS oprcanmerge, "
12486                                                   "oprcanhash "
12487                                                   "FROM pg_catalog.pg_operator "
12488                                                   "WHERE oid = '%u'::pg_catalog.oid",
12489                                                   oprinfo->dobj.catId.oid);
12490         }
12491
12492         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12493
12494         i_oprkind = PQfnumber(res, "oprkind");
12495         i_oprcode = PQfnumber(res, "oprcode");
12496         i_oprleft = PQfnumber(res, "oprleft");
12497         i_oprright = PQfnumber(res, "oprright");
12498         i_oprcom = PQfnumber(res, "oprcom");
12499         i_oprnegate = PQfnumber(res, "oprnegate");
12500         i_oprrest = PQfnumber(res, "oprrest");
12501         i_oprjoin = PQfnumber(res, "oprjoin");
12502         i_oprcanmerge = PQfnumber(res, "oprcanmerge");
12503         i_oprcanhash = PQfnumber(res, "oprcanhash");
12504
12505         oprkind = PQgetvalue(res, 0, i_oprkind);
12506         oprcode = PQgetvalue(res, 0, i_oprcode);
12507         oprleft = PQgetvalue(res, 0, i_oprleft);
12508         oprright = PQgetvalue(res, 0, i_oprright);
12509         oprcom = PQgetvalue(res, 0, i_oprcom);
12510         oprnegate = PQgetvalue(res, 0, i_oprnegate);
12511         oprrest = PQgetvalue(res, 0, i_oprrest);
12512         oprjoin = PQgetvalue(res, 0, i_oprjoin);
12513         oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
12514         oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
12515
12516         oprregproc = convertRegProcReference(fout, oprcode);
12517         if (oprregproc)
12518         {
12519                 appendPQExpBuffer(details, "    FUNCTION = %s", oprregproc);
12520                 free(oprregproc);
12521         }
12522
12523         appendPQExpBuffer(oprid, "%s (",
12524                                           oprinfo->dobj.name);
12525
12526         /*
12527          * right unary means there's a left arg and left unary means there's a
12528          * right arg
12529          */
12530         if (strcmp(oprkind, "r") == 0 ||
12531                 strcmp(oprkind, "b") == 0)
12532         {
12533                 appendPQExpBuffer(details, ",\n    LEFTARG = %s", oprleft);
12534                 appendPQExpBufferStr(oprid, oprleft);
12535         }
12536         else
12537                 appendPQExpBufferStr(oprid, "NONE");
12538
12539         if (strcmp(oprkind, "l") == 0 ||
12540                 strcmp(oprkind, "b") == 0)
12541         {
12542                 appendPQExpBuffer(details, ",\n    RIGHTARG = %s", oprright);
12543                 appendPQExpBuffer(oprid, ", %s)", oprright);
12544         }
12545         else
12546                 appendPQExpBufferStr(oprid, ", NONE)");
12547
12548         oprref = getFormattedOperatorName(fout, oprcom);
12549         if (oprref)
12550         {
12551                 appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", oprref);
12552                 free(oprref);
12553         }
12554
12555         oprref = getFormattedOperatorName(fout, oprnegate);
12556         if (oprref)
12557         {
12558                 appendPQExpBuffer(details, ",\n    NEGATOR = %s", oprref);
12559                 free(oprref);
12560         }
12561
12562         if (strcmp(oprcanmerge, "t") == 0)
12563                 appendPQExpBufferStr(details, ",\n    MERGES");
12564
12565         if (strcmp(oprcanhash, "t") == 0)
12566                 appendPQExpBufferStr(details, ",\n    HASHES");
12567
12568         oprregproc = convertRegProcReference(fout, oprrest);
12569         if (oprregproc)
12570         {
12571                 appendPQExpBuffer(details, ",\n    RESTRICT = %s", oprregproc);
12572                 free(oprregproc);
12573         }
12574
12575         oprregproc = convertRegProcReference(fout, oprjoin);
12576         if (oprregproc)
12577         {
12578                 appendPQExpBuffer(details, ",\n    JOIN = %s", oprregproc);
12579                 free(oprregproc);
12580         }
12581
12582         appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
12583                                           fmtId(oprinfo->dobj.namespace->dobj.name),
12584                                           oprid->data);
12585
12586         appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
12587                                           fmtId(oprinfo->dobj.namespace->dobj.name),
12588                                           oprinfo->dobj.name, details->data);
12589
12590         if (dopt->binary_upgrade)
12591                 binary_upgrade_extension_member(q, &oprinfo->dobj,
12592                                                                                 "OPERATOR", oprid->data,
12593                                                                                 oprinfo->dobj.namespace->dobj.name);
12594
12595         if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12596                 ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
12597                                          ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
12598                                                                   .namespace = oprinfo->dobj.namespace->dobj.name,
12599                                                                   .owner = oprinfo->rolname,
12600                                                                   .description = "OPERATOR",
12601                                                                   .section = SECTION_PRE_DATA,
12602                                                                   .createStmt = q->data,
12603                                                                   .dropStmt = delq->data));
12604
12605         /* Dump Operator Comments */
12606         if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12607                 dumpComment(fout, "OPERATOR", oprid->data,
12608                                         oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
12609                                         oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
12610
12611         PQclear(res);
12612
12613         destroyPQExpBuffer(query);
12614         destroyPQExpBuffer(q);
12615         destroyPQExpBuffer(delq);
12616         destroyPQExpBuffer(oprid);
12617         destroyPQExpBuffer(details);
12618 }
12619
12620 /*
12621  * Convert a function reference obtained from pg_operator
12622  *
12623  * Returns allocated string of what to print, or NULL if function references
12624  * is InvalidOid. Returned string is expected to be free'd by the caller.
12625  *
12626  * The input is a REGPROCEDURE display; we have to strip the argument-types
12627  * part.
12628  */
12629 static char *
12630 convertRegProcReference(Archive *fout, const char *proc)
12631 {
12632         char       *name;
12633         char       *paren;
12634         bool            inquote;
12635
12636         /* In all cases "-" means a null reference */
12637         if (strcmp(proc, "-") == 0)
12638                 return NULL;
12639
12640         name = pg_strdup(proc);
12641         /* find non-double-quoted left paren */
12642         inquote = false;
12643         for (paren = name; *paren; paren++)
12644         {
12645                 if (*paren == '(' && !inquote)
12646                 {
12647                         *paren = '\0';
12648                         break;
12649                 }
12650                 if (*paren == '"')
12651                         inquote = !inquote;
12652         }
12653         return name;
12654 }
12655
12656 /*
12657  * getFormattedOperatorName - retrieve the operator name for the
12658  * given operator OID (presented in string form).
12659  *
12660  * Returns an allocated string, or NULL if the given OID is invalid.
12661  * Caller is responsible for free'ing result string.
12662  *
12663  * What we produce has the format "OPERATOR(schema.oprname)".  This is only
12664  * useful in commands where the operator's argument types can be inferred from
12665  * context.  We always schema-qualify the name, though.  The predecessor to
12666  * this code tried to skip the schema qualification if possible, but that led
12667  * to wrong results in corner cases, such as if an operator and its negator
12668  * are in different schemas.
12669  */
12670 static char *
12671 getFormattedOperatorName(Archive *fout, const char *oproid)
12672 {
12673         OprInfo    *oprInfo;
12674
12675         /* In all cases "0" means a null reference */
12676         if (strcmp(oproid, "0") == 0)
12677                 return NULL;
12678
12679         oprInfo = findOprByOid(atooid(oproid));
12680         if (oprInfo == NULL)
12681         {
12682                 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
12683                                   oproid);
12684                 return NULL;
12685         }
12686
12687         return psprintf("OPERATOR(%s.%s)",
12688                                         fmtId(oprInfo->dobj.namespace->dobj.name),
12689                                         oprInfo->dobj.name);
12690 }
12691
12692 /*
12693  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
12694  *
12695  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
12696  * argument lists of these functions are predetermined.  Note that the
12697  * caller should ensure we are in the proper schema, because the results
12698  * are search path dependent!
12699  */
12700 static char *
12701 convertTSFunction(Archive *fout, Oid funcOid)
12702 {
12703         char       *result;
12704         char            query[128];
12705         PGresult   *res;
12706
12707         snprintf(query, sizeof(query),
12708                          "SELECT '%u'::pg_catalog.regproc", funcOid);
12709         res = ExecuteSqlQueryForSingleRow(fout, query);
12710
12711         result = pg_strdup(PQgetvalue(res, 0, 0));
12712
12713         PQclear(res);
12714
12715         return result;
12716 }
12717
12718 /*
12719  * dumpAccessMethod
12720  *        write out a single access method definition
12721  */
12722 static void
12723 dumpAccessMethod(Archive *fout, AccessMethodInfo *aminfo)
12724 {
12725         DumpOptions *dopt = fout->dopt;
12726         PQExpBuffer q;
12727         PQExpBuffer delq;
12728         char       *qamname;
12729
12730         /* Skip if not to be dumped */
12731         if (!aminfo->dobj.dump || dopt->dataOnly)
12732                 return;
12733
12734         q = createPQExpBuffer();
12735         delq = createPQExpBuffer();
12736
12737         qamname = pg_strdup(fmtId(aminfo->dobj.name));
12738
12739         appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
12740
12741         switch (aminfo->amtype)
12742         {
12743                 case AMTYPE_INDEX:
12744                         appendPQExpBuffer(q, "TYPE INDEX ");
12745                         break;
12746                 case AMTYPE_TABLE:
12747                         appendPQExpBuffer(q, "TYPE TABLE ");
12748                         break;
12749                 default:
12750                         write_msg(NULL, "WARNING: invalid type \"%c\" of access method \"%s\"\n",
12751                                           aminfo->amtype, qamname);
12752                         destroyPQExpBuffer(q);
12753                         destroyPQExpBuffer(delq);
12754                         free(qamname);
12755                         return;
12756         }
12757
12758         appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
12759
12760         appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
12761                                           qamname);
12762
12763         if (dopt->binary_upgrade)
12764                 binary_upgrade_extension_member(q, &aminfo->dobj,
12765                                                                                 "ACCESS METHOD", qamname, NULL);
12766
12767         if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12768                 ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
12769                                          ARCHIVE_OPTS(.tag = aminfo->dobj.name,
12770                                                                   .description = "ACCESS METHOD",
12771                                                                   .owner = "",
12772                                                                   .section = SECTION_PRE_DATA,
12773                                                                   .createStmt = q->data,
12774                                                                   .dropStmt = delq->data));
12775
12776         /* Dump Access Method Comments */
12777         if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12778                 dumpComment(fout, "ACCESS METHOD", qamname,
12779                                         NULL, "",
12780                                         aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
12781
12782         destroyPQExpBuffer(q);
12783         destroyPQExpBuffer(delq);
12784         free(qamname);
12785 }
12786
12787 /*
12788  * dumpOpclass
12789  *        write out a single operator class definition
12790  */
12791 static void
12792 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
12793 {
12794         DumpOptions *dopt = fout->dopt;
12795         PQExpBuffer query;
12796         PQExpBuffer q;
12797         PQExpBuffer delq;
12798         PQExpBuffer nameusing;
12799         PGresult   *res;
12800         int                     ntups;
12801         int                     i_opcintype;
12802         int                     i_opckeytype;
12803         int                     i_opcdefault;
12804         int                     i_opcfamily;
12805         int                     i_opcfamilyname;
12806         int                     i_opcfamilynsp;
12807         int                     i_amname;
12808         int                     i_amopstrategy;
12809         int                     i_amopreqcheck;
12810         int                     i_amopopr;
12811         int                     i_sortfamily;
12812         int                     i_sortfamilynsp;
12813         int                     i_amprocnum;
12814         int                     i_amproc;
12815         int                     i_amproclefttype;
12816         int                     i_amprocrighttype;
12817         char       *opcintype;
12818         char       *opckeytype;
12819         char       *opcdefault;
12820         char       *opcfamily;
12821         char       *opcfamilyname;
12822         char       *opcfamilynsp;
12823         char       *amname;
12824         char       *amopstrategy;
12825         char       *amopreqcheck;
12826         char       *amopopr;
12827         char       *sortfamily;
12828         char       *sortfamilynsp;
12829         char       *amprocnum;
12830         char       *amproc;
12831         char       *amproclefttype;
12832         char       *amprocrighttype;
12833         bool            needComma;
12834         int                     i;
12835
12836         /* Skip if not to be dumped */
12837         if (!opcinfo->dobj.dump || dopt->dataOnly)
12838                 return;
12839
12840         query = createPQExpBuffer();
12841         q = createPQExpBuffer();
12842         delq = createPQExpBuffer();
12843         nameusing = createPQExpBuffer();
12844
12845         /* Get additional fields from the pg_opclass row */
12846         if (fout->remoteVersion >= 80300)
12847         {
12848                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
12849                                                   "opckeytype::pg_catalog.regtype, "
12850                                                   "opcdefault, opcfamily, "
12851                                                   "opfname AS opcfamilyname, "
12852                                                   "nspname AS opcfamilynsp, "
12853                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
12854                                                   "FROM pg_catalog.pg_opclass c "
12855                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
12856                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12857                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
12858                                                   opcinfo->dobj.catId.oid);
12859         }
12860         else
12861         {
12862                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
12863                                                   "opckeytype::pg_catalog.regtype, "
12864                                                   "opcdefault, NULL AS opcfamily, "
12865                                                   "NULL AS opcfamilyname, "
12866                                                   "NULL AS opcfamilynsp, "
12867                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
12868                                                   "FROM pg_catalog.pg_opclass "
12869                                                   "WHERE oid = '%u'::pg_catalog.oid",
12870                                                   opcinfo->dobj.catId.oid);
12871         }
12872
12873         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12874
12875         i_opcintype = PQfnumber(res, "opcintype");
12876         i_opckeytype = PQfnumber(res, "opckeytype");
12877         i_opcdefault = PQfnumber(res, "opcdefault");
12878         i_opcfamily = PQfnumber(res, "opcfamily");
12879         i_opcfamilyname = PQfnumber(res, "opcfamilyname");
12880         i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
12881         i_amname = PQfnumber(res, "amname");
12882
12883         /* opcintype may still be needed after we PQclear res */
12884         opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
12885         opckeytype = PQgetvalue(res, 0, i_opckeytype);
12886         opcdefault = PQgetvalue(res, 0, i_opcdefault);
12887         /* opcfamily will still be needed after we PQclear res */
12888         opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
12889         opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
12890         opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
12891         /* amname will still be needed after we PQclear res */
12892         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
12893
12894         appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
12895                                           fmtQualifiedDumpable(opcinfo));
12896         appendPQExpBuffer(delq, " USING %s;\n",
12897                                           fmtId(amname));
12898
12899         /* Build the fixed portion of the CREATE command */
12900         appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
12901                                           fmtQualifiedDumpable(opcinfo));
12902         if (strcmp(opcdefault, "t") == 0)
12903                 appendPQExpBufferStr(q, "DEFAULT ");
12904         appendPQExpBuffer(q, "FOR TYPE %s USING %s",
12905                                           opcintype,
12906                                           fmtId(amname));
12907         if (strlen(opcfamilyname) > 0)
12908         {
12909                 appendPQExpBufferStr(q, " FAMILY ");
12910                 appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
12911                 appendPQExpBufferStr(q, fmtId(opcfamilyname));
12912         }
12913         appendPQExpBufferStr(q, " AS\n    ");
12914
12915         needComma = false;
12916
12917         if (strcmp(opckeytype, "-") != 0)
12918         {
12919                 appendPQExpBuffer(q, "STORAGE %s",
12920                                                   opckeytype);
12921                 needComma = true;
12922         }
12923
12924         PQclear(res);
12925
12926         /*
12927          * Now fetch and print the OPERATOR entries (pg_amop rows).
12928          *
12929          * Print only those opfamily members that are tied to the opclass by
12930          * pg_depend entries.
12931          *
12932          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
12933          * older server's opclass in which it is used.  This is to avoid
12934          * hard-to-detect breakage if a newer pg_dump is used to dump from an
12935          * older server and then reload into that old version.  This can go away
12936          * once 8.3 is so old as to not be of interest to anyone.
12937          */
12938         resetPQExpBuffer(query);
12939
12940         if (fout->remoteVersion >= 90100)
12941         {
12942                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12943                                                   "amopopr::pg_catalog.regoperator, "
12944                                                   "opfname AS sortfamily, "
12945                                                   "nspname AS sortfamilynsp "
12946                                                   "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
12947                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
12948                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
12949                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12950                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12951                                                   "AND refobjid = '%u'::pg_catalog.oid "
12952                                                   "AND amopfamily = '%s'::pg_catalog.oid "
12953                                                   "ORDER BY amopstrategy",
12954                                                   opcinfo->dobj.catId.oid,
12955                                                   opcfamily);
12956         }
12957         else if (fout->remoteVersion >= 80400)
12958         {
12959                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12960                                                   "amopopr::pg_catalog.regoperator, "
12961                                                   "NULL AS sortfamily, "
12962                                                   "NULL AS sortfamilynsp "
12963                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12964                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12965                                                   "AND refobjid = '%u'::pg_catalog.oid "
12966                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12967                                                   "AND objid = ao.oid "
12968                                                   "ORDER BY amopstrategy",
12969                                                   opcinfo->dobj.catId.oid);
12970         }
12971         else if (fout->remoteVersion >= 80300)
12972         {
12973                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
12974                                                   "amopopr::pg_catalog.regoperator, "
12975                                                   "NULL AS sortfamily, "
12976                                                   "NULL AS sortfamilynsp "
12977                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12978                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12979                                                   "AND refobjid = '%u'::pg_catalog.oid "
12980                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12981                                                   "AND objid = ao.oid "
12982                                                   "ORDER BY amopstrategy",
12983                                                   opcinfo->dobj.catId.oid);
12984         }
12985         else
12986         {
12987                 /*
12988                  * Here, we print all entries since there are no opfamilies and hence
12989                  * no loose operators to worry about.
12990                  */
12991                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
12992                                                   "amopopr::pg_catalog.regoperator, "
12993                                                   "NULL AS sortfamily, "
12994                                                   "NULL AS sortfamilynsp "
12995                                                   "FROM pg_catalog.pg_amop "
12996                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
12997                                                   "ORDER BY amopstrategy",
12998                                                   opcinfo->dobj.catId.oid);
12999         }
13000
13001         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13002
13003         ntups = PQntuples(res);
13004
13005         i_amopstrategy = PQfnumber(res, "amopstrategy");
13006         i_amopreqcheck = PQfnumber(res, "amopreqcheck");
13007         i_amopopr = PQfnumber(res, "amopopr");
13008         i_sortfamily = PQfnumber(res, "sortfamily");
13009         i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
13010
13011         for (i = 0; i < ntups; i++)
13012         {
13013                 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
13014                 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
13015                 amopopr = PQgetvalue(res, i, i_amopopr);
13016                 sortfamily = PQgetvalue(res, i, i_sortfamily);
13017                 sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
13018
13019                 if (needComma)
13020                         appendPQExpBufferStr(q, " ,\n    ");
13021
13022                 appendPQExpBuffer(q, "OPERATOR %s %s",
13023                                                   amopstrategy, amopopr);
13024
13025                 if (strlen(sortfamily) > 0)
13026                 {
13027                         appendPQExpBufferStr(q, " FOR ORDER BY ");
13028                         appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
13029                         appendPQExpBufferStr(q, fmtId(sortfamily));
13030                 }
13031
13032                 if (strcmp(amopreqcheck, "t") == 0)
13033                         appendPQExpBufferStr(q, " RECHECK");
13034
13035                 needComma = true;
13036         }
13037
13038         PQclear(res);
13039
13040         /*
13041          * Now fetch and print the FUNCTION entries (pg_amproc rows).
13042          *
13043          * Print only those opfamily members that are tied to the opclass by
13044          * pg_depend entries.
13045          *
13046          * We print the amproclefttype/amprocrighttype even though in most cases
13047          * the backend could deduce the right values, because of the corner case
13048          * of a btree sort support function for a cross-type comparison.  That's
13049          * only allowed in 9.2 and later, but for simplicity print them in all
13050          * versions that have the columns.
13051          */
13052         resetPQExpBuffer(query);
13053
13054         if (fout->remoteVersion >= 80300)
13055         {
13056                 appendPQExpBuffer(query, "SELECT amprocnum, "
13057                                                   "amproc::pg_catalog.regprocedure, "
13058                                                   "amproclefttype::pg_catalog.regtype, "
13059                                                   "amprocrighttype::pg_catalog.regtype "
13060                                                   "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
13061                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
13062                                                   "AND refobjid = '%u'::pg_catalog.oid "
13063                                                   "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
13064                                                   "AND objid = ap.oid "
13065                                                   "ORDER BY amprocnum",
13066                                                   opcinfo->dobj.catId.oid);
13067         }
13068         else
13069         {
13070                 appendPQExpBuffer(query, "SELECT amprocnum, "
13071                                                   "amproc::pg_catalog.regprocedure, "
13072                                                   "'' AS amproclefttype, "
13073                                                   "'' AS amprocrighttype "
13074                                                   "FROM pg_catalog.pg_amproc "
13075                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
13076                                                   "ORDER BY amprocnum",
13077                                                   opcinfo->dobj.catId.oid);
13078         }
13079
13080         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13081
13082         ntups = PQntuples(res);
13083
13084         i_amprocnum = PQfnumber(res, "amprocnum");
13085         i_amproc = PQfnumber(res, "amproc");
13086         i_amproclefttype = PQfnumber(res, "amproclefttype");
13087         i_amprocrighttype = PQfnumber(res, "amprocrighttype");
13088
13089         for (i = 0; i < ntups; i++)
13090         {
13091                 amprocnum = PQgetvalue(res, i, i_amprocnum);
13092                 amproc = PQgetvalue(res, i, i_amproc);
13093                 amproclefttype = PQgetvalue(res, i, i_amproclefttype);
13094                 amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
13095
13096                 if (needComma)
13097                         appendPQExpBufferStr(q, " ,\n    ");
13098
13099                 appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
13100
13101                 if (*amproclefttype && *amprocrighttype)
13102                         appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
13103
13104                 appendPQExpBuffer(q, " %s", amproc);
13105
13106                 needComma = true;
13107         }
13108
13109         PQclear(res);
13110
13111         /*
13112          * If needComma is still false it means we haven't added anything after
13113          * the AS keyword.  To avoid printing broken SQL, append a dummy STORAGE
13114          * clause with the same datatype.  This isn't sanctioned by the
13115          * documentation, but actually DefineOpClass will treat it as a no-op.
13116          */
13117         if (!needComma)
13118                 appendPQExpBuffer(q, "STORAGE %s", opcintype);
13119
13120         appendPQExpBufferStr(q, ";\n");
13121
13122         appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
13123         appendPQExpBuffer(nameusing, " USING %s",
13124                                           fmtId(amname));
13125
13126         if (dopt->binary_upgrade)
13127                 binary_upgrade_extension_member(q, &opcinfo->dobj,
13128                                                                                 "OPERATOR CLASS", nameusing->data,
13129                                                                                 opcinfo->dobj.namespace->dobj.name);
13130
13131         if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13132                 ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
13133                                          ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
13134                                                                   .namespace = opcinfo->dobj.namespace->dobj.name,
13135                                                                   .owner = opcinfo->rolname,
13136                                                                   .description = "OPERATOR CLASS",
13137                                                                   .section = SECTION_PRE_DATA,
13138                                                                   .createStmt = q->data,
13139                                                                   .dropStmt = delq->data));
13140
13141         /* Dump Operator Class Comments */
13142         if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13143                 dumpComment(fout, "OPERATOR CLASS", nameusing->data,
13144                                         opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
13145                                         opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
13146
13147         free(opcintype);
13148         free(opcfamily);
13149         free(amname);
13150         destroyPQExpBuffer(query);
13151         destroyPQExpBuffer(q);
13152         destroyPQExpBuffer(delq);
13153         destroyPQExpBuffer(nameusing);
13154 }
13155
13156 /*
13157  * dumpOpfamily
13158  *        write out a single operator family definition
13159  *
13160  * Note: this also dumps any "loose" operator members that aren't bound to a
13161  * specific opclass within the opfamily.
13162  */
13163 static void
13164 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
13165 {
13166         DumpOptions *dopt = fout->dopt;
13167         PQExpBuffer query;
13168         PQExpBuffer q;
13169         PQExpBuffer delq;
13170         PQExpBuffer nameusing;
13171         PGresult   *res;
13172         PGresult   *res_ops;
13173         PGresult   *res_procs;
13174         int                     ntups;
13175         int                     i_amname;
13176         int                     i_amopstrategy;
13177         int                     i_amopreqcheck;
13178         int                     i_amopopr;
13179         int                     i_sortfamily;
13180         int                     i_sortfamilynsp;
13181         int                     i_amprocnum;
13182         int                     i_amproc;
13183         int                     i_amproclefttype;
13184         int                     i_amprocrighttype;
13185         char       *amname;
13186         char       *amopstrategy;
13187         char       *amopreqcheck;
13188         char       *amopopr;
13189         char       *sortfamily;
13190         char       *sortfamilynsp;
13191         char       *amprocnum;
13192         char       *amproc;
13193         char       *amproclefttype;
13194         char       *amprocrighttype;
13195         bool            needComma;
13196         int                     i;
13197
13198         /* Skip if not to be dumped */
13199         if (!opfinfo->dobj.dump || dopt->dataOnly)
13200                 return;
13201
13202         query = createPQExpBuffer();
13203         q = createPQExpBuffer();
13204         delq = createPQExpBuffer();
13205         nameusing = createPQExpBuffer();
13206
13207         /*
13208          * Fetch only those opfamily members that are tied directly to the
13209          * opfamily by pg_depend entries.
13210          *
13211          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
13212          * older server's opclass in which it is used.  This is to avoid
13213          * hard-to-detect breakage if a newer pg_dump is used to dump from an
13214          * older server and then reload into that old version.  This can go away
13215          * once 8.3 is so old as to not be of interest to anyone.
13216          */
13217         if (fout->remoteVersion >= 90100)
13218         {
13219                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
13220                                                   "amopopr::pg_catalog.regoperator, "
13221                                                   "opfname AS sortfamily, "
13222                                                   "nspname AS sortfamilynsp "
13223                                                   "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
13224                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
13225                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
13226                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
13227                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13228                                                   "AND refobjid = '%u'::pg_catalog.oid "
13229                                                   "AND amopfamily = '%u'::pg_catalog.oid "
13230                                                   "ORDER BY amopstrategy",
13231                                                   opfinfo->dobj.catId.oid,
13232                                                   opfinfo->dobj.catId.oid);
13233         }
13234         else if (fout->remoteVersion >= 80400)
13235         {
13236                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
13237                                                   "amopopr::pg_catalog.regoperator, "
13238                                                   "NULL AS sortfamily, "
13239                                                   "NULL AS sortfamilynsp "
13240                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
13241                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13242                                                   "AND refobjid = '%u'::pg_catalog.oid "
13243                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
13244                                                   "AND objid = ao.oid "
13245                                                   "ORDER BY amopstrategy",
13246                                                   opfinfo->dobj.catId.oid);
13247         }
13248         else
13249         {
13250                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
13251                                                   "amopopr::pg_catalog.regoperator, "
13252                                                   "NULL AS sortfamily, "
13253                                                   "NULL AS sortfamilynsp "
13254                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
13255                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13256                                                   "AND refobjid = '%u'::pg_catalog.oid "
13257                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
13258                                                   "AND objid = ao.oid "
13259                                                   "ORDER BY amopstrategy",
13260                                                   opfinfo->dobj.catId.oid);
13261         }
13262
13263         res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13264
13265         resetPQExpBuffer(query);
13266
13267         appendPQExpBuffer(query, "SELECT amprocnum, "
13268                                           "amproc::pg_catalog.regprocedure, "
13269                                           "amproclefttype::pg_catalog.regtype, "
13270                                           "amprocrighttype::pg_catalog.regtype "
13271                                           "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
13272                                           "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13273                                           "AND refobjid = '%u'::pg_catalog.oid "
13274                                           "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
13275                                           "AND objid = ap.oid "
13276                                           "ORDER BY amprocnum",
13277                                           opfinfo->dobj.catId.oid);
13278
13279         res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13280
13281         /* Get additional fields from the pg_opfamily row */
13282         resetPQExpBuffer(query);
13283
13284         appendPQExpBuffer(query, "SELECT "
13285                                           "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
13286                                           "FROM pg_catalog.pg_opfamily "
13287                                           "WHERE oid = '%u'::pg_catalog.oid",
13288                                           opfinfo->dobj.catId.oid);
13289
13290         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13291
13292         i_amname = PQfnumber(res, "amname");
13293
13294         /* amname will still be needed after we PQclear res */
13295         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
13296
13297         appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
13298                                           fmtQualifiedDumpable(opfinfo));
13299         appendPQExpBuffer(delq, " USING %s;\n",
13300                                           fmtId(amname));
13301
13302         /* Build the fixed portion of the CREATE command */
13303         appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
13304                                           fmtQualifiedDumpable(opfinfo));
13305         appendPQExpBuffer(q, " USING %s;\n",
13306                                           fmtId(amname));
13307
13308         PQclear(res);
13309
13310         /* Do we need an ALTER to add loose members? */
13311         if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
13312         {
13313                 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
13314                                                   fmtQualifiedDumpable(opfinfo));
13315                 appendPQExpBuffer(q, " USING %s ADD\n    ",
13316                                                   fmtId(amname));
13317
13318                 needComma = false;
13319
13320                 /*
13321                  * Now fetch and print the OPERATOR entries (pg_amop rows).
13322                  */
13323                 ntups = PQntuples(res_ops);
13324
13325                 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
13326                 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
13327                 i_amopopr = PQfnumber(res_ops, "amopopr");
13328                 i_sortfamily = PQfnumber(res_ops, "sortfamily");
13329                 i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
13330
13331                 for (i = 0; i < ntups; i++)
13332                 {
13333                         amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
13334                         amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
13335                         amopopr = PQgetvalue(res_ops, i, i_amopopr);
13336                         sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
13337                         sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
13338
13339                         if (needComma)
13340                                 appendPQExpBufferStr(q, " ,\n    ");
13341
13342                         appendPQExpBuffer(q, "OPERATOR %s %s",
13343                                                           amopstrategy, amopopr);
13344
13345                         if (strlen(sortfamily) > 0)
13346                         {
13347                                 appendPQExpBufferStr(q, " FOR ORDER BY ");
13348                                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
13349                                 appendPQExpBufferStr(q, fmtId(sortfamily));
13350                         }
13351
13352                         if (strcmp(amopreqcheck, "t") == 0)
13353                                 appendPQExpBufferStr(q, " RECHECK");
13354
13355                         needComma = true;
13356                 }
13357
13358                 /*
13359                  * Now fetch and print the FUNCTION entries (pg_amproc rows).
13360                  */
13361                 ntups = PQntuples(res_procs);
13362
13363                 i_amprocnum = PQfnumber(res_procs, "amprocnum");
13364                 i_amproc = PQfnumber(res_procs, "amproc");
13365                 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
13366                 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
13367
13368                 for (i = 0; i < ntups; i++)
13369                 {
13370                         amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
13371                         amproc = PQgetvalue(res_procs, i, i_amproc);
13372                         amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
13373                         amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
13374
13375                         if (needComma)
13376                                 appendPQExpBufferStr(q, " ,\n    ");
13377
13378                         appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
13379                                                           amprocnum, amproclefttype, amprocrighttype,
13380                                                           amproc);
13381
13382                         needComma = true;
13383                 }
13384
13385                 appendPQExpBufferStr(q, ";\n");
13386         }
13387
13388         appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
13389         appendPQExpBuffer(nameusing, " USING %s",
13390                                           fmtId(amname));
13391
13392         if (dopt->binary_upgrade)
13393                 binary_upgrade_extension_member(q, &opfinfo->dobj,
13394                                                                                 "OPERATOR FAMILY", nameusing->data,
13395                                                                                 opfinfo->dobj.namespace->dobj.name);
13396
13397         if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13398                 ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
13399                                          ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
13400                                                                   .namespace = opfinfo->dobj.namespace->dobj.name,
13401                                                                   .owner = opfinfo->rolname,
13402                                                                   .description = "OPERATOR FAMILY",
13403                                                                   .section = SECTION_PRE_DATA,
13404                                                                   .createStmt = q->data,
13405                                                                   .dropStmt = delq->data));
13406
13407         /* Dump Operator Family Comments */
13408         if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13409                 dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
13410                                         opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
13411                                         opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
13412
13413         free(amname);
13414         PQclear(res_ops);
13415         PQclear(res_procs);
13416         destroyPQExpBuffer(query);
13417         destroyPQExpBuffer(q);
13418         destroyPQExpBuffer(delq);
13419         destroyPQExpBuffer(nameusing);
13420 }
13421
13422 /*
13423  * dumpCollation
13424  *        write out a single collation definition
13425  */
13426 static void
13427 dumpCollation(Archive *fout, CollInfo *collinfo)
13428 {
13429         DumpOptions *dopt = fout->dopt;
13430         PQExpBuffer query;
13431         PQExpBuffer q;
13432         PQExpBuffer delq;
13433         char       *qcollname;
13434         PGresult   *res;
13435         int                     i_collprovider;
13436         int                     i_collisdeterministic;
13437         int                     i_collcollate;
13438         int                     i_collctype;
13439         const char *collprovider;
13440         const char *collcollate;
13441         const char *collctype;
13442
13443         /* Skip if not to be dumped */
13444         if (!collinfo->dobj.dump || dopt->dataOnly)
13445                 return;
13446
13447         query = createPQExpBuffer();
13448         q = createPQExpBuffer();
13449         delq = createPQExpBuffer();
13450
13451         qcollname = pg_strdup(fmtId(collinfo->dobj.name));
13452
13453         /* Get collation-specific details */
13454         appendPQExpBuffer(query, "SELECT ");
13455
13456         if (fout->remoteVersion >= 100000)
13457                 appendPQExpBuffer(query,
13458                                                   "collprovider, "
13459                                                   "collversion, ");
13460         else
13461                 appendPQExpBuffer(query,
13462                                                   "'c' AS collprovider, "
13463                                                   "NULL AS collversion, ");
13464
13465         if (fout->remoteVersion >= 120000)
13466                 appendPQExpBuffer(query,
13467                                                   "collisdeterministic, ");
13468         else
13469                 appendPQExpBuffer(query,
13470                                                   "true AS collisdeterministic, ");
13471
13472         appendPQExpBuffer(query,
13473                                           "collcollate, "
13474                                           "collctype "
13475                                           "FROM pg_catalog.pg_collation c "
13476                                           "WHERE c.oid = '%u'::pg_catalog.oid",
13477                                           collinfo->dobj.catId.oid);
13478
13479         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13480
13481         i_collprovider = PQfnumber(res, "collprovider");
13482         i_collisdeterministic = PQfnumber(res, "collisdeterministic");
13483         i_collcollate = PQfnumber(res, "collcollate");
13484         i_collctype = PQfnumber(res, "collctype");
13485
13486         collprovider = PQgetvalue(res, 0, i_collprovider);
13487         collcollate = PQgetvalue(res, 0, i_collcollate);
13488         collctype = PQgetvalue(res, 0, i_collctype);
13489
13490         appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
13491                                           fmtQualifiedDumpable(collinfo));
13492
13493         appendPQExpBuffer(q, "CREATE COLLATION %s (",
13494                                           fmtQualifiedDumpable(collinfo));
13495
13496         appendPQExpBufferStr(q, "provider = ");
13497         if (collprovider[0] == 'c')
13498                 appendPQExpBufferStr(q, "libc");
13499         else if (collprovider[0] == 'i')
13500                 appendPQExpBufferStr(q, "icu");
13501         else if (collprovider[0] == 'd')
13502                 /* to allow dumping pg_catalog; not accepted on input */
13503                 appendPQExpBufferStr(q, "default");
13504         else
13505                 exit_horribly(NULL,
13506                                           "unrecognized collation provider: %s\n",
13507                                           collprovider);
13508
13509         if (strcmp(PQgetvalue(res, 0, i_collisdeterministic), "f") == 0)
13510                 appendPQExpBufferStr(q, ", deterministic = false");
13511
13512         if (strcmp(collcollate, collctype) == 0)
13513         {
13514                 appendPQExpBufferStr(q, ", locale = ");
13515                 appendStringLiteralAH(q, collcollate, fout);
13516         }
13517         else
13518         {
13519                 appendPQExpBufferStr(q, ", lc_collate = ");
13520                 appendStringLiteralAH(q, collcollate, fout);
13521                 appendPQExpBufferStr(q, ", lc_ctype = ");
13522                 appendStringLiteralAH(q, collctype, fout);
13523         }
13524
13525         /*
13526          * For binary upgrade, carry over the collation version.  For normal
13527          * dump/restore, omit the version, so that it is computed upon restore.
13528          */
13529         if (dopt->binary_upgrade)
13530         {
13531                 int                     i_collversion;
13532
13533                 i_collversion = PQfnumber(res, "collversion");
13534                 if (!PQgetisnull(res, 0, i_collversion))
13535                 {
13536                         appendPQExpBufferStr(q, ", version = ");
13537                         appendStringLiteralAH(q,
13538                                                                   PQgetvalue(res, 0, i_collversion),
13539                                                                   fout);
13540                 }
13541         }
13542
13543         appendPQExpBufferStr(q, ");\n");
13544
13545         if (dopt->binary_upgrade)
13546                 binary_upgrade_extension_member(q, &collinfo->dobj,
13547                                                                                 "COLLATION", qcollname,
13548                                                                                 collinfo->dobj.namespace->dobj.name);
13549
13550         if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13551                 ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
13552                                          ARCHIVE_OPTS(.tag = collinfo->dobj.name,
13553                                                                   .namespace = collinfo->dobj.namespace->dobj.name,
13554                                                                   .owner = collinfo->rolname,
13555                                                                   .description = "COLLATION",
13556                                                                   .section = SECTION_PRE_DATA,
13557                                                                   .createStmt = q->data,
13558                                                                   .dropStmt = delq->data));
13559
13560         /* Dump Collation Comments */
13561         if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13562                 dumpComment(fout, "COLLATION", qcollname,
13563                                         collinfo->dobj.namespace->dobj.name, collinfo->rolname,
13564                                         collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
13565
13566         PQclear(res);
13567
13568         destroyPQExpBuffer(query);
13569         destroyPQExpBuffer(q);
13570         destroyPQExpBuffer(delq);
13571         free(qcollname);
13572 }
13573
13574 /*
13575  * dumpConversion
13576  *        write out a single conversion definition
13577  */
13578 static void
13579 dumpConversion(Archive *fout, ConvInfo *convinfo)
13580 {
13581         DumpOptions *dopt = fout->dopt;
13582         PQExpBuffer query;
13583         PQExpBuffer q;
13584         PQExpBuffer delq;
13585         char       *qconvname;
13586         PGresult   *res;
13587         int                     i_conforencoding;
13588         int                     i_contoencoding;
13589         int                     i_conproc;
13590         int                     i_condefault;
13591         const char *conforencoding;
13592         const char *contoencoding;
13593         const char *conproc;
13594         bool            condefault;
13595
13596         /* Skip if not to be dumped */
13597         if (!convinfo->dobj.dump || dopt->dataOnly)
13598                 return;
13599
13600         query = createPQExpBuffer();
13601         q = createPQExpBuffer();
13602         delq = createPQExpBuffer();
13603
13604         qconvname = pg_strdup(fmtId(convinfo->dobj.name));
13605
13606         /* Get conversion-specific details */
13607         appendPQExpBuffer(query, "SELECT "
13608                                           "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
13609                                           "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
13610                                           "conproc, condefault "
13611                                           "FROM pg_catalog.pg_conversion c "
13612                                           "WHERE c.oid = '%u'::pg_catalog.oid",
13613                                           convinfo->dobj.catId.oid);
13614
13615         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13616
13617         i_conforencoding = PQfnumber(res, "conforencoding");
13618         i_contoencoding = PQfnumber(res, "contoencoding");
13619         i_conproc = PQfnumber(res, "conproc");
13620         i_condefault = PQfnumber(res, "condefault");
13621
13622         conforencoding = PQgetvalue(res, 0, i_conforencoding);
13623         contoencoding = PQgetvalue(res, 0, i_contoencoding);
13624         conproc = PQgetvalue(res, 0, i_conproc);
13625         condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
13626
13627         appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
13628                                           fmtQualifiedDumpable(convinfo));
13629
13630         appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
13631                                           (condefault) ? "DEFAULT " : "",
13632                                           fmtQualifiedDumpable(convinfo));
13633         appendStringLiteralAH(q, conforencoding, fout);
13634         appendPQExpBufferStr(q, " TO ");
13635         appendStringLiteralAH(q, contoencoding, fout);
13636         /* regproc output is already sufficiently quoted */
13637         appendPQExpBuffer(q, " FROM %s;\n", conproc);
13638
13639         if (dopt->binary_upgrade)
13640                 binary_upgrade_extension_member(q, &convinfo->dobj,
13641                                                                                 "CONVERSION", qconvname,
13642                                                                                 convinfo->dobj.namespace->dobj.name);
13643
13644         if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13645                 ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
13646                                          ARCHIVE_OPTS(.tag = convinfo->dobj.name,
13647                                                                   .namespace = convinfo->dobj.namespace->dobj.name,
13648                                                                   .owner = convinfo->rolname,
13649                                                                   .description = "CONVERSION",
13650                                                                   .section = SECTION_PRE_DATA,
13651                                                                   .createStmt = q->data,
13652                                                                   .dropStmt = delq->data));
13653
13654         /* Dump Conversion Comments */
13655         if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13656                 dumpComment(fout, "CONVERSION", qconvname,
13657                                         convinfo->dobj.namespace->dobj.name, convinfo->rolname,
13658                                         convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
13659
13660         PQclear(res);
13661
13662         destroyPQExpBuffer(query);
13663         destroyPQExpBuffer(q);
13664         destroyPQExpBuffer(delq);
13665         free(qconvname);
13666 }
13667
13668 /*
13669  * format_aggregate_signature: generate aggregate name and argument list
13670  *
13671  * The argument type names are qualified if needed.  The aggregate name
13672  * is never qualified.
13673  */
13674 static char *
13675 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
13676 {
13677         PQExpBufferData buf;
13678         int                     j;
13679
13680         initPQExpBuffer(&buf);
13681         if (honor_quotes)
13682                 appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
13683         else
13684                 appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
13685
13686         if (agginfo->aggfn.nargs == 0)
13687                 appendPQExpBuffer(&buf, "(*)");
13688         else
13689         {
13690                 appendPQExpBufferChar(&buf, '(');
13691                 for (j = 0; j < agginfo->aggfn.nargs; j++)
13692                 {
13693                         char       *typname;
13694
13695                         typname = getFormattedTypeName(fout, agginfo->aggfn.argtypes[j],
13696                                                                                    zeroAsOpaque);
13697
13698                         appendPQExpBuffer(&buf, "%s%s",
13699                                                           (j > 0) ? ", " : "",
13700                                                           typname);
13701                         free(typname);
13702                 }
13703                 appendPQExpBufferChar(&buf, ')');
13704         }
13705         return buf.data;
13706 }
13707
13708 /*
13709  * dumpAgg
13710  *        write out a single aggregate definition
13711  */
13712 static void
13713 dumpAgg(Archive *fout, AggInfo *agginfo)
13714 {
13715         DumpOptions *dopt = fout->dopt;
13716         PQExpBuffer query;
13717         PQExpBuffer q;
13718         PQExpBuffer delq;
13719         PQExpBuffer details;
13720         char       *aggsig;                     /* identity signature */
13721         char       *aggfullsig = NULL;  /* full signature */
13722         char       *aggsig_tag;
13723         PGresult   *res;
13724         int                     i_aggtransfn;
13725         int                     i_aggfinalfn;
13726         int                     i_aggcombinefn;
13727         int                     i_aggserialfn;
13728         int                     i_aggdeserialfn;
13729         int                     i_aggmtransfn;
13730         int                     i_aggminvtransfn;
13731         int                     i_aggmfinalfn;
13732         int                     i_aggfinalextra;
13733         int                     i_aggmfinalextra;
13734         int                     i_aggfinalmodify;
13735         int                     i_aggmfinalmodify;
13736         int                     i_aggsortop;
13737         int                     i_aggkind;
13738         int                     i_aggtranstype;
13739         int                     i_aggtransspace;
13740         int                     i_aggmtranstype;
13741         int                     i_aggmtransspace;
13742         int                     i_agginitval;
13743         int                     i_aggminitval;
13744         int                     i_convertok;
13745         int                     i_proparallel;
13746         const char *aggtransfn;
13747         const char *aggfinalfn;
13748         const char *aggcombinefn;
13749         const char *aggserialfn;
13750         const char *aggdeserialfn;
13751         const char *aggmtransfn;
13752         const char *aggminvtransfn;
13753         const char *aggmfinalfn;
13754         bool            aggfinalextra;
13755         bool            aggmfinalextra;
13756         char            aggfinalmodify;
13757         char            aggmfinalmodify;
13758         const char *aggsortop;
13759         char       *aggsortconvop;
13760         char            aggkind;
13761         const char *aggtranstype;
13762         const char *aggtransspace;
13763         const char *aggmtranstype;
13764         const char *aggmtransspace;
13765         const char *agginitval;
13766         const char *aggminitval;
13767         bool            convertok;
13768         const char *proparallel;
13769         char            defaultfinalmodify;
13770
13771         /* Skip if not to be dumped */
13772         if (!agginfo->aggfn.dobj.dump || dopt->dataOnly)
13773                 return;
13774
13775         query = createPQExpBuffer();
13776         q = createPQExpBuffer();
13777         delq = createPQExpBuffer();
13778         details = createPQExpBuffer();
13779
13780         /* Get aggregate-specific details */
13781         if (fout->remoteVersion >= 110000)
13782         {
13783                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13784                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13785                                                   "aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
13786                                                   "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13787                                                   "aggfinalextra, aggmfinalextra, "
13788                                                   "aggfinalmodify, aggmfinalmodify, "
13789                                                   "aggsortop, "
13790                                                   "aggkind, "
13791                                                   "aggtransspace, agginitval, "
13792                                                   "aggmtransspace, aggminitval, "
13793                                                   "true AS convertok, "
13794                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13795                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs, "
13796                                                   "p.proparallel "
13797                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13798                                                   "WHERE a.aggfnoid = p.oid "
13799                                                   "AND p.oid = '%u'::pg_catalog.oid",
13800                                                   agginfo->aggfn.dobj.catId.oid);
13801         }
13802         else if (fout->remoteVersion >= 90600)
13803         {
13804                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13805                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13806                                                   "aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
13807                                                   "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13808                                                   "aggfinalextra, aggmfinalextra, "
13809                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13810                                                   "aggsortop, "
13811                                                   "aggkind, "
13812                                                   "aggtransspace, agginitval, "
13813                                                   "aggmtransspace, aggminitval, "
13814                                                   "true AS convertok, "
13815                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13816                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs, "
13817                                                   "p.proparallel "
13818                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13819                                                   "WHERE a.aggfnoid = p.oid "
13820                                                   "AND p.oid = '%u'::pg_catalog.oid",
13821                                                   agginfo->aggfn.dobj.catId.oid);
13822         }
13823         else if (fout->remoteVersion >= 90400)
13824         {
13825                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13826                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13827                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13828                                                   "'-' AS aggdeserialfn, aggmtransfn, aggminvtransfn, "
13829                                                   "aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13830                                                   "aggfinalextra, aggmfinalextra, "
13831                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13832                                                   "aggsortop, "
13833                                                   "aggkind, "
13834                                                   "aggtransspace, agginitval, "
13835                                                   "aggmtransspace, aggminitval, "
13836                                                   "true AS convertok, "
13837                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13838                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
13839                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13840                                                   "WHERE a.aggfnoid = p.oid "
13841                                                   "AND p.oid = '%u'::pg_catalog.oid",
13842                                                   agginfo->aggfn.dobj.catId.oid);
13843         }
13844         else if (fout->remoteVersion >= 80400)
13845         {
13846                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13847                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13848                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13849                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13850                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13851                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13852                                                   "false AS aggmfinalextra, "
13853                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13854                                                   "aggsortop, "
13855                                                   "'n' AS aggkind, "
13856                                                   "0 AS aggtransspace, agginitval, "
13857                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13858                                                   "true AS convertok, "
13859                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13860                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
13861                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13862                                                   "WHERE a.aggfnoid = p.oid "
13863                                                   "AND p.oid = '%u'::pg_catalog.oid",
13864                                                   agginfo->aggfn.dobj.catId.oid);
13865         }
13866         else if (fout->remoteVersion >= 80100)
13867         {
13868                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13869                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13870                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13871                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13872                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13873                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13874                                                   "false AS aggmfinalextra, "
13875                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13876                                                   "aggsortop, "
13877                                                   "'n' AS aggkind, "
13878                                                   "0 AS aggtransspace, agginitval, "
13879                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13880                                                   "true AS convertok "
13881                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13882                                                   "WHERE a.aggfnoid = p.oid "
13883                                                   "AND p.oid = '%u'::pg_catalog.oid",
13884                                                   agginfo->aggfn.dobj.catId.oid);
13885         }
13886         else
13887         {
13888                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13889                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13890                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13891                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13892                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13893                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13894                                                   "false AS aggmfinalextra, "
13895                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13896                                                   "0 AS aggsortop, "
13897                                                   "'n' AS aggkind, "
13898                                                   "0 AS aggtransspace, agginitval, "
13899                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13900                                                   "true AS convertok "
13901                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13902                                                   "WHERE a.aggfnoid = p.oid "
13903                                                   "AND p.oid = '%u'::pg_catalog.oid",
13904                                                   agginfo->aggfn.dobj.catId.oid);
13905         }
13906
13907         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13908
13909         i_aggtransfn = PQfnumber(res, "aggtransfn");
13910         i_aggfinalfn = PQfnumber(res, "aggfinalfn");
13911         i_aggcombinefn = PQfnumber(res, "aggcombinefn");
13912         i_aggserialfn = PQfnumber(res, "aggserialfn");
13913         i_aggdeserialfn = PQfnumber(res, "aggdeserialfn");
13914         i_aggmtransfn = PQfnumber(res, "aggmtransfn");
13915         i_aggminvtransfn = PQfnumber(res, "aggminvtransfn");
13916         i_aggmfinalfn = PQfnumber(res, "aggmfinalfn");
13917         i_aggfinalextra = PQfnumber(res, "aggfinalextra");
13918         i_aggmfinalextra = PQfnumber(res, "aggmfinalextra");
13919         i_aggfinalmodify = PQfnumber(res, "aggfinalmodify");
13920         i_aggmfinalmodify = PQfnumber(res, "aggmfinalmodify");
13921         i_aggsortop = PQfnumber(res, "aggsortop");
13922         i_aggkind = PQfnumber(res, "aggkind");
13923         i_aggtranstype = PQfnumber(res, "aggtranstype");
13924         i_aggtransspace = PQfnumber(res, "aggtransspace");
13925         i_aggmtranstype = PQfnumber(res, "aggmtranstype");
13926         i_aggmtransspace = PQfnumber(res, "aggmtransspace");
13927         i_agginitval = PQfnumber(res, "agginitval");
13928         i_aggminitval = PQfnumber(res, "aggminitval");
13929         i_convertok = PQfnumber(res, "convertok");
13930         i_proparallel = PQfnumber(res, "proparallel");
13931
13932         aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
13933         aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
13934         aggcombinefn = PQgetvalue(res, 0, i_aggcombinefn);
13935         aggserialfn = PQgetvalue(res, 0, i_aggserialfn);
13936         aggdeserialfn = PQgetvalue(res, 0, i_aggdeserialfn);
13937         aggmtransfn = PQgetvalue(res, 0, i_aggmtransfn);
13938         aggminvtransfn = PQgetvalue(res, 0, i_aggminvtransfn);
13939         aggmfinalfn = PQgetvalue(res, 0, i_aggmfinalfn);
13940         aggfinalextra = (PQgetvalue(res, 0, i_aggfinalextra)[0] == 't');
13941         aggmfinalextra = (PQgetvalue(res, 0, i_aggmfinalextra)[0] == 't');
13942         aggfinalmodify = PQgetvalue(res, 0, i_aggfinalmodify)[0];
13943         aggmfinalmodify = PQgetvalue(res, 0, i_aggmfinalmodify)[0];
13944         aggsortop = PQgetvalue(res, 0, i_aggsortop);
13945         aggkind = PQgetvalue(res, 0, i_aggkind)[0];
13946         aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
13947         aggtransspace = PQgetvalue(res, 0, i_aggtransspace);
13948         aggmtranstype = PQgetvalue(res, 0, i_aggmtranstype);
13949         aggmtransspace = PQgetvalue(res, 0, i_aggmtransspace);
13950         agginitval = PQgetvalue(res, 0, i_agginitval);
13951         aggminitval = PQgetvalue(res, 0, i_aggminitval);
13952         convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
13953
13954         if (fout->remoteVersion >= 80400)
13955         {
13956                 /* 8.4 or later; we rely on server-side code for most of the work */
13957                 char       *funcargs;
13958                 char       *funciargs;
13959
13960                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
13961                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
13962                 aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
13963                 aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
13964         }
13965         else
13966                 /* pre-8.4, do it ourselves */
13967                 aggsig = format_aggregate_signature(agginfo, fout, true);
13968
13969         aggsig_tag = format_aggregate_signature(agginfo, fout, false);
13970
13971         if (i_proparallel != -1)
13972                 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
13973         else
13974                 proparallel = NULL;
13975
13976         if (!convertok)
13977         {
13978                 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
13979                                   aggsig);
13980
13981                 if (aggfullsig)
13982                         free(aggfullsig);
13983
13984                 free(aggsig);
13985
13986                 return;
13987         }
13988
13989         /* identify default modify flag for aggkind (must match DefineAggregate) */
13990         defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
13991         /* replace omitted flags for old versions */
13992         if (aggfinalmodify == '0')
13993                 aggfinalmodify = defaultfinalmodify;
13994         if (aggmfinalmodify == '0')
13995                 aggmfinalmodify = defaultfinalmodify;
13996
13997         /* regproc and regtype output is already sufficiently quoted */
13998         appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
13999                                           aggtransfn, aggtranstype);
14000
14001         if (strcmp(aggtransspace, "0") != 0)
14002         {
14003                 appendPQExpBuffer(details, ",\n    SSPACE = %s",
14004                                                   aggtransspace);
14005         }
14006
14007         if (!PQgetisnull(res, 0, i_agginitval))
14008         {
14009                 appendPQExpBufferStr(details, ",\n    INITCOND = ");
14010                 appendStringLiteralAH(details, agginitval, fout);
14011         }
14012
14013         if (strcmp(aggfinalfn, "-") != 0)
14014         {
14015                 appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
14016                                                   aggfinalfn);
14017                 if (aggfinalextra)
14018                         appendPQExpBufferStr(details, ",\n    FINALFUNC_EXTRA");
14019                 if (aggfinalmodify != defaultfinalmodify)
14020                 {
14021                         switch (aggfinalmodify)
14022                         {
14023                                 case AGGMODIFY_READ_ONLY:
14024                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_ONLY");
14025                                         break;
14026                                 case AGGMODIFY_SHAREABLE:
14027                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = SHAREABLE");
14028                                         break;
14029                                 case AGGMODIFY_READ_WRITE:
14030                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_WRITE");
14031                                         break;
14032                                 default:
14033                                         exit_horribly(NULL, "unrecognized aggfinalmodify value for aggregate \"%s\"\n",
14034                                                                   agginfo->aggfn.dobj.name);
14035                                         break;
14036                         }
14037                 }
14038         }
14039
14040         if (strcmp(aggcombinefn, "-") != 0)
14041                 appendPQExpBuffer(details, ",\n    COMBINEFUNC = %s", aggcombinefn);
14042
14043         if (strcmp(aggserialfn, "-") != 0)
14044                 appendPQExpBuffer(details, ",\n    SERIALFUNC = %s", aggserialfn);
14045
14046         if (strcmp(aggdeserialfn, "-") != 0)
14047                 appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s", aggdeserialfn);
14048
14049         if (strcmp(aggmtransfn, "-") != 0)
14050         {
14051                 appendPQExpBuffer(details, ",\n    MSFUNC = %s,\n    MINVFUNC = %s,\n    MSTYPE = %s",
14052                                                   aggmtransfn,
14053                                                   aggminvtransfn,
14054                                                   aggmtranstype);
14055         }
14056
14057         if (strcmp(aggmtransspace, "0") != 0)
14058         {
14059                 appendPQExpBuffer(details, ",\n    MSSPACE = %s",
14060                                                   aggmtransspace);
14061         }
14062
14063         if (!PQgetisnull(res, 0, i_aggminitval))
14064         {
14065                 appendPQExpBufferStr(details, ",\n    MINITCOND = ");
14066                 appendStringLiteralAH(details, aggminitval, fout);
14067         }
14068
14069         if (strcmp(aggmfinalfn, "-") != 0)
14070         {
14071                 appendPQExpBuffer(details, ",\n    MFINALFUNC = %s",
14072                                                   aggmfinalfn);
14073                 if (aggmfinalextra)
14074                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_EXTRA");
14075                 if (aggmfinalmodify != defaultfinalmodify)
14076                 {
14077                         switch (aggmfinalmodify)
14078                         {
14079                                 case AGGMODIFY_READ_ONLY:
14080                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_ONLY");
14081                                         break;
14082                                 case AGGMODIFY_SHAREABLE:
14083                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = SHAREABLE");
14084                                         break;
14085                                 case AGGMODIFY_READ_WRITE:
14086                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_WRITE");
14087                                         break;
14088                                 default:
14089                                         exit_horribly(NULL, "unrecognized aggmfinalmodify value for aggregate \"%s\"\n",
14090                                                                   agginfo->aggfn.dobj.name);
14091                                         break;
14092                         }
14093                 }
14094         }
14095
14096         aggsortconvop = getFormattedOperatorName(fout, aggsortop);
14097         if (aggsortconvop)
14098         {
14099                 appendPQExpBuffer(details, ",\n    SORTOP = %s",
14100                                                   aggsortconvop);
14101                 free(aggsortconvop);
14102         }
14103
14104         if (aggkind == AGGKIND_HYPOTHETICAL)
14105                 appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
14106
14107         if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
14108         {
14109                 if (proparallel[0] == PROPARALLEL_SAFE)
14110                         appendPQExpBufferStr(details, ",\n    PARALLEL = safe");
14111                 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
14112                         appendPQExpBufferStr(details, ",\n    PARALLEL = restricted");
14113                 else if (proparallel[0] != PROPARALLEL_UNSAFE)
14114                         exit_horribly(NULL, "unrecognized proparallel value for function \"%s\"\n",
14115                                                   agginfo->aggfn.dobj.name);
14116         }
14117
14118         appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
14119                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
14120                                           aggsig);
14121
14122         appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
14123                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
14124                                           aggfullsig ? aggfullsig : aggsig, details->data);
14125
14126         if (dopt->binary_upgrade)
14127                 binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
14128                                                                                 "AGGREGATE", aggsig,
14129                                                                                 agginfo->aggfn.dobj.namespace->dobj.name);
14130
14131         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
14132                 ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
14133                                          agginfo->aggfn.dobj.dumpId,
14134                                          ARCHIVE_OPTS(.tag = aggsig_tag,
14135                                                                   .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
14136                                                                   .owner = agginfo->aggfn.rolname,
14137                                                                   .description = "AGGREGATE",
14138                                                                   .section = SECTION_PRE_DATA,
14139                                                                   .createStmt = q->data,
14140                                                                   .dropStmt = delq->data));
14141
14142         /* Dump Aggregate Comments */
14143         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
14144                 dumpComment(fout, "AGGREGATE", aggsig,
14145                                         agginfo->aggfn.dobj.namespace->dobj.name,
14146                                         agginfo->aggfn.rolname,
14147                                         agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
14148
14149         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
14150                 dumpSecLabel(fout, "AGGREGATE", aggsig,
14151                                          agginfo->aggfn.dobj.namespace->dobj.name,
14152                                          agginfo->aggfn.rolname,
14153                                          agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
14154
14155         /*
14156          * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
14157          * command look like a function's GRANT; in particular this affects the
14158          * syntax for zero-argument aggregates and ordered-set aggregates.
14159          */
14160         free(aggsig);
14161
14162         aggsig = format_function_signature(fout, &agginfo->aggfn, true);
14163
14164         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
14165                 dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
14166                                 "FUNCTION", aggsig, NULL,
14167                                 agginfo->aggfn.dobj.namespace->dobj.name,
14168                                 agginfo->aggfn.rolname, agginfo->aggfn.proacl,
14169                                 agginfo->aggfn.rproacl,
14170                                 agginfo->aggfn.initproacl, agginfo->aggfn.initrproacl);
14171
14172         free(aggsig);
14173         if (aggfullsig)
14174                 free(aggfullsig);
14175         free(aggsig_tag);
14176
14177         PQclear(res);
14178
14179         destroyPQExpBuffer(query);
14180         destroyPQExpBuffer(q);
14181         destroyPQExpBuffer(delq);
14182         destroyPQExpBuffer(details);
14183 }
14184
14185 /*
14186  * dumpTSParser
14187  *        write out a single text search parser
14188  */
14189 static void
14190 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
14191 {
14192         DumpOptions *dopt = fout->dopt;
14193         PQExpBuffer q;
14194         PQExpBuffer delq;
14195         char       *qprsname;
14196
14197         /* Skip if not to be dumped */
14198         if (!prsinfo->dobj.dump || dopt->dataOnly)
14199                 return;
14200
14201         q = createPQExpBuffer();
14202         delq = createPQExpBuffer();
14203
14204         qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
14205
14206         appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
14207                                           fmtQualifiedDumpable(prsinfo));
14208
14209         appendPQExpBuffer(q, "    START = %s,\n",
14210                                           convertTSFunction(fout, prsinfo->prsstart));
14211         appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
14212                                           convertTSFunction(fout, prsinfo->prstoken));
14213         appendPQExpBuffer(q, "    END = %s,\n",
14214                                           convertTSFunction(fout, prsinfo->prsend));
14215         if (prsinfo->prsheadline != InvalidOid)
14216                 appendPQExpBuffer(q, "    HEADLINE = %s,\n",
14217                                                   convertTSFunction(fout, prsinfo->prsheadline));
14218         appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
14219                                           convertTSFunction(fout, prsinfo->prslextype));
14220
14221         appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
14222                                           fmtQualifiedDumpable(prsinfo));
14223
14224         if (dopt->binary_upgrade)
14225                 binary_upgrade_extension_member(q, &prsinfo->dobj,
14226                                                                                 "TEXT SEARCH PARSER", qprsname,
14227                                                                                 prsinfo->dobj.namespace->dobj.name);
14228
14229         if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14230                 ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
14231                                          ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
14232                                                                   .namespace = prsinfo->dobj.namespace->dobj.name,
14233                                                                   .description = "TEXT SEARCH PARSER",
14234                                                                   .owner = "",
14235                                                                   .section = SECTION_PRE_DATA,
14236                                                                   .createStmt = q->data,
14237                                                                   .dropStmt = delq->data));
14238
14239         /* Dump Parser Comments */
14240         if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14241                 dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
14242                                         prsinfo->dobj.namespace->dobj.name, "",
14243                                         prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
14244
14245         destroyPQExpBuffer(q);
14246         destroyPQExpBuffer(delq);
14247         free(qprsname);
14248 }
14249
14250 /*
14251  * dumpTSDictionary
14252  *        write out a single text search dictionary
14253  */
14254 static void
14255 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
14256 {
14257         DumpOptions *dopt = fout->dopt;
14258         PQExpBuffer q;
14259         PQExpBuffer delq;
14260         PQExpBuffer query;
14261         char       *qdictname;
14262         PGresult   *res;
14263         char       *nspname;
14264         char       *tmplname;
14265
14266         /* Skip if not to be dumped */
14267         if (!dictinfo->dobj.dump || dopt->dataOnly)
14268                 return;
14269
14270         q = createPQExpBuffer();
14271         delq = createPQExpBuffer();
14272         query = createPQExpBuffer();
14273
14274         qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
14275
14276         /* Fetch name and namespace of the dictionary's template */
14277         appendPQExpBuffer(query, "SELECT nspname, tmplname "
14278                                           "FROM pg_ts_template p, pg_namespace n "
14279                                           "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
14280                                           dictinfo->dicttemplate);
14281         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14282         nspname = PQgetvalue(res, 0, 0);
14283         tmplname = PQgetvalue(res, 0, 1);
14284
14285         appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
14286                                           fmtQualifiedDumpable(dictinfo));
14287
14288         appendPQExpBufferStr(q, "    TEMPLATE = ");
14289         appendPQExpBuffer(q, "%s.", fmtId(nspname));
14290         appendPQExpBufferStr(q, fmtId(tmplname));
14291
14292         PQclear(res);
14293
14294         /* the dictinitoption can be dumped straight into the command */
14295         if (dictinfo->dictinitoption)
14296                 appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
14297
14298         appendPQExpBufferStr(q, " );\n");
14299
14300         appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
14301                                           fmtQualifiedDumpable(dictinfo));
14302
14303         if (dopt->binary_upgrade)
14304                 binary_upgrade_extension_member(q, &dictinfo->dobj,
14305                                                                                 "TEXT SEARCH DICTIONARY", qdictname,
14306                                                                                 dictinfo->dobj.namespace->dobj.name);
14307
14308         if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14309                 ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
14310                                          ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
14311                                                                   .namespace = dictinfo->dobj.namespace->dobj.name,
14312                                                                   .owner = dictinfo->rolname,
14313                                                                   .description = "TEXT SEARCH DICTIONARY",
14314                                                                   .section = SECTION_PRE_DATA,
14315                                                                   .createStmt = q->data,
14316                                                                   .dropStmt = delq->data));
14317
14318         /* Dump Dictionary Comments */
14319         if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14320                 dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
14321                                         dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
14322                                         dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
14323
14324         destroyPQExpBuffer(q);
14325         destroyPQExpBuffer(delq);
14326         destroyPQExpBuffer(query);
14327         free(qdictname);
14328 }
14329
14330 /*
14331  * dumpTSTemplate
14332  *        write out a single text search template
14333  */
14334 static void
14335 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
14336 {
14337         DumpOptions *dopt = fout->dopt;
14338         PQExpBuffer q;
14339         PQExpBuffer delq;
14340         char       *qtmplname;
14341
14342         /* Skip if not to be dumped */
14343         if (!tmplinfo->dobj.dump || dopt->dataOnly)
14344                 return;
14345
14346         q = createPQExpBuffer();
14347         delq = createPQExpBuffer();
14348
14349         qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
14350
14351         appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
14352                                           fmtQualifiedDumpable(tmplinfo));
14353
14354         if (tmplinfo->tmplinit != InvalidOid)
14355                 appendPQExpBuffer(q, "    INIT = %s,\n",
14356                                                   convertTSFunction(fout, tmplinfo->tmplinit));
14357         appendPQExpBuffer(q, "    LEXIZE = %s );\n",
14358                                           convertTSFunction(fout, tmplinfo->tmpllexize));
14359
14360         appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
14361                                           fmtQualifiedDumpable(tmplinfo));
14362
14363         if (dopt->binary_upgrade)
14364                 binary_upgrade_extension_member(q, &tmplinfo->dobj,
14365                                                                                 "TEXT SEARCH TEMPLATE", qtmplname,
14366                                                                                 tmplinfo->dobj.namespace->dobj.name);
14367
14368         if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14369                 ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
14370                                          ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
14371                                                                   .namespace = tmplinfo->dobj.namespace->dobj.name,
14372                                                                   .description = "TEXT SEARCH TEMPLATE",
14373                                                                   .owner = "",
14374                                                                   .section = SECTION_PRE_DATA,
14375                                                                   .createStmt = q->data,
14376                                                                   .dropStmt = delq->data));
14377
14378         /* Dump Template Comments */
14379         if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14380                 dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
14381                                         tmplinfo->dobj.namespace->dobj.name, "",
14382                                         tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
14383
14384         destroyPQExpBuffer(q);
14385         destroyPQExpBuffer(delq);
14386         free(qtmplname);
14387 }
14388
14389 /*
14390  * dumpTSConfig
14391  *        write out a single text search configuration
14392  */
14393 static void
14394 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
14395 {
14396         DumpOptions *dopt = fout->dopt;
14397         PQExpBuffer q;
14398         PQExpBuffer delq;
14399         PQExpBuffer query;
14400         char       *qcfgname;
14401         PGresult   *res;
14402         char       *nspname;
14403         char       *prsname;
14404         int                     ntups,
14405                                 i;
14406         int                     i_tokenname;
14407         int                     i_dictname;
14408
14409         /* Skip if not to be dumped */
14410         if (!cfginfo->dobj.dump || dopt->dataOnly)
14411                 return;
14412
14413         q = createPQExpBuffer();
14414         delq = createPQExpBuffer();
14415         query = createPQExpBuffer();
14416
14417         qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
14418
14419         /* Fetch name and namespace of the config's parser */
14420         appendPQExpBuffer(query, "SELECT nspname, prsname "
14421                                           "FROM pg_ts_parser p, pg_namespace n "
14422                                           "WHERE p.oid = '%u' AND n.oid = prsnamespace",
14423                                           cfginfo->cfgparser);
14424         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14425         nspname = PQgetvalue(res, 0, 0);
14426         prsname = PQgetvalue(res, 0, 1);
14427
14428         appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
14429                                           fmtQualifiedDumpable(cfginfo));
14430
14431         appendPQExpBuffer(q, "    PARSER = %s.", fmtId(nspname));
14432         appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
14433
14434         PQclear(res);
14435
14436         resetPQExpBuffer(query);
14437         appendPQExpBuffer(query,
14438                                           "SELECT\n"
14439                                           "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
14440                                           "    WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
14441                                           "  m.mapdict::pg_catalog.regdictionary AS dictname\n"
14442                                           "FROM pg_catalog.pg_ts_config_map AS m\n"
14443                                           "WHERE m.mapcfg = '%u'\n"
14444                                           "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
14445                                           cfginfo->cfgparser, cfginfo->dobj.catId.oid);
14446
14447         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14448         ntups = PQntuples(res);
14449
14450         i_tokenname = PQfnumber(res, "tokenname");
14451         i_dictname = PQfnumber(res, "dictname");
14452
14453         for (i = 0; i < ntups; i++)
14454         {
14455                 char       *tokenname = PQgetvalue(res, i, i_tokenname);
14456                 char       *dictname = PQgetvalue(res, i, i_dictname);
14457
14458                 if (i == 0 ||
14459                         strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
14460                 {
14461                         /* starting a new token type, so start a new command */
14462                         if (i > 0)
14463                                 appendPQExpBufferStr(q, ";\n");
14464                         appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
14465                                                           fmtQualifiedDumpable(cfginfo));
14466                         /* tokenname needs quoting, dictname does NOT */
14467                         appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
14468                                                           fmtId(tokenname), dictname);
14469                 }
14470                 else
14471                         appendPQExpBuffer(q, ", %s", dictname);
14472         }
14473
14474         if (ntups > 0)
14475                 appendPQExpBufferStr(q, ";\n");
14476
14477         PQclear(res);
14478
14479         appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
14480                                           fmtQualifiedDumpable(cfginfo));
14481
14482         if (dopt->binary_upgrade)
14483                 binary_upgrade_extension_member(q, &cfginfo->dobj,
14484                                                                                 "TEXT SEARCH CONFIGURATION", qcfgname,
14485                                                                                 cfginfo->dobj.namespace->dobj.name);
14486
14487         if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14488                 ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
14489                                          ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
14490                                                                   .namespace = cfginfo->dobj.namespace->dobj.name,
14491                                                                   .owner = cfginfo->rolname,
14492                                                                   .description = "TEXT SEARCH CONFIGURATION",
14493                                                                   .section = SECTION_PRE_DATA,
14494                                                                   .createStmt = q->data,
14495                                                                   .dropStmt = delq->data));
14496
14497         /* Dump Configuration Comments */
14498         if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14499                 dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
14500                                         cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
14501                                         cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
14502
14503         destroyPQExpBuffer(q);
14504         destroyPQExpBuffer(delq);
14505         destroyPQExpBuffer(query);
14506         free(qcfgname);
14507 }
14508
14509 /*
14510  * dumpForeignDataWrapper
14511  *        write out a single foreign-data wrapper definition
14512  */
14513 static void
14514 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
14515 {
14516         DumpOptions *dopt = fout->dopt;
14517         PQExpBuffer q;
14518         PQExpBuffer delq;
14519         char       *qfdwname;
14520
14521         /* Skip if not to be dumped */
14522         if (!fdwinfo->dobj.dump || dopt->dataOnly)
14523                 return;
14524
14525         q = createPQExpBuffer();
14526         delq = createPQExpBuffer();
14527
14528         qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
14529
14530         appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
14531                                           qfdwname);
14532
14533         if (strcmp(fdwinfo->fdwhandler, "-") != 0)
14534                 appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
14535
14536         if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
14537                 appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
14538
14539         if (strlen(fdwinfo->fdwoptions) > 0)
14540                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
14541
14542         appendPQExpBufferStr(q, ";\n");
14543
14544         appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
14545                                           qfdwname);
14546
14547         if (dopt->binary_upgrade)
14548                 binary_upgrade_extension_member(q, &fdwinfo->dobj,
14549                                                                                 "FOREIGN DATA WRAPPER", qfdwname,
14550                                                                                 NULL);
14551
14552         if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14553                 ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14554                                          ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
14555                                                                   .owner = fdwinfo->rolname,
14556                                                                   .description = "FOREIGN DATA WRAPPER",
14557                                                                   .section = SECTION_PRE_DATA,
14558                                                                   .createStmt = q->data,
14559                                                                   .dropStmt = delq->data));
14560
14561         /* Dump Foreign Data Wrapper Comments */
14562         if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14563                 dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
14564                                         NULL, fdwinfo->rolname,
14565                                         fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
14566
14567         /* Handle the ACL */
14568         if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
14569                 dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14570                                 "FOREIGN DATA WRAPPER", qfdwname, NULL,
14571                                 NULL, fdwinfo->rolname,
14572                                 fdwinfo->fdwacl, fdwinfo->rfdwacl,
14573                                 fdwinfo->initfdwacl, fdwinfo->initrfdwacl);
14574
14575         free(qfdwname);
14576
14577         destroyPQExpBuffer(q);
14578         destroyPQExpBuffer(delq);
14579 }
14580
14581 /*
14582  * dumpForeignServer
14583  *        write out a foreign server definition
14584  */
14585 static void
14586 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
14587 {
14588         DumpOptions *dopt = fout->dopt;
14589         PQExpBuffer q;
14590         PQExpBuffer delq;
14591         PQExpBuffer query;
14592         PGresult   *res;
14593         char       *qsrvname;
14594         char       *fdwname;
14595
14596         /* Skip if not to be dumped */
14597         if (!srvinfo->dobj.dump || dopt->dataOnly)
14598                 return;
14599
14600         q = createPQExpBuffer();
14601         delq = createPQExpBuffer();
14602         query = createPQExpBuffer();
14603
14604         qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
14605
14606         /* look up the foreign-data wrapper */
14607         appendPQExpBuffer(query, "SELECT fdwname "
14608                                           "FROM pg_foreign_data_wrapper w "
14609                                           "WHERE w.oid = '%u'",
14610                                           srvinfo->srvfdw);
14611         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14612         fdwname = PQgetvalue(res, 0, 0);
14613
14614         appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
14615         if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
14616         {
14617                 appendPQExpBufferStr(q, " TYPE ");
14618                 appendStringLiteralAH(q, srvinfo->srvtype, fout);
14619         }
14620         if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
14621         {
14622                 appendPQExpBufferStr(q, " VERSION ");
14623                 appendStringLiteralAH(q, srvinfo->srvversion, fout);
14624         }
14625
14626         appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
14627         appendPQExpBufferStr(q, fmtId(fdwname));
14628
14629         if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
14630                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
14631
14632         appendPQExpBufferStr(q, ";\n");
14633
14634         appendPQExpBuffer(delq, "DROP SERVER %s;\n",
14635                                           qsrvname);
14636
14637         if (dopt->binary_upgrade)
14638                 binary_upgrade_extension_member(q, &srvinfo->dobj,
14639                                                                                 "SERVER", qsrvname, NULL);
14640
14641         if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14642                 ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14643                                          ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
14644                                                                   .owner = srvinfo->rolname,
14645                                                                   .description = "SERVER",
14646                                                                   .section = SECTION_PRE_DATA,
14647                                                                   .createStmt = q->data,
14648                                                                   .dropStmt = delq->data));
14649
14650         /* Dump Foreign Server Comments */
14651         if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14652                 dumpComment(fout, "SERVER", qsrvname,
14653                                         NULL, srvinfo->rolname,
14654                                         srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
14655
14656         /* Handle the ACL */
14657         if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
14658                 dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14659                                 "FOREIGN SERVER", qsrvname, NULL,
14660                                 NULL, srvinfo->rolname,
14661                                 srvinfo->srvacl, srvinfo->rsrvacl,
14662                                 srvinfo->initsrvacl, srvinfo->initrsrvacl);
14663
14664         /* Dump user mappings */
14665         if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
14666                 dumpUserMappings(fout,
14667                                                  srvinfo->dobj.name, NULL,
14668                                                  srvinfo->rolname,
14669                                                  srvinfo->dobj.catId, srvinfo->dobj.dumpId);
14670
14671         free(qsrvname);
14672
14673         destroyPQExpBuffer(q);
14674         destroyPQExpBuffer(delq);
14675         destroyPQExpBuffer(query);
14676 }
14677
14678 /*
14679  * dumpUserMappings
14680  *
14681  * This routine is used to dump any user mappings associated with the
14682  * server handed to this routine. Should be called after ArchiveEntry()
14683  * for the server.
14684  */
14685 static void
14686 dumpUserMappings(Archive *fout,
14687                                  const char *servername, const char *namespace,
14688                                  const char *owner,
14689                                  CatalogId catalogId, DumpId dumpId)
14690 {
14691         PQExpBuffer q;
14692         PQExpBuffer delq;
14693         PQExpBuffer query;
14694         PQExpBuffer tag;
14695         PGresult   *res;
14696         int                     ntups;
14697         int                     i_usename;
14698         int                     i_umoptions;
14699         int                     i;
14700
14701         q = createPQExpBuffer();
14702         tag = createPQExpBuffer();
14703         delq = createPQExpBuffer();
14704         query = createPQExpBuffer();
14705
14706         /*
14707          * We read from the publicly accessible view pg_user_mappings, so as not
14708          * to fail if run by a non-superuser.  Note that the view will show
14709          * umoptions as null if the user hasn't got privileges for the associated
14710          * server; this means that pg_dump will dump such a mapping, but with no
14711          * OPTIONS clause.  A possible alternative is to skip such mappings
14712          * altogether, but it's not clear that that's an improvement.
14713          */
14714         appendPQExpBuffer(query,
14715                                           "SELECT usename, "
14716                                           "array_to_string(ARRAY("
14717                                           "SELECT quote_ident(option_name) || ' ' || "
14718                                           "quote_literal(option_value) "
14719                                           "FROM pg_options_to_table(umoptions) "
14720                                           "ORDER BY option_name"
14721                                           "), E',\n    ') AS umoptions "
14722                                           "FROM pg_user_mappings "
14723                                           "WHERE srvid = '%u' "
14724                                           "ORDER BY usename",
14725                                           catalogId.oid);
14726
14727         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14728
14729         ntups = PQntuples(res);
14730         i_usename = PQfnumber(res, "usename");
14731         i_umoptions = PQfnumber(res, "umoptions");
14732
14733         for (i = 0; i < ntups; i++)
14734         {
14735                 char       *usename;
14736                 char       *umoptions;
14737
14738                 usename = PQgetvalue(res, i, i_usename);
14739                 umoptions = PQgetvalue(res, i, i_umoptions);
14740
14741                 resetPQExpBuffer(q);
14742                 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
14743                 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
14744
14745                 if (umoptions && strlen(umoptions) > 0)
14746                         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
14747
14748                 appendPQExpBufferStr(q, ";\n");
14749
14750                 resetPQExpBuffer(delq);
14751                 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
14752                 appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
14753
14754                 resetPQExpBuffer(tag);
14755                 appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
14756                                                   usename, servername);
14757
14758                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14759                                          ARCHIVE_OPTS(.tag = tag->data,
14760                                                                   .namespace = namespace,
14761                                                                   .owner = owner,
14762                                                                   .description = "USER MAPPING",
14763                                                                   .section = SECTION_PRE_DATA,
14764                                                                   .createStmt = q->data,
14765                                                                   .dropStmt = delq->data));
14766         }
14767
14768         PQclear(res);
14769
14770         destroyPQExpBuffer(query);
14771         destroyPQExpBuffer(delq);
14772         destroyPQExpBuffer(tag);
14773         destroyPQExpBuffer(q);
14774 }
14775
14776 /*
14777  * Write out default privileges information
14778  */
14779 static void
14780 dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
14781 {
14782         DumpOptions *dopt = fout->dopt;
14783         PQExpBuffer q;
14784         PQExpBuffer tag;
14785         const char *type;
14786
14787         /* Skip if not to be dumped */
14788         if (!daclinfo->dobj.dump || dopt->dataOnly || dopt->aclsSkip)
14789                 return;
14790
14791         q = createPQExpBuffer();
14792         tag = createPQExpBuffer();
14793
14794         switch (daclinfo->defaclobjtype)
14795         {
14796                 case DEFACLOBJ_RELATION:
14797                         type = "TABLES";
14798                         break;
14799                 case DEFACLOBJ_SEQUENCE:
14800                         type = "SEQUENCES";
14801                         break;
14802                 case DEFACLOBJ_FUNCTION:
14803                         type = "FUNCTIONS";
14804                         break;
14805                 case DEFACLOBJ_TYPE:
14806                         type = "TYPES";
14807                         break;
14808                 case DEFACLOBJ_NAMESPACE:
14809                         type = "SCHEMAS";
14810                         break;
14811                 default:
14812                         /* shouldn't get here */
14813                         exit_horribly(NULL,
14814                                                   "unrecognized object type in default privileges: %d\n",
14815                                                   (int) daclinfo->defaclobjtype);
14816                         type = "";                      /* keep compiler quiet */
14817         }
14818
14819         appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
14820
14821         /* build the actual command(s) for this tuple */
14822         if (!buildDefaultACLCommands(type,
14823                                                                  daclinfo->dobj.namespace != NULL ?
14824                                                                  daclinfo->dobj.namespace->dobj.name : NULL,
14825                                                                  daclinfo->defaclacl,
14826                                                                  daclinfo->rdefaclacl,
14827                                                                  daclinfo->initdefaclacl,
14828                                                                  daclinfo->initrdefaclacl,
14829                                                                  daclinfo->defaclrole,
14830                                                                  fout->remoteVersion,
14831                                                                  q))
14832                 exit_horribly(NULL, "could not parse default ACL list (%s)\n",
14833                                           daclinfo->defaclacl);
14834
14835         if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
14836                 ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
14837                                          ARCHIVE_OPTS(.tag = tag->data,
14838                                                                   .namespace = daclinfo->dobj.namespace ?
14839                                                                   daclinfo->dobj.namespace->dobj.name : NULL,
14840                                                                   .owner = daclinfo->defaclrole,
14841                                                                   .description = "DEFAULT ACL",
14842                                                                   .section = SECTION_POST_DATA,
14843                                                                   .createStmt = q->data,
14844                                                                   .dropStmt = ""));
14845
14846         destroyPQExpBuffer(tag);
14847         destroyPQExpBuffer(q);
14848 }
14849
14850 /*----------
14851  * Write out grant/revoke information
14852  *
14853  * 'objCatId' is the catalog ID of the underlying object.
14854  * 'objDumpId' is the dump ID of the underlying object.
14855  * 'type' must be one of
14856  *              TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
14857  *              FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
14858  * 'name' is the formatted name of the object.  Must be quoted etc. already.
14859  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
14860  *              (Currently we assume that subname is only provided for table columns.)
14861  * 'nspname' is the namespace the object is in (NULL if none).
14862  * 'owner' is the owner, NULL if there is no owner (for languages).
14863  * 'acls' contains the ACL string of the object from the appropriate system
14864  *              catalog field; it will be passed to buildACLCommands for building the
14865  *              appropriate GRANT commands.
14866  * 'racls' contains the ACL string of any initial-but-now-revoked ACLs of the
14867  *              object; it will be passed to buildACLCommands for building the
14868  *              appropriate REVOKE commands.
14869  * 'initacls' In binary-upgrade mode, ACL string of the object's initial
14870  *              privileges, to be recorded into pg_init_privs
14871  * 'initracls' In binary-upgrade mode, ACL string of the object's
14872  *              revoked-from-default privileges, to be recorded into pg_init_privs
14873  *
14874  * NB: initacls/initracls are needed because extensions can set privileges on
14875  * an object during the extension's script file and we record those into
14876  * pg_init_privs as that object's initial privileges.
14877  *----------
14878  */
14879 static void
14880 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
14881                 const char *type, const char *name, const char *subname,
14882                 const char *nspname, const char *owner,
14883                 const char *acls, const char *racls,
14884                 const char *initacls, const char *initracls)
14885 {
14886         DumpOptions *dopt = fout->dopt;
14887         PQExpBuffer sql;
14888
14889         /* Do nothing if ACL dump is not enabled */
14890         if (dopt->aclsSkip)
14891                 return;
14892
14893         /* --data-only skips ACLs *except* BLOB ACLs */
14894         if (dopt->dataOnly && strcmp(type, "LARGE OBJECT") != 0)
14895                 return;
14896
14897         sql = createPQExpBuffer();
14898
14899         /*
14900          * Check to see if this object has had any initial ACLs included for it.
14901          * If so, we are in binary upgrade mode and these are the ACLs to turn
14902          * into GRANT and REVOKE statements to set and record the initial
14903          * privileges for an extension object.  Let the backend know that these
14904          * are to be recorded by calling binary_upgrade_set_record_init_privs()
14905          * before and after.
14906          */
14907         if (strlen(initacls) != 0 || strlen(initracls) != 0)
14908         {
14909                 appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
14910                 if (!buildACLCommands(name, subname, nspname, type,
14911                                                           initacls, initracls, owner,
14912                                                           "", fout->remoteVersion, sql))
14913                         exit_horribly(NULL,
14914                                                   "could not parse initial GRANT ACL list (%s) or initial REVOKE ACL list (%s) for object \"%s\" (%s)\n",
14915                                                   initacls, initracls, name, type);
14916                 appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
14917         }
14918
14919         if (!buildACLCommands(name, subname, nspname, type,
14920                                                   acls, racls, owner,
14921                                                   "", fout->remoteVersion, sql))
14922                 exit_horribly(NULL,
14923                                           "could not parse GRANT ACL list (%s) or REVOKE ACL list (%s) for object \"%s\" (%s)\n",
14924                                           acls, racls, name, type);
14925
14926         if (sql->len > 0)
14927         {
14928                 PQExpBuffer tag = createPQExpBuffer();
14929
14930                 if (subname)
14931                         appendPQExpBuffer(tag, "COLUMN %s.%s", name, subname);
14932                 else
14933                         appendPQExpBuffer(tag, "%s %s", type, name);
14934
14935                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14936                                          ARCHIVE_OPTS(.tag = tag->data,
14937                                                                   .namespace = nspname,
14938                                                                   .owner = owner,
14939                                                                   .description = "ACL",
14940                                                                   .section = SECTION_NONE,
14941                                                                   .createStmt = sql->data,
14942                                                                   .dropStmt = "",
14943                                                                   .deps = &objDumpId,
14944                                                                   .nDeps = 1));
14945                 destroyPQExpBuffer(tag);
14946         }
14947
14948         destroyPQExpBuffer(sql);
14949 }
14950
14951 /*
14952  * dumpSecLabel
14953  *
14954  * This routine is used to dump any security labels associated with the
14955  * object handed to this routine. The routine takes the object type
14956  * and object name (ready to print, except for schema decoration), plus
14957  * the namespace and owner of the object (for labeling the ArchiveEntry),
14958  * plus catalog ID and subid which are the lookup key for pg_seclabel,
14959  * plus the dump ID for the object (for setting a dependency).
14960  * If a matching pg_seclabel entry is found, it is dumped.
14961  *
14962  * Note: although this routine takes a dumpId for dependency purposes,
14963  * that purpose is just to mark the dependency in the emitted dump file
14964  * for possible future use by pg_restore.  We do NOT use it for determining
14965  * ordering of the label in the dump file, because this routine is called
14966  * after dependency sorting occurs.  This routine should be called just after
14967  * calling ArchiveEntry() for the specified object.
14968  */
14969 static void
14970 dumpSecLabel(Archive *fout, const char *type, const char *name,
14971                          const char *namespace, const char *owner,
14972                          CatalogId catalogId, int subid, DumpId dumpId)
14973 {
14974         DumpOptions *dopt = fout->dopt;
14975         SecLabelItem *labels;
14976         int                     nlabels;
14977         int                     i;
14978         PQExpBuffer query;
14979
14980         /* do nothing, if --no-security-labels is supplied */
14981         if (dopt->no_security_labels)
14982                 return;
14983
14984         /* Security labels are schema not data ... except blob labels are data */
14985         if (strcmp(type, "LARGE OBJECT") != 0)
14986         {
14987                 if (dopt->dataOnly)
14988                         return;
14989         }
14990         else
14991         {
14992                 /* We do dump blob security labels in binary-upgrade mode */
14993                 if (dopt->schemaOnly && !dopt->binary_upgrade)
14994                         return;
14995         }
14996
14997         /* Search for security labels associated with catalogId, using table */
14998         nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
14999
15000         query = createPQExpBuffer();
15001
15002         for (i = 0; i < nlabels; i++)
15003         {
15004                 /*
15005                  * Ignore label entries for which the subid doesn't match.
15006                  */
15007                 if (labels[i].objsubid != subid)
15008                         continue;
15009
15010                 appendPQExpBuffer(query,
15011                                                   "SECURITY LABEL FOR %s ON %s ",
15012                                                   fmtId(labels[i].provider), type);
15013                 if (namespace && *namespace)
15014                         appendPQExpBuffer(query, "%s.", fmtId(namespace));
15015                 appendPQExpBuffer(query, "%s IS ", name);
15016                 appendStringLiteralAH(query, labels[i].label, fout);
15017                 appendPQExpBufferStr(query, ";\n");
15018         }
15019
15020         if (query->len > 0)
15021         {
15022                 PQExpBuffer tag = createPQExpBuffer();
15023
15024                 appendPQExpBuffer(tag, "%s %s", type, name);
15025                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
15026                                          ARCHIVE_OPTS(.tag = tag->data,
15027                                                                   .namespace = namespace,
15028                                                                   .owner = owner,
15029                                                                   .description = "SECURITY LABEL",
15030                                                                   .section = SECTION_NONE,
15031                                                                   .createStmt = query->data,
15032                                                                   .dropStmt = "",
15033                                                                   .deps = &dumpId,
15034                                                                   .nDeps = 1));
15035                 destroyPQExpBuffer(tag);
15036         }
15037
15038         destroyPQExpBuffer(query);
15039 }
15040
15041 /*
15042  * dumpTableSecLabel
15043  *
15044  * As above, but dump security label for both the specified table (or view)
15045  * and its columns.
15046  */
15047 static void
15048 dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
15049 {
15050         DumpOptions *dopt = fout->dopt;
15051         SecLabelItem *labels;
15052         int                     nlabels;
15053         int                     i;
15054         PQExpBuffer query;
15055         PQExpBuffer target;
15056
15057         /* do nothing, if --no-security-labels is supplied */
15058         if (dopt->no_security_labels)
15059                 return;
15060
15061         /* SecLabel are SCHEMA not data */
15062         if (dopt->dataOnly)
15063                 return;
15064
15065         /* Search for comments associated with relation, using table */
15066         nlabels = findSecLabels(fout,
15067                                                         tbinfo->dobj.catId.tableoid,
15068                                                         tbinfo->dobj.catId.oid,
15069                                                         &labels);
15070
15071         /* If security labels exist, build SECURITY LABEL statements */
15072         if (nlabels <= 0)
15073                 return;
15074
15075         query = createPQExpBuffer();
15076         target = createPQExpBuffer();
15077
15078         for (i = 0; i < nlabels; i++)
15079         {
15080                 const char *colname;
15081                 const char *provider = labels[i].provider;
15082                 const char *label = labels[i].label;
15083                 int                     objsubid = labels[i].objsubid;
15084
15085                 resetPQExpBuffer(target);
15086                 if (objsubid == 0)
15087                 {
15088                         appendPQExpBuffer(target, "%s %s", reltypename,
15089                                                           fmtQualifiedDumpable(tbinfo));
15090                 }
15091                 else
15092                 {
15093                         colname = getAttrName(objsubid, tbinfo);
15094                         /* first fmtXXX result must be consumed before calling again */
15095                         appendPQExpBuffer(target, "COLUMN %s",
15096                                                           fmtQualifiedDumpable(tbinfo));
15097                         appendPQExpBuffer(target, ".%s", fmtId(colname));
15098                 }
15099                 appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
15100                                                   fmtId(provider), target->data);
15101                 appendStringLiteralAH(query, label, fout);
15102                 appendPQExpBufferStr(query, ";\n");
15103         }
15104         if (query->len > 0)
15105         {
15106                 resetPQExpBuffer(target);
15107                 appendPQExpBuffer(target, "%s %s", reltypename,
15108                                                   fmtId(tbinfo->dobj.name));
15109                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
15110                                          ARCHIVE_OPTS(.tag = target->data,
15111                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
15112                                                                   .owner = tbinfo->rolname,
15113                                                                   .description = "SECURITY LABEL",
15114                                                                   .section = SECTION_NONE,
15115                                                                   .createStmt = query->data,
15116                                                                   .dropStmt = "",
15117                                                                   .deps = &(tbinfo->dobj.dumpId),
15118                                                                   .nDeps = 1));
15119         }
15120         destroyPQExpBuffer(query);
15121         destroyPQExpBuffer(target);
15122 }
15123
15124 /*
15125  * findSecLabels
15126  *
15127  * Find the security label(s), if any, associated with the given object.
15128  * All the objsubid values associated with the given classoid/objoid are
15129  * found with one search.
15130  */
15131 static int
15132 findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
15133 {
15134         /* static storage for table of security labels */
15135         static SecLabelItem *labels = NULL;
15136         static int      nlabels = -1;
15137
15138         SecLabelItem *middle = NULL;
15139         SecLabelItem *low;
15140         SecLabelItem *high;
15141         int                     nmatch;
15142
15143         /* Get security labels if we didn't already */
15144         if (nlabels < 0)
15145                 nlabels = collectSecLabels(fout, &labels);
15146
15147         if (nlabels <= 0)                       /* no labels, so no match is possible */
15148         {
15149                 *items = NULL;
15150                 return 0;
15151         }
15152
15153         /*
15154          * Do binary search to find some item matching the object.
15155          */
15156         low = &labels[0];
15157         high = &labels[nlabels - 1];
15158         while (low <= high)
15159         {
15160                 middle = low + (high - low) / 2;
15161
15162                 if (classoid < middle->classoid)
15163                         high = middle - 1;
15164                 else if (classoid > middle->classoid)
15165                         low = middle + 1;
15166                 else if (objoid < middle->objoid)
15167                         high = middle - 1;
15168                 else if (objoid > middle->objoid)
15169                         low = middle + 1;
15170                 else
15171                         break;                          /* found a match */
15172         }
15173
15174         if (low > high)                         /* no matches */
15175         {
15176                 *items = NULL;
15177                 return 0;
15178         }
15179
15180         /*
15181          * Now determine how many items match the object.  The search loop
15182          * invariant still holds: only items between low and high inclusive could
15183          * match.
15184          */
15185         nmatch = 1;
15186         while (middle > low)
15187         {
15188                 if (classoid != middle[-1].classoid ||
15189                         objoid != middle[-1].objoid)
15190                         break;
15191                 middle--;
15192                 nmatch++;
15193         }
15194
15195         *items = middle;
15196
15197         middle += nmatch;
15198         while (middle <= high)
15199         {
15200                 if (classoid != middle->classoid ||
15201                         objoid != middle->objoid)
15202                         break;
15203                 middle++;
15204                 nmatch++;
15205         }
15206
15207         return nmatch;
15208 }
15209
15210 /*
15211  * collectSecLabels
15212  *
15213  * Construct a table of all security labels available for database objects.
15214  * It's much faster to pull them all at once.
15215  *
15216  * The table is sorted by classoid/objid/objsubid for speed in lookup.
15217  */
15218 static int
15219 collectSecLabels(Archive *fout, SecLabelItem **items)
15220 {
15221         PGresult   *res;
15222         PQExpBuffer query;
15223         int                     i_label;
15224         int                     i_provider;
15225         int                     i_classoid;
15226         int                     i_objoid;
15227         int                     i_objsubid;
15228         int                     ntups;
15229         int                     i;
15230         SecLabelItem *labels;
15231
15232         query = createPQExpBuffer();
15233
15234         appendPQExpBufferStr(query,
15235                                                  "SELECT label, provider, classoid, objoid, objsubid "
15236                                                  "FROM pg_catalog.pg_seclabel "
15237                                                  "ORDER BY classoid, objoid, objsubid");
15238
15239         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15240
15241         /* Construct lookup table containing OIDs in numeric form */
15242         i_label = PQfnumber(res, "label");
15243         i_provider = PQfnumber(res, "provider");
15244         i_classoid = PQfnumber(res, "classoid");
15245         i_objoid = PQfnumber(res, "objoid");
15246         i_objsubid = PQfnumber(res, "objsubid");
15247
15248         ntups = PQntuples(res);
15249
15250         labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
15251
15252         for (i = 0; i < ntups; i++)
15253         {
15254                 labels[i].label = PQgetvalue(res, i, i_label);
15255                 labels[i].provider = PQgetvalue(res, i, i_provider);
15256                 labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
15257                 labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
15258                 labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
15259         }
15260
15261         /* Do NOT free the PGresult since we are keeping pointers into it */
15262         destroyPQExpBuffer(query);
15263
15264         *items = labels;
15265         return ntups;
15266 }
15267
15268 /*
15269  * dumpTable
15270  *        write out to fout the declarations (not data) of a user-defined table
15271  */
15272 static void
15273 dumpTable(Archive *fout, TableInfo *tbinfo)
15274 {
15275         DumpOptions *dopt = fout->dopt;
15276         char       *namecopy;
15277
15278         /*
15279          * noop if we are not dumping anything about this table, or if we are
15280          * doing a data-only dump
15281          */
15282         if (!tbinfo->dobj.dump || dopt->dataOnly)
15283                 return;
15284
15285         if (tbinfo->relkind == RELKIND_SEQUENCE)
15286                 dumpSequence(fout, tbinfo);
15287         else
15288                 dumpTableSchema(fout, tbinfo);
15289
15290         /* Handle the ACL here */
15291         namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
15292         if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15293         {
15294                 const char *objtype =
15295                 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
15296
15297                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
15298                                 objtype, namecopy, NULL,
15299                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15300                                 tbinfo->relacl, tbinfo->rrelacl,
15301                                 tbinfo->initrelacl, tbinfo->initrrelacl);
15302         }
15303
15304         /*
15305          * Handle column ACLs, if any.  Note: we pull these with a separate query
15306          * rather than trying to fetch them during getTableAttrs, so that we won't
15307          * miss ACLs on system columns.
15308          */
15309         if (fout->remoteVersion >= 80400 && tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15310         {
15311                 PQExpBuffer query = createPQExpBuffer();
15312                 PGresult   *res;
15313                 int                     i;
15314
15315                 if (fout->remoteVersion >= 90600)
15316                 {
15317                         PQExpBuffer acl_subquery = createPQExpBuffer();
15318                         PQExpBuffer racl_subquery = createPQExpBuffer();
15319                         PQExpBuffer initacl_subquery = createPQExpBuffer();
15320                         PQExpBuffer initracl_subquery = createPQExpBuffer();
15321
15322                         buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
15323                                                         initracl_subquery, "at.attacl", "c.relowner", "'c'",
15324                                                         dopt->binary_upgrade);
15325
15326                         appendPQExpBuffer(query,
15327                                                           "SELECT at.attname, "
15328                                                           "%s AS attacl, "
15329                                                           "%s AS rattacl, "
15330                                                           "%s AS initattacl, "
15331                                                           "%s AS initrattacl "
15332                                                           "FROM pg_catalog.pg_attribute at "
15333                                                           "JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
15334                                                           "LEFT JOIN pg_catalog.pg_init_privs pip ON "
15335                                                           "(at.attrelid = pip.objoid "
15336                                                           "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
15337                                                           "AND at.attnum = pip.objsubid) "
15338                                                           "WHERE at.attrelid = '%u'::pg_catalog.oid AND "
15339                                                           "NOT at.attisdropped "
15340                                                           "AND ("
15341                                                           "%s IS NOT NULL OR "
15342                                                           "%s IS NOT NULL OR "
15343                                                           "%s IS NOT NULL OR "
15344                                                           "%s IS NOT NULL)"
15345                                                           "ORDER BY at.attnum",
15346                                                           acl_subquery->data,
15347                                                           racl_subquery->data,
15348                                                           initacl_subquery->data,
15349                                                           initracl_subquery->data,
15350                                                           tbinfo->dobj.catId.oid,
15351                                                           acl_subquery->data,
15352                                                           racl_subquery->data,
15353                                                           initacl_subquery->data,
15354                                                           initracl_subquery->data);
15355
15356                         destroyPQExpBuffer(acl_subquery);
15357                         destroyPQExpBuffer(racl_subquery);
15358                         destroyPQExpBuffer(initacl_subquery);
15359                         destroyPQExpBuffer(initracl_subquery);
15360                 }
15361                 else
15362                 {
15363                         appendPQExpBuffer(query,
15364                                                           "SELECT attname, attacl, NULL as rattacl, "
15365                                                           "NULL AS initattacl, NULL AS initrattacl "
15366                                                           "FROM pg_catalog.pg_attribute "
15367                                                           "WHERE attrelid = '%u'::pg_catalog.oid AND NOT attisdropped "
15368                                                           "AND attacl IS NOT NULL "
15369                                                           "ORDER BY attnum",
15370                                                           tbinfo->dobj.catId.oid);
15371                 }
15372
15373                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15374
15375                 for (i = 0; i < PQntuples(res); i++)
15376                 {
15377                         char       *attname = PQgetvalue(res, i, 0);
15378                         char       *attacl = PQgetvalue(res, i, 1);
15379                         char       *rattacl = PQgetvalue(res, i, 2);
15380                         char       *initattacl = PQgetvalue(res, i, 3);
15381                         char       *initrattacl = PQgetvalue(res, i, 4);
15382                         char       *attnamecopy;
15383
15384                         attnamecopy = pg_strdup(fmtId(attname));
15385                         /* Column's GRANT type is always TABLE */
15386                         dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
15387                                         "TABLE", namecopy, attnamecopy,
15388                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15389                                         attacl, rattacl, initattacl, initrattacl);
15390                         free(attnamecopy);
15391                 }
15392                 PQclear(res);
15393                 destroyPQExpBuffer(query);
15394         }
15395
15396         free(namecopy);
15397
15398         return;
15399 }
15400
15401 /*
15402  * Create the AS clause for a view or materialized view. The semicolon is
15403  * stripped because a materialized view must add a WITH NO DATA clause.
15404  *
15405  * This returns a new buffer which must be freed by the caller.
15406  */
15407 static PQExpBuffer
15408 createViewAsClause(Archive *fout, TableInfo *tbinfo)
15409 {
15410         PQExpBuffer query = createPQExpBuffer();
15411         PQExpBuffer result = createPQExpBuffer();
15412         PGresult   *res;
15413         int                     len;
15414
15415         /* Fetch the view definition */
15416         appendPQExpBuffer(query,
15417                                           "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
15418                                           tbinfo->dobj.catId.oid);
15419
15420         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15421
15422         if (PQntuples(res) != 1)
15423         {
15424                 if (PQntuples(res) < 1)
15425                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned no data\n",
15426                                                   tbinfo->dobj.name);
15427                 else
15428                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
15429                                                   tbinfo->dobj.name);
15430         }
15431
15432         len = PQgetlength(res, 0, 0);
15433
15434         if (len == 0)
15435                 exit_horribly(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
15436                                           tbinfo->dobj.name);
15437
15438         /* Strip off the trailing semicolon so that other things may follow. */
15439         Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
15440         appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
15441
15442         PQclear(res);
15443         destroyPQExpBuffer(query);
15444
15445         return result;
15446 }
15447
15448 /*
15449  * Create a dummy AS clause for a view.  This is used when the real view
15450  * definition has to be postponed because of circular dependencies.
15451  * We must duplicate the view's external properties -- column names and types
15452  * (including collation) -- so that it works for subsequent references.
15453  *
15454  * This returns a new buffer which must be freed by the caller.
15455  */
15456 static PQExpBuffer
15457 createDummyViewAsClause(Archive *fout, TableInfo *tbinfo)
15458 {
15459         PQExpBuffer result = createPQExpBuffer();
15460         int                     j;
15461
15462         appendPQExpBufferStr(result, "SELECT");
15463
15464         for (j = 0; j < tbinfo->numatts; j++)
15465         {
15466                 if (j > 0)
15467                         appendPQExpBufferChar(result, ',');
15468                 appendPQExpBufferStr(result, "\n    ");
15469
15470                 appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
15471
15472                 /*
15473                  * Must add collation if not default for the type, because CREATE OR
15474                  * REPLACE VIEW won't change it
15475                  */
15476                 if (OidIsValid(tbinfo->attcollation[j]))
15477                 {
15478                         CollInfo   *coll;
15479
15480                         coll = findCollationByOid(tbinfo->attcollation[j]);
15481                         if (coll)
15482                                 appendPQExpBuffer(result, " COLLATE %s",
15483                                                                   fmtQualifiedDumpable(coll));
15484                 }
15485
15486                 appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
15487         }
15488
15489         return result;
15490 }
15491
15492 /*
15493  * dumpTableSchema
15494  *        write the declaration (not data) of one user-defined table or view
15495  */
15496 static void
15497 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
15498 {
15499         DumpOptions *dopt = fout->dopt;
15500         PQExpBuffer q = createPQExpBuffer();
15501         PQExpBuffer delq = createPQExpBuffer();
15502         char       *qrelname;
15503         char       *qualrelname;
15504         int                     numParents;
15505         TableInfo **parents;
15506         int                     actual_atts;    /* number of attrs in this CREATE statement */
15507         const char *reltypename;
15508         char       *storage;
15509         int                     j,
15510                                 k;
15511
15512         qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
15513         qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
15514
15515
15516         if (tbinfo->hasoids)
15517                 write_msg(NULL,
15518                                   "WARNING: WITH OIDS is not supported anymore (table \"%s\")\n",
15519                                   qrelname);
15520
15521         if (dopt->binary_upgrade)
15522                 binary_upgrade_set_type_oids_by_rel_oid(fout, q,
15523                                                                                                 tbinfo->dobj.catId.oid);
15524
15525         /* Is it a table or a view? */
15526         if (tbinfo->relkind == RELKIND_VIEW)
15527         {
15528                 PQExpBuffer result;
15529
15530                 /*
15531                  * Note: keep this code in sync with the is_view case in dumpRule()
15532                  */
15533
15534                 reltypename = "VIEW";
15535
15536                 appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
15537
15538                 if (dopt->binary_upgrade)
15539                         binary_upgrade_set_pg_class_oids(fout, q,
15540                                                                                          tbinfo->dobj.catId.oid, false);
15541
15542                 appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
15543
15544                 if (tbinfo->dummy_view)
15545                         result = createDummyViewAsClause(fout, tbinfo);
15546                 else
15547                 {
15548                         if (nonemptyReloptions(tbinfo->reloptions))
15549                         {
15550                                 appendPQExpBufferStr(q, " WITH (");
15551                                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15552                                 appendPQExpBufferChar(q, ')');
15553                         }
15554                         result = createViewAsClause(fout, tbinfo);
15555                 }
15556                 appendPQExpBuffer(q, " AS\n%s", result->data);
15557                 destroyPQExpBuffer(result);
15558
15559                 if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
15560                         appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
15561                 appendPQExpBufferStr(q, ";\n");
15562         }
15563         else
15564         {
15565                 char       *ftoptions = NULL;
15566                 char       *srvname = NULL;
15567
15568                 switch (tbinfo->relkind)
15569                 {
15570                         case RELKIND_FOREIGN_TABLE:
15571                                 {
15572                                         PQExpBuffer query = createPQExpBuffer();
15573                                         PGresult   *res;
15574                                         int                     i_srvname;
15575                                         int                     i_ftoptions;
15576
15577                                         reltypename = "FOREIGN TABLE";
15578
15579                                         /* retrieve name of foreign server and generic options */
15580                                         appendPQExpBuffer(query,
15581                                                                           "SELECT fs.srvname, "
15582                                                                           "pg_catalog.array_to_string(ARRAY("
15583                                                                           "SELECT pg_catalog.quote_ident(option_name) || "
15584                                                                           "' ' || pg_catalog.quote_literal(option_value) "
15585                                                                           "FROM pg_catalog.pg_options_to_table(ftoptions) "
15586                                                                           "ORDER BY option_name"
15587                                                                           "), E',\n    ') AS ftoptions "
15588                                                                           "FROM pg_catalog.pg_foreign_table ft "
15589                                                                           "JOIN pg_catalog.pg_foreign_server fs "
15590                                                                           "ON (fs.oid = ft.ftserver) "
15591                                                                           "WHERE ft.ftrelid = '%u'",
15592                                                                           tbinfo->dobj.catId.oid);
15593                                         res = ExecuteSqlQueryForSingleRow(fout, query->data);
15594                                         i_srvname = PQfnumber(res, "srvname");
15595                                         i_ftoptions = PQfnumber(res, "ftoptions");
15596                                         srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
15597                                         ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
15598                                         PQclear(res);
15599                                         destroyPQExpBuffer(query);
15600                                         break;
15601                                 }
15602                         case RELKIND_MATVIEW:
15603                                 reltypename = "MATERIALIZED VIEW";
15604                                 break;
15605                         default:
15606                                 reltypename = "TABLE";
15607                 }
15608
15609                 numParents = tbinfo->numParents;
15610                 parents = tbinfo->parents;
15611
15612                 appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
15613
15614                 if (dopt->binary_upgrade)
15615                         binary_upgrade_set_pg_class_oids(fout, q,
15616                                                                                          tbinfo->dobj.catId.oid, false);
15617
15618                 appendPQExpBuffer(q, "CREATE %s%s %s",
15619                                                   tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
15620                                                   "UNLOGGED " : "",
15621                                                   reltypename,
15622                                                   qualrelname);
15623
15624                 /*
15625                  * Attach to type, if reloftype; except in case of a binary upgrade,
15626                  * we dump the table normally and attach it to the type afterward.
15627                  */
15628                 if (tbinfo->reloftype && !dopt->binary_upgrade)
15629                         appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
15630
15631                 /*
15632                  * If the table is a partition, dump it as such; except in the case of
15633                  * a binary upgrade, we dump the table normally and attach it to the
15634                  * parent afterward.
15635                  */
15636                 if (tbinfo->ispartition && !dopt->binary_upgrade)
15637                 {
15638                         TableInfo  *parentRel = tbinfo->parents[0];
15639
15640                         /*
15641                          * With partitions, unlike inheritance, there can only be one
15642                          * parent.
15643                          */
15644                         if (tbinfo->numParents != 1)
15645                                 exit_horribly(NULL, "invalid number of parents %d for table \"%s\"\n",
15646                                                           tbinfo->numParents, tbinfo->dobj.name);
15647
15648                         appendPQExpBuffer(q, " PARTITION OF %s",
15649                                                           fmtQualifiedDumpable(parentRel));
15650                 }
15651
15652                 if (tbinfo->relkind != RELKIND_MATVIEW)
15653                 {
15654                         /* Dump the attributes */
15655                         actual_atts = 0;
15656                         for (j = 0; j < tbinfo->numatts; j++)
15657                         {
15658                                 /*
15659                                  * Normally, dump if it's locally defined in this table, and
15660                                  * not dropped.  But for binary upgrade, we'll dump all the
15661                                  * columns, and then fix up the dropped and nonlocal cases
15662                                  * below.
15663                                  */
15664                                 if (shouldPrintColumn(dopt, tbinfo, j))
15665                                 {
15666                                         /*
15667                                          * Default value --- suppress if to be printed separately.
15668                                          */
15669                                         bool            has_default = (tbinfo->attrdefs[j] != NULL &&
15670                                                                                            !tbinfo->attrdefs[j]->separate);
15671
15672                                         /*
15673                                          * Not Null constraint --- suppress if inherited, except
15674                                          * in binary-upgrade case where that won't work.
15675                                          */
15676                                         bool            has_notnull = (tbinfo->notnull[j] &&
15677                                                                                            (!tbinfo->inhNotNull[j] ||
15678                                                                                                 dopt->binary_upgrade));
15679
15680                                         /*
15681                                          * Skip column if fully defined by reloftype or the
15682                                          * partition parent.
15683                                          */
15684                                         if ((tbinfo->reloftype || tbinfo->ispartition) &&
15685                                                 !has_default && !has_notnull && !dopt->binary_upgrade)
15686                                                 continue;
15687
15688                                         /* Format properly if not first attr */
15689                                         if (actual_atts == 0)
15690                                                 appendPQExpBufferStr(q, " (");
15691                                         else
15692                                                 appendPQExpBufferChar(q, ',');
15693                                         appendPQExpBufferStr(q, "\n    ");
15694                                         actual_atts++;
15695
15696                                         /* Attribute name */
15697                                         appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
15698
15699                                         if (tbinfo->attisdropped[j])
15700                                         {
15701                                                 /*
15702                                                  * ALTER TABLE DROP COLUMN clears
15703                                                  * pg_attribute.atttypid, so we will not have gotten a
15704                                                  * valid type name; insert INTEGER as a stopgap. We'll
15705                                                  * clean things up later.
15706                                                  */
15707                                                 appendPQExpBufferStr(q, " INTEGER /* dummy */");
15708                                                 /* Skip all the rest, too */
15709                                                 continue;
15710                                         }
15711
15712                                         /*
15713                                          * Attribute type
15714                                          *
15715                                          * In binary-upgrade mode, we always include the type. If
15716                                          * we aren't in binary-upgrade mode, then we skip the type
15717                                          * when creating a typed table ('OF type_name') or a
15718                                          * partition ('PARTITION OF'), since the type comes from
15719                                          * the parent/partitioned table.
15720                                          */
15721                                         if (dopt->binary_upgrade || (!tbinfo->reloftype && !tbinfo->ispartition))
15722                                         {
15723                                                 appendPQExpBuffer(q, " %s",
15724                                                                                   tbinfo->atttypnames[j]);
15725                                         }
15726
15727                                         if (has_default)
15728                                         {
15729                                                 if (tbinfo->attgenerated[j] == ATTRIBUTE_GENERATED_STORED)
15730                                                         appendPQExpBuffer(q, " GENERATED ALWAYS AS (%s) STORED",
15731                                                                                           tbinfo->attrdefs[j]->adef_expr);
15732                                                 else
15733                                                         appendPQExpBuffer(q, " DEFAULT %s",
15734                                                                                           tbinfo->attrdefs[j]->adef_expr);
15735                                         }
15736
15737
15738                                         if (has_notnull)
15739                                                 appendPQExpBufferStr(q, " NOT NULL");
15740
15741                                         /* Add collation if not default for the type */
15742                                         if (OidIsValid(tbinfo->attcollation[j]))
15743                                         {
15744                                                 CollInfo   *coll;
15745
15746                                                 coll = findCollationByOid(tbinfo->attcollation[j]);
15747                                                 if (coll)
15748                                                         appendPQExpBuffer(q, " COLLATE %s",
15749                                                                                           fmtQualifiedDumpable(coll));
15750                                         }
15751                                 }
15752                         }
15753
15754                         /*
15755                          * Add non-inherited CHECK constraints, if any.
15756                          */
15757                         for (j = 0; j < tbinfo->ncheck; j++)
15758                         {
15759                                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
15760
15761                                 if (constr->separate || !constr->conislocal)
15762                                         continue;
15763
15764                                 if (actual_atts == 0)
15765                                         appendPQExpBufferStr(q, " (\n    ");
15766                                 else
15767                                         appendPQExpBufferStr(q, ",\n    ");
15768
15769                                 appendPQExpBuffer(q, "CONSTRAINT %s ",
15770                                                                   fmtId(constr->dobj.name));
15771                                 appendPQExpBufferStr(q, constr->condef);
15772
15773                                 actual_atts++;
15774                         }
15775
15776                         if (actual_atts)
15777                                 appendPQExpBufferStr(q, "\n)");
15778                         else if (!((tbinfo->reloftype || tbinfo->ispartition) &&
15779                                            !dopt->binary_upgrade))
15780                         {
15781                                 /*
15782                                  * We must have a parenthesized attribute list, even though
15783                                  * empty, when not using the OF TYPE or PARTITION OF syntax.
15784                                  */
15785                                 appendPQExpBufferStr(q, " (\n)");
15786                         }
15787
15788                         if (tbinfo->ispartition && !dopt->binary_upgrade)
15789                         {
15790                                 appendPQExpBufferChar(q, '\n');
15791                                 appendPQExpBufferStr(q, tbinfo->partbound);
15792                         }
15793
15794                         /* Emit the INHERITS clause, except if this is a partition. */
15795                         if (numParents > 0 &&
15796                                 !tbinfo->ispartition &&
15797                                 !dopt->binary_upgrade)
15798                         {
15799                                 appendPQExpBufferStr(q, "\nINHERITS (");
15800                                 for (k = 0; k < numParents; k++)
15801                                 {
15802                                         TableInfo  *parentRel = parents[k];
15803
15804                                         if (k > 0)
15805                                                 appendPQExpBufferStr(q, ", ");
15806                                         appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
15807                                 }
15808                                 appendPQExpBufferChar(q, ')');
15809                         }
15810
15811                         if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15812                                 appendPQExpBuffer(q, "\nPARTITION BY %s", tbinfo->partkeydef);
15813
15814                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
15815                                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
15816                 }
15817
15818                 if (nonemptyReloptions(tbinfo->reloptions) ||
15819                         nonemptyReloptions(tbinfo->toast_reloptions))
15820                 {
15821                         bool            addcomma = false;
15822
15823                         appendPQExpBufferStr(q, "\nWITH (");
15824                         if (nonemptyReloptions(tbinfo->reloptions))
15825                         {
15826                                 addcomma = true;
15827                                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15828                         }
15829                         if (nonemptyReloptions(tbinfo->toast_reloptions))
15830                         {
15831                                 if (addcomma)
15832                                         appendPQExpBufferStr(q, ", ");
15833                                 appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
15834                                                                                 fout);
15835                         }
15836                         appendPQExpBufferChar(q, ')');
15837                 }
15838
15839                 /* Dump generic options if any */
15840                 if (ftoptions && ftoptions[0])
15841                         appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
15842
15843                 /*
15844                  * For materialized views, create the AS clause just like a view. At
15845                  * this point, we always mark the view as not populated.
15846                  */
15847                 if (tbinfo->relkind == RELKIND_MATVIEW)
15848                 {
15849                         PQExpBuffer result;
15850
15851                         result = createViewAsClause(fout, tbinfo);
15852                         appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
15853                                                           result->data);
15854                         destroyPQExpBuffer(result);
15855                 }
15856                 else
15857                         appendPQExpBufferStr(q, ";\n");
15858
15859                 /*
15860                  * in binary upgrade mode, update the catalog with any missing values
15861                  * that might be present.
15862                  */
15863                 if (dopt->binary_upgrade)
15864                 {
15865                         for (j = 0; j < tbinfo->numatts; j++)
15866                         {
15867                                 if (tbinfo->attmissingval[j][0] != '\0')
15868                                 {
15869                                         appendPQExpBufferStr(q, "\n-- set missing value.\n");
15870                                         appendPQExpBufferStr(q,
15871                                                                                  "SELECT pg_catalog.binary_upgrade_set_missing_value(");
15872                                         appendStringLiteralAH(q, qualrelname, fout);
15873                                         appendPQExpBufferStr(q, "::pg_catalog.regclass,");
15874                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15875                                         appendPQExpBufferStr(q, ",");
15876                                         appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
15877                                         appendPQExpBufferStr(q, ");\n\n");
15878                                 }
15879                         }
15880                 }
15881
15882                 /*
15883                  * To create binary-compatible heap files, we have to ensure the same
15884                  * physical column order, including dropped columns, as in the
15885                  * original.  Therefore, we create dropped columns above and drop them
15886                  * here, also updating their attlen/attalign values so that the
15887                  * dropped column can be skipped properly.  (We do not bother with
15888                  * restoring the original attbyval setting.)  Also, inheritance
15889                  * relationships are set up by doing ALTER TABLE INHERIT rather than
15890                  * using an INHERITS clause --- the latter would possibly mess up the
15891                  * column order.  That also means we have to take care about setting
15892                  * attislocal correctly, plus fix up any inherited CHECK constraints.
15893                  * Analogously, we set up typed tables using ALTER TABLE / OF here.
15894                  *
15895                  * We process foreign and partitioned tables here, even though they
15896                  * lack heap storage, because they can participate in inheritance
15897                  * relationships and we want this stuff to be consistent across the
15898                  * inheritance tree.  We can exclude indexes, toast tables, sequences
15899                  * and matviews, even though they have storage, because we don't
15900                  * support altering or dropping columns in them, nor can they be part
15901                  * of inheritance trees.
15902                  */
15903                 if (dopt->binary_upgrade &&
15904                         (tbinfo->relkind == RELKIND_RELATION ||
15905                          tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
15906                          tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
15907                 {
15908                         for (j = 0; j < tbinfo->numatts; j++)
15909                         {
15910                                 if (tbinfo->attisdropped[j])
15911                                 {
15912                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
15913                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
15914                                                                           "SET attlen = %d, "
15915                                                                           "attalign = '%c', attbyval = false\n"
15916                                                                           "WHERE attname = ",
15917                                                                           tbinfo->attlen[j],
15918                                                                           tbinfo->attalign[j]);
15919                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15920                                         appendPQExpBufferStr(q, "\n  AND attrelid = ");
15921                                         appendStringLiteralAH(q, qualrelname, fout);
15922                                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15923
15924                                         if (tbinfo->relkind == RELKIND_RELATION ||
15925                                                 tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15926                                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15927                                                                                   qualrelname);
15928                                         else
15929                                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE ONLY %s ",
15930                                                                                   qualrelname);
15931                                         appendPQExpBuffer(q, "DROP COLUMN %s;\n",
15932                                                                           fmtId(tbinfo->attnames[j]));
15933                                 }
15934                                 else if (!tbinfo->attislocal[j])
15935                                 {
15936                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
15937                                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
15938                                                                                  "SET attislocal = false\n"
15939                                                                                  "WHERE attname = ");
15940                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15941                                         appendPQExpBufferStr(q, "\n  AND attrelid = ");
15942                                         appendStringLiteralAH(q, qualrelname, fout);
15943                                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15944                                 }
15945                         }
15946
15947                         for (k = 0; k < tbinfo->ncheck; k++)
15948                         {
15949                                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
15950
15951                                 if (constr->separate || constr->conislocal)
15952                                         continue;
15953
15954                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
15955                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15956                                                                   qualrelname);
15957                                 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
15958                                                                   fmtId(constr->dobj.name));
15959                                 appendPQExpBuffer(q, "%s;\n", constr->condef);
15960                                 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
15961                                                                          "SET conislocal = false\n"
15962                                                                          "WHERE contype = 'c' AND conname = ");
15963                                 appendStringLiteralAH(q, constr->dobj.name, fout);
15964                                 appendPQExpBufferStr(q, "\n  AND conrelid = ");
15965                                 appendStringLiteralAH(q, qualrelname, fout);
15966                                 appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15967                         }
15968
15969                         if (numParents > 0)
15970                         {
15971                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance and partitioning this way.\n");
15972                                 for (k = 0; k < numParents; k++)
15973                                 {
15974                                         TableInfo  *parentRel = parents[k];
15975
15976                                         /* In the partitioning case, we alter the parent */
15977                                         if (tbinfo->ispartition)
15978                                                 appendPQExpBuffer(q,
15979                                                                                   "ALTER TABLE ONLY %s ATTACH PARTITION ",
15980                                                                                   fmtQualifiedDumpable(parentRel));
15981                                         else
15982                                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
15983                                                                                   qualrelname);
15984
15985                                         /* Partition needs specifying the bounds */
15986                                         if (tbinfo->ispartition)
15987                                                 appendPQExpBuffer(q, "%s %s;\n",
15988                                                                                   qualrelname,
15989                                                                                   tbinfo->partbound);
15990                                         else
15991                                                 appendPQExpBuffer(q, "%s;\n",
15992                                                                                   fmtQualifiedDumpable(parentRel));
15993                                 }
15994                         }
15995
15996                         if (tbinfo->reloftype)
15997                         {
15998                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
15999                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
16000                                                                   qualrelname,
16001                                                                   tbinfo->reloftype);
16002                         }
16003                 }
16004
16005                 /*
16006                  * In binary_upgrade mode, arrange to restore the old relfrozenxid and
16007                  * relminmxid of all vacuumable relations.  (While vacuum.c processes
16008                  * TOAST tables semi-independently, here we see them only as children
16009                  * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
16010                  * child toast table is handled below.)
16011                  */
16012                 if (dopt->binary_upgrade &&
16013                         (tbinfo->relkind == RELKIND_RELATION ||
16014                          tbinfo->relkind == RELKIND_MATVIEW))
16015                 {
16016                         appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
16017                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
16018                                                           "SET relfrozenxid = '%u', relminmxid = '%u'\n"
16019                                                           "WHERE oid = ",
16020                                                           tbinfo->frozenxid, tbinfo->minmxid);
16021                         appendStringLiteralAH(q, qualrelname, fout);
16022                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16023
16024                         if (tbinfo->toast_oid)
16025                         {
16026                                 /*
16027                                  * The toast table will have the same OID at restore, so we
16028                                  * can safely target it by OID.
16029                                  */
16030                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
16031                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
16032                                                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
16033                                                                   "WHERE oid = '%u';\n",
16034                                                                   tbinfo->toast_frozenxid,
16035                                                                   tbinfo->toast_minmxid, tbinfo->toast_oid);
16036                         }
16037                 }
16038
16039                 /*
16040                  * In binary_upgrade mode, restore matviews' populated status by
16041                  * poking pg_class directly.  This is pretty ugly, but we can't use
16042                  * REFRESH MATERIALIZED VIEW since it's possible that some underlying
16043                  * matview is not populated even though this matview is; in any case,
16044                  * we want to transfer the matview's heap storage, not run REFRESH.
16045                  */
16046                 if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
16047                         tbinfo->relispopulated)
16048                 {
16049                         appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
16050                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
16051                                                                  "SET relispopulated = 't'\n"
16052                                                                  "WHERE oid = ");
16053                         appendStringLiteralAH(q, qualrelname, fout);
16054                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16055                 }
16056
16057                 /*
16058                  * Dump additional per-column properties that we can't handle in the
16059                  * main CREATE TABLE command.
16060                  */
16061                 for (j = 0; j < tbinfo->numatts; j++)
16062                 {
16063                         /* None of this applies to dropped columns */
16064                         if (tbinfo->attisdropped[j])
16065                                 continue;
16066
16067                         /*
16068                          * If we didn't dump the column definition explicitly above, and
16069                          * it is NOT NULL and did not inherit that property from a parent,
16070                          * we have to mark it separately.
16071                          */
16072                         if (!shouldPrintColumn(dopt, tbinfo, j) &&
16073                                 tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
16074                         {
16075                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16076                                                                   qualrelname);
16077                                 appendPQExpBuffer(q, "ALTER COLUMN %s SET NOT NULL;\n",
16078                                                                   fmtId(tbinfo->attnames[j]));
16079                         }
16080
16081                         /*
16082                          * Dump per-column statistics information. We only issue an ALTER
16083                          * TABLE statement if the attstattarget entry for this column is
16084                          * non-negative (i.e. it's not the default value)
16085                          */
16086                         if (tbinfo->attstattarget[j] >= 0)
16087                         {
16088                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16089                                                                   qualrelname);
16090                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
16091                                                                   fmtId(tbinfo->attnames[j]));
16092                                 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
16093                                                                   tbinfo->attstattarget[j]);
16094                         }
16095
16096                         /*
16097                          * Dump per-column storage information.  The statement is only
16098                          * dumped if the storage has been changed from the type's default.
16099                          */
16100                         if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
16101                         {
16102                                 switch (tbinfo->attstorage[j])
16103                                 {
16104                                         case 'p':
16105                                                 storage = "PLAIN";
16106                                                 break;
16107                                         case 'e':
16108                                                 storage = "EXTERNAL";
16109                                                 break;
16110                                         case 'm':
16111                                                 storage = "MAIN";
16112                                                 break;
16113                                         case 'x':
16114                                                 storage = "EXTENDED";
16115                                                 break;
16116                                         default:
16117                                                 storage = NULL;
16118                                 }
16119
16120                                 /*
16121                                  * Only dump the statement if it's a storage type we recognize
16122                                  */
16123                                 if (storage != NULL)
16124                                 {
16125                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16126                                                                           qualrelname);
16127                                         appendPQExpBuffer(q, "ALTER COLUMN %s ",
16128                                                                           fmtId(tbinfo->attnames[j]));
16129                                         appendPQExpBuffer(q, "SET STORAGE %s;\n",
16130                                                                           storage);
16131                                 }
16132                         }
16133
16134                         /*
16135                          * Dump per-column attributes.
16136                          */
16137                         if (tbinfo->attoptions[j][0] != '\0')
16138                         {
16139                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16140                                                                   qualrelname);
16141                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
16142                                                                   fmtId(tbinfo->attnames[j]));
16143                                 appendPQExpBuffer(q, "SET (%s);\n",
16144                                                                   tbinfo->attoptions[j]);
16145                         }
16146
16147                         /*
16148                          * Dump per-column fdw options.
16149                          */
16150                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
16151                                 tbinfo->attfdwoptions[j][0] != '\0')
16152                         {
16153                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
16154                                                                   qualrelname);
16155                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
16156                                                                   fmtId(tbinfo->attnames[j]));
16157                                 appendPQExpBuffer(q, "OPTIONS (\n    %s\n);\n",
16158                                                                   tbinfo->attfdwoptions[j]);
16159                         }
16160                 }
16161
16162                 if (ftoptions)
16163                         free(ftoptions);
16164                 if (srvname)
16165                         free(srvname);
16166         }
16167
16168         /*
16169          * dump properties we only have ALTER TABLE syntax for
16170          */
16171         if ((tbinfo->relkind == RELKIND_RELATION ||
16172                  tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
16173                  tbinfo->relkind == RELKIND_MATVIEW) &&
16174                 tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
16175         {
16176                 if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
16177                 {
16178                         /* nothing to do, will be set when the index is dumped */
16179                 }
16180                 else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
16181                 {
16182                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
16183                                                           qualrelname);
16184                 }
16185                 else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
16186                 {
16187                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
16188                                                           qualrelname);
16189                 }
16190         }
16191
16192         if (tbinfo->forcerowsec)
16193                 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
16194                                                   qualrelname);
16195
16196         if (dopt->binary_upgrade)
16197                 binary_upgrade_extension_member(q, &tbinfo->dobj,
16198                                                                                 reltypename, qrelname,
16199                                                                                 tbinfo->dobj.namespace->dobj.name);
16200
16201         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16202         {
16203                 char *tableam = NULL;
16204
16205                 if (tbinfo->relkind == RELKIND_RELATION ||
16206                         tbinfo->relkind == RELKIND_MATVIEW)
16207                         tableam = tbinfo->amname;
16208
16209                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
16210                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
16211                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
16212                                                                   .tablespace = (tbinfo->relkind == RELKIND_VIEW) ?
16213                                                                   NULL : tbinfo->reltablespace,
16214                                                                   .tableam = tableam,
16215                                                                   .owner = tbinfo->rolname,
16216                                                                   .description = reltypename,
16217                                                                   .section = tbinfo->postponed_def ?
16218                                                                   SECTION_POST_DATA : SECTION_PRE_DATA,
16219                                                                   .createStmt = q->data,
16220                                                                   .dropStmt = delq->data));
16221         }
16222
16223         /* Dump Table Comments */
16224         if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16225                 dumpTableComment(fout, tbinfo, reltypename);
16226
16227         /* Dump Table Security Labels */
16228         if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
16229                 dumpTableSecLabel(fout, tbinfo, reltypename);
16230
16231         /* Dump comments on inlined table constraints */
16232         for (j = 0; j < tbinfo->ncheck; j++)
16233         {
16234                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
16235
16236                 if (constr->separate || !constr->conislocal)
16237                         continue;
16238
16239                 if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16240                         dumpTableConstraintComment(fout, constr);
16241         }
16242
16243         destroyPQExpBuffer(q);
16244         destroyPQExpBuffer(delq);
16245         free(qrelname);
16246         free(qualrelname);
16247 }
16248
16249 /*
16250  * dumpAttrDef --- dump an attribute's default-value declaration
16251  */
16252 static void
16253 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
16254 {
16255         DumpOptions *dopt = fout->dopt;
16256         TableInfo  *tbinfo = adinfo->adtable;
16257         int                     adnum = adinfo->adnum;
16258         PQExpBuffer q;
16259         PQExpBuffer delq;
16260         char       *qualrelname;
16261         char       *tag;
16262
16263         /* Skip if table definition not to be dumped */
16264         if (!tbinfo->dobj.dump || dopt->dataOnly)
16265                 return;
16266
16267         /* Skip if not "separate"; it was dumped in the table's definition */
16268         if (!adinfo->separate)
16269                 return;
16270
16271         q = createPQExpBuffer();
16272         delq = createPQExpBuffer();
16273
16274         qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
16275
16276         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16277                                           qualrelname);
16278         appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
16279                                           fmtId(tbinfo->attnames[adnum - 1]),
16280                                           adinfo->adef_expr);
16281
16282         appendPQExpBuffer(delq, "ALTER TABLE %s ",
16283                                           qualrelname);
16284         appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
16285                                           fmtId(tbinfo->attnames[adnum - 1]));
16286
16287         tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
16288
16289         if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16290                 ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
16291                                          ARCHIVE_OPTS(.tag = tag,
16292                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
16293                                                                   .owner = tbinfo->rolname,
16294                                                                   .description = "DEFAULT",
16295                                                                   .section = SECTION_PRE_DATA,
16296                                                                   .createStmt = q->data,
16297                                                                   .dropStmt = delq->data));
16298
16299         free(tag);
16300         destroyPQExpBuffer(q);
16301         destroyPQExpBuffer(delq);
16302         free(qualrelname);
16303 }
16304
16305 /*
16306  * getAttrName: extract the correct name for an attribute
16307  *
16308  * The array tblInfo->attnames[] only provides names of user attributes;
16309  * if a system attribute number is supplied, we have to fake it.
16310  * We also do a little bit of bounds checking for safety's sake.
16311  */
16312 static const char *
16313 getAttrName(int attrnum, TableInfo *tblInfo)
16314 {
16315         if (attrnum > 0 && attrnum <= tblInfo->numatts)
16316                 return tblInfo->attnames[attrnum - 1];
16317         switch (attrnum)
16318         {
16319                 case SelfItemPointerAttributeNumber:
16320                         return "ctid";
16321                 case MinTransactionIdAttributeNumber:
16322                         return "xmin";
16323                 case MinCommandIdAttributeNumber:
16324                         return "cmin";
16325                 case MaxTransactionIdAttributeNumber:
16326                         return "xmax";
16327                 case MaxCommandIdAttributeNumber:
16328                         return "cmax";
16329                 case TableOidAttributeNumber:
16330                         return "tableoid";
16331         }
16332         exit_horribly(NULL, "invalid column number %d for table \"%s\"\n",
16333                                   attrnum, tblInfo->dobj.name);
16334         return NULL;                            /* keep compiler quiet */
16335 }
16336
16337 /*
16338  * dumpIndex
16339  *        write out to fout a user-defined index
16340  */
16341 static void
16342 dumpIndex(Archive *fout, IndxInfo *indxinfo)
16343 {
16344         DumpOptions *dopt = fout->dopt;
16345         TableInfo  *tbinfo = indxinfo->indextable;
16346         bool            is_constraint = (indxinfo->indexconstraint != 0);
16347         PQExpBuffer q;
16348         PQExpBuffer delq;
16349         char       *qindxname;
16350
16351         if (dopt->dataOnly)
16352                 return;
16353
16354         q = createPQExpBuffer();
16355         delq = createPQExpBuffer();
16356
16357         qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
16358
16359         /*
16360          * If there's an associated constraint, don't dump the index per se, but
16361          * do dump any comment for it.  (This is safe because dependency ordering
16362          * will have ensured the constraint is emitted first.)  Note that the
16363          * emitted comment has to be shown as depending on the constraint, not the
16364          * index, in such cases.
16365          */
16366         if (!is_constraint)
16367         {
16368                 char       *indstatcols = indxinfo->indstatcols;
16369                 char       *indstatvals = indxinfo->indstatvals;
16370                 char      **indstatcolsarray = NULL;
16371                 char      **indstatvalsarray = NULL;
16372                 int                     nstatcols;
16373                 int                     nstatvals;
16374
16375                 if (dopt->binary_upgrade)
16376                         binary_upgrade_set_pg_class_oids(fout, q,
16377                                                                                          indxinfo->dobj.catId.oid, true);
16378
16379                 /* Plain secondary index */
16380                 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
16381
16382                 /*
16383                  * Append ALTER TABLE commands as needed to set properties that we
16384                  * only have ALTER TABLE syntax for.  Keep this in sync with the
16385                  * similar code in dumpConstraint!
16386                  */
16387
16388                 /* If the index is clustered, we need to record that. */
16389                 if (indxinfo->indisclustered)
16390                 {
16391                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16392                                                           fmtQualifiedDumpable(tbinfo));
16393                         /* index name is not qualified in this syntax */
16394                         appendPQExpBuffer(q, " ON %s;\n",
16395                                                           qindxname);
16396                 }
16397
16398                 /*
16399                  * If the index has any statistics on some of its columns, generate
16400                  * the associated ALTER INDEX queries.
16401                  */
16402                 if (parsePGArray(indstatcols, &indstatcolsarray, &nstatcols) &&
16403                         parsePGArray(indstatvals, &indstatvalsarray, &nstatvals) &&
16404                         nstatcols == nstatvals)
16405                 {
16406                         int                     j;
16407
16408                         for (j = 0; j < nstatcols; j++)
16409                         {
16410                                 appendPQExpBuffer(q, "ALTER INDEX %s ",
16411                                                                   fmtQualifiedDumpable(indxinfo));
16412
16413                                 /*
16414                                  * Note that this is a column number, so no quotes should be
16415                                  * used.
16416                                  */
16417                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
16418                                                                   indstatcolsarray[j]);
16419                                 appendPQExpBuffer(q, "SET STATISTICS %s;\n",
16420                                                                   indstatvalsarray[j]);
16421                         }
16422                 }
16423
16424                 /* If the index defines identity, we need to record that. */
16425                 if (indxinfo->indisreplident)
16426                 {
16427                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
16428                                                           fmtQualifiedDumpable(tbinfo));
16429                         /* index name is not qualified in this syntax */
16430                         appendPQExpBuffer(q, " INDEX %s;\n",
16431                                                           qindxname);
16432                 }
16433
16434                 appendPQExpBuffer(delq, "DROP INDEX %s;\n",
16435                                                   fmtQualifiedDumpable(indxinfo));
16436
16437                 if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16438                         ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
16439                                                  ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
16440                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
16441                                                                           .tablespace = indxinfo->tablespace,
16442                                                                           .owner = tbinfo->rolname,
16443                                                                           .description = "INDEX",
16444                                                                           .section = SECTION_POST_DATA,
16445                                                                           .createStmt = q->data,
16446                                                                           .dropStmt = delq->data));
16447
16448                 if (indstatcolsarray)
16449                         free(indstatcolsarray);
16450                 if (indstatvalsarray)
16451                         free(indstatvalsarray);
16452         }
16453
16454         /* Dump Index Comments */
16455         if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16456                 dumpComment(fout, "INDEX", qindxname,
16457                                         tbinfo->dobj.namespace->dobj.name,
16458                                         tbinfo->rolname,
16459                                         indxinfo->dobj.catId, 0,
16460                                         is_constraint ? indxinfo->indexconstraint :
16461                                         indxinfo->dobj.dumpId);
16462
16463         destroyPQExpBuffer(q);
16464         destroyPQExpBuffer(delq);
16465         free(qindxname);
16466 }
16467
16468 /*
16469  * dumpIndexAttach
16470  *        write out to fout a partitioned-index attachment clause
16471  */
16472 static void
16473 dumpIndexAttach(Archive *fout, IndexAttachInfo *attachinfo)
16474 {
16475         if (fout->dopt->dataOnly)
16476                 return;
16477
16478         if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
16479         {
16480                 PQExpBuffer q = createPQExpBuffer();
16481
16482                 appendPQExpBuffer(q, "ALTER INDEX %s ",
16483                                                   fmtQualifiedDumpable(attachinfo->parentIdx));
16484                 appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
16485                                                   fmtQualifiedDumpable(attachinfo->partitionIdx));
16486
16487                 ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
16488                                          ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
16489                                                                   .namespace = attachinfo->dobj.namespace->dobj.name,
16490                                                                   .description = "INDEX ATTACH",
16491                                                                   .owner = "",
16492                                                                   .section = SECTION_POST_DATA,
16493                                                                   .createStmt = q->data,
16494                                                                   .dropStmt = ""));
16495
16496                 destroyPQExpBuffer(q);
16497         }
16498 }
16499
16500 /*
16501  * dumpStatisticsExt
16502  *        write out to fout an extended statistics object
16503  */
16504 static void
16505 dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo)
16506 {
16507         DumpOptions *dopt = fout->dopt;
16508         PQExpBuffer q;
16509         PQExpBuffer delq;
16510         PQExpBuffer query;
16511         char       *qstatsextname;
16512         PGresult   *res;
16513         char       *stxdef;
16514
16515         /* Skip if not to be dumped */
16516         if (!statsextinfo->dobj.dump || dopt->dataOnly)
16517                 return;
16518
16519         q = createPQExpBuffer();
16520         delq = createPQExpBuffer();
16521         query = createPQExpBuffer();
16522
16523         qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
16524
16525         appendPQExpBuffer(query, "SELECT "
16526                                           "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
16527                                           statsextinfo->dobj.catId.oid);
16528
16529         res = ExecuteSqlQueryForSingleRow(fout, query->data);
16530
16531         stxdef = PQgetvalue(res, 0, 0);
16532
16533         /* Result of pg_get_statisticsobjdef is complete except for semicolon */
16534         appendPQExpBuffer(q, "%s;\n", stxdef);
16535
16536         appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
16537                                           fmtQualifiedDumpable(statsextinfo));
16538
16539         if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16540                 ArchiveEntry(fout, statsextinfo->dobj.catId,
16541                                          statsextinfo->dobj.dumpId,
16542                                          ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
16543                                                                   .namespace = statsextinfo->dobj.namespace->dobj.name,
16544                                                                   .owner = statsextinfo->rolname,
16545                                                                   .description = "STATISTICS",
16546                                                                   .section = SECTION_POST_DATA,
16547                                                                   .createStmt = q->data,
16548                                                                   .dropStmt = delq->data));
16549
16550         /* Dump Statistics Comments */
16551         if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16552                 dumpComment(fout, "STATISTICS", qstatsextname,
16553                                         statsextinfo->dobj.namespace->dobj.name,
16554                                         statsextinfo->rolname,
16555                                         statsextinfo->dobj.catId, 0,
16556                                         statsextinfo->dobj.dumpId);
16557
16558         PQclear(res);
16559         destroyPQExpBuffer(q);
16560         destroyPQExpBuffer(delq);
16561         destroyPQExpBuffer(query);
16562         free(qstatsextname);
16563 }
16564
16565 /*
16566  * dumpConstraint
16567  *        write out to fout a user-defined constraint
16568  */
16569 static void
16570 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
16571 {
16572         DumpOptions *dopt = fout->dopt;
16573         TableInfo  *tbinfo = coninfo->contable;
16574         PQExpBuffer q;
16575         PQExpBuffer delq;
16576         char       *tag = NULL;
16577
16578         /* Skip if not to be dumped */
16579         if (!coninfo->dobj.dump || dopt->dataOnly)
16580                 return;
16581
16582         q = createPQExpBuffer();
16583         delq = createPQExpBuffer();
16584
16585         if (coninfo->contype == 'p' ||
16586                 coninfo->contype == 'u' ||
16587                 coninfo->contype == 'x')
16588         {
16589                 /* Index-related constraint */
16590                 IndxInfo   *indxinfo;
16591                 int                     k;
16592
16593                 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
16594
16595                 if (indxinfo == NULL)
16596                         exit_horribly(NULL, "missing index for constraint \"%s\"\n",
16597                                                   coninfo->dobj.name);
16598
16599                 if (dopt->binary_upgrade)
16600                         binary_upgrade_set_pg_class_oids(fout, q,
16601                                                                                          indxinfo->dobj.catId.oid, true);
16602
16603                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
16604                                                   fmtQualifiedDumpable(tbinfo));
16605                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
16606                                                   fmtId(coninfo->dobj.name));
16607
16608                 if (coninfo->condef)
16609                 {
16610                         /* pg_get_constraintdef should have provided everything */
16611                         appendPQExpBuffer(q, "%s;\n", coninfo->condef);
16612                 }
16613                 else
16614                 {
16615                         appendPQExpBuffer(q, "%s (",
16616                                                           coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
16617                         for (k = 0; k < indxinfo->indnkeyattrs; k++)
16618                         {
16619                                 int                     indkey = (int) indxinfo->indkeys[k];
16620                                 const char *attname;
16621
16622                                 if (indkey == InvalidAttrNumber)
16623                                         break;
16624                                 attname = getAttrName(indkey, tbinfo);
16625
16626                                 appendPQExpBuffer(q, "%s%s",
16627                                                                   (k == 0) ? "" : ", ",
16628                                                                   fmtId(attname));
16629                         }
16630
16631                         if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
16632                                 appendPQExpBuffer(q, ") INCLUDE (");
16633
16634                         for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
16635                         {
16636                                 int                     indkey = (int) indxinfo->indkeys[k];
16637                                 const char *attname;
16638
16639                                 if (indkey == InvalidAttrNumber)
16640                                         break;
16641                                 attname = getAttrName(indkey, tbinfo);
16642
16643                                 appendPQExpBuffer(q, "%s%s",
16644                                                                   (k == indxinfo->indnkeyattrs) ? "" : ", ",
16645                                                                   fmtId(attname));
16646                         }
16647
16648                         appendPQExpBufferChar(q, ')');
16649
16650                         if (nonemptyReloptions(indxinfo->indreloptions))
16651                         {
16652                                 appendPQExpBufferStr(q, " WITH (");
16653                                 appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
16654                                 appendPQExpBufferChar(q, ')');
16655                         }
16656
16657                         if (coninfo->condeferrable)
16658                         {
16659                                 appendPQExpBufferStr(q, " DEFERRABLE");
16660                                 if (coninfo->condeferred)
16661                                         appendPQExpBufferStr(q, " INITIALLY DEFERRED");
16662                         }
16663
16664                         appendPQExpBufferStr(q, ";\n");
16665                 }
16666
16667                 /*
16668                  * Append ALTER TABLE commands as needed to set properties that we
16669                  * only have ALTER TABLE syntax for.  Keep this in sync with the
16670                  * similar code in dumpIndex!
16671                  */
16672
16673                 /* If the index is clustered, we need to record that. */
16674                 if (indxinfo->indisclustered)
16675                 {
16676                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16677                                                           fmtQualifiedDumpable(tbinfo));
16678                         /* index name is not qualified in this syntax */
16679                         appendPQExpBuffer(q, " ON %s;\n",
16680                                                           fmtId(indxinfo->dobj.name));
16681                 }
16682
16683                 /* If the index defines identity, we need to record that. */
16684                 if (indxinfo->indisreplident)
16685                 {
16686                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
16687                                                           fmtQualifiedDumpable(tbinfo));
16688                         /* index name is not qualified in this syntax */
16689                         appendPQExpBuffer(q, " INDEX %s;\n",
16690                                                           fmtId(indxinfo->dobj.name));
16691                 }
16692
16693                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s ",
16694                                                   fmtQualifiedDumpable(tbinfo));
16695                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16696                                                   fmtId(coninfo->dobj.name));
16697
16698                 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16699
16700                 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16701                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16702                                                  ARCHIVE_OPTS(.tag = tag,
16703                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
16704                                                                           .tablespace = indxinfo->tablespace,
16705                                                                           .owner = tbinfo->rolname,
16706                                                                           .description = "CONSTRAINT",
16707                                                                           .section = SECTION_POST_DATA,
16708                                                                           .createStmt = q->data,
16709                                                                           .dropStmt = delq->data));
16710         }
16711         else if (coninfo->contype == 'f')
16712         {
16713                 char       *only;
16714
16715                 /*
16716                  * Foreign keys on partitioned tables are always declared as
16717                  * inheriting to partitions; for all other cases, emit them as
16718                  * applying ONLY directly to the named table, because that's how they
16719                  * work for regular inherited tables.
16720                  */
16721                 only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
16722
16723                 /*
16724                  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
16725                  * current table data is not processed
16726                  */
16727                 appendPQExpBuffer(q, "ALTER TABLE %s%s\n",
16728                                                   only, fmtQualifiedDumpable(tbinfo));
16729                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16730                                                   fmtId(coninfo->dobj.name),
16731                                                   coninfo->condef);
16732
16733                 appendPQExpBuffer(delq, "ALTER TABLE %s%s ",
16734                                                   only, fmtQualifiedDumpable(tbinfo));
16735                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16736                                                   fmtId(coninfo->dobj.name));
16737
16738                 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16739
16740                 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16741                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16742                                                  ARCHIVE_OPTS(.tag = tag,
16743                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
16744                                                                           .owner = tbinfo->rolname,
16745                                                                           .description = "FK CONSTRAINT",
16746                                                                           .section = SECTION_POST_DATA,
16747                                                                           .createStmt = q->data,
16748                                                                           .dropStmt = delq->data));
16749         }
16750         else if (coninfo->contype == 'c' && tbinfo)
16751         {
16752                 /* CHECK constraint on a table */
16753
16754                 /* Ignore if not to be dumped separately, or if it was inherited */
16755                 if (coninfo->separate && coninfo->conislocal)
16756                 {
16757                         /* not ONLY since we want it to propagate to children */
16758                         appendPQExpBuffer(q, "ALTER TABLE %s\n",
16759                                                           fmtQualifiedDumpable(tbinfo));
16760                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16761                                                           fmtId(coninfo->dobj.name),
16762                                                           coninfo->condef);
16763
16764                         appendPQExpBuffer(delq, "ALTER TABLE %s ",
16765                                                           fmtQualifiedDumpable(tbinfo));
16766                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16767                                                           fmtId(coninfo->dobj.name));
16768
16769                         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16770
16771                         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16772                                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16773                                                          ARCHIVE_OPTS(.tag = tag,
16774                                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
16775                                                                                   .owner = tbinfo->rolname,
16776                                                                                   .description = "CHECK CONSTRAINT",
16777                                                                                   .section = SECTION_POST_DATA,
16778                                                                                   .createStmt = q->data,
16779                                                                                   .dropStmt = delq->data));
16780                 }
16781         }
16782         else if (coninfo->contype == 'c' && tbinfo == NULL)
16783         {
16784                 /* CHECK constraint on a domain */
16785                 TypeInfo   *tyinfo = coninfo->condomain;
16786
16787                 /* Ignore if not to be dumped separately */
16788                 if (coninfo->separate)
16789                 {
16790                         appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
16791                                                           fmtQualifiedDumpable(tyinfo));
16792                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16793                                                           fmtId(coninfo->dobj.name),
16794                                                           coninfo->condef);
16795
16796                         appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
16797                                                           fmtQualifiedDumpable(tyinfo));
16798                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16799                                                           fmtId(coninfo->dobj.name));
16800
16801                         tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
16802
16803                         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16804                                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16805                                                          ARCHIVE_OPTS(.tag = tag,
16806                                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
16807                                                                                   .owner = tyinfo->rolname,
16808                                                                                   .description = "CHECK CONSTRAINT",
16809                                                                                   .section = SECTION_POST_DATA,
16810                                                                                   .createStmt = q->data,
16811                                                                                   .dropStmt = delq->data));
16812                 }
16813         }
16814         else
16815         {
16816                 exit_horribly(NULL, "unrecognized constraint type: %c\n",
16817                                           coninfo->contype);
16818         }
16819
16820         /* Dump Constraint Comments --- only works for table constraints */
16821         if (tbinfo && coninfo->separate &&
16822                 coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16823                 dumpTableConstraintComment(fout, coninfo);
16824
16825         free(tag);
16826         destroyPQExpBuffer(q);
16827         destroyPQExpBuffer(delq);
16828 }
16829
16830 /*
16831  * dumpTableConstraintComment --- dump a constraint's comment if any
16832  *
16833  * This is split out because we need the function in two different places
16834  * depending on whether the constraint is dumped as part of CREATE TABLE
16835  * or as a separate ALTER command.
16836  */
16837 static void
16838 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
16839 {
16840         TableInfo  *tbinfo = coninfo->contable;
16841         PQExpBuffer conprefix = createPQExpBuffer();
16842         char       *qtabname;
16843
16844         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
16845
16846         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
16847                                           fmtId(coninfo->dobj.name));
16848
16849         if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16850                 dumpComment(fout, conprefix->data, qtabname,
16851                                         tbinfo->dobj.namespace->dobj.name,
16852                                         tbinfo->rolname,
16853                                         coninfo->dobj.catId, 0,
16854                                         coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
16855
16856         destroyPQExpBuffer(conprefix);
16857         free(qtabname);
16858 }
16859
16860 /*
16861  * findLastBuiltinOid_V71 -
16862  *
16863  * find the last built in oid
16864  *
16865  * For 7.1 through 8.0, we do this by retrieving datlastsysoid from the
16866  * pg_database entry for the current database.  (Note: current_database()
16867  * requires 7.3; pg_dump requires 8.0 now.)
16868  */
16869 static Oid
16870 findLastBuiltinOid_V71(Archive *fout)
16871 {
16872         PGresult   *res;
16873         Oid                     last_oid;
16874
16875         res = ExecuteSqlQueryForSingleRow(fout,
16876                                                                           "SELECT datlastsysoid FROM pg_database WHERE datname = current_database()");
16877         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
16878         PQclear(res);
16879
16880         return last_oid;
16881 }
16882
16883 /*
16884  * dumpSequence
16885  *        write the declaration (not data) of one user-defined sequence
16886  */
16887 static void
16888 dumpSequence(Archive *fout, TableInfo *tbinfo)
16889 {
16890         DumpOptions *dopt = fout->dopt;
16891         PGresult   *res;
16892         char       *startv,
16893                            *incby,
16894                            *maxv,
16895                            *minv,
16896                            *cache,
16897                            *seqtype;
16898         bool            cycled;
16899         bool            is_ascending;
16900         int64           default_minv,
16901                                 default_maxv;
16902         char            bufm[32],
16903                                 bufx[32];
16904         PQExpBuffer query = createPQExpBuffer();
16905         PQExpBuffer delqry = createPQExpBuffer();
16906         char       *qseqname;
16907
16908         qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
16909
16910         if (fout->remoteVersion >= 100000)
16911         {
16912                 appendPQExpBuffer(query,
16913                                                   "SELECT format_type(seqtypid, NULL), "
16914                                                   "seqstart, seqincrement, "
16915                                                   "seqmax, seqmin, "
16916                                                   "seqcache, seqcycle "
16917                                                   "FROM pg_catalog.pg_sequence "
16918                                                   "WHERE seqrelid = '%u'::oid",
16919                                                   tbinfo->dobj.catId.oid);
16920         }
16921         else if (fout->remoteVersion >= 80400)
16922         {
16923                 /*
16924                  * Before PostgreSQL 10, sequence metadata is in the sequence itself.
16925                  *
16926                  * Note: it might seem that 'bigint' potentially needs to be
16927                  * schema-qualified, but actually that's a keyword.
16928                  */
16929                 appendPQExpBuffer(query,
16930                                                   "SELECT 'bigint' AS sequence_type, "
16931                                                   "start_value, increment_by, max_value, min_value, "
16932                                                   "cache_value, is_cycled FROM %s",
16933                                                   fmtQualifiedDumpable(tbinfo));
16934         }
16935         else
16936         {
16937                 appendPQExpBuffer(query,
16938                                                   "SELECT 'bigint' AS sequence_type, "
16939                                                   "0 AS start_value, increment_by, max_value, min_value, "
16940                                                   "cache_value, is_cycled FROM %s",
16941                                                   fmtQualifiedDumpable(tbinfo));
16942         }
16943
16944         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16945
16946         if (PQntuples(res) != 1)
16947         {
16948                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
16949                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
16950                                                                  PQntuples(res)),
16951                                   tbinfo->dobj.name, PQntuples(res));
16952                 exit_nicely(1);
16953         }
16954
16955         seqtype = PQgetvalue(res, 0, 0);
16956         startv = PQgetvalue(res, 0, 1);
16957         incby = PQgetvalue(res, 0, 2);
16958         maxv = PQgetvalue(res, 0, 3);
16959         minv = PQgetvalue(res, 0, 4);
16960         cache = PQgetvalue(res, 0, 5);
16961         cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
16962
16963         /* Calculate default limits for a sequence of this type */
16964         is_ascending = (incby[0] != '-');
16965         if (strcmp(seqtype, "smallint") == 0)
16966         {
16967                 default_minv = is_ascending ? 1 : PG_INT16_MIN;
16968                 default_maxv = is_ascending ? PG_INT16_MAX : -1;
16969         }
16970         else if (strcmp(seqtype, "integer") == 0)
16971         {
16972                 default_minv = is_ascending ? 1 : PG_INT32_MIN;
16973                 default_maxv = is_ascending ? PG_INT32_MAX : -1;
16974         }
16975         else if (strcmp(seqtype, "bigint") == 0)
16976         {
16977                 default_minv = is_ascending ? 1 : PG_INT64_MIN;
16978                 default_maxv = is_ascending ? PG_INT64_MAX : -1;
16979         }
16980         else
16981         {
16982                 exit_horribly(NULL, "unrecognized sequence type: %s\n", seqtype);
16983                 default_minv = default_maxv = 0;        /* keep compiler quiet */
16984         }
16985
16986         /*
16987          * 64-bit strtol() isn't very portable, so convert the limits to strings
16988          * and compare that way.
16989          */
16990         snprintf(bufm, sizeof(bufm), INT64_FORMAT, default_minv);
16991         snprintf(bufx, sizeof(bufx), INT64_FORMAT, default_maxv);
16992
16993         /* Don't print minv/maxv if they match the respective default limit */
16994         if (strcmp(minv, bufm) == 0)
16995                 minv = NULL;
16996         if (strcmp(maxv, bufx) == 0)
16997                 maxv = NULL;
16998
16999         /*
17000          * Identity sequences are not to be dropped separately.
17001          */
17002         if (!tbinfo->is_identity_sequence)
17003         {
17004                 appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
17005                                                   fmtQualifiedDumpable(tbinfo));
17006         }
17007
17008         resetPQExpBuffer(query);
17009
17010         if (dopt->binary_upgrade)
17011         {
17012                 binary_upgrade_set_pg_class_oids(fout, query,
17013                                                                                  tbinfo->dobj.catId.oid, false);
17014                 binary_upgrade_set_type_oids_by_rel_oid(fout, query,
17015                                                                                                 tbinfo->dobj.catId.oid);
17016         }
17017
17018         if (tbinfo->is_identity_sequence)
17019         {
17020                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
17021
17022                 appendPQExpBuffer(query,
17023                                                   "ALTER TABLE %s ",
17024                                                   fmtQualifiedDumpable(owning_tab));
17025                 appendPQExpBuffer(query,
17026                                                   "ALTER COLUMN %s ADD GENERATED ",
17027                                                   fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
17028                 if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
17029                         appendPQExpBuffer(query, "ALWAYS");
17030                 else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
17031                         appendPQExpBuffer(query, "BY DEFAULT");
17032                 appendPQExpBuffer(query, " AS IDENTITY (\n    SEQUENCE NAME %s\n",
17033                                                   fmtQualifiedDumpable(tbinfo));
17034         }
17035         else
17036         {
17037                 appendPQExpBuffer(query,
17038                                                   "CREATE SEQUENCE %s\n",
17039                                                   fmtQualifiedDumpable(tbinfo));
17040
17041                 if (strcmp(seqtype, "bigint") != 0)
17042                         appendPQExpBuffer(query, "    AS %s\n", seqtype);
17043         }
17044
17045         if (fout->remoteVersion >= 80400)
17046                 appendPQExpBuffer(query, "    START WITH %s\n", startv);
17047
17048         appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
17049
17050         if (minv)
17051                 appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
17052         else
17053                 appendPQExpBufferStr(query, "    NO MINVALUE\n");
17054
17055         if (maxv)
17056                 appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
17057         else
17058                 appendPQExpBufferStr(query, "    NO MAXVALUE\n");
17059
17060         appendPQExpBuffer(query,
17061                                           "    CACHE %s%s",
17062                                           cache, (cycled ? "\n    CYCLE" : ""));
17063
17064         if (tbinfo->is_identity_sequence)
17065                 appendPQExpBufferStr(query, "\n);\n");
17066         else
17067                 appendPQExpBufferStr(query, ";\n");
17068
17069         /* binary_upgrade:      no need to clear TOAST table oid */
17070
17071         if (dopt->binary_upgrade)
17072                 binary_upgrade_extension_member(query, &tbinfo->dobj,
17073                                                                                 "SEQUENCE", qseqname,
17074                                                                                 tbinfo->dobj.namespace->dobj.name);
17075
17076         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17077                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
17078                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17079                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17080                                                                   .owner = tbinfo->rolname,
17081                                                                   .description = "SEQUENCE",
17082                                                                   .section = SECTION_PRE_DATA,
17083                                                                   .createStmt = query->data,
17084                                                                   .dropStmt = delqry->data));
17085
17086         /*
17087          * If the sequence is owned by a table column, emit the ALTER for it as a
17088          * separate TOC entry immediately following the sequence's own entry. It's
17089          * OK to do this rather than using full sorting logic, because the
17090          * dependency that tells us it's owned will have forced the table to be
17091          * created first.  We can't just include the ALTER in the TOC entry
17092          * because it will fail if we haven't reassigned the sequence owner to
17093          * match the table's owner.
17094          *
17095          * We need not schema-qualify the table reference because both sequence
17096          * and table must be in the same schema.
17097          */
17098         if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
17099         {
17100                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
17101
17102                 if (owning_tab == NULL)
17103                         exit_horribly(NULL, "failed sanity check, parent table with OID %u of sequence with OID %u not found\n",
17104                                                   tbinfo->owning_tab, tbinfo->dobj.catId.oid);
17105
17106                 if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
17107                 {
17108                         resetPQExpBuffer(query);
17109                         appendPQExpBuffer(query, "ALTER SEQUENCE %s",
17110                                                           fmtQualifiedDumpable(tbinfo));
17111                         appendPQExpBuffer(query, " OWNED BY %s",
17112                                                           fmtQualifiedDumpable(owning_tab));
17113                         appendPQExpBuffer(query, ".%s;\n",
17114                                                           fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
17115
17116                         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17117                                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
17118                                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17119                                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17120                                                                                   .owner = tbinfo->rolname,
17121                                                                                   .description = "SEQUENCE OWNED BY",
17122                                                                                   .section = SECTION_PRE_DATA,
17123                                                                                   .createStmt = query->data,
17124                                                                                   .dropStmt = "",
17125                                                                                   .deps = &(tbinfo->dobj.dumpId),
17126                                                                                   .nDeps = 1));
17127                 }
17128         }
17129
17130         /* Dump Sequence Comments and Security Labels */
17131         if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17132                 dumpComment(fout, "SEQUENCE", qseqname,
17133                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17134                                         tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
17135
17136         if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
17137                 dumpSecLabel(fout, "SEQUENCE", qseqname,
17138                                          tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17139                                          tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
17140
17141         PQclear(res);
17142
17143         destroyPQExpBuffer(query);
17144         destroyPQExpBuffer(delqry);
17145         free(qseqname);
17146 }
17147
17148 /*
17149  * dumpSequenceData
17150  *        write the data of one user-defined sequence
17151  */
17152 static void
17153 dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
17154 {
17155         TableInfo  *tbinfo = tdinfo->tdtable;
17156         PGresult   *res;
17157         char       *last;
17158         bool            called;
17159         PQExpBuffer query = createPQExpBuffer();
17160
17161         appendPQExpBuffer(query,
17162                                           "SELECT last_value, is_called FROM %s",
17163                                           fmtQualifiedDumpable(tbinfo));
17164
17165         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17166
17167         if (PQntuples(res) != 1)
17168         {
17169                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
17170                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
17171                                                                  PQntuples(res)),
17172                                   tbinfo->dobj.name, PQntuples(res));
17173                 exit_nicely(1);
17174         }
17175
17176         last = PQgetvalue(res, 0, 0);
17177         called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
17178
17179         resetPQExpBuffer(query);
17180         appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
17181         appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
17182         appendPQExpBuffer(query, ", %s, %s);\n",
17183                                           last, (called ? "true" : "false"));
17184
17185         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
17186                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
17187                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17188                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17189                                                                   .owner = tbinfo->rolname,
17190                                                                   .description = "SEQUENCE SET",
17191                                                                   .section = SECTION_DATA,
17192                                                                   .createStmt = query->data,
17193                                                                   .dropStmt = "",
17194                                                                   .deps = &(tbinfo->dobj.dumpId),
17195                                                                   .nDeps = 1));
17196
17197         PQclear(res);
17198
17199         destroyPQExpBuffer(query);
17200 }
17201
17202 /*
17203  * dumpTrigger
17204  *        write the declaration of one user-defined table trigger
17205  */
17206 static void
17207 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
17208 {
17209         DumpOptions *dopt = fout->dopt;
17210         TableInfo  *tbinfo = tginfo->tgtable;
17211         PQExpBuffer query;
17212         PQExpBuffer delqry;
17213         PQExpBuffer trigprefix;
17214         char       *qtabname;
17215         char       *tgargs;
17216         size_t          lentgargs;
17217         const char *p;
17218         int                     findx;
17219         char       *tag;
17220
17221         /*
17222          * we needn't check dobj.dump because TriggerInfo wouldn't have been
17223          * created in the first place for non-dumpable triggers
17224          */
17225         if (dopt->dataOnly)
17226                 return;
17227
17228         query = createPQExpBuffer();
17229         delqry = createPQExpBuffer();
17230         trigprefix = createPQExpBuffer();
17231
17232         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17233
17234         appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
17235                                           fmtId(tginfo->dobj.name));
17236         appendPQExpBuffer(delqry, "ON %s;\n",
17237                                           fmtQualifiedDumpable(tbinfo));
17238
17239         if (tginfo->tgdef)
17240         {
17241                 appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
17242         }
17243         else
17244         {
17245                 if (tginfo->tgisconstraint)
17246                 {
17247                         appendPQExpBufferStr(query, "CREATE CONSTRAINT TRIGGER ");
17248                         appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
17249                 }
17250                 else
17251                 {
17252                         appendPQExpBufferStr(query, "CREATE TRIGGER ");
17253                         appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
17254                 }
17255                 appendPQExpBufferStr(query, "\n    ");
17256
17257                 /* Trigger type */
17258                 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
17259                         appendPQExpBufferStr(query, "BEFORE");
17260                 else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
17261                         appendPQExpBufferStr(query, "AFTER");
17262                 else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
17263                         appendPQExpBufferStr(query, "INSTEAD OF");
17264                 else
17265                 {
17266                         write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
17267                         exit_nicely(1);
17268                 }
17269
17270                 findx = 0;
17271                 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
17272                 {
17273                         appendPQExpBufferStr(query, " INSERT");
17274                         findx++;
17275                 }
17276                 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
17277                 {
17278                         if (findx > 0)
17279                                 appendPQExpBufferStr(query, " OR DELETE");
17280                         else
17281                                 appendPQExpBufferStr(query, " DELETE");
17282                         findx++;
17283                 }
17284                 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
17285                 {
17286                         if (findx > 0)
17287                                 appendPQExpBufferStr(query, " OR UPDATE");
17288                         else
17289                                 appendPQExpBufferStr(query, " UPDATE");
17290                         findx++;
17291                 }
17292                 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
17293                 {
17294                         if (findx > 0)
17295                                 appendPQExpBufferStr(query, " OR TRUNCATE");
17296                         else
17297                                 appendPQExpBufferStr(query, " TRUNCATE");
17298                         findx++;
17299                 }
17300                 appendPQExpBuffer(query, " ON %s\n",
17301                                                   fmtQualifiedDumpable(tbinfo));
17302
17303                 if (tginfo->tgisconstraint)
17304                 {
17305                         if (OidIsValid(tginfo->tgconstrrelid))
17306                         {
17307                                 /* regclass output is already quoted */
17308                                 appendPQExpBuffer(query, "    FROM %s\n    ",
17309                                                                   tginfo->tgconstrrelname);
17310                         }
17311                         if (!tginfo->tgdeferrable)
17312                                 appendPQExpBufferStr(query, "NOT ");
17313                         appendPQExpBufferStr(query, "DEFERRABLE INITIALLY ");
17314                         if (tginfo->tginitdeferred)
17315                                 appendPQExpBufferStr(query, "DEFERRED\n");
17316                         else
17317                                 appendPQExpBufferStr(query, "IMMEDIATE\n");
17318                 }
17319
17320                 if (TRIGGER_FOR_ROW(tginfo->tgtype))
17321                         appendPQExpBufferStr(query, "    FOR EACH ROW\n    ");
17322                 else
17323                         appendPQExpBufferStr(query, "    FOR EACH STATEMENT\n    ");
17324
17325                 /* regproc output is already sufficiently quoted */
17326                 appendPQExpBuffer(query, "EXECUTE FUNCTION %s(",
17327                                                   tginfo->tgfname);
17328
17329                 tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
17330                                                                                   &lentgargs);
17331                 p = tgargs;
17332                 for (findx = 0; findx < tginfo->tgnargs; findx++)
17333                 {
17334                         /* find the embedded null that terminates this trigger argument */
17335                         size_t          tlen = strlen(p);
17336
17337                         if (p + tlen >= tgargs + lentgargs)
17338                         {
17339                                 /* hm, not found before end of bytea value... */
17340                                 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
17341                                                   tginfo->tgargs,
17342                                                   tginfo->dobj.name,
17343                                                   tbinfo->dobj.name);
17344                                 exit_nicely(1);
17345                         }
17346
17347                         if (findx > 0)
17348                                 appendPQExpBufferStr(query, ", ");
17349                         appendStringLiteralAH(query, p, fout);
17350                         p += tlen + 1;
17351                 }
17352                 free(tgargs);
17353                 appendPQExpBufferStr(query, ");\n");
17354         }
17355
17356         if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
17357         {
17358                 appendPQExpBuffer(query, "\nALTER TABLE %s ",
17359                                                   fmtQualifiedDumpable(tbinfo));
17360                 switch (tginfo->tgenabled)
17361                 {
17362                         case 'D':
17363                         case 'f':
17364                                 appendPQExpBufferStr(query, "DISABLE");
17365                                 break;
17366                         case 'A':
17367                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
17368                                 break;
17369                         case 'R':
17370                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
17371                                 break;
17372                         default:
17373                                 appendPQExpBufferStr(query, "ENABLE");
17374                                 break;
17375                 }
17376                 appendPQExpBuffer(query, " TRIGGER %s;\n",
17377                                                   fmtId(tginfo->dobj.name));
17378         }
17379
17380         appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
17381                                           fmtId(tginfo->dobj.name));
17382
17383         tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
17384
17385         if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17386                 ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
17387                                          ARCHIVE_OPTS(.tag = tag,
17388                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17389                                                                   .owner = tbinfo->rolname,
17390                                                                   .description = "TRIGGER",
17391                                                                   .section = SECTION_POST_DATA,
17392                                                                   .createStmt = query->data,
17393                                                                   .dropStmt = delqry->data));
17394
17395         if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17396                 dumpComment(fout, trigprefix->data, qtabname,
17397                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17398                                         tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
17399
17400         free(tag);
17401         destroyPQExpBuffer(query);
17402         destroyPQExpBuffer(delqry);
17403         destroyPQExpBuffer(trigprefix);
17404         free(qtabname);
17405 }
17406
17407 /*
17408  * dumpEventTrigger
17409  *        write the declaration of one user-defined event trigger
17410  */
17411 static void
17412 dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
17413 {
17414         DumpOptions *dopt = fout->dopt;
17415         PQExpBuffer query;
17416         PQExpBuffer delqry;
17417         char       *qevtname;
17418
17419         /* Skip if not to be dumped */
17420         if (!evtinfo->dobj.dump || dopt->dataOnly)
17421                 return;
17422
17423         query = createPQExpBuffer();
17424         delqry = createPQExpBuffer();
17425
17426         qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
17427
17428         appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
17429         appendPQExpBufferStr(query, qevtname);
17430         appendPQExpBufferStr(query, " ON ");
17431         appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
17432
17433         if (strcmp("", evtinfo->evttags) != 0)
17434         {
17435                 appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
17436                 appendPQExpBufferStr(query, evtinfo->evttags);
17437                 appendPQExpBufferChar(query, ')');
17438         }
17439
17440         appendPQExpBufferStr(query, "\n   EXECUTE FUNCTION ");
17441         appendPQExpBufferStr(query, evtinfo->evtfname);
17442         appendPQExpBufferStr(query, "();\n");
17443
17444         if (evtinfo->evtenabled != 'O')
17445         {
17446                 appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
17447                                                   qevtname);
17448                 switch (evtinfo->evtenabled)
17449                 {
17450                         case 'D':
17451                                 appendPQExpBufferStr(query, "DISABLE");
17452                                 break;
17453                         case 'A':
17454                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
17455                                 break;
17456                         case 'R':
17457                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
17458                                 break;
17459                         default:
17460                                 appendPQExpBufferStr(query, "ENABLE");
17461                                 break;
17462                 }
17463                 appendPQExpBufferStr(query, ";\n");
17464         }
17465
17466         appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
17467                                           qevtname);
17468
17469         if (dopt->binary_upgrade)
17470                 binary_upgrade_extension_member(query, &evtinfo->dobj,
17471                                                                                 "EVENT TRIGGER", qevtname, NULL);
17472
17473         if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17474                 ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
17475                                          ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
17476                                                                   .owner = evtinfo->evtowner,
17477                                                                   .description = "EVENT TRIGGER",
17478                                                                   .section = SECTION_POST_DATA,
17479                                                                   .createStmt = query->data,
17480                                                                   .dropStmt = delqry->data));
17481
17482         if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17483                 dumpComment(fout, "EVENT TRIGGER", qevtname,
17484                                         NULL, evtinfo->evtowner,
17485                                         evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
17486
17487         destroyPQExpBuffer(query);
17488         destroyPQExpBuffer(delqry);
17489         free(qevtname);
17490 }
17491
17492 /*
17493  * dumpRule
17494  *              Dump a rule
17495  */
17496 static void
17497 dumpRule(Archive *fout, RuleInfo *rinfo)
17498 {
17499         DumpOptions *dopt = fout->dopt;
17500         TableInfo  *tbinfo = rinfo->ruletable;
17501         bool            is_view;
17502         PQExpBuffer query;
17503         PQExpBuffer cmd;
17504         PQExpBuffer delcmd;
17505         PQExpBuffer ruleprefix;
17506         char       *qtabname;
17507         PGresult   *res;
17508         char       *tag;
17509
17510         /* Skip if not to be dumped */
17511         if (!rinfo->dobj.dump || dopt->dataOnly)
17512                 return;
17513
17514         /*
17515          * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
17516          * we do not want to dump it as a separate object.
17517          */
17518         if (!rinfo->separate)
17519                 return;
17520
17521         /*
17522          * If it's an ON SELECT rule, we want to print it as a view definition,
17523          * instead of a rule.
17524          */
17525         is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
17526
17527         query = createPQExpBuffer();
17528         cmd = createPQExpBuffer();
17529         delcmd = createPQExpBuffer();
17530         ruleprefix = createPQExpBuffer();
17531
17532         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17533
17534         if (is_view)
17535         {
17536                 PQExpBuffer result;
17537
17538                 /*
17539                  * We need OR REPLACE here because we'll be replacing a dummy view.
17540                  * Otherwise this should look largely like the regular view dump code.
17541                  */
17542                 appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
17543                                                   fmtQualifiedDumpable(tbinfo));
17544                 if (nonemptyReloptions(tbinfo->reloptions))
17545                 {
17546                         appendPQExpBufferStr(cmd, " WITH (");
17547                         appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
17548                         appendPQExpBufferChar(cmd, ')');
17549                 }
17550                 result = createViewAsClause(fout, tbinfo);
17551                 appendPQExpBuffer(cmd, " AS\n%s", result->data);
17552                 destroyPQExpBuffer(result);
17553                 if (tbinfo->checkoption != NULL)
17554                         appendPQExpBuffer(cmd, "\n  WITH %s CHECK OPTION",
17555                                                           tbinfo->checkoption);
17556                 appendPQExpBufferStr(cmd, ";\n");
17557         }
17558         else
17559         {
17560                 /* In the rule case, just print pg_get_ruledef's result verbatim */
17561                 appendPQExpBuffer(query,
17562                                                   "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
17563                                                   rinfo->dobj.catId.oid);
17564
17565                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17566
17567                 if (PQntuples(res) != 1)
17568                 {
17569                         write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
17570                                           rinfo->dobj.name, tbinfo->dobj.name);
17571                         exit_nicely(1);
17572                 }
17573
17574                 printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
17575
17576                 PQclear(res);
17577         }
17578
17579         /*
17580          * Add the command to alter the rules replication firing semantics if it
17581          * differs from the default.
17582          */
17583         if (rinfo->ev_enabled != 'O')
17584         {
17585                 appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
17586                 switch (rinfo->ev_enabled)
17587                 {
17588                         case 'A':
17589                                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
17590                                                                   fmtId(rinfo->dobj.name));
17591                                 break;
17592                         case 'R':
17593                                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
17594                                                                   fmtId(rinfo->dobj.name));
17595                                 break;
17596                         case 'D':
17597                                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
17598                                                                   fmtId(rinfo->dobj.name));
17599                                 break;
17600                 }
17601         }
17602
17603         if (is_view)
17604         {
17605                 /*
17606                  * We can't DROP a view's ON SELECT rule.  Instead, use CREATE OR
17607                  * REPLACE VIEW to replace the rule with something with minimal
17608                  * dependencies.
17609                  */
17610                 PQExpBuffer result;
17611
17612                 appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
17613                                                   fmtQualifiedDumpable(tbinfo));
17614                 result = createDummyViewAsClause(fout, tbinfo);
17615                 appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
17616                 destroyPQExpBuffer(result);
17617         }
17618         else
17619         {
17620                 appendPQExpBuffer(delcmd, "DROP RULE %s ",
17621                                                   fmtId(rinfo->dobj.name));
17622                 appendPQExpBuffer(delcmd, "ON %s;\n",
17623                                                   fmtQualifiedDumpable(tbinfo));
17624         }
17625
17626         appendPQExpBuffer(ruleprefix, "RULE %s ON",
17627                                           fmtId(rinfo->dobj.name));
17628
17629         tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
17630
17631         if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17632                 ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
17633                                          ARCHIVE_OPTS(.tag = tag,
17634                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17635                                                                   .owner = tbinfo->rolname,
17636                                                                   .description = "RULE",
17637                                                                   .section = SECTION_POST_DATA,
17638                                                                   .createStmt = cmd->data,
17639                                                                   .dropStmt = delcmd->data));
17640
17641         /* Dump rule comments */
17642         if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17643                 dumpComment(fout, ruleprefix->data, qtabname,
17644                                         tbinfo->dobj.namespace->dobj.name,
17645                                         tbinfo->rolname,
17646                                         rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
17647
17648         free(tag);
17649         destroyPQExpBuffer(query);
17650         destroyPQExpBuffer(cmd);
17651         destroyPQExpBuffer(delcmd);
17652         destroyPQExpBuffer(ruleprefix);
17653         free(qtabname);
17654 }
17655
17656 /*
17657  * getExtensionMembership --- obtain extension membership data
17658  *
17659  * We need to identify objects that are extension members as soon as they're
17660  * loaded, so that we can correctly determine whether they need to be dumped.
17661  * Generally speaking, extension member objects will get marked as *not* to
17662  * be dumped, as they will be recreated by the single CREATE EXTENSION
17663  * command.  However, in binary upgrade mode we still need to dump the members
17664  * individually.
17665  */
17666 void
17667 getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
17668                                            int numExtensions)
17669 {
17670         PQExpBuffer query;
17671         PGresult   *res;
17672         int                     ntups,
17673                                 nextmembers,
17674                                 i;
17675         int                     i_classid,
17676                                 i_objid,
17677                                 i_refobjid;
17678         ExtensionMemberId *extmembers;
17679         ExtensionInfo *ext;
17680
17681         /* Nothing to do if no extensions */
17682         if (numExtensions == 0)
17683                 return;
17684
17685         query = createPQExpBuffer();
17686
17687         /* refclassid constraint is redundant but may speed the search */
17688         appendPQExpBufferStr(query, "SELECT "
17689                                                  "classid, objid, refobjid "
17690                                                  "FROM pg_depend "
17691                                                  "WHERE refclassid = 'pg_extension'::regclass "
17692                                                  "AND deptype = 'e' "
17693                                                  "ORDER BY 3");
17694
17695         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17696
17697         ntups = PQntuples(res);
17698
17699         i_classid = PQfnumber(res, "classid");
17700         i_objid = PQfnumber(res, "objid");
17701         i_refobjid = PQfnumber(res, "refobjid");
17702
17703         extmembers = (ExtensionMemberId *) pg_malloc(ntups * sizeof(ExtensionMemberId));
17704         nextmembers = 0;
17705
17706         /*
17707          * Accumulate data into extmembers[].
17708          *
17709          * Since we ordered the SELECT by referenced ID, we can expect that
17710          * multiple entries for the same extension will appear together; this
17711          * saves on searches.
17712          */
17713         ext = NULL;
17714
17715         for (i = 0; i < ntups; i++)
17716         {
17717                 CatalogId       objId;
17718                 Oid                     extId;
17719
17720                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17721                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
17722                 extId = atooid(PQgetvalue(res, i, i_refobjid));
17723
17724                 if (ext == NULL ||
17725                         ext->dobj.catId.oid != extId)
17726                         ext = findExtensionByOid(extId);
17727
17728                 if (ext == NULL)
17729                 {
17730                         /* shouldn't happen */
17731                         fprintf(stderr, "could not find referenced extension %u\n", extId);
17732                         continue;
17733                 }
17734
17735                 extmembers[nextmembers].catId = objId;
17736                 extmembers[nextmembers].ext = ext;
17737                 nextmembers++;
17738         }
17739
17740         PQclear(res);
17741
17742         /* Remember the data for use later */
17743         setExtensionMembership(extmembers, nextmembers);
17744
17745         destroyPQExpBuffer(query);
17746 }
17747
17748 /*
17749  * processExtensionTables --- deal with extension configuration tables
17750  *
17751  * There are two parts to this process:
17752  *
17753  * 1. Identify and create dump records for extension configuration tables.
17754  *
17755  *        Extensions can mark tables as "configuration", which means that the user
17756  *        is able and expected to modify those tables after the extension has been
17757  *        loaded.  For these tables, we dump out only the data- the structure is
17758  *        expected to be handled at CREATE EXTENSION time, including any indexes or
17759  *        foreign keys, which brings us to-
17760  *
17761  * 2. Record FK dependencies between configuration tables.
17762  *
17763  *        Due to the FKs being created at CREATE EXTENSION time and therefore before
17764  *        the data is loaded, we have to work out what the best order for reloading
17765  *        the data is, to avoid FK violations when the tables are restored.  This is
17766  *        not perfect- we can't handle circular dependencies and if any exist they
17767  *        will cause an invalid dump to be produced (though at least all of the data
17768  *        is included for a user to manually restore).  This is currently documented
17769  *        but perhaps we can provide a better solution in the future.
17770  */
17771 void
17772 processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
17773                                            int numExtensions)
17774 {
17775         DumpOptions *dopt = fout->dopt;
17776         PQExpBuffer query;
17777         PGresult   *res;
17778         int                     ntups,
17779                                 i;
17780         int                     i_conrelid,
17781                                 i_confrelid;
17782
17783         /* Nothing to do if no extensions */
17784         if (numExtensions == 0)
17785                 return;
17786
17787         /*
17788          * Identify extension configuration tables and create TableDataInfo
17789          * objects for them, ensuring their data will be dumped even though the
17790          * tables themselves won't be.
17791          *
17792          * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
17793          * user data in a configuration table is treated like schema data. This
17794          * seems appropriate since system data in a config table would get
17795          * reloaded by CREATE EXTENSION.
17796          */
17797         for (i = 0; i < numExtensions; i++)
17798         {
17799                 ExtensionInfo *curext = &(extinfo[i]);
17800                 char       *extconfig = curext->extconfig;
17801                 char       *extcondition = curext->extcondition;
17802                 char      **extconfigarray = NULL;
17803                 char      **extconditionarray = NULL;
17804                 int                     nconfigitems;
17805                 int                     nconditionitems;
17806
17807                 if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
17808                         parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
17809                         nconfigitems == nconditionitems)
17810                 {
17811                         int                     j;
17812
17813                         for (j = 0; j < nconfigitems; j++)
17814                         {
17815                                 TableInfo  *configtbl;
17816                                 Oid                     configtbloid = atooid(extconfigarray[j]);
17817                                 bool            dumpobj =
17818                                 curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
17819
17820                                 configtbl = findTableByOid(configtbloid);
17821                                 if (configtbl == NULL)
17822                                         continue;
17823
17824                                 /*
17825                                  * Tables of not-to-be-dumped extensions shouldn't be dumped
17826                                  * unless the table or its schema is explicitly included
17827                                  */
17828                                 if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
17829                                 {
17830                                         /* check table explicitly requested */
17831                                         if (table_include_oids.head != NULL &&
17832                                                 simple_oid_list_member(&table_include_oids,
17833                                                                                            configtbloid))
17834                                                 dumpobj = true;
17835
17836                                         /* check table's schema explicitly requested */
17837                                         if (configtbl->dobj.namespace->dobj.dump &
17838                                                 DUMP_COMPONENT_DATA)
17839                                                 dumpobj = true;
17840                                 }
17841
17842                                 /* check table excluded by an exclusion switch */
17843                                 if (table_exclude_oids.head != NULL &&
17844                                         simple_oid_list_member(&table_exclude_oids,
17845                                                                                    configtbloid))
17846                                         dumpobj = false;
17847
17848                                 /* check schema excluded by an exclusion switch */
17849                                 if (simple_oid_list_member(&schema_exclude_oids,
17850                                                                                    configtbl->dobj.namespace->dobj.catId.oid))
17851                                         dumpobj = false;
17852
17853                                 if (dumpobj)
17854                                 {
17855                                         makeTableDataInfo(dopt, configtbl);
17856                                         if (configtbl->dataObj != NULL)
17857                                         {
17858                                                 if (strlen(extconditionarray[j]) > 0)
17859                                                         configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
17860                                         }
17861                                 }
17862                         }
17863                 }
17864                 if (extconfigarray)
17865                         free(extconfigarray);
17866                 if (extconditionarray)
17867                         free(extconditionarray);
17868         }
17869
17870         /*
17871          * Now that all the TableInfoData objects have been created for all the
17872          * extensions, check their FK dependencies and register them to try and
17873          * dump the data out in an order that they can be restored in.
17874          *
17875          * Note that this is not a problem for user tables as their FKs are
17876          * recreated after the data has been loaded.
17877          */
17878
17879         query = createPQExpBuffer();
17880
17881         printfPQExpBuffer(query,
17882                                           "SELECT conrelid, confrelid "
17883                                           "FROM pg_constraint "
17884                                           "JOIN pg_depend ON (objid = confrelid) "
17885                                           "WHERE contype = 'f' "
17886                                           "AND refclassid = 'pg_extension'::regclass "
17887                                           "AND classid = 'pg_class'::regclass;");
17888
17889         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17890         ntups = PQntuples(res);
17891
17892         i_conrelid = PQfnumber(res, "conrelid");
17893         i_confrelid = PQfnumber(res, "confrelid");
17894
17895         /* Now get the dependencies and register them */
17896         for (i = 0; i < ntups; i++)
17897         {
17898                 Oid                     conrelid,
17899                                         confrelid;
17900                 TableInfo  *reftable,
17901                                    *contable;
17902
17903                 conrelid = atooid(PQgetvalue(res, i, i_conrelid));
17904                 confrelid = atooid(PQgetvalue(res, i, i_confrelid));
17905                 contable = findTableByOid(conrelid);
17906                 reftable = findTableByOid(confrelid);
17907
17908                 if (reftable == NULL ||
17909                         reftable->dataObj == NULL ||
17910                         contable == NULL ||
17911                         contable->dataObj == NULL)
17912                         continue;
17913
17914                 /*
17915                  * Make referencing TABLE_DATA object depend on the referenced table's
17916                  * TABLE_DATA object.
17917                  */
17918                 addObjectDependency(&contable->dataObj->dobj,
17919                                                         reftable->dataObj->dobj.dumpId);
17920         }
17921         PQclear(res);
17922         destroyPQExpBuffer(query);
17923 }
17924
17925 /*
17926  * getDependencies --- obtain available dependency data
17927  */
17928 static void
17929 getDependencies(Archive *fout)
17930 {
17931         PQExpBuffer query;
17932         PGresult   *res;
17933         int                     ntups,
17934                                 i;
17935         int                     i_classid,
17936                                 i_objid,
17937                                 i_refclassid,
17938                                 i_refobjid,
17939                                 i_deptype;
17940         DumpableObject *dobj,
17941                            *refdobj;
17942
17943         if (g_verbose)
17944                 write_msg(NULL, "reading dependency data\n");
17945
17946         query = createPQExpBuffer();
17947
17948         /*
17949          * PIN dependencies aren't interesting, and EXTENSION dependencies were
17950          * already processed by getExtensionMembership.
17951          */
17952         appendPQExpBufferStr(query, "SELECT "
17953                                                  "classid, objid, refclassid, refobjid, deptype "
17954                                                  "FROM pg_depend "
17955                                                  "WHERE deptype != 'p' AND deptype != 'e' "
17956                                                  "ORDER BY 1,2");
17957
17958         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17959
17960         ntups = PQntuples(res);
17961
17962         i_classid = PQfnumber(res, "classid");
17963         i_objid = PQfnumber(res, "objid");
17964         i_refclassid = PQfnumber(res, "refclassid");
17965         i_refobjid = PQfnumber(res, "refobjid");
17966         i_deptype = PQfnumber(res, "deptype");
17967
17968         /*
17969          * Since we ordered the SELECT by referencing ID, we can expect that
17970          * multiple entries for the same object will appear together; this saves
17971          * on searches.
17972          */
17973         dobj = NULL;
17974
17975         for (i = 0; i < ntups; i++)
17976         {
17977                 CatalogId       objId;
17978                 CatalogId       refobjId;
17979                 char            deptype;
17980
17981                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17982                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
17983                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
17984                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
17985                 deptype = *(PQgetvalue(res, i, i_deptype));
17986
17987                 if (dobj == NULL ||
17988                         dobj->catId.tableoid != objId.tableoid ||
17989                         dobj->catId.oid != objId.oid)
17990                         dobj = findObjectByCatalogId(objId);
17991
17992                 /*
17993                  * Failure to find objects mentioned in pg_depend is not unexpected,
17994                  * since for example we don't collect info about TOAST tables.
17995                  */
17996                 if (dobj == NULL)
17997                 {
17998 #ifdef NOT_USED
17999                         fprintf(stderr, "no referencing object %u %u\n",
18000                                         objId.tableoid, objId.oid);
18001 #endif
18002                         continue;
18003                 }
18004
18005                 refdobj = findObjectByCatalogId(refobjId);
18006
18007                 if (refdobj == NULL)
18008                 {
18009 #ifdef NOT_USED
18010                         fprintf(stderr, "no referenced object %u %u\n",
18011                                         refobjId.tableoid, refobjId.oid);
18012 #endif
18013                         continue;
18014                 }
18015
18016                 /*
18017                  * Ordinarily, table rowtypes have implicit dependencies on their
18018                  * tables.  However, for a composite type the implicit dependency goes
18019                  * the other way in pg_depend; which is the right thing for DROP but
18020                  * it doesn't produce the dependency ordering we need. So in that one
18021                  * case, we reverse the direction of the dependency.
18022                  */
18023                 if (deptype == 'i' &&
18024                         dobj->objType == DO_TABLE &&
18025                         refdobj->objType == DO_TYPE)
18026                         addObjectDependency(refdobj, dobj->dumpId);
18027                 else
18028                         /* normal case */
18029                         addObjectDependency(dobj, refdobj->dumpId);
18030         }
18031
18032         PQclear(res);
18033
18034         destroyPQExpBuffer(query);
18035 }
18036
18037
18038 /*
18039  * createBoundaryObjects - create dummy DumpableObjects to represent
18040  * dump section boundaries.
18041  */
18042 static DumpableObject *
18043 createBoundaryObjects(void)
18044 {
18045         DumpableObject *dobjs;
18046
18047         dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
18048
18049         dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
18050         dobjs[0].catId = nilCatalogId;
18051         AssignDumpId(dobjs + 0);
18052         dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
18053
18054         dobjs[1].objType = DO_POST_DATA_BOUNDARY;
18055         dobjs[1].catId = nilCatalogId;
18056         AssignDumpId(dobjs + 1);
18057         dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
18058
18059         return dobjs;
18060 }
18061
18062 /*
18063  * addBoundaryDependencies - add dependencies as needed to enforce the dump
18064  * section boundaries.
18065  */
18066 static void
18067 addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
18068                                                 DumpableObject *boundaryObjs)
18069 {
18070         DumpableObject *preDataBound = boundaryObjs + 0;
18071         DumpableObject *postDataBound = boundaryObjs + 1;
18072         int                     i;
18073
18074         for (i = 0; i < numObjs; i++)
18075         {
18076                 DumpableObject *dobj = dobjs[i];
18077
18078                 /*
18079                  * The classification of object types here must match the SECTION_xxx
18080                  * values assigned during subsequent ArchiveEntry calls!
18081                  */
18082                 switch (dobj->objType)
18083                 {
18084                         case DO_NAMESPACE:
18085                         case DO_EXTENSION:
18086                         case DO_TYPE:
18087                         case DO_SHELL_TYPE:
18088                         case DO_FUNC:
18089                         case DO_AGG:
18090                         case DO_OPERATOR:
18091                         case DO_ACCESS_METHOD:
18092                         case DO_OPCLASS:
18093                         case DO_OPFAMILY:
18094                         case DO_COLLATION:
18095                         case DO_CONVERSION:
18096                         case DO_TABLE:
18097                         case DO_ATTRDEF:
18098                         case DO_PROCLANG:
18099                         case DO_CAST:
18100                         case DO_DUMMY_TYPE:
18101                         case DO_TSPARSER:
18102                         case DO_TSDICT:
18103                         case DO_TSTEMPLATE:
18104                         case DO_TSCONFIG:
18105                         case DO_FDW:
18106                         case DO_FOREIGN_SERVER:
18107                         case DO_TRANSFORM:
18108                         case DO_BLOB:
18109                                 /* Pre-data objects: must come before the pre-data boundary */
18110                                 addObjectDependency(preDataBound, dobj->dumpId);
18111                                 break;
18112                         case DO_TABLE_DATA:
18113                         case DO_SEQUENCE_SET:
18114                         case DO_BLOB_DATA:
18115                                 /* Data objects: must come between the boundaries */
18116                                 addObjectDependency(dobj, preDataBound->dumpId);
18117                                 addObjectDependency(postDataBound, dobj->dumpId);
18118                                 break;
18119                         case DO_INDEX:
18120                         case DO_INDEX_ATTACH:
18121                         case DO_STATSEXT:
18122                         case DO_REFRESH_MATVIEW:
18123                         case DO_TRIGGER:
18124                         case DO_EVENT_TRIGGER:
18125                         case DO_DEFAULT_ACL:
18126                         case DO_POLICY:
18127                         case DO_PUBLICATION:
18128                         case DO_PUBLICATION_REL:
18129                         case DO_SUBSCRIPTION:
18130                                 /* Post-data objects: must come after the post-data boundary */
18131                                 addObjectDependency(dobj, postDataBound->dumpId);
18132                                 break;
18133                         case DO_RULE:
18134                                 /* Rules are post-data, but only if dumped separately */
18135                                 if (((RuleInfo *) dobj)->separate)
18136                                         addObjectDependency(dobj, postDataBound->dumpId);
18137                                 break;
18138                         case DO_CONSTRAINT:
18139                         case DO_FK_CONSTRAINT:
18140                                 /* Constraints are post-data, but only if dumped separately */
18141                                 if (((ConstraintInfo *) dobj)->separate)
18142                                         addObjectDependency(dobj, postDataBound->dumpId);
18143                                 break;
18144                         case DO_PRE_DATA_BOUNDARY:
18145                                 /* nothing to do */
18146                                 break;
18147                         case DO_POST_DATA_BOUNDARY:
18148                                 /* must come after the pre-data boundary */
18149                                 addObjectDependency(dobj, preDataBound->dumpId);
18150                                 break;
18151                 }
18152         }
18153 }
18154
18155
18156 /*
18157  * BuildArchiveDependencies - create dependency data for archive TOC entries
18158  *
18159  * The raw dependency data obtained by getDependencies() is not terribly
18160  * useful in an archive dump, because in many cases there are dependency
18161  * chains linking through objects that don't appear explicitly in the dump.
18162  * For example, a view will depend on its _RETURN rule while the _RETURN rule
18163  * will depend on other objects --- but the rule will not appear as a separate
18164  * object in the dump.  We need to adjust the view's dependencies to include
18165  * whatever the rule depends on that is included in the dump.
18166  *
18167  * Just to make things more complicated, there are also "special" dependencies
18168  * such as the dependency of a TABLE DATA item on its TABLE, which we must
18169  * not rearrange because pg_restore knows that TABLE DATA only depends on
18170  * its table.  In these cases we must leave the dependencies strictly as-is
18171  * even if they refer to not-to-be-dumped objects.
18172  *
18173  * To handle this, the convention is that "special" dependencies are created
18174  * during ArchiveEntry calls, and an archive TOC item that has any such
18175  * entries will not be touched here.  Otherwise, we recursively search the
18176  * DumpableObject data structures to build the correct dependencies for each
18177  * archive TOC item.
18178  */
18179 static void
18180 BuildArchiveDependencies(Archive *fout)
18181 {
18182         ArchiveHandle *AH = (ArchiveHandle *) fout;
18183         TocEntry   *te;
18184
18185         /* Scan all TOC entries in the archive */
18186         for (te = AH->toc->next; te != AH->toc; te = te->next)
18187         {
18188                 DumpableObject *dobj;
18189                 DumpId     *dependencies;
18190                 int                     nDeps;
18191                 int                     allocDeps;
18192
18193                 /* No need to process entries that will not be dumped */
18194                 if (te->reqs == 0)
18195                         continue;
18196                 /* Ignore entries that already have "special" dependencies */
18197                 if (te->nDeps > 0)
18198                         continue;
18199                 /* Otherwise, look up the item's original DumpableObject, if any */
18200                 dobj = findObjectByDumpId(te->dumpId);
18201                 if (dobj == NULL)
18202                         continue;
18203                 /* No work if it has no dependencies */
18204                 if (dobj->nDeps <= 0)
18205                         continue;
18206                 /* Set up work array */
18207                 allocDeps = 64;
18208                 dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
18209                 nDeps = 0;
18210                 /* Recursively find all dumpable dependencies */
18211                 findDumpableDependencies(AH, dobj,
18212                                                                  &dependencies, &nDeps, &allocDeps);
18213                 /* And save 'em ... */
18214                 if (nDeps > 0)
18215                 {
18216                         dependencies = (DumpId *) pg_realloc(dependencies,
18217                                                                                                  nDeps * sizeof(DumpId));
18218                         te->dependencies = dependencies;
18219                         te->nDeps = nDeps;
18220                 }
18221                 else
18222                         free(dependencies);
18223         }
18224 }
18225
18226 /* Recursive search subroutine for BuildArchiveDependencies */
18227 static void
18228 findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
18229                                                  DumpId **dependencies, int *nDeps, int *allocDeps)
18230 {
18231         int                     i;
18232
18233         /*
18234          * Ignore section boundary objects: if we search through them, we'll
18235          * report lots of bogus dependencies.
18236          */
18237         if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
18238                 dobj->objType == DO_POST_DATA_BOUNDARY)
18239                 return;
18240
18241         for (i = 0; i < dobj->nDeps; i++)
18242         {
18243                 DumpId          depid = dobj->dependencies[i];
18244
18245                 if (TocIDRequired(AH, depid) != 0)
18246                 {
18247                         /* Object will be dumped, so just reference it as a dependency */
18248                         if (*nDeps >= *allocDeps)
18249                         {
18250                                 *allocDeps *= 2;
18251                                 *dependencies = (DumpId *) pg_realloc(*dependencies,
18252                                                                                                           *allocDeps * sizeof(DumpId));
18253                         }
18254                         (*dependencies)[*nDeps] = depid;
18255                         (*nDeps)++;
18256                 }
18257                 else
18258                 {
18259                         /*
18260                          * Object will not be dumped, so recursively consider its deps. We
18261                          * rely on the assumption that sortDumpableObjects already broke
18262                          * any dependency loops, else we might recurse infinitely.
18263                          */
18264                         DumpableObject *otherdobj = findObjectByDumpId(depid);
18265
18266                         if (otherdobj)
18267                                 findDumpableDependencies(AH, otherdobj,
18268                                                                                  dependencies, nDeps, allocDeps);
18269                 }
18270         }
18271 }
18272
18273
18274 /*
18275  * getFormattedTypeName - retrieve a nicely-formatted type name for the
18276  * given type OID.
18277  *
18278  * This does not guarantee to schema-qualify the output, so it should not
18279  * be used to create the target object name for CREATE or ALTER commands.
18280  *
18281  * TODO: there might be some value in caching the results.
18282  */
18283 static char *
18284 getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
18285 {
18286         char       *result;
18287         PQExpBuffer query;
18288         PGresult   *res;
18289
18290         if (oid == 0)
18291         {
18292                 if ((opts & zeroAsOpaque) != 0)
18293                         return pg_strdup(g_opaque_type);
18294                 else if ((opts & zeroAsAny) != 0)
18295                         return pg_strdup("'any'");
18296                 else if ((opts & zeroAsStar) != 0)
18297                         return pg_strdup("*");
18298                 else if ((opts & zeroAsNone) != 0)
18299                         return pg_strdup("NONE");
18300         }
18301
18302         query = createPQExpBuffer();
18303         appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
18304                                           oid);
18305
18306         res = ExecuteSqlQueryForSingleRow(fout, query->data);
18307
18308         /* result of format_type is already quoted */
18309         result = pg_strdup(PQgetvalue(res, 0, 0));
18310
18311         PQclear(res);
18312         destroyPQExpBuffer(query);
18313
18314         return result;
18315 }
18316
18317 /*
18318  * Return a column list clause for the given relation.
18319  *
18320  * Special case: if there are no undropped columns in the relation, return
18321  * "", not an invalid "()" column list.
18322  */
18323 static const char *
18324 fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
18325 {
18326         int                     numatts = ti->numatts;
18327         char      **attnames = ti->attnames;
18328         bool       *attisdropped = ti->attisdropped;
18329         char       *attgenerated = ti->attgenerated;
18330         bool            needComma;
18331         int                     i;
18332
18333         appendPQExpBufferChar(buffer, '(');
18334         needComma = false;
18335         for (i = 0; i < numatts; i++)
18336         {
18337                 if (attisdropped[i])
18338                         continue;
18339                 if (attgenerated[i])
18340                         continue;
18341                 if (needComma)
18342                         appendPQExpBufferStr(buffer, ", ");
18343                 appendPQExpBufferStr(buffer, fmtId(attnames[i]));
18344                 needComma = true;
18345         }
18346
18347         if (!needComma)
18348                 return "";                              /* no undropped columns */
18349
18350         appendPQExpBufferChar(buffer, ')');
18351         return buffer->data;
18352 }
18353
18354 /*
18355  * Check if a reloptions array is nonempty.
18356  */
18357 static bool
18358 nonemptyReloptions(const char *reloptions)
18359 {
18360         /* Don't want to print it if it's just "{}" */
18361         return (reloptions != NULL && strlen(reloptions) > 2);
18362 }
18363
18364 /*
18365  * Format a reloptions array and append it to the given buffer.
18366  *
18367  * "prefix" is prepended to the option names; typically it's "" or "toast.".
18368  */
18369 static void
18370 appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
18371                                                 const char *prefix, Archive *fout)
18372 {
18373         bool            res;
18374
18375         res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
18376                                                                 fout->std_strings);
18377         if (!res)
18378                 write_msg(NULL, "WARNING: could not parse reloptions array\n");
18379 }