]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_dump.c
Provide an extra-float-digits setting for pg_dump / pg_dumpall
[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 #ifdef HAVE_TERMIOS_H
37 #include <termios.h>
38 #endif
39
40 #include "getopt_long.h"
41
42 #include "access/attnum.h"
43 #include "access/sysattr.h"
44 #include "access/transam.h"
45 #include "catalog/pg_aggregate_d.h"
46 #include "catalog/pg_am_d.h"
47 #include "catalog/pg_attribute_d.h"
48 #include "catalog/pg_cast_d.h"
49 #include "catalog/pg_class_d.h"
50 #include "catalog/pg_default_acl_d.h"
51 #include "catalog/pg_largeobject_d.h"
52 #include "catalog/pg_largeobject_metadata_d.h"
53 #include "catalog/pg_proc_d.h"
54 #include "catalog/pg_trigger_d.h"
55 #include "catalog/pg_type_d.h"
56 #include "libpq/libpq-fs.h"
57 #include "storage/block.h"
58
59 #include "dumputils.h"
60 #include "parallel.h"
61 #include "pg_backup_db.h"
62 #include "pg_backup_utils.h"
63 #include "pg_dump.h"
64 #include "fe_utils/connect.h"
65 #include "fe_utils/string_utils.h"
66
67
68 typedef struct
69 {
70         const char *descr;                      /* comment for an object */
71         Oid                     classoid;               /* object class (catalog OID) */
72         Oid                     objoid;                 /* object OID */
73         int                     objsubid;               /* subobject (table column #) */
74 } CommentItem;
75
76 typedef struct
77 {
78         const char *provider;           /* label provider of this security label */
79         const char *label;                      /* security label for an object */
80         Oid                     classoid;               /* object class (catalog OID) */
81         Oid                     objoid;                 /* object OID */
82         int                     objsubid;               /* subobject (table column #) */
83 } SecLabelItem;
84
85 typedef enum OidOptions
86 {
87         zeroAsOpaque = 1,
88         zeroAsAny = 2,
89         zeroAsStar = 4,
90         zeroAsNone = 8
91 } OidOptions;
92
93 /* global decls */
94 bool            g_verbose;                      /* User wants verbose narration of our
95                                                                  * activities. */
96 static bool dosync = true;              /* Issue fsync() to make dump durable on disk. */
97
98 /* subquery used to convert user ID (eg, datdba) to user name */
99 static const char *username_subquery;
100
101 /*
102  * For 8.0 and earlier servers, pulled from pg_database, for 8.1+ we use
103  * FirstNormalObjectId - 1.
104  */
105 static Oid      g_last_builtin_oid; /* value of the last builtin oid */
106
107 /* The specified names/patterns should to match at least one entity */
108 static int      strict_names = 0;
109
110 /*
111  * Object inclusion/exclusion lists
112  *
113  * The string lists record the patterns given by command-line switches,
114  * which we then convert to lists of OIDs of matching objects.
115  */
116 static SimpleStringList schema_include_patterns = {NULL, NULL};
117 static SimpleOidList schema_include_oids = {NULL, NULL};
118 static SimpleStringList schema_exclude_patterns = {NULL, NULL};
119 static SimpleOidList schema_exclude_oids = {NULL, NULL};
120
121 static SimpleStringList table_include_patterns = {NULL, NULL};
122 static SimpleOidList table_include_oids = {NULL, NULL};
123 static SimpleStringList table_exclude_patterns = {NULL, NULL};
124 static SimpleOidList table_exclude_oids = {NULL, NULL};
125 static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
126 static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
127
128
129 char            g_opaque_type[10];      /* name for the opaque type */
130
131 /* placeholders for the delimiters for comments */
132 char            g_comment_start[10];
133 char            g_comment_end[10];
134
135 static const CatalogId nilCatalogId = {0, 0};
136
137 /* override for standard extra_float_digits setting */
138 static bool have_extra_float_digits = false;
139 static int extra_float_digits;
140
141 /*
142  * Macro for producing quoted, schema-qualified name of a dumpable object.
143  */
144 #define fmtQualifiedDumpable(obj) \
145         fmtQualifiedId((obj)->dobj.namespace->dobj.name, \
146                                    (obj)->dobj.name)
147
148 static void help(const char *progname);
149 static void setup_connection(Archive *AH,
150                                  const char *dumpencoding, const char *dumpsnapshot,
151                                  char *use_role);
152 static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
153 static void expand_schema_name_patterns(Archive *fout,
154                                                         SimpleStringList *patterns,
155                                                         SimpleOidList *oids,
156                                                         bool strict_names);
157 static void expand_table_name_patterns(Archive *fout,
158                                                    SimpleStringList *patterns,
159                                                    SimpleOidList *oids,
160                                                    bool strict_names);
161 static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid);
162 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
163 static void refreshMatViewData(Archive *fout, TableDataInfo *tdinfo);
164 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
165 static void dumpComment(Archive *fout, const char *type, const char *name,
166                         const char *namespace, const char *owner,
167                         CatalogId catalogId, int subid, DumpId dumpId);
168 static int findComments(Archive *fout, Oid classoid, Oid objoid,
169                          CommentItem **items);
170 static int      collectComments(Archive *fout, CommentItem **items);
171 static void dumpSecLabel(Archive *fout, const char *type, const char *name,
172                          const char *namespace, const char *owner,
173                          CatalogId catalogId, int subid, DumpId dumpId);
174 static int findSecLabels(Archive *fout, Oid classoid, Oid objoid,
175                           SecLabelItem **items);
176 static int      collectSecLabels(Archive *fout, SecLabelItem **items);
177 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
178 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
179 static void dumpExtension(Archive *fout, ExtensionInfo *extinfo);
180 static void dumpType(Archive *fout, TypeInfo *tyinfo);
181 static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
182 static void dumpEnumType(Archive *fout, TypeInfo *tyinfo);
183 static void dumpRangeType(Archive *fout, TypeInfo *tyinfo);
184 static void dumpUndefinedType(Archive *fout, TypeInfo *tyinfo);
185 static void dumpDomain(Archive *fout, TypeInfo *tyinfo);
186 static void dumpCompositeType(Archive *fout, TypeInfo *tyinfo);
187 static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
188 static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
189 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
190 static void dumpFunc(Archive *fout, FuncInfo *finfo);
191 static void dumpCast(Archive *fout, CastInfo *cast);
192 static void dumpTransform(Archive *fout, TransformInfo *transform);
193 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
194 static void dumpAccessMethod(Archive *fout, AccessMethodInfo *oprinfo);
195 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
196 static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
197 static void dumpCollation(Archive *fout, CollInfo *collinfo);
198 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
199 static void dumpRule(Archive *fout, RuleInfo *rinfo);
200 static void dumpAgg(Archive *fout, AggInfo *agginfo);
201 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
202 static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
203 static void dumpTable(Archive *fout, TableInfo *tbinfo);
204 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
205 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
206 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
207 static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo);
208 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
209 static void dumpIndexAttach(Archive *fout, IndexAttachInfo *attachinfo);
210 static void dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo);
211 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
212 static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
213 static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
214 static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
215 static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
216 static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
217 static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
218 static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
219 static void dumpUserMappings(Archive *fout,
220                                  const char *servername, const char *namespace,
221                                  const char *owner, CatalogId catalogId, DumpId dumpId);
222 static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
223
224 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
225                 const char *type, const char *name, const char *subname,
226                 const char *nspname, const char *owner,
227                 const char *acls, const char *racls,
228                 const char *initacls, const char *initracls);
229
230 static void getDependencies(Archive *fout);
231 static void BuildArchiveDependencies(Archive *fout);
232 static void findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
233                                                  DumpId **dependencies, int *nDeps, int *allocDeps);
234
235 static DumpableObject *createBoundaryObjects(void);
236 static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
237                                                 DumpableObject *boundaryObjs);
238
239 static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
240 static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind);
241 static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo);
242 static void buildMatViewRefreshDependencies(Archive *fout);
243 static void getTableDataFKConstraints(void);
244 static char *format_function_arguments(FuncInfo *finfo, char *funcargs,
245                                                   bool is_agg);
246 static char *format_function_arguments_old(Archive *fout,
247                                                           FuncInfo *finfo, int nallargs,
248                                                           char **allargtypes,
249                                                           char **argmodes,
250                                                           char **argnames);
251 static char *format_function_signature(Archive *fout,
252                                                   FuncInfo *finfo, bool honor_quotes);
253 static char *convertRegProcReference(Archive *fout,
254                                                 const char *proc);
255 static char *getFormattedOperatorName(Archive *fout, const char *oproid);
256 static char *convertTSFunction(Archive *fout, Oid funcOid);
257 static Oid      findLastBuiltinOid_V71(Archive *fout);
258 static char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
259 static void getBlobs(Archive *fout);
260 static void dumpBlob(Archive *fout, BlobInfo *binfo);
261 static int      dumpBlobs(Archive *fout, void *arg);
262 static void dumpPolicy(Archive *fout, PolicyInfo *polinfo);
263 static void dumpPublication(Archive *fout, PublicationInfo *pubinfo);
264 static void dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo);
265 static void dumpSubscription(Archive *fout, SubscriptionInfo *subinfo);
266 static void dumpDatabase(Archive *AH);
267 static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
268                                    const char *dbname, Oid dboid);
269 static void dumpEncoding(Archive *AH);
270 static void dumpStdStrings(Archive *AH);
271 static void dumpSearchPath(Archive *AH);
272 static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
273                                                                                  PQExpBuffer upgrade_buffer,
274                                                                                  Oid pg_type_oid,
275                                                                                  bool force_array_type);
276 static bool binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
277                                                                                 PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
278 static void binary_upgrade_set_pg_class_oids(Archive *fout,
279                                                                  PQExpBuffer upgrade_buffer,
280                                                                  Oid pg_class_oid, bool is_index);
281 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
282                                                                 DumpableObject *dobj,
283                                                                 const char *objtype,
284                                                                 const char *objname,
285                                                                 const char *objnamespace);
286 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
287 static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
288 static bool nonemptyReloptions(const char *reloptions);
289 static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
290                                                 const char *prefix, Archive *fout);
291 static char *get_synchronized_snapshot(Archive *fout);
292 static void setupDumpWorker(Archive *AHX);
293 static TableInfo *getRootTableInfo(TableInfo *tbinfo);
294
295
296 int
297 main(int argc, char **argv)
298 {
299         int                     c;
300         const char *filename = NULL;
301         const char *format = "p";
302         TableInfo  *tblinfo;
303         int                     numTables;
304         DumpableObject **dobjs;
305         int                     numObjs;
306         DumpableObject *boundaryObjs;
307         int                     i;
308         int                     optindex;
309         RestoreOptions *ropt;
310         Archive    *fout;                       /* the script file */
311         const char *dumpencoding = NULL;
312         const char *dumpsnapshot = NULL;
313         char       *use_role = NULL;
314         int                     numWorkers = 1;
315         trivalue        prompt_password = TRI_DEFAULT;
316         int                     compressLevel = -1;
317         int                     plainText = 0;
318         ArchiveFormat archiveFormat = archUnknown;
319         ArchiveMode archiveMode;
320
321         static DumpOptions dopt;
322
323         static struct option long_options[] = {
324                 {"data-only", no_argument, NULL, 'a'},
325                 {"blobs", no_argument, NULL, 'b'},
326                 {"no-blobs", no_argument, NULL, 'B'},
327                 {"clean", no_argument, NULL, 'c'},
328                 {"create", no_argument, NULL, 'C'},
329                 {"dbname", required_argument, NULL, 'd'},
330                 {"file", required_argument, NULL, 'f'},
331                 {"format", required_argument, NULL, 'F'},
332                 {"host", required_argument, NULL, 'h'},
333                 {"jobs", 1, NULL, 'j'},
334                 {"no-reconnect", no_argument, NULL, 'R'},
335                 {"no-owner", no_argument, NULL, 'O'},
336                 {"port", required_argument, NULL, 'p'},
337                 {"schema", required_argument, NULL, 'n'},
338                 {"exclude-schema", required_argument, NULL, 'N'},
339                 {"schema-only", no_argument, NULL, 's'},
340                 {"superuser", required_argument, NULL, 'S'},
341                 {"table", required_argument, NULL, 't'},
342                 {"exclude-table", required_argument, NULL, 'T'},
343                 {"no-password", no_argument, NULL, 'w'},
344                 {"password", no_argument, NULL, 'W'},
345                 {"username", required_argument, NULL, 'U'},
346                 {"verbose", no_argument, NULL, 'v'},
347                 {"no-privileges", no_argument, NULL, 'x'},
348                 {"no-acl", no_argument, NULL, 'x'},
349                 {"compress", required_argument, NULL, 'Z'},
350                 {"encoding", required_argument, NULL, 'E'},
351                 {"help", no_argument, NULL, '?'},
352                 {"version", no_argument, NULL, 'V'},
353
354                 /*
355                  * the following options don't have an equivalent short option letter
356                  */
357                 {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
358                 {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
359                 {"column-inserts", no_argument, &dopt.column_inserts, 1},
360                 {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
361                 {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
362                 {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
363                 {"exclude-table-data", required_argument, NULL, 4},
364                 {"extra-float-digits", required_argument, NULL, 8},
365                 {"if-exists", no_argument, &dopt.if_exists, 1},
366                 {"inserts", no_argument, &dopt.dump_inserts, 1},
367                 {"lock-wait-timeout", required_argument, NULL, 2},
368                 {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
369                 {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
370                 {"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
371                 {"role", required_argument, NULL, 3},
372                 {"section", required_argument, NULL, 5},
373                 {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
374                 {"snapshot", required_argument, NULL, 6},
375                 {"strict-names", no_argument, &strict_names, 1},
376                 {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
377                 {"no-comments", no_argument, &dopt.no_comments, 1},
378                 {"no-publications", no_argument, &dopt.no_publications, 1},
379                 {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
380                 {"no-synchronized-snapshots", no_argument, &dopt.no_synchronized_snapshots, 1},
381                 {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
382                 {"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
383                 {"no-sync", no_argument, NULL, 7},
384                 {"on-conflict-do-nothing", no_argument, &dopt.do_nothing, 1},
385
386                 {NULL, 0, NULL, 0}
387         };
388
389         set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
390
391         /*
392          * Initialize what we need for parallel execution, especially for thread
393          * support on Windows.
394          */
395         init_parallel_dump_utils();
396
397         g_verbose = false;
398
399         strcpy(g_comment_start, "-- ");
400         g_comment_end[0] = '\0';
401         strcpy(g_opaque_type, "opaque");
402
403         progname = get_progname(argv[0]);
404
405         if (argc > 1)
406         {
407                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
408                 {
409                         help(progname);
410                         exit_nicely(0);
411                 }
412                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
413                 {
414                         puts("pg_dump (PostgreSQL) " PG_VERSION);
415                         exit_nicely(0);
416                 }
417         }
418
419         InitDumpOptions(&dopt);
420
421         while ((c = getopt_long(argc, argv, "abBcCd:E:f:F:h:j:n:N:oOp:RsS:t:T:U:vwWxZ:",
422                                                         long_options, &optindex)) != -1)
423         {
424                 switch (c)
425                 {
426                         case 'a':                       /* Dump data only */
427                                 dopt.dataOnly = true;
428                                 break;
429
430                         case 'b':                       /* Dump blobs */
431                                 dopt.outputBlobs = true;
432                                 break;
433
434                         case 'B':                       /* Don't dump blobs */
435                                 dopt.dontOutputBlobs = true;
436                                 break;
437
438                         case 'c':                       /* clean (i.e., drop) schema prior to create */
439                                 dopt.outputClean = 1;
440                                 break;
441
442                         case 'C':                       /* Create DB */
443                                 dopt.outputCreateDB = 1;
444                                 break;
445
446                         case 'd':                       /* database name */
447                                 dopt.dbname = pg_strdup(optarg);
448                                 break;
449
450                         case 'E':                       /* Dump encoding */
451                                 dumpencoding = pg_strdup(optarg);
452                                 break;
453
454                         case 'f':
455                                 filename = pg_strdup(optarg);
456                                 break;
457
458                         case 'F':
459                                 format = pg_strdup(optarg);
460                                 break;
461
462                         case 'h':                       /* server host */
463                                 dopt.pghost = pg_strdup(optarg);
464                                 break;
465
466                         case 'j':                       /* number of dump jobs */
467                                 numWorkers = atoi(optarg);
468                                 break;
469
470                         case 'n':                       /* include schema(s) */
471                                 simple_string_list_append(&schema_include_patterns, optarg);
472                                 dopt.include_everything = false;
473                                 break;
474
475                         case 'N':                       /* exclude schema(s) */
476                                 simple_string_list_append(&schema_exclude_patterns, optarg);
477                                 break;
478
479                         case 'O':                       /* Don't reconnect to match owner */
480                                 dopt.outputNoOwner = 1;
481                                 break;
482
483                         case 'p':                       /* server port */
484                                 dopt.pgport = pg_strdup(optarg);
485                                 break;
486
487                         case 'R':
488                                 /* no-op, still accepted for backwards compatibility */
489                                 break;
490
491                         case 's':                       /* dump schema only */
492                                 dopt.schemaOnly = true;
493                                 break;
494
495                         case 'S':                       /* Username for superuser in plain text output */
496                                 dopt.outputSuperuser = pg_strdup(optarg);
497                                 break;
498
499                         case 't':                       /* include table(s) */
500                                 simple_string_list_append(&table_include_patterns, optarg);
501                                 dopt.include_everything = false;
502                                 break;
503
504                         case 'T':                       /* exclude table(s) */
505                                 simple_string_list_append(&table_exclude_patterns, optarg);
506                                 break;
507
508                         case 'U':
509                                 dopt.username = pg_strdup(optarg);
510                                 break;
511
512                         case 'v':                       /* verbose */
513                                 g_verbose = true;
514                                 break;
515
516                         case 'w':
517                                 prompt_password = TRI_NO;
518                                 break;
519
520                         case 'W':
521                                 prompt_password = TRI_YES;
522                                 break;
523
524                         case 'x':                       /* skip ACL dump */
525                                 dopt.aclsSkip = true;
526                                 break;
527
528                         case 'Z':                       /* Compression Level */
529                                 compressLevel = atoi(optarg);
530                                 if (compressLevel < 0 || compressLevel > 9)
531                                 {
532                                         write_msg(NULL, "compression level must be in range 0..9\n");
533                                         exit_nicely(1);
534                                 }
535                                 break;
536
537                         case 0:
538                                 /* This covers the long options. */
539                                 break;
540
541                         case 2:                         /* lock-wait-timeout */
542                                 dopt.lockWaitTimeout = pg_strdup(optarg);
543                                 break;
544
545                         case 3:                         /* SET ROLE */
546                                 use_role = pg_strdup(optarg);
547                                 break;
548
549                         case 4:                         /* exclude table(s) data */
550                                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
551                                 break;
552
553                         case 5:                         /* section */
554                                 set_dump_section(optarg, &dopt.dumpSections);
555                                 break;
556
557                         case 6:                         /* snapshot */
558                                 dumpsnapshot = pg_strdup(optarg);
559                                 break;
560
561                         case 7:                         /* no-sync */
562                                 dosync = false;
563                                 break;
564
565                         case 8:
566                                 have_extra_float_digits = true;
567                                 extra_float_digits = atoi(optarg);
568                                 if (extra_float_digits < -15 || extra_float_digits > 3)
569                                 {
570                                         write_msg(NULL, "extra_float_digits must be in range -15..3\n");
571                                         exit_nicely(1);
572                                 }
573                                 break;
574
575                         default:
576                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
577                                 exit_nicely(1);
578                 }
579         }
580
581         /*
582          * Non-option argument specifies database name as long as it wasn't
583          * already specified with -d / --dbname
584          */
585         if (optind < argc && dopt.dbname == NULL)
586                 dopt.dbname = argv[optind++];
587
588         /* Complain if any arguments remain */
589         if (optind < argc)
590         {
591                 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
592                                 progname, argv[optind]);
593                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
594                                 progname);
595                 exit_nicely(1);
596         }
597
598         /* --column-inserts implies --inserts */
599         if (dopt.column_inserts)
600                 dopt.dump_inserts = 1;
601
602         /*
603          * Binary upgrade mode implies dumping sequence data even in schema-only
604          * mode.  This is not exposed as a separate option, but kept separate
605          * internally for clarity.
606          */
607         if (dopt.binary_upgrade)
608                 dopt.sequence_data = 1;
609
610         if (dopt.dataOnly && dopt.schemaOnly)
611         {
612                 write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
613                 exit_nicely(1);
614         }
615
616         if (dopt.dataOnly && dopt.outputClean)
617         {
618                 write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
619                 exit_nicely(1);
620         }
621
622         if (dopt.if_exists && !dopt.outputClean)
623                 exit_horribly(NULL, "option --if-exists requires option -c/--clean\n");
624
625         if (dopt.do_nothing && !(dopt.dump_inserts || dopt.column_inserts))
626                 exit_horribly(NULL, "option --on-conflict-do-nothing requires option --inserts or --column-inserts\n");
627
628         /* Identify archive format to emit */
629         archiveFormat = parseArchiveFormat(format, &archiveMode);
630
631         /* archiveFormat specific setup */
632         if (archiveFormat == archNull)
633                 plainText = 1;
634
635         /* Custom and directory formats are compressed by default, others not */
636         if (compressLevel == -1)
637         {
638 #ifdef HAVE_LIBZ
639                 if (archiveFormat == archCustom || archiveFormat == archDirectory)
640                         compressLevel = Z_DEFAULT_COMPRESSION;
641                 else
642 #endif
643                         compressLevel = 0;
644         }
645
646 #ifndef HAVE_LIBZ
647         if (compressLevel != 0)
648                 write_msg(NULL, "WARNING: requested compression not available in this "
649                                   "installation -- archive will be uncompressed\n");
650         compressLevel = 0;
651 #endif
652
653         /*
654          * If emitting an archive format, we always want to emit a DATABASE item,
655          * in case --create is specified at pg_restore time.
656          */
657         if (!plainText)
658                 dopt.outputCreateDB = 1;
659
660         /*
661          * On Windows we can only have at most MAXIMUM_WAIT_OBJECTS (= 64 usually)
662          * parallel jobs because that's the maximum limit for the
663          * WaitForMultipleObjects() call.
664          */
665         if (numWorkers <= 0
666 #ifdef WIN32
667                 || numWorkers > MAXIMUM_WAIT_OBJECTS
668 #endif
669                 )
670                 exit_horribly(NULL, "invalid number of parallel jobs\n");
671
672         /* Parallel backup only in the directory archive format so far */
673         if (archiveFormat != archDirectory && numWorkers > 1)
674                 exit_horribly(NULL, "parallel backup only supported by the directory format\n");
675
676         /* Open the output file */
677         fout = CreateArchive(filename, archiveFormat, compressLevel, dosync,
678                                                  archiveMode, setupDumpWorker);
679
680         /* Make dump options accessible right away */
681         SetArchiveOptions(fout, &dopt, NULL);
682
683         /* Register the cleanup hook */
684         on_exit_close_archive(fout);
685
686         /* Let the archiver know how noisy to be */
687         fout->verbose = g_verbose;
688
689         /*
690          * We allow the server to be back to 8.0, and up to any minor release of
691          * our own major version.  (See also version check in pg_dumpall.c.)
692          */
693         fout->minRemoteVersion = 80000;
694         fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
695
696         fout->numWorkers = numWorkers;
697
698         /*
699          * Open the database using the Archiver, so it knows about it. Errors mean
700          * death.
701          */
702         ConnectDatabase(fout, dopt.dbname, dopt.pghost, dopt.pgport, dopt.username, prompt_password);
703         setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
704
705         /*
706          * Disable security label support if server version < v9.1.x (prevents
707          * access to nonexistent pg_seclabel catalog)
708          */
709         if (fout->remoteVersion < 90100)
710                 dopt.no_security_labels = 1;
711
712         /*
713          * On hot standbys, never try to dump unlogged table data, since it will
714          * just throw an error.
715          */
716         if (fout->isStandby)
717                 dopt.no_unlogged_table_data = true;
718
719         /* Select the appropriate subquery to convert user IDs to names */
720         if (fout->remoteVersion >= 80100)
721                 username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
722         else
723                 username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
724
725         /* check the version for the synchronized snapshots feature */
726         if (numWorkers > 1 && fout->remoteVersion < 90200
727                 && !dopt.no_synchronized_snapshots)
728                 exit_horribly(NULL,
729                                           "Synchronized snapshots are not supported by this server version.\n"
730                                           "Run with --no-synchronized-snapshots instead if you do not need\n"
731                                           "synchronized snapshots.\n");
732
733         /* check the version when a snapshot is explicitly specified by user */
734         if (dumpsnapshot && fout->remoteVersion < 90200)
735                 exit_horribly(NULL,
736                                           "Exported snapshots are not supported by this server version.\n");
737
738         /*
739          * Find the last built-in OID, if needed (prior to 8.1)
740          *
741          * With 8.1 and above, we can just use FirstNormalObjectId - 1.
742          */
743         if (fout->remoteVersion < 80100)
744                 g_last_builtin_oid = findLastBuiltinOid_V71(fout);
745         else
746                 g_last_builtin_oid = FirstNormalObjectId - 1;
747
748         if (g_verbose)
749                 write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
750
751         /* Expand schema selection patterns into OID lists */
752         if (schema_include_patterns.head != NULL)
753         {
754                 expand_schema_name_patterns(fout, &schema_include_patterns,
755                                                                         &schema_include_oids,
756                                                                         strict_names);
757                 if (schema_include_oids.head == NULL)
758                         exit_horribly(NULL, "no matching schemas were found\n");
759         }
760         expand_schema_name_patterns(fout, &schema_exclude_patterns,
761                                                                 &schema_exclude_oids,
762                                                                 false);
763         /* non-matching exclusion patterns aren't an error */
764
765         /* Expand table selection patterns into OID lists */
766         if (table_include_patterns.head != NULL)
767         {
768                 expand_table_name_patterns(fout, &table_include_patterns,
769                                                                    &table_include_oids,
770                                                                    strict_names);
771                 if (table_include_oids.head == NULL)
772                         exit_horribly(NULL, "no matching tables were found\n");
773         }
774         expand_table_name_patterns(fout, &table_exclude_patterns,
775                                                            &table_exclude_oids,
776                                                            false);
777
778         expand_table_name_patterns(fout, &tabledata_exclude_patterns,
779                                                            &tabledata_exclude_oids,
780                                                            false);
781
782         /* non-matching exclusion patterns aren't an error */
783
784         /*
785          * Dumping blobs is the default for dumps where an inclusion switch is not
786          * used (an "include everything" dump).  -B can be used to exclude blobs
787          * from those dumps.  -b can be used to include blobs even when an
788          * inclusion switch is used.
789          *
790          * -s means "schema only" and blobs are data, not schema, so we never
791          * include blobs when -s is used.
792          */
793         if (dopt.include_everything && !dopt.schemaOnly && !dopt.dontOutputBlobs)
794                 dopt.outputBlobs = true;
795
796         /*
797          * Now scan the database and create DumpableObject structs for all the
798          * objects we intend to dump.
799          */
800         tblinfo = getSchemaData(fout, &numTables);
801
802         if (fout->remoteVersion < 80400)
803                 guessConstraintInheritance(tblinfo, numTables);
804
805         if (!dopt.schemaOnly)
806         {
807                 getTableData(&dopt, tblinfo, numTables, 0);
808                 buildMatViewRefreshDependencies(fout);
809                 if (dopt.dataOnly)
810                         getTableDataFKConstraints();
811         }
812
813         if (dopt.schemaOnly && dopt.sequence_data)
814                 getTableData(&dopt, tblinfo, numTables, RELKIND_SEQUENCE);
815
816         /*
817          * In binary-upgrade mode, we do not have to worry about the actual blob
818          * data or the associated metadata that resides in the pg_largeobject and
819          * pg_largeobject_metadata tables, respectively.
820          *
821          * However, we do need to collect blob information as there may be
822          * comments or other information on blobs that we do need to dump out.
823          */
824         if (dopt.outputBlobs || dopt.binary_upgrade)
825                 getBlobs(fout);
826
827         /*
828          * Collect dependency data to assist in ordering the objects.
829          */
830         getDependencies(fout);
831
832         /* Lastly, create dummy objects to represent the section boundaries */
833         boundaryObjs = createBoundaryObjects();
834
835         /* Get pointers to all the known DumpableObjects */
836         getDumpableObjects(&dobjs, &numObjs);
837
838         /*
839          * Add dummy dependencies to enforce the dump section ordering.
840          */
841         addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
842
843         /*
844          * Sort the objects into a safe dump order (no forward references).
845          *
846          * We rely on dependency information to help us determine a safe order, so
847          * the initial sort is mostly for cosmetic purposes: we sort by name to
848          * ensure that logically identical schemas will dump identically.
849          */
850         sortDumpableObjectsByTypeName(dobjs, numObjs);
851
852         sortDumpableObjects(dobjs, numObjs,
853                                                 boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
854
855         /*
856          * Create archive TOC entries for all the objects to be dumped, in a safe
857          * order.
858          */
859
860         /* First the special ENCODING, STDSTRINGS, and SEARCHPATH entries. */
861         dumpEncoding(fout);
862         dumpStdStrings(fout);
863         dumpSearchPath(fout);
864
865         /* The database items are always next, unless we don't want them at all */
866         if (dopt.outputCreateDB)
867                 dumpDatabase(fout);
868
869         /* Now the rearrangeable objects. */
870         for (i = 0; i < numObjs; i++)
871                 dumpDumpableObject(fout, dobjs[i]);
872
873         /*
874          * Set up options info to ensure we dump what we want.
875          */
876         ropt = NewRestoreOptions();
877         ropt->filename = filename;
878
879         /* if you change this list, see dumpOptionsFromRestoreOptions */
880         ropt->dropSchema = dopt.outputClean;
881         ropt->dataOnly = dopt.dataOnly;
882         ropt->schemaOnly = dopt.schemaOnly;
883         ropt->if_exists = dopt.if_exists;
884         ropt->column_inserts = dopt.column_inserts;
885         ropt->dumpSections = dopt.dumpSections;
886         ropt->aclsSkip = dopt.aclsSkip;
887         ropt->superuser = dopt.outputSuperuser;
888         ropt->createDB = dopt.outputCreateDB;
889         ropt->noOwner = dopt.outputNoOwner;
890         ropt->noTablespace = dopt.outputNoTablespaces;
891         ropt->disable_triggers = dopt.disable_triggers;
892         ropt->use_setsessauth = dopt.use_setsessauth;
893         ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
894         ropt->dump_inserts = dopt.dump_inserts;
895         ropt->no_comments = dopt.no_comments;
896         ropt->no_publications = dopt.no_publications;
897         ropt->no_security_labels = dopt.no_security_labels;
898         ropt->no_subscriptions = dopt.no_subscriptions;
899         ropt->lockWaitTimeout = dopt.lockWaitTimeout;
900         ropt->include_everything = dopt.include_everything;
901         ropt->enable_row_security = dopt.enable_row_security;
902         ropt->sequence_data = dopt.sequence_data;
903         ropt->binary_upgrade = dopt.binary_upgrade;
904
905         if (compressLevel == -1)
906                 ropt->compression = 0;
907         else
908                 ropt->compression = compressLevel;
909
910         ropt->suppressDumpWarnings = true;      /* We've already shown them */
911
912         SetArchiveOptions(fout, &dopt, ropt);
913
914         /* Mark which entries should be output */
915         ProcessArchiveRestoreOptions(fout);
916
917         /*
918          * The archive's TOC entries are now marked as to which ones will actually
919          * be output, so we can set up their dependency lists properly. This isn't
920          * necessary for plain-text output, though.
921          */
922         if (!plainText)
923                 BuildArchiveDependencies(fout);
924
925         /*
926          * And finally we can do the actual output.
927          *
928          * Note: for non-plain-text output formats, the output file is written
929          * inside CloseArchive().  This is, um, bizarre; but not worth changing
930          * right now.
931          */
932         if (plainText)
933                 RestoreArchive(fout);
934
935         CloseArchive(fout);
936
937         exit_nicely(0);
938 }
939
940
941 static void
942 help(const char *progname)
943 {
944         printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
945         printf(_("Usage:\n"));
946         printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
947
948         printf(_("\nGeneral options:\n"));
949         printf(_("  -f, --file=FILENAME          output file or directory name\n"));
950         printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
951                          "                               plain text (default))\n"));
952         printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
953         printf(_("  -v, --verbose                verbose mode\n"));
954         printf(_("  -V, --version                output version information, then exit\n"));
955         printf(_("  -Z, --compress=0-9           compression level for compressed formats\n"));
956         printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
957         printf(_("  --no-sync                    do not wait for changes to be written safely to disk\n"));
958         printf(_("  -?, --help                   show this help, then exit\n"));
959
960         printf(_("\nOptions controlling the output content:\n"));
961         printf(_("  -a, --data-only              dump only the data, not the schema\n"));
962         printf(_("  -b, --blobs                  include large objects in dump\n"));
963         printf(_("  -B, --no-blobs               exclude large objects in dump\n"));
964         printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
965         printf(_("  -C, --create                 include commands to create database in dump\n"));
966         printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
967         printf(_("  -n, --schema=SCHEMA          dump the named schema(s) only\n"));
968         printf(_("  -N, --exclude-schema=SCHEMA  do NOT dump the named schema(s)\n"));
969         printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
970                          "                               plain-text format\n"));
971         printf(_("  -s, --schema-only            dump only the schema, no data\n"));
972         printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
973         printf(_("  -t, --table=TABLE            dump the named table(s) only\n"));
974         printf(_("  -T, --exclude-table=TABLE    do NOT dump the named table(s)\n"));
975         printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
976         printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
977         printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
978         printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
979         printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
980         printf(_("  --enable-row-security        enable row security (dump only content user has\n"
981                          "                               access to)\n"));
982         printf(_("  --exclude-table-data=TABLE   do NOT dump data for the named table(s)\n"));
983         printf(_("  --extra-float-digits=NUM     override default setting for extra_float_digits\n"));
984         printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
985         printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
986         printf(_("  --load-via-partition-root    load partitions via the root table\n"));
987         printf(_("  --no-comments                do not dump comments\n"));
988         printf(_("  --no-publications            do not dump publications\n"));
989         printf(_("  --no-security-labels         do not dump security label assignments\n"));
990         printf(_("  --no-subscriptions           do not dump subscriptions\n"));
991         printf(_("  --no-synchronized-snapshots  do not use synchronized snapshots in parallel jobs\n"));
992         printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
993         printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
994         printf(_("  --on-conflict-do-nothing     add ON CONFLICT DO NOTHING to INSERT commands\n"));
995         printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
996         printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
997         printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
998         printf(_("  --snapshot=SNAPSHOT          use given snapshot for the dump\n"));
999         printf(_("  --strict-names               require table and/or schema include patterns to\n"
1000                          "                               match at least one entity each\n"));
1001         printf(_("  --use-set-session-authorization\n"
1002                          "                               use SET SESSION AUTHORIZATION commands instead of\n"
1003                          "                               ALTER OWNER commands to set ownership\n"));
1004
1005         printf(_("\nConnection options:\n"));
1006         printf(_("  -d, --dbname=DBNAME      database to dump\n"));
1007         printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
1008         printf(_("  -p, --port=PORT          database server port number\n"));
1009         printf(_("  -U, --username=NAME      connect as specified database user\n"));
1010         printf(_("  -w, --no-password        never prompt for password\n"));
1011         printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
1012         printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
1013
1014         printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
1015                          "variable value is used.\n\n"));
1016         printf(_("Report bugs to <pgsql-bugs@lists.postgresql.org>.\n"));
1017 }
1018
1019 static void
1020 setup_connection(Archive *AH, const char *dumpencoding,
1021                                  const char *dumpsnapshot, char *use_role)
1022 {
1023         DumpOptions *dopt = AH->dopt;
1024         PGconn     *conn = GetConnection(AH);
1025         const char *std_strings;
1026
1027         PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
1028
1029         /*
1030          * Set the client encoding if requested.
1031          */
1032         if (dumpencoding)
1033         {
1034                 if (PQsetClientEncoding(conn, dumpencoding) < 0)
1035                         exit_horribly(NULL, "invalid client encoding \"%s\" specified\n",
1036                                                   dumpencoding);
1037         }
1038
1039         /*
1040          * Get the active encoding and the standard_conforming_strings setting, so
1041          * we know how to escape strings.
1042          */
1043         AH->encoding = PQclientEncoding(conn);
1044
1045         std_strings = PQparameterStatus(conn, "standard_conforming_strings");
1046         AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
1047
1048         /*
1049          * Set the role if requested.  In a parallel dump worker, we'll be passed
1050          * use_role == NULL, but AH->use_role is already set (if user specified it
1051          * originally) and we should use that.
1052          */
1053         if (!use_role && AH->use_role)
1054                 use_role = AH->use_role;
1055
1056         /* Set the role if requested */
1057         if (use_role && AH->remoteVersion >= 80100)
1058         {
1059                 PQExpBuffer query = createPQExpBuffer();
1060
1061                 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
1062                 ExecuteSqlStatement(AH, query->data);
1063                 destroyPQExpBuffer(query);
1064
1065                 /* save it for possible later use by parallel workers */
1066                 if (!AH->use_role)
1067                         AH->use_role = pg_strdup(use_role);
1068         }
1069
1070         /* Set the datestyle to ISO to ensure the dump's portability */
1071         ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
1072
1073         /* Likewise, avoid using sql_standard intervalstyle */
1074         if (AH->remoteVersion >= 80400)
1075                 ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
1076
1077         /*
1078          * Use an explicitly specified extra_float_digits if it has been
1079          * provided. Otherwise, set extra_float_digits so that we can dump float
1080          * data exactly (given correctly implemented float I/O code, anyway).
1081          */
1082         if (have_extra_float_digits)
1083         {
1084                 PQExpBuffer q = createPQExpBuffer();
1085                 appendPQExpBuffer(q, "SET extra_float_digits TO %d",
1086                                                   extra_float_digits);
1087                 ExecuteSqlStatement(AH, q->data);
1088                 destroyPQExpBuffer(q);
1089         }
1090         else if (AH->remoteVersion >= 90000)
1091                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
1092         else
1093                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 2");
1094
1095         /*
1096          * If synchronized scanning is supported, disable it, to prevent
1097          * unpredictable changes in row ordering across a dump and reload.
1098          */
1099         if (AH->remoteVersion >= 80300)
1100                 ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
1101
1102         /*
1103          * Disable timeouts if supported.
1104          */
1105         ExecuteSqlStatement(AH, "SET statement_timeout = 0");
1106         if (AH->remoteVersion >= 90300)
1107                 ExecuteSqlStatement(AH, "SET lock_timeout = 0");
1108         if (AH->remoteVersion >= 90600)
1109                 ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
1110
1111         /*
1112          * Quote all identifiers, if requested.
1113          */
1114         if (quote_all_identifiers && AH->remoteVersion >= 90100)
1115                 ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1116
1117         /*
1118          * Adjust row-security mode, if supported.
1119          */
1120         if (AH->remoteVersion >= 90500)
1121         {
1122                 if (dopt->enable_row_security)
1123                         ExecuteSqlStatement(AH, "SET row_security = on");
1124                 else
1125                         ExecuteSqlStatement(AH, "SET row_security = off");
1126         }
1127
1128         /*
1129          * Start transaction-snapshot mode transaction to dump consistent data.
1130          */
1131         ExecuteSqlStatement(AH, "BEGIN");
1132         if (AH->remoteVersion >= 90100)
1133         {
1134                 /*
1135                  * To support the combination of serializable_deferrable with the jobs
1136                  * option we use REPEATABLE READ for the worker connections that are
1137                  * passed a snapshot.  As long as the snapshot is acquired in a
1138                  * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
1139                  * REPEATABLE READ transaction provides the appropriate integrity
1140                  * guarantees.  This is a kluge, but safe for back-patching.
1141                  */
1142                 if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
1143                         ExecuteSqlStatement(AH,
1144                                                                 "SET TRANSACTION ISOLATION LEVEL "
1145                                                                 "SERIALIZABLE, READ ONLY, DEFERRABLE");
1146                 else
1147                         ExecuteSqlStatement(AH,
1148                                                                 "SET TRANSACTION ISOLATION LEVEL "
1149                                                                 "REPEATABLE READ, READ ONLY");
1150         }
1151         else
1152         {
1153                 ExecuteSqlStatement(AH,
1154                                                         "SET TRANSACTION ISOLATION LEVEL "
1155                                                         "SERIALIZABLE, READ ONLY");
1156         }
1157
1158         /*
1159          * If user specified a snapshot to use, select that.  In a parallel dump
1160          * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
1161          * is already set (if the server can handle it) and we should use that.
1162          */
1163         if (dumpsnapshot)
1164                 AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
1165
1166         if (AH->sync_snapshot_id)
1167         {
1168                 PQExpBuffer query = createPQExpBuffer();
1169
1170                 appendPQExpBuffer(query, "SET TRANSACTION SNAPSHOT ");
1171                 appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
1172                 ExecuteSqlStatement(AH, query->data);
1173                 destroyPQExpBuffer(query);
1174         }
1175         else if (AH->numWorkers > 1 &&
1176                          AH->remoteVersion >= 90200 &&
1177                          !dopt->no_synchronized_snapshots)
1178         {
1179                 if (AH->isStandby && AH->remoteVersion < 100000)
1180                         exit_horribly(NULL,
1181                                                   "Synchronized snapshots on standby servers are not supported by this server version.\n"
1182                                                   "Run with --no-synchronized-snapshots instead if you do not need\n"
1183                                                   "synchronized snapshots.\n");
1184
1185
1186                 AH->sync_snapshot_id = get_synchronized_snapshot(AH);
1187         }
1188 }
1189
1190 /* Set up connection for a parallel worker process */
1191 static void
1192 setupDumpWorker(Archive *AH)
1193 {
1194         /*
1195          * We want to re-select all the same values the master connection is
1196          * using.  We'll have inherited directly-usable values in
1197          * AH->sync_snapshot_id and AH->use_role, but we need to translate the
1198          * inherited encoding value back to a string to pass to setup_connection.
1199          */
1200         setup_connection(AH,
1201                                          pg_encoding_to_char(AH->encoding),
1202                                          NULL,
1203                                          NULL);
1204 }
1205
1206 static char *
1207 get_synchronized_snapshot(Archive *fout)
1208 {
1209         char       *query = "SELECT pg_catalog.pg_export_snapshot()";
1210         char       *result;
1211         PGresult   *res;
1212
1213         res = ExecuteSqlQueryForSingleRow(fout, query);
1214         result = pg_strdup(PQgetvalue(res, 0, 0));
1215         PQclear(res);
1216
1217         return result;
1218 }
1219
1220 static ArchiveFormat
1221 parseArchiveFormat(const char *format, ArchiveMode *mode)
1222 {
1223         ArchiveFormat archiveFormat;
1224
1225         *mode = archModeWrite;
1226
1227         if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1228         {
1229                 /* This is used by pg_dumpall, and is not documented */
1230                 archiveFormat = archNull;
1231                 *mode = archModeAppend;
1232         }
1233         else if (pg_strcasecmp(format, "c") == 0)
1234                 archiveFormat = archCustom;
1235         else if (pg_strcasecmp(format, "custom") == 0)
1236                 archiveFormat = archCustom;
1237         else if (pg_strcasecmp(format, "d") == 0)
1238                 archiveFormat = archDirectory;
1239         else if (pg_strcasecmp(format, "directory") == 0)
1240                 archiveFormat = archDirectory;
1241         else if (pg_strcasecmp(format, "p") == 0)
1242                 archiveFormat = archNull;
1243         else if (pg_strcasecmp(format, "plain") == 0)
1244                 archiveFormat = archNull;
1245         else if (pg_strcasecmp(format, "t") == 0)
1246                 archiveFormat = archTar;
1247         else if (pg_strcasecmp(format, "tar") == 0)
1248                 archiveFormat = archTar;
1249         else
1250                 exit_horribly(NULL, "invalid output format \"%s\" specified\n", format);
1251         return archiveFormat;
1252 }
1253
1254 /*
1255  * Find the OIDs of all schemas matching the given list of patterns,
1256  * and append them to the given OID list.
1257  */
1258 static void
1259 expand_schema_name_patterns(Archive *fout,
1260                                                         SimpleStringList *patterns,
1261                                                         SimpleOidList *oids,
1262                                                         bool strict_names)
1263 {
1264         PQExpBuffer query;
1265         PGresult   *res;
1266         SimpleStringListCell *cell;
1267         int                     i;
1268
1269         if (patterns->head == NULL)
1270                 return;                                 /* nothing to do */
1271
1272         query = createPQExpBuffer();
1273
1274         /*
1275          * The loop below runs multiple SELECTs might sometimes result in
1276          * duplicate entries in the OID list, but we don't care.
1277          */
1278
1279         for (cell = patterns->head; cell; cell = cell->next)
1280         {
1281                 appendPQExpBuffer(query,
1282                                                   "SELECT oid FROM pg_catalog.pg_namespace n\n");
1283                 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1284                                                           false, NULL, "n.nspname", NULL, NULL);
1285
1286                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1287                 if (strict_names && PQntuples(res) == 0)
1288                         exit_horribly(NULL, "no matching schemas were found for pattern \"%s\"\n", cell->val);
1289
1290                 for (i = 0; i < PQntuples(res); i++)
1291                 {
1292                         simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1293                 }
1294
1295                 PQclear(res);
1296                 resetPQExpBuffer(query);
1297         }
1298
1299         destroyPQExpBuffer(query);
1300 }
1301
1302 /*
1303  * Find the OIDs of all tables matching the given list of patterns,
1304  * and append them to the given OID list.
1305  */
1306 static void
1307 expand_table_name_patterns(Archive *fout,
1308                                                    SimpleStringList *patterns, SimpleOidList *oids,
1309                                                    bool strict_names)
1310 {
1311         PQExpBuffer query;
1312         PGresult   *res;
1313         SimpleStringListCell *cell;
1314         int                     i;
1315
1316         if (patterns->head == NULL)
1317                 return;                                 /* nothing to do */
1318
1319         query = createPQExpBuffer();
1320
1321         /*
1322          * this might sometimes result in duplicate entries in the OID list, but
1323          * we don't care.
1324          */
1325
1326         for (cell = patterns->head; cell; cell = cell->next)
1327         {
1328                 /*
1329                  * Query must remain ABSOLUTELY devoid of unqualified names.  This
1330                  * would be unnecessary given a pg_table_is_visible() variant taking a
1331                  * search_path argument.
1332                  */
1333                 appendPQExpBuffer(query,
1334                                                   "SELECT c.oid"
1335                                                   "\nFROM pg_catalog.pg_class c"
1336                                                   "\n     LEFT JOIN pg_catalog.pg_namespace n"
1337                                                   "\n     ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
1338                                                   "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
1339                                                   "\n    (array['%c', '%c', '%c', '%c', '%c', '%c'])\n",
1340                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1341                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
1342                                                   RELKIND_PARTITIONED_TABLE);
1343                 processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1344                                                           false, "n.nspname", "c.relname", NULL,
1345                                                           "pg_catalog.pg_table_is_visible(c.oid)");
1346
1347                 ExecuteSqlStatement(fout, "RESET search_path");
1348                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1349                 PQclear(ExecuteSqlQueryForSingleRow(fout,
1350                                                                                         ALWAYS_SECURE_SEARCH_PATH_SQL));
1351                 if (strict_names && PQntuples(res) == 0)
1352                         exit_horribly(NULL, "no matching tables were found for pattern \"%s\"\n", cell->val);
1353
1354                 for (i = 0; i < PQntuples(res); i++)
1355                 {
1356                         simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1357                 }
1358
1359                 PQclear(res);
1360                 resetPQExpBuffer(query);
1361         }
1362
1363         destroyPQExpBuffer(query);
1364 }
1365
1366 /*
1367  * checkExtensionMembership
1368  *              Determine whether object is an extension member, and if so,
1369  *              record an appropriate dependency and set the object's dump flag.
1370  *
1371  * It's important to call this for each object that could be an extension
1372  * member.  Generally, we integrate this with determining the object's
1373  * to-be-dumped-ness, since extension membership overrides other rules for that.
1374  *
1375  * Returns true if object is an extension member, else false.
1376  */
1377 static bool
1378 checkExtensionMembership(DumpableObject *dobj, Archive *fout)
1379 {
1380         ExtensionInfo *ext = findOwningExtension(dobj->catId);
1381
1382         if (ext == NULL)
1383                 return false;
1384
1385         dobj->ext_member = true;
1386
1387         /* Record dependency so that getDependencies needn't deal with that */
1388         addObjectDependency(dobj, ext->dobj.dumpId);
1389
1390         /*
1391          * In 9.6 and above, mark the member object to have any non-initial ACL,
1392          * policies, and security labels dumped.
1393          *
1394          * Note that any initial ACLs (see pg_init_privs) will be removed when we
1395          * extract the information about the object.  We don't provide support for
1396          * initial policies and security labels and it seems unlikely for those to
1397          * ever exist, but we may have to revisit this later.
1398          *
1399          * Prior to 9.6, we do not include any extension member components.
1400          *
1401          * In binary upgrades, we still dump all components of the members
1402          * individually, since the idea is to exactly reproduce the database
1403          * contents rather than replace the extension contents with something
1404          * different.
1405          */
1406         if (fout->dopt->binary_upgrade)
1407                 dobj->dump = ext->dobj.dump;
1408         else
1409         {
1410                 if (fout->remoteVersion < 90600)
1411                         dobj->dump = DUMP_COMPONENT_NONE;
1412                 else
1413                         dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL |
1414                                                                                                         DUMP_COMPONENT_SECLABEL |
1415                                                                                                         DUMP_COMPONENT_POLICY);
1416         }
1417
1418         return true;
1419 }
1420
1421 /*
1422  * selectDumpableNamespace: policy-setting subroutine
1423  *              Mark a namespace as to be dumped or not
1424  */
1425 static void
1426 selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
1427 {
1428         /*
1429          * If specific tables are being dumped, do not dump any complete
1430          * namespaces. If specific namespaces are being dumped, dump just those
1431          * namespaces. Otherwise, dump all non-system namespaces.
1432          */
1433         if (table_include_oids.head != NULL)
1434                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1435         else if (schema_include_oids.head != NULL)
1436                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
1437                         simple_oid_list_member(&schema_include_oids,
1438                                                                    nsinfo->dobj.catId.oid) ?
1439                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1440         else if (fout->remoteVersion >= 90600 &&
1441                          strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
1442         {
1443                 /*
1444                  * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
1445                  * they are interesting (and not the original ACLs which were set at
1446                  * initdb time, see pg_init_privs).
1447                  */
1448                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1449         }
1450         else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1451                          strcmp(nsinfo->dobj.name, "information_schema") == 0)
1452         {
1453                 /* Other system schemas don't get dumped */
1454                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1455         }
1456         else if (strcmp(nsinfo->dobj.name, "public") == 0)
1457         {
1458                 /*
1459                  * The public schema is a strange beast that sits in a sort of
1460                  * no-mans-land between being a system object and a user object.  We
1461                  * don't want to dump creation or comment commands for it, because
1462                  * that complicates matters for non-superuser use of pg_dump.  But we
1463                  * should dump any ACL changes that have occurred for it, and of
1464                  * course we should dump contained objects.
1465                  */
1466                 nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1467                 nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
1468         }
1469         else
1470                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
1471
1472         /*
1473          * In any case, a namespace can be excluded by an exclusion switch
1474          */
1475         if (nsinfo->dobj.dump_contains &&
1476                 simple_oid_list_member(&schema_exclude_oids,
1477                                                            nsinfo->dobj.catId.oid))
1478                 nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1479
1480         /*
1481          * If the schema belongs to an extension, allow extension membership to
1482          * override the dump decision for the schema itself.  However, this does
1483          * not change dump_contains, so this won't change what we do with objects
1484          * within the schema.  (If they belong to the extension, they'll get
1485          * suppressed by it, otherwise not.)
1486          */
1487         (void) checkExtensionMembership(&nsinfo->dobj, fout);
1488 }
1489
1490 /*
1491  * selectDumpableTable: policy-setting subroutine
1492  *              Mark a table as to be dumped or not
1493  */
1494 static void
1495 selectDumpableTable(TableInfo *tbinfo, Archive *fout)
1496 {
1497         if (checkExtensionMembership(&tbinfo->dobj, fout))
1498                 return;                                 /* extension membership overrides all else */
1499
1500         /*
1501          * If specific tables are being dumped, dump just those tables; else, dump
1502          * according to the parent namespace's dump flag.
1503          */
1504         if (table_include_oids.head != NULL)
1505                 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1506                                                                                                    tbinfo->dobj.catId.oid) ?
1507                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1508         else
1509                 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
1510
1511         /*
1512          * In any case, a table can be excluded by an exclusion switch
1513          */
1514         if (tbinfo->dobj.dump &&
1515                 simple_oid_list_member(&table_exclude_oids,
1516                                                            tbinfo->dobj.catId.oid))
1517                 tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
1518 }
1519
1520 /*
1521  * selectDumpableType: policy-setting subroutine
1522  *              Mark a type as to be dumped or not
1523  *
1524  * If it's a table's rowtype or an autogenerated array type, we also apply a
1525  * special type code to facilitate sorting into the desired order.  (We don't
1526  * want to consider those to be ordinary types because that would bring tables
1527  * up into the datatype part of the dump order.)  We still set the object's
1528  * dump flag; that's not going to cause the dummy type to be dumped, but we
1529  * need it so that casts involving such types will be dumped correctly -- see
1530  * dumpCast.  This means the flag should be set the same as for the underlying
1531  * object (the table or base type).
1532  */
1533 static void
1534 selectDumpableType(TypeInfo *tyinfo, Archive *fout)
1535 {
1536         /* skip complex types, except for standalone composite types */
1537         if (OidIsValid(tyinfo->typrelid) &&
1538                 tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1539         {
1540                 TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
1541
1542                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1543                 if (tytable != NULL)
1544                         tyinfo->dobj.dump = tytable->dobj.dump;
1545                 else
1546                         tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
1547                 return;
1548         }
1549
1550         /* skip auto-generated array types */
1551         if (tyinfo->isArray)
1552         {
1553                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1554
1555                 /*
1556                  * Fall through to set the dump flag; we assume that the subsequent
1557                  * rules will do the same thing as they would for the array's base
1558                  * type.  (We cannot reliably look up the base type here, since
1559                  * getTypes may not have processed it yet.)
1560                  */
1561         }
1562
1563         if (checkExtensionMembership(&tyinfo->dobj, fout))
1564                 return;                                 /* extension membership overrides all else */
1565
1566         /* Dump based on if the contents of the namespace are being dumped */
1567         tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
1568 }
1569
1570 /*
1571  * selectDumpableDefaultACL: policy-setting subroutine
1572  *              Mark a default ACL as to be dumped or not
1573  *
1574  * For per-schema default ACLs, dump if the schema is to be dumped.
1575  * Otherwise dump if we are dumping "everything".  Note that dataOnly
1576  * and aclsSkip are checked separately.
1577  */
1578 static void
1579 selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
1580 {
1581         /* Default ACLs can't be extension members */
1582
1583         if (dinfo->dobj.namespace)
1584                 /* default ACLs are considered part of the namespace */
1585                 dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
1586         else
1587                 dinfo->dobj.dump = dopt->include_everything ?
1588                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1589 }
1590
1591 /*
1592  * selectDumpableCast: policy-setting subroutine
1593  *              Mark a cast as to be dumped or not
1594  *
1595  * Casts do not belong to any particular namespace (since they haven't got
1596  * names), nor do they have identifiable owners.  To distinguish user-defined
1597  * casts from built-in ones, we must resort to checking whether the cast's
1598  * OID is in the range reserved for initdb.
1599  */
1600 static void
1601 selectDumpableCast(CastInfo *cast, Archive *fout)
1602 {
1603         if (checkExtensionMembership(&cast->dobj, fout))
1604                 return;                                 /* extension membership overrides all else */
1605
1606         /*
1607          * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
1608          * support ACLs currently.
1609          */
1610         if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1611                 cast->dobj.dump = DUMP_COMPONENT_NONE;
1612         else
1613                 cast->dobj.dump = fout->dopt->include_everything ?
1614                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1615 }
1616
1617 /*
1618  * selectDumpableProcLang: policy-setting subroutine
1619  *              Mark a procedural language as to be dumped or not
1620  *
1621  * Procedural languages do not belong to any particular namespace.  To
1622  * identify built-in languages, we must resort to checking whether the
1623  * language's OID is in the range reserved for initdb.
1624  */
1625 static void
1626 selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
1627 {
1628         if (checkExtensionMembership(&plang->dobj, fout))
1629                 return;                                 /* extension membership overrides all else */
1630
1631         /*
1632          * Only include procedural languages when we are dumping everything.
1633          *
1634          * For from-initdb procedural languages, only include ACLs, as we do for
1635          * the pg_catalog namespace.  We need this because procedural languages do
1636          * not live in any namespace.
1637          */
1638         if (!fout->dopt->include_everything)
1639                 plang->dobj.dump = DUMP_COMPONENT_NONE;
1640         else
1641         {
1642                 if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1643                         plang->dobj.dump = fout->remoteVersion < 90600 ?
1644                                 DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
1645                 else
1646                         plang->dobj.dump = DUMP_COMPONENT_ALL;
1647         }
1648 }
1649
1650 /*
1651  * selectDumpableAccessMethod: policy-setting subroutine
1652  *              Mark an access method as to be dumped or not
1653  *
1654  * Access methods do not belong to any particular namespace.  To identify
1655  * built-in access methods, we must resort to checking whether the
1656  * method's OID is in the range reserved for initdb.
1657  */
1658 static void
1659 selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
1660 {
1661         if (checkExtensionMembership(&method->dobj, fout))
1662                 return;                                 /* extension membership overrides all else */
1663
1664         /*
1665          * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
1666          * they do not support ACLs currently.
1667          */
1668         if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1669                 method->dobj.dump = DUMP_COMPONENT_NONE;
1670         else
1671                 method->dobj.dump = fout->dopt->include_everything ?
1672                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1673 }
1674
1675 /*
1676  * selectDumpableExtension: policy-setting subroutine
1677  *              Mark an extension as to be dumped or not
1678  *
1679  * Built-in extensions should be skipped except for checking ACLs, since we
1680  * assume those will already be installed in the target database.  We identify
1681  * such extensions by their having OIDs in the range reserved for initdb.
1682  * We dump all user-added extensions by default, or none of them if
1683  * include_everything is false (i.e., a --schema or --table switch was given).
1684  */
1685 static void
1686 selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
1687 {
1688         /*
1689          * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
1690          * change permissions on their member objects, if they wish to, and have
1691          * those changes preserved.
1692          */
1693         if (extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1694                 extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
1695         else
1696                 extinfo->dobj.dump = extinfo->dobj.dump_contains =
1697                         dopt->include_everything ? DUMP_COMPONENT_ALL :
1698                         DUMP_COMPONENT_NONE;
1699 }
1700
1701 /*
1702  * selectDumpablePublicationTable: policy-setting subroutine
1703  *              Mark a publication table as to be dumped or not
1704  *
1705  * Publication tables have schemas, but those are ignored in decision making,
1706  * because publications are only dumped when we are dumping everything.
1707  */
1708 static void
1709 selectDumpablePublicationTable(DumpableObject *dobj, Archive *fout)
1710 {
1711         if (checkExtensionMembership(dobj, fout))
1712                 return;                                 /* extension membership overrides all else */
1713
1714         dobj->dump = fout->dopt->include_everything ?
1715                 DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1716 }
1717
1718 /*
1719  * selectDumpableObject: policy-setting subroutine
1720  *              Mark a generic dumpable object as to be dumped or not
1721  *
1722  * Use this only for object types without a special-case routine above.
1723  */
1724 static void
1725 selectDumpableObject(DumpableObject *dobj, Archive *fout)
1726 {
1727         if (checkExtensionMembership(dobj, fout))
1728                 return;                                 /* extension membership overrides all else */
1729
1730         /*
1731          * Default policy is to dump if parent namespace is dumpable, or for
1732          * non-namespace-associated items, dump if we're dumping "everything".
1733          */
1734         if (dobj->namespace)
1735                 dobj->dump = dobj->namespace->dobj.dump_contains;
1736         else
1737                 dobj->dump = fout->dopt->include_everything ?
1738                         DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1739 }
1740
1741 /*
1742  *      Dump a table's contents for loading using the COPY command
1743  *      - this routine is called by the Archiver when it wants the table
1744  *        to be dumped.
1745  */
1746
1747 static int
1748 dumpTableData_copy(Archive *fout, void *dcontext)
1749 {
1750         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1751         TableInfo  *tbinfo = tdinfo->tdtable;
1752         const char *classname = tbinfo->dobj.name;
1753         PQExpBuffer q = createPQExpBuffer();
1754
1755         /*
1756          * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
1757          * which uses it already.
1758          */
1759         PQExpBuffer clistBuf = createPQExpBuffer();
1760         PGconn     *conn = GetConnection(fout);
1761         PGresult   *res;
1762         int                     ret;
1763         char       *copybuf;
1764         const char *column_list;
1765
1766         if (g_verbose)
1767                 write_msg(NULL, "dumping contents of table \"%s.%s\"\n",
1768                                   tbinfo->dobj.namespace->dobj.name, classname);
1769
1770         /*
1771          * Specify the column list explicitly so that we have no possibility of
1772          * retrieving data in the wrong column order.  (The default column
1773          * ordering of COPY will not be what we want in certain corner cases
1774          * involving ADD COLUMN and inheritance.)
1775          */
1776         column_list = fmtCopyColumnList(tbinfo, clistBuf);
1777
1778         if (tdinfo->filtercond)
1779         {
1780                 /* Note: this syntax is only supported in 8.2 and up */
1781                 appendPQExpBufferStr(q, "COPY (SELECT ");
1782                 /* klugery to get rid of parens in column list */
1783                 if (strlen(column_list) > 2)
1784                 {
1785                         appendPQExpBufferStr(q, column_list + 1);
1786                         q->data[q->len - 1] = ' ';
1787                 }
1788                 else
1789                         appendPQExpBufferStr(q, "* ");
1790                 appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
1791                                                   fmtQualifiedDumpable(tbinfo),
1792                                                   tdinfo->filtercond);
1793         }
1794         else
1795         {
1796                 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1797                                                   fmtQualifiedDumpable(tbinfo),
1798                                                   column_list);
1799         }
1800         res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
1801         PQclear(res);
1802         destroyPQExpBuffer(clistBuf);
1803
1804         for (;;)
1805         {
1806                 ret = PQgetCopyData(conn, &copybuf, 0);
1807
1808                 if (ret < 0)
1809                         break;                          /* done or error */
1810
1811                 if (copybuf)
1812                 {
1813                         WriteData(fout, copybuf, ret);
1814                         PQfreemem(copybuf);
1815                 }
1816
1817                 /* ----------
1818                  * THROTTLE:
1819                  *
1820                  * There was considerable discussion in late July, 2000 regarding
1821                  * slowing down pg_dump when backing up large tables. Users with both
1822                  * slow & fast (multi-processor) machines experienced performance
1823                  * degradation when doing a backup.
1824                  *
1825                  * Initial attempts based on sleeping for a number of ms for each ms
1826                  * of work were deemed too complex, then a simple 'sleep in each loop'
1827                  * implementation was suggested. The latter failed because the loop
1828                  * was too tight. Finally, the following was implemented:
1829                  *
1830                  * If throttle is non-zero, then
1831                  *              See how long since the last sleep.
1832                  *              Work out how long to sleep (based on ratio).
1833                  *              If sleep is more than 100ms, then
1834                  *                      sleep
1835                  *                      reset timer
1836                  *              EndIf
1837                  * EndIf
1838                  *
1839                  * where the throttle value was the number of ms to sleep per ms of
1840                  * work. The calculation was done in each loop.
1841                  *
1842                  * Most of the hard work is done in the backend, and this solution
1843                  * still did not work particularly well: on slow machines, the ratio
1844                  * was 50:1, and on medium paced machines, 1:1, and on fast
1845                  * multi-processor machines, it had little or no effect, for reasons
1846                  * that were unclear.
1847                  *
1848                  * Further discussion ensued, and the proposal was dropped.
1849                  *
1850                  * For those people who want this feature, it can be implemented using
1851                  * gettimeofday in each loop, calculating the time since last sleep,
1852                  * multiplying that by the sleep ratio, then if the result is more
1853                  * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1854                  * function to sleep for a subsecond period ie.
1855                  *
1856                  * select(0, NULL, NULL, NULL, &tvi);
1857                  *
1858                  * This will return after the interval specified in the structure tvi.
1859                  * Finally, call gettimeofday again to save the 'last sleep time'.
1860                  * ----------
1861                  */
1862         }
1863         archprintf(fout, "\\.\n\n\n");
1864
1865         if (ret == -2)
1866         {
1867                 /* copy data transfer failed */
1868                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
1869                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1870                 write_msg(NULL, "The command was: %s\n", q->data);
1871                 exit_nicely(1);
1872         }
1873
1874         /* Check command status and return to normal libpq state */
1875         res = PQgetResult(conn);
1876         if (PQresultStatus(res) != PGRES_COMMAND_OK)
1877         {
1878                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetResult() failed.\n", classname);
1879                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1880                 write_msg(NULL, "The command was: %s\n", q->data);
1881                 exit_nicely(1);
1882         }
1883         PQclear(res);
1884
1885         /* Do this to ensure we've pumped libpq back to idle state */
1886         if (PQgetResult(conn) != NULL)
1887                 write_msg(NULL, "WARNING: unexpected extra results during COPY of table \"%s\"\n",
1888                                   classname);
1889
1890         destroyPQExpBuffer(q);
1891         return 1;
1892 }
1893
1894 /*
1895  * Dump table data using INSERT commands.
1896  *
1897  * Caution: when we restore from an archive file direct to database, the
1898  * INSERT commands emitted by this function have to be parsed by
1899  * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
1900  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
1901  */
1902 static int
1903 dumpTableData_insert(Archive *fout, void *dcontext)
1904 {
1905         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1906         TableInfo  *tbinfo = tdinfo->tdtable;
1907         DumpOptions *dopt = fout->dopt;
1908         PQExpBuffer q = createPQExpBuffer();
1909         PQExpBuffer insertStmt = NULL;
1910         PGresult   *res;
1911         int                     tuple;
1912         int                     nfields;
1913         int                     field;
1914
1915         appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1916                                           "SELECT * FROM ONLY %s",
1917                                           fmtQualifiedDumpable(tbinfo));
1918         if (tdinfo->filtercond)
1919                 appendPQExpBuffer(q, " %s", tdinfo->filtercond);
1920
1921         ExecuteSqlStatement(fout, q->data);
1922
1923         while (1)
1924         {
1925                 res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
1926                                                           PGRES_TUPLES_OK);
1927                 nfields = PQnfields(res);
1928                 for (tuple = 0; tuple < PQntuples(res); tuple++)
1929                 {
1930                         /*
1931                          * First time through, we build as much of the INSERT statement as
1932                          * possible in "insertStmt", which we can then just print for each
1933                          * line. If the table happens to have zero columns then this will
1934                          * be a complete statement, otherwise it will end in "VALUES(" and
1935                          * be ready to have the row's column values appended.
1936                          */
1937                         if (insertStmt == NULL)
1938                         {
1939                                 TableInfo  *targettab;
1940
1941                                 insertStmt = createPQExpBuffer();
1942
1943                                 /*
1944                                  * When load-via-partition-root is set, get the root table
1945                                  * name for the partition table, so that we can reload data
1946                                  * through the root table.
1947                                  */
1948                                 if (dopt->load_via_partition_root && tbinfo->ispartition)
1949                                         targettab = getRootTableInfo(tbinfo);
1950                                 else
1951                                         targettab = tbinfo;
1952
1953                                 appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
1954                                                                   fmtQualifiedDumpable(targettab));
1955
1956                                 /* corner case for zero-column table */
1957                                 if (nfields == 0)
1958                                 {
1959                                         appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
1960                                 }
1961                                 else
1962                                 {
1963                                         /* append the list of column names if required */
1964                                         if (dopt->column_inserts)
1965                                         {
1966                                                 appendPQExpBufferChar(insertStmt, '(');
1967                                                 for (field = 0; field < nfields; field++)
1968                                                 {
1969                                                         if (field > 0)
1970                                                                 appendPQExpBufferStr(insertStmt, ", ");
1971                                                         appendPQExpBufferStr(insertStmt,
1972                                                                                                  fmtId(PQfname(res, field)));
1973                                                 }
1974                                                 appendPQExpBufferStr(insertStmt, ") ");
1975                                         }
1976
1977                                         if (tbinfo->needs_override)
1978                                                 appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
1979
1980                                         appendPQExpBufferStr(insertStmt, "VALUES (");
1981                                 }
1982                         }
1983
1984                         archputs(insertStmt->data, fout);
1985
1986                         /* if it is zero-column table then we're done */
1987                         if (nfields == 0)
1988                                 continue;
1989
1990                         for (field = 0; field < nfields; field++)
1991                         {
1992                                 if (field > 0)
1993                                         archputs(", ", fout);
1994                                 if (PQgetisnull(res, tuple, field))
1995                                 {
1996                                         archputs("NULL", fout);
1997                                         continue;
1998                                 }
1999
2000                                 /* XXX This code is partially duplicated in ruleutils.c */
2001                                 switch (PQftype(res, field))
2002                                 {
2003                                         case INT2OID:
2004                                         case INT4OID:
2005                                         case INT8OID:
2006                                         case OIDOID:
2007                                         case FLOAT4OID:
2008                                         case FLOAT8OID:
2009                                         case NUMERICOID:
2010                                                 {
2011                                                         /*
2012                                                          * These types are printed without quotes unless
2013                                                          * they contain values that aren't accepted by the
2014                                                          * scanner unquoted (e.g., 'NaN').  Note that
2015                                                          * strtod() and friends might accept NaN, so we
2016                                                          * can't use that to test.
2017                                                          *
2018                                                          * In reality we only need to defend against
2019                                                          * infinity and NaN, so we need not get too crazy
2020                                                          * about pattern matching here.
2021                                                          */
2022                                                         const char *s = PQgetvalue(res, tuple, field);
2023
2024                                                         if (strspn(s, "0123456789 +-eE.") == strlen(s))
2025                                                                 archputs(s, fout);
2026                                                         else
2027                                                                 archprintf(fout, "'%s'", s);
2028                                                 }
2029                                                 break;
2030
2031                                         case BITOID:
2032                                         case VARBITOID:
2033                                                 archprintf(fout, "B'%s'",
2034                                                                    PQgetvalue(res, tuple, field));
2035                                                 break;
2036
2037                                         case BOOLOID:
2038                                                 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
2039                                                         archputs("true", fout);
2040                                                 else
2041                                                         archputs("false", fout);
2042                                                 break;
2043
2044                                         default:
2045                                                 /* All other types are printed as string literals. */
2046                                                 resetPQExpBuffer(q);
2047                                                 appendStringLiteralAH(q,
2048                                                                                           PQgetvalue(res, tuple, field),
2049                                                                                           fout);
2050                                                 archputs(q->data, fout);
2051                                                 break;
2052                                 }
2053                         }
2054
2055                         if (!dopt->do_nothing)
2056                                 archputs(");\n", fout);
2057                         else
2058                                 archputs(") ON CONFLICT DO NOTHING;\n", fout);
2059                 }
2060
2061                 if (PQntuples(res) <= 0)
2062                 {
2063                         PQclear(res);
2064                         break;
2065                 }
2066                 PQclear(res);
2067         }
2068
2069         archputs("\n\n", fout);
2070
2071         ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
2072
2073         destroyPQExpBuffer(q);
2074         if (insertStmt != NULL)
2075                 destroyPQExpBuffer(insertStmt);
2076
2077         return 1;
2078 }
2079
2080 /*
2081  * getRootTableInfo:
2082  *     get the root TableInfo for the given partition table.
2083  */
2084 static TableInfo *
2085 getRootTableInfo(TableInfo *tbinfo)
2086 {
2087         TableInfo  *parentTbinfo;
2088
2089         Assert(tbinfo->ispartition);
2090         Assert(tbinfo->numParents == 1);
2091
2092         parentTbinfo = tbinfo->parents[0];
2093         while (parentTbinfo->ispartition)
2094         {
2095                 Assert(parentTbinfo->numParents == 1);
2096                 parentTbinfo = parentTbinfo->parents[0];
2097         }
2098
2099         return parentTbinfo;
2100 }
2101
2102 /*
2103  * dumpTableData -
2104  *        dump the contents of a single table
2105  *
2106  * Actually, this just makes an ArchiveEntry for the table contents.
2107  */
2108 static void
2109 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
2110 {
2111         DumpOptions *dopt = fout->dopt;
2112         TableInfo  *tbinfo = tdinfo->tdtable;
2113         PQExpBuffer copyBuf = createPQExpBuffer();
2114         PQExpBuffer clistBuf = createPQExpBuffer();
2115         DataDumperPtr dumpFn;
2116         char       *copyStmt;
2117         const char *copyFrom;
2118
2119         if (!dopt->dump_inserts)
2120         {
2121                 /* Dump/restore using COPY */
2122                 dumpFn = dumpTableData_copy;
2123
2124                 /*
2125                  * When load-via-partition-root is set, get the root table name for
2126                  * the partition table, so that we can reload data through the root
2127                  * table.
2128                  */
2129                 if (dopt->load_via_partition_root && tbinfo->ispartition)
2130                 {
2131                         TableInfo  *parentTbinfo;
2132
2133                         parentTbinfo = getRootTableInfo(tbinfo);
2134                         copyFrom = fmtQualifiedDumpable(parentTbinfo);
2135                 }
2136                 else
2137                         copyFrom = fmtQualifiedDumpable(tbinfo);
2138
2139                 /* must use 2 steps here 'cause fmtId is nonreentrant */
2140                 appendPQExpBuffer(copyBuf, "COPY %s ",
2141                                                   copyFrom);
2142                 appendPQExpBuffer(copyBuf, "%s FROM stdin;\n",
2143                                                   fmtCopyColumnList(tbinfo, clistBuf));
2144                 copyStmt = copyBuf->data;
2145         }
2146         else
2147         {
2148                 /* Restore using INSERT */
2149                 dumpFn = dumpTableData_insert;
2150                 copyStmt = NULL;
2151         }
2152
2153         /*
2154          * Note: although the TableDataInfo is a full DumpableObject, we treat its
2155          * dependency on its table as "special" and pass it to ArchiveEntry now.
2156          * See comments for BuildArchiveDependencies.
2157          */
2158         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2159         {
2160                 TocEntry   *te;
2161
2162                 te = ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
2163                                                   ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
2164                                                                            .namespace = tbinfo->dobj.namespace->dobj.name,
2165                                                                            .owner = tbinfo->rolname,
2166                                                                            .description = "TABLE DATA",
2167                                                                            .section = SECTION_DATA,
2168                                                                            .copyStmt = copyStmt,
2169                                                                            .deps = &(tbinfo->dobj.dumpId),
2170                                                                            .nDeps = 1,
2171                                                                            .dumpFn = dumpFn,
2172                                                                            .dumpArg = tdinfo));
2173
2174                 /*
2175                  * Set the TocEntry's dataLength in case we are doing a parallel dump
2176                  * and want to order dump jobs by table size.  We choose to measure
2177                  * dataLength in table pages during dump, so no scaling is needed.
2178                  * However, relpages is declared as "integer" in pg_class, and hence
2179                  * also in TableInfo, but it's really BlockNumber a/k/a unsigned int.
2180                  * Cast so that we get the right interpretation of table sizes
2181                  * exceeding INT_MAX pages.
2182                  */
2183                 te->dataLength = (BlockNumber) tbinfo->relpages;
2184         }
2185
2186         destroyPQExpBuffer(copyBuf);
2187         destroyPQExpBuffer(clistBuf);
2188 }
2189
2190 /*
2191  * refreshMatViewData -
2192  *        load or refresh the contents of a single materialized view
2193  *
2194  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
2195  * statement.
2196  */
2197 static void
2198 refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
2199 {
2200         TableInfo  *tbinfo = tdinfo->tdtable;
2201         PQExpBuffer q;
2202
2203         /* If the materialized view is not flagged as populated, skip this. */
2204         if (!tbinfo->relispopulated)
2205                 return;
2206
2207         q = createPQExpBuffer();
2208
2209         appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
2210                                           fmtQualifiedDumpable(tbinfo));
2211
2212         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2213                 ArchiveEntry(fout,
2214                                          tdinfo->dobj.catId,    /* catalog ID */
2215                                          tdinfo->dobj.dumpId,   /* dump ID */
2216                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
2217                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
2218                                                                   .owner = tbinfo->rolname,
2219                                                                   .description = "MATERIALIZED VIEW DATA",
2220                                                                   .section = SECTION_POST_DATA,
2221                                                                   .createStmt = q->data,
2222                                                                   .deps = tdinfo->dobj.dependencies,
2223                                                                   .nDeps = tdinfo->dobj.nDeps));
2224
2225         destroyPQExpBuffer(q);
2226 }
2227
2228 /*
2229  * getTableData -
2230  *        set up dumpable objects representing the contents of tables
2231  */
2232 static void
2233 getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, char relkind)
2234 {
2235         int                     i;
2236
2237         for (i = 0; i < numTables; i++)
2238         {
2239                 if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
2240                         (!relkind || tblinfo[i].relkind == relkind))
2241                         makeTableDataInfo(dopt, &(tblinfo[i]));
2242         }
2243 }
2244
2245 /*
2246  * Make a dumpable object for the data of this specific table
2247  *
2248  * Note: we make a TableDataInfo if and only if we are going to dump the
2249  * table data; the "dump" flag in such objects isn't used.
2250  */
2251 static void
2252 makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
2253 {
2254         TableDataInfo *tdinfo;
2255
2256         /*
2257          * Nothing to do if we already decided to dump the table.  This will
2258          * happen for "config" tables.
2259          */
2260         if (tbinfo->dataObj != NULL)
2261                 return;
2262
2263         /* Skip VIEWs (no data to dump) */
2264         if (tbinfo->relkind == RELKIND_VIEW)
2265                 return;
2266         /* Skip FOREIGN TABLEs (no data to dump) */
2267         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2268                 return;
2269         /* Skip partitioned tables (data in partitions) */
2270         if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
2271                 return;
2272
2273         /* Don't dump data in unlogged tables, if so requested */
2274         if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
2275                 dopt->no_unlogged_table_data)
2276                 return;
2277
2278         /* Check that the data is not explicitly excluded */
2279         if (simple_oid_list_member(&tabledata_exclude_oids,
2280                                                            tbinfo->dobj.catId.oid))
2281                 return;
2282
2283         /* OK, let's dump it */
2284         tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
2285
2286         if (tbinfo->relkind == RELKIND_MATVIEW)
2287                 tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
2288         else if (tbinfo->relkind == RELKIND_SEQUENCE)
2289                 tdinfo->dobj.objType = DO_SEQUENCE_SET;
2290         else
2291                 tdinfo->dobj.objType = DO_TABLE_DATA;
2292
2293         /*
2294          * Note: use tableoid 0 so that this object won't be mistaken for
2295          * something that pg_depend entries apply to.
2296          */
2297         tdinfo->dobj.catId.tableoid = 0;
2298         tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
2299         AssignDumpId(&tdinfo->dobj);
2300         tdinfo->dobj.name = tbinfo->dobj.name;
2301         tdinfo->dobj.namespace = tbinfo->dobj.namespace;
2302         tdinfo->tdtable = tbinfo;
2303         tdinfo->filtercond = NULL;      /* might get set later */
2304         addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
2305
2306         tbinfo->dataObj = tdinfo;
2307 }
2308
2309 /*
2310  * The refresh for a materialized view must be dependent on the refresh for
2311  * any materialized view that this one is dependent on.
2312  *
2313  * This must be called after all the objects are created, but before they are
2314  * sorted.
2315  */
2316 static void
2317 buildMatViewRefreshDependencies(Archive *fout)
2318 {
2319         PQExpBuffer query;
2320         PGresult   *res;
2321         int                     ntups,
2322                                 i;
2323         int                     i_classid,
2324                                 i_objid,
2325                                 i_refobjid;
2326
2327         /* No Mat Views before 9.3. */
2328         if (fout->remoteVersion < 90300)
2329                 return;
2330
2331         query = createPQExpBuffer();
2332
2333         appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
2334                                                  "( "
2335                                                  "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
2336                                                  "FROM pg_depend d1 "
2337                                                  "JOIN pg_class c1 ON c1.oid = d1.objid "
2338                                                  "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
2339                                                  " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
2340                                                  "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
2341                                                  "AND d2.objid = r1.oid "
2342                                                  "AND d2.refobjid <> d1.objid "
2343                                                  "JOIN pg_class c2 ON c2.oid = d2.refobjid "
2344                                                  "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2345                                                  CppAsString2(RELKIND_VIEW) ") "
2346                                                  "WHERE d1.classid = 'pg_class'::regclass "
2347                                                  "UNION "
2348                                                  "SELECT w.objid, d3.refobjid, c3.relkind "
2349                                                  "FROM w "
2350                                                  "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
2351                                                  "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
2352                                                  "AND d3.objid = r3.oid "
2353                                                  "AND d3.refobjid <> w.refobjid "
2354                                                  "JOIN pg_class c3 ON c3.oid = d3.refobjid "
2355                                                  "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2356                                                  CppAsString2(RELKIND_VIEW) ") "
2357                                                  ") "
2358                                                  "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
2359                                                  "FROM w "
2360                                                  "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
2361
2362         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2363
2364         ntups = PQntuples(res);
2365
2366         i_classid = PQfnumber(res, "classid");
2367         i_objid = PQfnumber(res, "objid");
2368         i_refobjid = PQfnumber(res, "refobjid");
2369
2370         for (i = 0; i < ntups; i++)
2371         {
2372                 CatalogId       objId;
2373                 CatalogId       refobjId;
2374                 DumpableObject *dobj;
2375                 DumpableObject *refdobj;
2376                 TableInfo  *tbinfo;
2377                 TableInfo  *reftbinfo;
2378
2379                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
2380                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
2381                 refobjId.tableoid = objId.tableoid;
2382                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
2383
2384                 dobj = findObjectByCatalogId(objId);
2385                 if (dobj == NULL)
2386                         continue;
2387
2388                 Assert(dobj->objType == DO_TABLE);
2389                 tbinfo = (TableInfo *) dobj;
2390                 Assert(tbinfo->relkind == RELKIND_MATVIEW);
2391                 dobj = (DumpableObject *) tbinfo->dataObj;
2392                 if (dobj == NULL)
2393                         continue;
2394                 Assert(dobj->objType == DO_REFRESH_MATVIEW);
2395
2396                 refdobj = findObjectByCatalogId(refobjId);
2397                 if (refdobj == NULL)
2398                         continue;
2399
2400                 Assert(refdobj->objType == DO_TABLE);
2401                 reftbinfo = (TableInfo *) refdobj;
2402                 Assert(reftbinfo->relkind == RELKIND_MATVIEW);
2403                 refdobj = (DumpableObject *) reftbinfo->dataObj;
2404                 if (refdobj == NULL)
2405                         continue;
2406                 Assert(refdobj->objType == DO_REFRESH_MATVIEW);
2407
2408                 addObjectDependency(dobj, refdobj->dumpId);
2409
2410                 if (!reftbinfo->relispopulated)
2411                         tbinfo->relispopulated = false;
2412         }
2413
2414         PQclear(res);
2415
2416         destroyPQExpBuffer(query);
2417 }
2418
2419 /*
2420  * getTableDataFKConstraints -
2421  *        add dump-order dependencies reflecting foreign key constraints
2422  *
2423  * This code is executed only in a data-only dump --- in schema+data dumps
2424  * we handle foreign key issues by not creating the FK constraints until
2425  * after the data is loaded.  In a data-only dump, however, we want to
2426  * order the table data objects in such a way that a table's referenced
2427  * tables are restored first.  (In the presence of circular references or
2428  * self-references this may be impossible; we'll detect and complain about
2429  * that during the dependency sorting step.)
2430  */
2431 static void
2432 getTableDataFKConstraints(void)
2433 {
2434         DumpableObject **dobjs;
2435         int                     numObjs;
2436         int                     i;
2437
2438         /* Search through all the dumpable objects for FK constraints */
2439         getDumpableObjects(&dobjs, &numObjs);
2440         for (i = 0; i < numObjs; i++)
2441         {
2442                 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
2443                 {
2444                         ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
2445                         TableInfo  *ftable;
2446
2447                         /* Not interesting unless both tables are to be dumped */
2448                         if (cinfo->contable == NULL ||
2449                                 cinfo->contable->dataObj == NULL)
2450                                 continue;
2451                         ftable = findTableByOid(cinfo->confrelid);
2452                         if (ftable == NULL ||
2453                                 ftable->dataObj == NULL)
2454                                 continue;
2455
2456                         /*
2457                          * Okay, make referencing table's TABLE_DATA object depend on the
2458                          * referenced table's TABLE_DATA object.
2459                          */
2460                         addObjectDependency(&cinfo->contable->dataObj->dobj,
2461                                                                 ftable->dataObj->dobj.dumpId);
2462                 }
2463         }
2464         free(dobjs);
2465 }
2466
2467
2468 /*
2469  * guessConstraintInheritance:
2470  *      In pre-8.4 databases, we can't tell for certain which constraints
2471  *      are inherited.  We assume a CHECK constraint is inherited if its name
2472  *      matches the name of any constraint in the parent.  Originally this code
2473  *      tried to compare the expression texts, but that can fail for various
2474  *      reasons --- for example, if the parent and child tables are in different
2475  *      schemas, reverse-listing of function calls may produce different text
2476  *      (schema-qualified or not) depending on search path.
2477  *
2478  *      In 8.4 and up we can rely on the conislocal field to decide which
2479  *      constraints must be dumped; much safer.
2480  *
2481  *      This function assumes all conislocal flags were initialized to true.
2482  *      It clears the flag on anything that seems to be inherited.
2483  */
2484 static void
2485 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
2486 {
2487         int                     i,
2488                                 j,
2489                                 k;
2490
2491         for (i = 0; i < numTables; i++)
2492         {
2493                 TableInfo  *tbinfo = &(tblinfo[i]);
2494                 int                     numParents;
2495                 TableInfo **parents;
2496                 TableInfo  *parent;
2497
2498                 /* Sequences and views never have parents */
2499                 if (tbinfo->relkind == RELKIND_SEQUENCE ||
2500                         tbinfo->relkind == RELKIND_VIEW)
2501                         continue;
2502
2503                 /* Don't bother computing anything for non-target tables, either */
2504                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
2505                         continue;
2506
2507                 numParents = tbinfo->numParents;
2508                 parents = tbinfo->parents;
2509
2510                 if (numParents == 0)
2511                         continue;                       /* nothing to see here, move along */
2512
2513                 /* scan for inherited CHECK constraints */
2514                 for (j = 0; j < tbinfo->ncheck; j++)
2515                 {
2516                         ConstraintInfo *constr;
2517
2518                         constr = &(tbinfo->checkexprs[j]);
2519
2520                         for (k = 0; k < numParents; k++)
2521                         {
2522                                 int                     l;
2523
2524                                 parent = parents[k];
2525                                 for (l = 0; l < parent->ncheck; l++)
2526                                 {
2527                                         ConstraintInfo *pconstr = &(parent->checkexprs[l]);
2528
2529                                         if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
2530                                         {
2531                                                 constr->conislocal = false;
2532                                                 break;
2533                                         }
2534                                 }
2535                                 if (!constr->conislocal)
2536                                         break;
2537                         }
2538                 }
2539         }
2540 }
2541
2542
2543 /*
2544  * dumpDatabase:
2545  *      dump the database definition
2546  */
2547 static void
2548 dumpDatabase(Archive *fout)
2549 {
2550         DumpOptions *dopt = fout->dopt;
2551         PQExpBuffer dbQry = createPQExpBuffer();
2552         PQExpBuffer delQry = createPQExpBuffer();
2553         PQExpBuffer creaQry = createPQExpBuffer();
2554         PQExpBuffer labelq = createPQExpBuffer();
2555         PGconn     *conn = GetConnection(fout);
2556         PGresult   *res;
2557         int                     i_tableoid,
2558                                 i_oid,
2559                                 i_datname,
2560                                 i_dba,
2561                                 i_encoding,
2562                                 i_collate,
2563                                 i_ctype,
2564                                 i_frozenxid,
2565                                 i_minmxid,
2566                                 i_datacl,
2567                                 i_rdatacl,
2568                                 i_datistemplate,
2569                                 i_datconnlimit,
2570                                 i_tablespace;
2571         CatalogId       dbCatId;
2572         DumpId          dbDumpId;
2573         const char *datname,
2574                            *dba,
2575                            *encoding,
2576                            *collate,
2577                            *ctype,
2578                            *datacl,
2579                            *rdatacl,
2580                            *datistemplate,
2581                            *datconnlimit,
2582                            *tablespace;
2583         uint32          frozenxid,
2584                                 minmxid;
2585         char       *qdatname;
2586
2587         if (g_verbose)
2588                 write_msg(NULL, "saving database definition\n");
2589
2590         /* Fetch the database-level properties for this database */
2591         if (fout->remoteVersion >= 90600)
2592         {
2593                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2594                                                   "(%s datdba) AS dba, "
2595                                                   "pg_encoding_to_char(encoding) AS encoding, "
2596                                                   "datcollate, datctype, datfrozenxid, datminmxid, "
2597                                                   "(SELECT array_agg(acl ORDER BY acl::text COLLATE \"C\") FROM ( "
2598                                                   "  SELECT unnest(coalesce(datacl,acldefault('d',datdba))) AS acl "
2599                                                   "  EXCEPT SELECT unnest(acldefault('d',datdba))) as datacls)"
2600                                                   " AS datacl, "
2601                                                   "(SELECT array_agg(acl ORDER BY acl::text COLLATE \"C\") FROM ( "
2602                                                   "  SELECT unnest(acldefault('d',datdba)) AS acl "
2603                                                   "  EXCEPT SELECT unnest(coalesce(datacl,acldefault('d',datdba)))) as rdatacls)"
2604                                                   " AS rdatacl, "
2605                                                   "datistemplate, datconnlimit, "
2606                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2607                                                   "shobj_description(oid, 'pg_database') AS description "
2608
2609                                                   "FROM pg_database "
2610                                                   "WHERE datname = current_database()",
2611                                                   username_subquery);
2612         }
2613         else if (fout->remoteVersion >= 90300)
2614         {
2615                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2616                                                   "(%s datdba) AS dba, "
2617                                                   "pg_encoding_to_char(encoding) AS encoding, "
2618                                                   "datcollate, datctype, datfrozenxid, datminmxid, "
2619                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2620                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2621                                                   "shobj_description(oid, 'pg_database') AS description "
2622
2623                                                   "FROM pg_database "
2624                                                   "WHERE datname = current_database()",
2625                                                   username_subquery);
2626         }
2627         else if (fout->remoteVersion >= 80400)
2628         {
2629                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2630                                                   "(%s datdba) AS dba, "
2631                                                   "pg_encoding_to_char(encoding) AS encoding, "
2632                                                   "datcollate, datctype, datfrozenxid, 0 AS datminmxid, "
2633                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2634                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2635                                                   "shobj_description(oid, 'pg_database') AS description "
2636
2637                                                   "FROM pg_database "
2638                                                   "WHERE datname = current_database()",
2639                                                   username_subquery);
2640         }
2641         else if (fout->remoteVersion >= 80200)
2642         {
2643                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2644                                                   "(%s datdba) AS dba, "
2645                                                   "pg_encoding_to_char(encoding) AS encoding, "
2646                                                   "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2647                                                   "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2648                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2649                                                   "shobj_description(oid, 'pg_database') AS description "
2650
2651                                                   "FROM pg_database "
2652                                                   "WHERE datname = current_database()",
2653                                                   username_subquery);
2654         }
2655         else
2656         {
2657                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2658                                                   "(%s datdba) AS dba, "
2659                                                   "pg_encoding_to_char(encoding) AS encoding, "
2660                                                   "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2661                                                   "datacl, '' as rdatacl, datistemplate, "
2662                                                   "-1 as datconnlimit, "
2663                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
2664                                                   "FROM pg_database "
2665                                                   "WHERE datname = current_database()",
2666                                                   username_subquery);
2667         }
2668
2669         res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
2670
2671         i_tableoid = PQfnumber(res, "tableoid");
2672         i_oid = PQfnumber(res, "oid");
2673         i_datname = PQfnumber(res, "datname");
2674         i_dba = PQfnumber(res, "dba");
2675         i_encoding = PQfnumber(res, "encoding");
2676         i_collate = PQfnumber(res, "datcollate");
2677         i_ctype = PQfnumber(res, "datctype");
2678         i_frozenxid = PQfnumber(res, "datfrozenxid");
2679         i_minmxid = PQfnumber(res, "datminmxid");
2680         i_datacl = PQfnumber(res, "datacl");
2681         i_rdatacl = PQfnumber(res, "rdatacl");
2682         i_datistemplate = PQfnumber(res, "datistemplate");
2683         i_datconnlimit = PQfnumber(res, "datconnlimit");
2684         i_tablespace = PQfnumber(res, "tablespace");
2685
2686         dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
2687         dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
2688         datname = PQgetvalue(res, 0, i_datname);
2689         dba = PQgetvalue(res, 0, i_dba);
2690         encoding = PQgetvalue(res, 0, i_encoding);
2691         collate = PQgetvalue(res, 0, i_collate);
2692         ctype = PQgetvalue(res, 0, i_ctype);
2693         frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
2694         minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
2695         datacl = PQgetvalue(res, 0, i_datacl);
2696         rdatacl = PQgetvalue(res, 0, i_rdatacl);
2697         datistemplate = PQgetvalue(res, 0, i_datistemplate);
2698         datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
2699         tablespace = PQgetvalue(res, 0, i_tablespace);
2700
2701         qdatname = pg_strdup(fmtId(datname));
2702
2703         /*
2704          * Prepare the CREATE DATABASE command.  We must specify encoding, locale,
2705          * and tablespace since those can't be altered later.  Other DB properties
2706          * are left to the DATABASE PROPERTIES entry, so that they can be applied
2707          * after reconnecting to the target DB.
2708          */
2709         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
2710                                           qdatname);
2711         if (strlen(encoding) > 0)
2712         {
2713                 appendPQExpBufferStr(creaQry, " ENCODING = ");
2714                 appendStringLiteralAH(creaQry, encoding, fout);
2715         }
2716         if (strlen(collate) > 0)
2717         {
2718                 appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
2719                 appendStringLiteralAH(creaQry, collate, fout);
2720         }
2721         if (strlen(ctype) > 0)
2722         {
2723                 appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
2724                 appendStringLiteralAH(creaQry, ctype, fout);
2725         }
2726
2727         /*
2728          * Note: looking at dopt->outputNoTablespaces here is completely the wrong
2729          * thing; the decision whether to specify a tablespace should be left till
2730          * pg_restore, so that pg_restore --no-tablespaces applies.  Ideally we'd
2731          * label the DATABASE entry with the tablespace and let the normal
2732          * tablespace selection logic work ... but CREATE DATABASE doesn't pay
2733          * attention to default_tablespace, so that won't work.
2734          */
2735         if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
2736                 !dopt->outputNoTablespaces)
2737                 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
2738                                                   fmtId(tablespace));
2739         appendPQExpBufferStr(creaQry, ";\n");
2740
2741         appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
2742                                           qdatname);
2743
2744         dbDumpId = createDumpId();
2745
2746         ArchiveEntry(fout,
2747                                  dbCatId,               /* catalog ID */
2748                                  dbDumpId,              /* dump ID */
2749                                  ARCHIVE_OPTS(.tag = datname,
2750                                                           .owner = dba,
2751                                                           .description = "DATABASE",
2752                                                           .section = SECTION_PRE_DATA,
2753                                                           .createStmt = creaQry->data,
2754                                                           .dropStmt = delQry->data));
2755
2756         /* Compute correct tag for archive entry */
2757         appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
2758
2759         /* Dump DB comment if any */
2760         if (fout->remoteVersion >= 80200)
2761         {
2762                 /*
2763                  * 8.2 and up keep comments on shared objects in a shared table, so we
2764                  * cannot use the dumpComment() code used for other database objects.
2765                  * Be careful that the ArchiveEntry parameters match that function.
2766                  */
2767                 char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
2768
2769                 if (comment && *comment && !dopt->no_comments)
2770                 {
2771                         resetPQExpBuffer(dbQry);
2772
2773                         /*
2774                          * Generates warning when loaded into a differently-named
2775                          * database.
2776                          */
2777                         appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
2778                         appendStringLiteralAH(dbQry, comment, fout);
2779                         appendPQExpBufferStr(dbQry, ";\n");
2780
2781                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2782                                                  ARCHIVE_OPTS(.tag = labelq->data,
2783                                                                           .owner = dba,
2784                                                                           .description = "COMMENT",
2785                                                                           .section = SECTION_NONE,
2786                                                                           .createStmt = dbQry->data,
2787                                                                           .deps = &dbDumpId,
2788                                                                           .nDeps = 1));
2789                 }
2790         }
2791         else
2792         {
2793                 dumpComment(fout, "DATABASE", qdatname, NULL, dba,
2794                                         dbCatId, 0, dbDumpId);
2795         }
2796
2797         /* Dump DB security label, if enabled */
2798         if (!dopt->no_security_labels && fout->remoteVersion >= 90200)
2799         {
2800                 PGresult   *shres;
2801                 PQExpBuffer seclabelQry;
2802
2803                 seclabelQry = createPQExpBuffer();
2804
2805                 buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
2806                 shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
2807                 resetPQExpBuffer(seclabelQry);
2808                 emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
2809                 if (seclabelQry->len > 0)
2810                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2811                                                  ARCHIVE_OPTS(.tag = labelq->data,
2812                                                                           .owner = dba,
2813                                                                           .description = "SECURITY LABEL",
2814                                                                           .section = SECTION_NONE,
2815                                                                           .createStmt = seclabelQry->data,
2816                                                                           .deps = &dbDumpId,
2817                                                                           .nDeps = 1));
2818                 destroyPQExpBuffer(seclabelQry);
2819                 PQclear(shres);
2820         }
2821
2822         /*
2823          * Dump ACL if any.  Note that we do not support initial privileges
2824          * (pg_init_privs) on databases.
2825          */
2826         dumpACL(fout, dbCatId, dbDumpId, "DATABASE",
2827                         qdatname, NULL, NULL,
2828                         dba, datacl, rdatacl, "", "");
2829
2830         /*
2831          * Now construct a DATABASE PROPERTIES archive entry to restore any
2832          * non-default database-level properties.  (The reason this must be
2833          * separate is that we cannot put any additional commands into the TOC
2834          * entry that has CREATE DATABASE.  pg_restore would execute such a group
2835          * in an implicit transaction block, and the backend won't allow CREATE
2836          * DATABASE in that context.)
2837          */
2838         resetPQExpBuffer(creaQry);
2839         resetPQExpBuffer(delQry);
2840
2841         if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
2842                 appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
2843                                                   qdatname, datconnlimit);
2844
2845         if (strcmp(datistemplate, "t") == 0)
2846         {
2847                 appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
2848                                                   qdatname);
2849
2850                 /*
2851                  * The backend won't accept DROP DATABASE on a template database.  We
2852                  * can deal with that by removing the template marking before the DROP
2853                  * gets issued.  We'd prefer to use ALTER DATABASE IF EXISTS here, but
2854                  * since no such command is currently supported, fake it with a direct
2855                  * UPDATE on pg_database.
2856                  */
2857                 appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
2858                                                          "SET datistemplate = false WHERE datname = ");
2859                 appendStringLiteralAH(delQry, datname, fout);
2860                 appendPQExpBufferStr(delQry, ";\n");
2861         }
2862
2863         /* Add database-specific SET options */
2864         dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
2865
2866         /*
2867          * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
2868          * entry, too, for lack of a better place.
2869          */
2870         if (dopt->binary_upgrade)
2871         {
2872                 appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
2873                 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
2874                                                   "SET datfrozenxid = '%u', datminmxid = '%u'\n"
2875                                                   "WHERE datname = ",
2876                                                   frozenxid, minmxid);
2877                 appendStringLiteralAH(creaQry, datname, fout);
2878                 appendPQExpBufferStr(creaQry, ";\n");
2879         }
2880
2881         if (creaQry->len > 0)
2882                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
2883                                          ARCHIVE_OPTS(.tag = datname,
2884                                                                   .owner = dba,
2885                                                                   .description = "DATABASE PROPERTIES",
2886                                                                   .section = SECTION_PRE_DATA,
2887                                                                   .createStmt = creaQry->data,
2888                                                                   .dropStmt = delQry->data,
2889                                                                   .deps = &dbDumpId));
2890
2891         /*
2892          * pg_largeobject comes from the old system intact, so set its
2893          * relfrozenxids and relminmxids.
2894          */
2895         if (dopt->binary_upgrade)
2896         {
2897                 PGresult   *lo_res;
2898                 PQExpBuffer loFrozenQry = createPQExpBuffer();
2899                 PQExpBuffer loOutQry = createPQExpBuffer();
2900                 int                     i_relfrozenxid,
2901                                         i_relminmxid;
2902
2903                 /*
2904                  * pg_largeobject
2905                  */
2906                 if (fout->remoteVersion >= 90300)
2907                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
2908                                                           "FROM pg_catalog.pg_class\n"
2909                                                           "WHERE oid = %u;\n",
2910                                                           LargeObjectRelationId);
2911                 else
2912                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
2913                                                           "FROM pg_catalog.pg_class\n"
2914                                                           "WHERE oid = %u;\n",
2915                                                           LargeObjectRelationId);
2916
2917                 lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2918
2919                 i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2920                 i_relminmxid = PQfnumber(lo_res, "relminmxid");
2921
2922                 appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
2923                 appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2924                                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
2925                                                   "WHERE oid = %u;\n",
2926                                                   atooid(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2927                                                   atooid(PQgetvalue(lo_res, 0, i_relminmxid)),
2928                                                   LargeObjectRelationId);
2929                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
2930                                          ARCHIVE_OPTS(.tag = "pg_largeobject",
2931                                                                   .description = "pg_largeobject",
2932                                                                   .section = SECTION_PRE_DATA,
2933                                                                   .createStmt = loOutQry->data));
2934
2935                 PQclear(lo_res);
2936
2937                 destroyPQExpBuffer(loFrozenQry);
2938                 destroyPQExpBuffer(loOutQry);
2939         }
2940
2941         PQclear(res);
2942
2943         free(qdatname);
2944         destroyPQExpBuffer(dbQry);
2945         destroyPQExpBuffer(delQry);
2946         destroyPQExpBuffer(creaQry);
2947         destroyPQExpBuffer(labelq);
2948 }
2949
2950 /*
2951  * Collect any database-specific or role-and-database-specific SET options
2952  * for this database, and append them to outbuf.
2953  */
2954 static void
2955 dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
2956                                    const char *dbname, Oid dboid)
2957 {
2958         PGconn     *conn = GetConnection(AH);
2959         PQExpBuffer buf = createPQExpBuffer();
2960         PGresult   *res;
2961         int                     count = 1;
2962
2963         /*
2964          * First collect database-specific options.  Pre-8.4 server versions lack
2965          * unnest(), so we do this the hard way by querying once per subscript.
2966          */
2967         for (;;)
2968         {
2969                 if (AH->remoteVersion >= 90000)
2970                         printfPQExpBuffer(buf, "SELECT setconfig[%d] FROM pg_db_role_setting "
2971                                                           "WHERE setrole = 0 AND setdatabase = '%u'::oid",
2972                                                           count, dboid);
2973                 else
2974                         printfPQExpBuffer(buf, "SELECT datconfig[%d] FROM pg_database WHERE oid = '%u'::oid", count, dboid);
2975
2976                 res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
2977
2978                 if (PQntuples(res) == 1 &&
2979                         !PQgetisnull(res, 0, 0))
2980                 {
2981                         makeAlterConfigCommand(conn, PQgetvalue(res, 0, 0),
2982                                                                    "DATABASE", dbname, NULL, NULL,
2983                                                                    outbuf);
2984                         PQclear(res);
2985                         count++;
2986                 }
2987                 else
2988                 {
2989                         PQclear(res);
2990                         break;
2991                 }
2992         }
2993
2994         /* Now look for role-and-database-specific options */
2995         if (AH->remoteVersion >= 90000)
2996         {
2997                 /* Here we can assume we have unnest() */
2998                 printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
2999                                                   "FROM pg_db_role_setting s, pg_roles r "
3000                                                   "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
3001                                                   dboid);
3002
3003                 res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3004
3005                 if (PQntuples(res) > 0)
3006                 {
3007                         int                     i;
3008
3009                         for (i = 0; i < PQntuples(res); i++)
3010                                 makeAlterConfigCommand(conn, PQgetvalue(res, i, 1),
3011                                                                            "ROLE", PQgetvalue(res, i, 0),
3012                                                                            "DATABASE", dbname,
3013                                                                            outbuf);
3014                 }
3015
3016                 PQclear(res);
3017         }
3018
3019         destroyPQExpBuffer(buf);
3020 }
3021
3022 /*
3023  * dumpEncoding: put the correct encoding into the archive
3024  */
3025 static void
3026 dumpEncoding(Archive *AH)
3027 {
3028         const char *encname = pg_encoding_to_char(AH->encoding);
3029         PQExpBuffer qry = createPQExpBuffer();
3030
3031         if (g_verbose)
3032                 write_msg(NULL, "saving encoding = %s\n", encname);
3033
3034         appendPQExpBufferStr(qry, "SET client_encoding = ");
3035         appendStringLiteralAH(qry, encname, AH);
3036         appendPQExpBufferStr(qry, ";\n");
3037
3038         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3039                                  ARCHIVE_OPTS(.tag = "ENCODING",
3040                                                           .description = "ENCODING",
3041                                                           .section = SECTION_PRE_DATA,
3042                                                           .createStmt = qry->data));
3043
3044         destroyPQExpBuffer(qry);
3045 }
3046
3047
3048 /*
3049  * dumpStdStrings: put the correct escape string behavior into the archive
3050  */
3051 static void
3052 dumpStdStrings(Archive *AH)
3053 {
3054         const char *stdstrings = AH->std_strings ? "on" : "off";
3055         PQExpBuffer qry = createPQExpBuffer();
3056
3057         if (g_verbose)
3058                 write_msg(NULL, "saving standard_conforming_strings = %s\n",
3059                                   stdstrings);
3060
3061         appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
3062                                           stdstrings);
3063
3064         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3065                                  ARCHIVE_OPTS(.tag = "STDSTRINGS",
3066                                                           .description = "STDSTRINGS",
3067                                                           .section = SECTION_PRE_DATA,
3068                                                           .createStmt = qry->data));
3069
3070         destroyPQExpBuffer(qry);
3071 }
3072
3073 /*
3074  * dumpSearchPath: record the active search_path in the archive
3075  */
3076 static void
3077 dumpSearchPath(Archive *AH)
3078 {
3079         PQExpBuffer qry = createPQExpBuffer();
3080         PQExpBuffer path = createPQExpBuffer();
3081         PGresult   *res;
3082         char      **schemanames = NULL;
3083         int                     nschemanames = 0;
3084         int                     i;
3085
3086         /*
3087          * We use the result of current_schemas(), not the search_path GUC,
3088          * because that might contain wildcards such as "$user", which won't
3089          * necessarily have the same value during restore.  Also, this way avoids
3090          * listing schemas that may appear in search_path but not actually exist,
3091          * which seems like a prudent exclusion.
3092          */
3093         res = ExecuteSqlQueryForSingleRow(AH,
3094                                                                           "SELECT pg_catalog.current_schemas(false)");
3095
3096         if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
3097                 exit_horribly(NULL, "could not parse result of current_schemas()\n");
3098
3099         /*
3100          * We use set_config(), not a simple "SET search_path" command, because
3101          * the latter has less-clean behavior if the search path is empty.  While
3102          * that's likely to get fixed at some point, it seems like a good idea to
3103          * be as backwards-compatible as possible in what we put into archives.
3104          */
3105         for (i = 0; i < nschemanames; i++)
3106         {
3107                 if (i > 0)
3108                         appendPQExpBufferStr(path, ", ");
3109                 appendPQExpBufferStr(path, fmtId(schemanames[i]));
3110         }
3111
3112         appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
3113         appendStringLiteralAH(qry, path->data, AH);
3114         appendPQExpBufferStr(qry, ", false);\n");
3115
3116         if (g_verbose)
3117                 write_msg(NULL, "saving search_path = %s\n", path->data);
3118
3119         ArchiveEntry(AH, nilCatalogId, createDumpId(),
3120                                  ARCHIVE_OPTS(.tag = "SEARCHPATH",
3121                                                           .description = "SEARCHPATH",
3122                                                           .section = SECTION_PRE_DATA,
3123                                                           .createStmt = qry->data));
3124
3125         /* Also save it in AH->searchpath, in case we're doing plain text dump */
3126         AH->searchpath = pg_strdup(qry->data);
3127
3128         if (schemanames)
3129                 free(schemanames);
3130         PQclear(res);
3131         destroyPQExpBuffer(qry);
3132         destroyPQExpBuffer(path);
3133 }
3134
3135
3136 /*
3137  * getBlobs:
3138  *      Collect schema-level data about large objects
3139  */
3140 static void
3141 getBlobs(Archive *fout)
3142 {
3143         DumpOptions *dopt = fout->dopt;
3144         PQExpBuffer blobQry = createPQExpBuffer();
3145         BlobInfo   *binfo;
3146         DumpableObject *bdata;
3147         PGresult   *res;
3148         int                     ntups;
3149         int                     i;
3150         int                     i_oid;
3151         int                     i_lomowner;
3152         int                     i_lomacl;
3153         int                     i_rlomacl;
3154         int                     i_initlomacl;
3155         int                     i_initrlomacl;
3156
3157         /* Verbose message */
3158         if (g_verbose)
3159                 write_msg(NULL, "reading large objects\n");
3160
3161         /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
3162         if (fout->remoteVersion >= 90600)
3163         {
3164                 PQExpBuffer acl_subquery = createPQExpBuffer();
3165                 PQExpBuffer racl_subquery = createPQExpBuffer();
3166                 PQExpBuffer init_acl_subquery = createPQExpBuffer();
3167                 PQExpBuffer init_racl_subquery = createPQExpBuffer();
3168
3169                 buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
3170                                                 init_racl_subquery, "l.lomacl", "l.lomowner", "'L'",
3171                                                 dopt->binary_upgrade);
3172
3173                 appendPQExpBuffer(blobQry,
3174                                                   "SELECT l.oid, (%s l.lomowner) AS rolname, "
3175                                                   "%s AS lomacl, "
3176                                                   "%s AS rlomacl, "
3177                                                   "%s AS initlomacl, "
3178                                                   "%s AS initrlomacl "
3179                                                   "FROM pg_largeobject_metadata l "
3180                                                   "LEFT JOIN pg_init_privs pip ON "
3181                                                   "(l.oid = pip.objoid "
3182                                                   "AND pip.classoid = 'pg_largeobject'::regclass "
3183                                                   "AND pip.objsubid = 0) ",
3184                                                   username_subquery,
3185                                                   acl_subquery->data,
3186                                                   racl_subquery->data,
3187                                                   init_acl_subquery->data,
3188                                                   init_racl_subquery->data);
3189
3190                 destroyPQExpBuffer(acl_subquery);
3191                 destroyPQExpBuffer(racl_subquery);
3192                 destroyPQExpBuffer(init_acl_subquery);
3193                 destroyPQExpBuffer(init_racl_subquery);
3194         }
3195         else if (fout->remoteVersion >= 90000)
3196                 appendPQExpBuffer(blobQry,
3197                                                   "SELECT oid, (%s lomowner) AS rolname, lomacl, "
3198                                                   "NULL AS rlomacl, NULL AS initlomacl, "
3199                                                   "NULL AS initrlomacl "
3200                                                   " FROM pg_largeobject_metadata",
3201                                                   username_subquery);
3202         else
3203                 appendPQExpBufferStr(blobQry,
3204                                                          "SELECT DISTINCT loid AS oid, "
3205                                                          "NULL::name AS rolname, NULL::oid AS lomacl, "
3206                                                          "NULL::oid AS rlomacl, NULL::oid AS initlomacl, "
3207                                                          "NULL::oid AS initrlomacl "
3208                                                          " FROM pg_largeobject");
3209
3210         res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
3211
3212         i_oid = PQfnumber(res, "oid");
3213         i_lomowner = PQfnumber(res, "rolname");
3214         i_lomacl = PQfnumber(res, "lomacl");
3215         i_rlomacl = PQfnumber(res, "rlomacl");
3216         i_initlomacl = PQfnumber(res, "initlomacl");
3217         i_initrlomacl = PQfnumber(res, "initrlomacl");
3218
3219         ntups = PQntuples(res);
3220
3221         /*
3222          * Each large object has its own BLOB archive entry.
3223          */
3224         binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
3225
3226         for (i = 0; i < ntups; i++)
3227         {
3228                 binfo[i].dobj.objType = DO_BLOB;
3229                 binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
3230                 binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3231                 AssignDumpId(&binfo[i].dobj);
3232
3233                 binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oid));
3234                 binfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_lomowner));
3235                 binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, i_lomacl));
3236                 binfo[i].rblobacl = pg_strdup(PQgetvalue(res, i, i_rlomacl));
3237                 binfo[i].initblobacl = pg_strdup(PQgetvalue(res, i, i_initlomacl));
3238                 binfo[i].initrblobacl = pg_strdup(PQgetvalue(res, i, i_initrlomacl));
3239
3240                 if (PQgetisnull(res, i, i_lomacl) &&
3241                         PQgetisnull(res, i, i_rlomacl) &&
3242                         PQgetisnull(res, i, i_initlomacl) &&
3243                         PQgetisnull(res, i, i_initrlomacl))
3244                         binfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
3245
3246                 /*
3247                  * In binary-upgrade mode for blobs, we do *not* dump out the blob
3248                  * data, as it will be copied by pg_upgrade, which simply copies the
3249                  * pg_largeobject table. We *do* however dump out anything but the
3250                  * data, as pg_upgrade copies just pg_largeobject, but not
3251                  * pg_largeobject_metadata, after the dump is restored.
3252                  */
3253                 if (dopt->binary_upgrade)
3254                         binfo[i].dobj.dump &= ~DUMP_COMPONENT_DATA;
3255         }
3256
3257         /*
3258          * If we have any large objects, a "BLOBS" archive entry is needed. This
3259          * is just a placeholder for sorting; it carries no data now.
3260          */
3261         if (ntups > 0)
3262         {
3263                 bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
3264                 bdata->objType = DO_BLOB_DATA;
3265                 bdata->catId = nilCatalogId;
3266                 AssignDumpId(bdata);
3267                 bdata->name = pg_strdup("BLOBS");
3268         }
3269
3270         PQclear(res);
3271         destroyPQExpBuffer(blobQry);
3272 }
3273
3274 /*
3275  * dumpBlob
3276  *
3277  * dump the definition (metadata) of the given large object
3278  */
3279 static void
3280 dumpBlob(Archive *fout, BlobInfo *binfo)
3281 {
3282         PQExpBuffer cquery = createPQExpBuffer();
3283         PQExpBuffer dquery = createPQExpBuffer();
3284
3285         appendPQExpBuffer(cquery,
3286                                           "SELECT pg_catalog.lo_create('%s');\n",
3287                                           binfo->dobj.name);
3288
3289         appendPQExpBuffer(dquery,
3290                                           "SELECT pg_catalog.lo_unlink('%s');\n",
3291                                           binfo->dobj.name);
3292
3293         if (binfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
3294                 ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
3295                                          ARCHIVE_OPTS(.tag = binfo->dobj.name,
3296                                                                   .owner = binfo->rolname,
3297                                                                   .description = "BLOB",
3298                                                                   .section = SECTION_PRE_DATA,
3299                                                                   .createStmt = cquery->data,
3300                                                                   .dropStmt = dquery->data));
3301
3302         /* Dump comment if any */
3303         if (binfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3304                 dumpComment(fout, "LARGE OBJECT", binfo->dobj.name,
3305                                         NULL, binfo->rolname,
3306                                         binfo->dobj.catId, 0, binfo->dobj.dumpId);
3307
3308         /* Dump security label if any */
3309         if (binfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3310                 dumpSecLabel(fout, "LARGE OBJECT", binfo->dobj.name,
3311                                          NULL, binfo->rolname,
3312                                          binfo->dobj.catId, 0, binfo->dobj.dumpId);
3313
3314         /* Dump ACL if any */
3315         if (binfo->blobacl && (binfo->dobj.dump & DUMP_COMPONENT_ACL))
3316                 dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
3317                                 binfo->dobj.name, NULL,
3318                                 NULL, binfo->rolname, binfo->blobacl, binfo->rblobacl,
3319                                 binfo->initblobacl, binfo->initrblobacl);
3320
3321         destroyPQExpBuffer(cquery);
3322         destroyPQExpBuffer(dquery);
3323 }
3324
3325 /*
3326  * dumpBlobs:
3327  *      dump the data contents of all large objects
3328  */
3329 static int
3330 dumpBlobs(Archive *fout, void *arg)
3331 {
3332         const char *blobQry;
3333         const char *blobFetchQry;
3334         PGconn     *conn = GetConnection(fout);
3335         PGresult   *res;
3336         char            buf[LOBBUFSIZE];
3337         int                     ntups;
3338         int                     i;
3339         int                     cnt;
3340
3341         if (g_verbose)
3342                 write_msg(NULL, "saving large objects\n");
3343
3344         /*
3345          * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
3346          * the already-in-memory dumpable objects instead...
3347          */
3348         if (fout->remoteVersion >= 90000)
3349                 blobQry =
3350                         "DECLARE bloboid CURSOR FOR "
3351                         "SELECT oid FROM pg_largeobject_metadata ORDER BY 1";
3352         else
3353                 blobQry =
3354                         "DECLARE bloboid CURSOR FOR "
3355                         "SELECT DISTINCT loid FROM pg_largeobject ORDER BY 1";
3356
3357         ExecuteSqlStatement(fout, blobQry);
3358
3359         /* Command to fetch from cursor */
3360         blobFetchQry = "FETCH 1000 IN bloboid";
3361
3362         do
3363         {
3364                 /* Do a fetch */
3365                 res = ExecuteSqlQuery(fout, blobFetchQry, PGRES_TUPLES_OK);
3366
3367                 /* Process the tuples, if any */
3368                 ntups = PQntuples(res);
3369                 for (i = 0; i < ntups; i++)
3370                 {
3371                         Oid                     blobOid;
3372                         int                     loFd;
3373
3374                         blobOid = atooid(PQgetvalue(res, i, 0));
3375                         /* Open the BLOB */
3376                         loFd = lo_open(conn, blobOid, INV_READ);
3377                         if (loFd == -1)
3378                                 exit_horribly(NULL, "could not open large object %u: %s",
3379                                                           blobOid, PQerrorMessage(conn));
3380
3381                         StartBlob(fout, blobOid);
3382
3383                         /* Now read it in chunks, sending data to archive */
3384                         do
3385                         {
3386                                 cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
3387                                 if (cnt < 0)
3388                                         exit_horribly(NULL, "error reading large object %u: %s",
3389                                                                   blobOid, PQerrorMessage(conn));
3390
3391                                 WriteData(fout, buf, cnt);
3392                         } while (cnt > 0);
3393
3394                         lo_close(conn, loFd);
3395
3396                         EndBlob(fout, blobOid);
3397                 }
3398
3399                 PQclear(res);
3400         } while (ntups > 0);
3401
3402         return 1;
3403 }
3404
3405 /*
3406  * getPolicies
3407  *        get information about policies on a dumpable table.
3408  */
3409 void
3410 getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
3411 {
3412         PQExpBuffer query;
3413         PGresult   *res;
3414         PolicyInfo *polinfo;
3415         int                     i_oid;
3416         int                     i_tableoid;
3417         int                     i_polname;
3418         int                     i_polcmd;
3419         int                     i_polpermissive;
3420         int                     i_polroles;
3421         int                     i_polqual;
3422         int                     i_polwithcheck;
3423         int                     i,
3424                                 j,
3425                                 ntups;
3426
3427         if (fout->remoteVersion < 90500)
3428                 return;
3429
3430         query = createPQExpBuffer();
3431
3432         for (i = 0; i < numTables; i++)
3433         {
3434                 TableInfo  *tbinfo = &tblinfo[i];
3435
3436                 /* Ignore row security on tables not to be dumped */
3437                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
3438                         continue;
3439
3440                 if (g_verbose)
3441                         write_msg(NULL, "reading row security enabled for table \"%s.%s\"\n",
3442                                           tbinfo->dobj.namespace->dobj.name,
3443                                           tbinfo->dobj.name);
3444
3445                 /*
3446                  * Get row security enabled information for the table. We represent
3447                  * RLS being enabled on a table by creating a PolicyInfo object with
3448                  * null polname.
3449                  */
3450                 if (tbinfo->rowsec)
3451                 {
3452                         /*
3453                          * Note: use tableoid 0 so that this object won't be mistaken for
3454                          * something that pg_depend entries apply to.
3455                          */
3456                         polinfo = pg_malloc(sizeof(PolicyInfo));
3457                         polinfo->dobj.objType = DO_POLICY;
3458                         polinfo->dobj.catId.tableoid = 0;
3459                         polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
3460                         AssignDumpId(&polinfo->dobj);
3461                         polinfo->dobj.namespace = tbinfo->dobj.namespace;
3462                         polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
3463                         polinfo->poltable = tbinfo;
3464                         polinfo->polname = NULL;
3465                         polinfo->polcmd = '\0';
3466                         polinfo->polpermissive = 0;
3467                         polinfo->polroles = NULL;
3468                         polinfo->polqual = NULL;
3469                         polinfo->polwithcheck = NULL;
3470                 }
3471
3472                 if (g_verbose)
3473                         write_msg(NULL, "reading policies for table \"%s.%s\"\n",
3474                                           tbinfo->dobj.namespace->dobj.name,
3475                                           tbinfo->dobj.name);
3476
3477                 resetPQExpBuffer(query);
3478
3479                 /* Get the policies for the table. */
3480                 if (fout->remoteVersion >= 100000)
3481                         appendPQExpBuffer(query,
3482                                                           "SELECT oid, tableoid, pol.polname, pol.polcmd, pol.polpermissive, "
3483                                                           "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3484                                                           "   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, "
3485                                                           "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3486                                                           "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3487                                                           "FROM pg_catalog.pg_policy pol "
3488                                                           "WHERE polrelid = '%u'",
3489                                                           tbinfo->dobj.catId.oid);
3490                 else
3491                         appendPQExpBuffer(query,
3492                                                           "SELECT oid, tableoid, pol.polname, pol.polcmd, 't' as polpermissive, "
3493                                                           "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3494                                                           "   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, "
3495                                                           "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3496                                                           "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3497                                                           "FROM pg_catalog.pg_policy pol "
3498                                                           "WHERE polrelid = '%u'",
3499                                                           tbinfo->dobj.catId.oid);
3500                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3501
3502                 ntups = PQntuples(res);
3503
3504                 if (ntups == 0)
3505                 {
3506                         /*
3507                          * No explicit policies to handle (only the default-deny policy,
3508                          * which is handled as part of the table definition).  Clean up
3509                          * and return.
3510                          */
3511                         PQclear(res);
3512                         continue;
3513                 }
3514
3515                 i_oid = PQfnumber(res, "oid");
3516                 i_tableoid = PQfnumber(res, "tableoid");
3517                 i_polname = PQfnumber(res, "polname");
3518                 i_polcmd = PQfnumber(res, "polcmd");
3519                 i_polpermissive = PQfnumber(res, "polpermissive");
3520                 i_polroles = PQfnumber(res, "polroles");
3521                 i_polqual = PQfnumber(res, "polqual");
3522                 i_polwithcheck = PQfnumber(res, "polwithcheck");
3523
3524                 polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
3525
3526                 for (j = 0; j < ntups; j++)
3527                 {
3528                         polinfo[j].dobj.objType = DO_POLICY;
3529                         polinfo[j].dobj.catId.tableoid =
3530                                 atooid(PQgetvalue(res, j, i_tableoid));
3531                         polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3532                         AssignDumpId(&polinfo[j].dobj);
3533                         polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3534                         polinfo[j].poltable = tbinfo;
3535                         polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
3536                         polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
3537
3538                         polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
3539                         polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
3540
3541                         if (PQgetisnull(res, j, i_polroles))
3542                                 polinfo[j].polroles = NULL;
3543                         else
3544                                 polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
3545
3546                         if (PQgetisnull(res, j, i_polqual))
3547                                 polinfo[j].polqual = NULL;
3548                         else
3549                                 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
3550
3551                         if (PQgetisnull(res, j, i_polwithcheck))
3552                                 polinfo[j].polwithcheck = NULL;
3553                         else
3554                                 polinfo[j].polwithcheck
3555                                         = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
3556                 }
3557                 PQclear(res);
3558         }
3559         destroyPQExpBuffer(query);
3560 }
3561
3562 /*
3563  * dumpPolicy
3564  *        dump the definition of the given policy
3565  */
3566 static void
3567 dumpPolicy(Archive *fout, PolicyInfo *polinfo)
3568 {
3569         DumpOptions *dopt = fout->dopt;
3570         TableInfo  *tbinfo = polinfo->poltable;
3571         PQExpBuffer query;
3572         PQExpBuffer delqry;
3573         const char *cmd;
3574         char       *tag;
3575
3576         if (dopt->dataOnly)
3577                 return;
3578
3579         /*
3580          * If polname is NULL, then this record is just indicating that ROW LEVEL
3581          * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
3582          * ROW LEVEL SECURITY.
3583          */
3584         if (polinfo->polname == NULL)
3585         {
3586                 query = createPQExpBuffer();
3587
3588                 appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
3589                                                   fmtQualifiedDumpable(tbinfo));
3590
3591                 /*
3592                  * We must emit the ROW SECURITY object's dependency on its table
3593                  * explicitly, because it will not match anything in pg_depend (unlike
3594                  * the case for other PolicyInfo objects).
3595                  */
3596                 if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3597                         ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3598                                                  ARCHIVE_OPTS(.tag = polinfo->dobj.name,
3599                                                                           .namespace = polinfo->dobj.namespace->dobj.name,
3600                                                                           .owner = tbinfo->rolname,
3601                                                                           .description = "ROW SECURITY",
3602                                                                           .section = SECTION_POST_DATA,
3603                                                                           .createStmt = query->data,
3604                                                                           .deps = &(tbinfo->dobj.dumpId),
3605                                                                           .nDeps = 1));
3606
3607                 destroyPQExpBuffer(query);
3608                 return;
3609         }
3610
3611         if (polinfo->polcmd == '*')
3612                 cmd = "";
3613         else if (polinfo->polcmd == 'r')
3614                 cmd = " FOR SELECT";
3615         else if (polinfo->polcmd == 'a')
3616                 cmd = " FOR INSERT";
3617         else if (polinfo->polcmd == 'w')
3618                 cmd = " FOR UPDATE";
3619         else if (polinfo->polcmd == 'd')
3620                 cmd = " FOR DELETE";
3621         else
3622         {
3623                 write_msg(NULL, "unexpected policy command type: %c\n",
3624                                   polinfo->polcmd);
3625                 exit_nicely(1);
3626         }
3627
3628         query = createPQExpBuffer();
3629         delqry = createPQExpBuffer();
3630
3631         appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
3632
3633         appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
3634                                           !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
3635
3636         if (polinfo->polroles != NULL)
3637                 appendPQExpBuffer(query, " TO %s", polinfo->polroles);
3638
3639         if (polinfo->polqual != NULL)
3640                 appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
3641
3642         if (polinfo->polwithcheck != NULL)
3643                 appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
3644
3645         appendPQExpBuffer(query, ";\n");
3646
3647         appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
3648         appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
3649
3650         tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
3651
3652         if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3653                 ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3654                                          ARCHIVE_OPTS(.tag = tag,
3655                                                                   .namespace = polinfo->dobj.namespace->dobj.name,
3656                                                                   .owner = tbinfo->rolname,
3657                                                                   .description = "POLICY",
3658                                                                   .section = SECTION_POST_DATA,
3659                                                                   .createStmt = query->data,
3660                                                                   .dropStmt = delqry->data));
3661
3662         free(tag);
3663         destroyPQExpBuffer(query);
3664         destroyPQExpBuffer(delqry);
3665 }
3666
3667 /*
3668  * getPublications
3669  *        get information about publications
3670  */
3671 void
3672 getPublications(Archive *fout)
3673 {
3674         DumpOptions *dopt = fout->dopt;
3675         PQExpBuffer query;
3676         PGresult   *res;
3677         PublicationInfo *pubinfo;
3678         int                     i_tableoid;
3679         int                     i_oid;
3680         int                     i_pubname;
3681         int                     i_rolname;
3682         int                     i_puballtables;
3683         int                     i_pubinsert;
3684         int                     i_pubupdate;
3685         int                     i_pubdelete;
3686         int                     i_pubtruncate;
3687         int                     i,
3688                                 ntups;
3689
3690         if (dopt->no_publications || fout->remoteVersion < 100000)
3691                 return;
3692
3693         query = createPQExpBuffer();
3694
3695         resetPQExpBuffer(query);
3696
3697         /* Get the publications. */
3698         if (fout->remoteVersion >= 110000)
3699                 appendPQExpBuffer(query,
3700                                                   "SELECT p.tableoid, p.oid, p.pubname, "
3701                                                   "(%s p.pubowner) AS rolname, "
3702                                                   "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, p.pubtruncate "
3703                                                   "FROM pg_publication p",
3704                                                   username_subquery);
3705         else
3706                 appendPQExpBuffer(query,
3707                                                   "SELECT p.tableoid, p.oid, p.pubname, "
3708                                                   "(%s p.pubowner) AS rolname, "
3709                                                   "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, false AS pubtruncate "
3710                                                   "FROM pg_publication p",
3711                                                   username_subquery);
3712
3713         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3714
3715         ntups = PQntuples(res);
3716
3717         i_tableoid = PQfnumber(res, "tableoid");
3718         i_oid = PQfnumber(res, "oid");
3719         i_pubname = PQfnumber(res, "pubname");
3720         i_rolname = PQfnumber(res, "rolname");
3721         i_puballtables = PQfnumber(res, "puballtables");
3722         i_pubinsert = PQfnumber(res, "pubinsert");
3723         i_pubupdate = PQfnumber(res, "pubupdate");
3724         i_pubdelete = PQfnumber(res, "pubdelete");
3725         i_pubtruncate = PQfnumber(res, "pubtruncate");
3726
3727         pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
3728
3729         for (i = 0; i < ntups; i++)
3730         {
3731                 pubinfo[i].dobj.objType = DO_PUBLICATION;
3732                 pubinfo[i].dobj.catId.tableoid =
3733                         atooid(PQgetvalue(res, i, i_tableoid));
3734                 pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3735                 AssignDumpId(&pubinfo[i].dobj);
3736                 pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
3737                 pubinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3738                 pubinfo[i].puballtables =
3739                         (strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
3740                 pubinfo[i].pubinsert =
3741                         (strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
3742                 pubinfo[i].pubupdate =
3743                         (strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
3744                 pubinfo[i].pubdelete =
3745                         (strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
3746                 pubinfo[i].pubtruncate =
3747                         (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
3748
3749                 if (strlen(pubinfo[i].rolname) == 0)
3750                         write_msg(NULL, "WARNING: owner of publication \"%s\" appears to be invalid\n",
3751                                           pubinfo[i].dobj.name);
3752
3753                 /* Decide whether we want to dump it */
3754                 selectDumpableObject(&(pubinfo[i].dobj), fout);
3755         }
3756         PQclear(res);
3757
3758         destroyPQExpBuffer(query);
3759 }
3760
3761 /*
3762  * dumpPublication
3763  *        dump the definition of the given publication
3764  */
3765 static void
3766 dumpPublication(Archive *fout, PublicationInfo *pubinfo)
3767 {
3768         PQExpBuffer delq;
3769         PQExpBuffer query;
3770         char       *qpubname;
3771         bool            first = true;
3772
3773         if (!(pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3774                 return;
3775
3776         delq = createPQExpBuffer();
3777         query = createPQExpBuffer();
3778
3779         qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
3780
3781         appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
3782                                           qpubname);
3783
3784         appendPQExpBuffer(query, "CREATE PUBLICATION %s",
3785                                           qpubname);
3786
3787         if (pubinfo->puballtables)
3788                 appendPQExpBufferStr(query, " FOR ALL TABLES");
3789
3790         appendPQExpBufferStr(query, " WITH (publish = '");
3791         if (pubinfo->pubinsert)
3792         {
3793                 appendPQExpBufferStr(query, "insert");
3794                 first = false;
3795         }
3796
3797         if (pubinfo->pubupdate)
3798         {
3799                 if (!first)
3800                         appendPQExpBufferStr(query, ", ");
3801
3802                 appendPQExpBufferStr(query, "update");
3803                 first = false;
3804         }
3805
3806         if (pubinfo->pubdelete)
3807         {
3808                 if (!first)
3809                         appendPQExpBufferStr(query, ", ");
3810
3811                 appendPQExpBufferStr(query, "delete");
3812                 first = false;
3813         }
3814
3815         if (pubinfo->pubtruncate)
3816         {
3817                 if (!first)
3818                         appendPQExpBufferStr(query, ", ");
3819
3820                 appendPQExpBufferStr(query, "truncate");
3821                 first = false;
3822         }
3823
3824         appendPQExpBufferStr(query, "');\n");
3825
3826         ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
3827                                  ARCHIVE_OPTS(.tag = pubinfo->dobj.name,
3828                                                           .owner = pubinfo->rolname,
3829                                                           .description = "PUBLICATION",
3830                                                           .section = SECTION_POST_DATA,
3831                                                           .createStmt = query->data,
3832                                                           .dropStmt = delq->data));
3833
3834         if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3835                 dumpComment(fout, "PUBLICATION", qpubname,
3836                                         NULL, pubinfo->rolname,
3837                                         pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
3838
3839         if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3840                 dumpSecLabel(fout, "PUBLICATION", qpubname,
3841                                          NULL, pubinfo->rolname,
3842                                          pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
3843
3844         destroyPQExpBuffer(delq);
3845         destroyPQExpBuffer(query);
3846         free(qpubname);
3847 }
3848
3849 /*
3850  * getPublicationTables
3851  *        get information about publication membership for dumpable tables.
3852  */
3853 void
3854 getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
3855 {
3856         PQExpBuffer query;
3857         PGresult   *res;
3858         PublicationRelInfo *pubrinfo;
3859         DumpOptions *dopt = fout->dopt;
3860         int                     i_tableoid;
3861         int                     i_oid;
3862         int                     i_pubname;
3863         int                     i,
3864                                 j,
3865                                 ntups;
3866
3867         if (dopt->no_publications || fout->remoteVersion < 100000)
3868                 return;
3869
3870         query = createPQExpBuffer();
3871
3872         for (i = 0; i < numTables; i++)
3873         {
3874                 TableInfo  *tbinfo = &tblinfo[i];
3875
3876                 /* Only plain tables can be aded to publications. */
3877                 if (tbinfo->relkind != RELKIND_RELATION)
3878                         continue;
3879
3880                 /*
3881                  * Ignore publication membership of tables whose definitions are not
3882                  * to be dumped.
3883                  */
3884                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3885                         continue;
3886
3887                 if (g_verbose)
3888                         write_msg(NULL, "reading publication membership for table \"%s.%s\"\n",
3889                                           tbinfo->dobj.namespace->dobj.name,
3890                                           tbinfo->dobj.name);
3891
3892                 resetPQExpBuffer(query);
3893
3894                 /* Get the publication membership for the table. */
3895                 appendPQExpBuffer(query,
3896                                                   "SELECT pr.tableoid, pr.oid, p.pubname "
3897                                                   "FROM pg_publication_rel pr, pg_publication p "
3898                                                   "WHERE pr.prrelid = '%u'"
3899                                                   "  AND p.oid = pr.prpubid",
3900                                                   tbinfo->dobj.catId.oid);
3901                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3902
3903                 ntups = PQntuples(res);
3904
3905                 if (ntups == 0)
3906                 {
3907                         /*
3908                          * Table is not member of any publications. Clean up and return.
3909                          */
3910                         PQclear(res);
3911                         continue;
3912                 }
3913
3914                 i_tableoid = PQfnumber(res, "tableoid");
3915                 i_oid = PQfnumber(res, "oid");
3916                 i_pubname = PQfnumber(res, "pubname");
3917
3918                 pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
3919
3920                 for (j = 0; j < ntups; j++)
3921                 {
3922                         pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
3923                         pubrinfo[j].dobj.catId.tableoid =
3924                                 atooid(PQgetvalue(res, j, i_tableoid));
3925                         pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3926                         AssignDumpId(&pubrinfo[j].dobj);
3927                         pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3928                         pubrinfo[j].dobj.name = tbinfo->dobj.name;
3929                         pubrinfo[j].pubname = pg_strdup(PQgetvalue(res, j, i_pubname));
3930                         pubrinfo[j].pubtable = tbinfo;
3931
3932                         /* Decide whether we want to dump it */
3933                         selectDumpablePublicationTable(&(pubrinfo[j].dobj), fout);
3934                 }
3935                 PQclear(res);
3936         }
3937         destroyPQExpBuffer(query);
3938 }
3939
3940 /*
3941  * dumpPublicationTable
3942  *        dump the definition of the given publication table mapping
3943  */
3944 static void
3945 dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo)
3946 {
3947         TableInfo  *tbinfo = pubrinfo->pubtable;
3948         PQExpBuffer query;
3949         char       *tag;
3950
3951         if (!(pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3952                 return;
3953
3954         tag = psprintf("%s %s", pubrinfo->pubname, tbinfo->dobj.name);
3955
3956         query = createPQExpBuffer();
3957
3958         appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
3959                                           fmtId(pubrinfo->pubname));
3960         appendPQExpBuffer(query, " %s;\n",
3961                                           fmtQualifiedDumpable(tbinfo));
3962
3963         /*
3964          * There is no point in creating drop query as drop query as the drop is
3965          * done by table drop.
3966          */
3967         ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
3968                                  ARCHIVE_OPTS(.tag = tag,
3969                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
3970                                                           .description = "PUBLICATION TABLE",
3971                                                           .section = SECTION_POST_DATA,
3972                                                           .createStmt = query->data));
3973
3974         free(tag);
3975         destroyPQExpBuffer(query);
3976 }
3977
3978 /*
3979  * Is the currently connected user a superuser?
3980  */
3981 static bool
3982 is_superuser(Archive *fout)
3983 {
3984         ArchiveHandle *AH = (ArchiveHandle *) fout;
3985         const char *val;
3986
3987         val = PQparameterStatus(AH->connection, "is_superuser");
3988
3989         if (val && strcmp(val, "on") == 0)
3990                 return true;
3991
3992         return false;
3993 }
3994
3995 /*
3996  * getSubscriptions
3997  *        get information about subscriptions
3998  */
3999 void
4000 getSubscriptions(Archive *fout)
4001 {
4002         DumpOptions *dopt = fout->dopt;
4003         PQExpBuffer query;
4004         PGresult   *res;
4005         SubscriptionInfo *subinfo;
4006         int                     i_tableoid;
4007         int                     i_oid;
4008         int                     i_subname;
4009         int                     i_rolname;
4010         int                     i_subconninfo;
4011         int                     i_subslotname;
4012         int                     i_subsynccommit;
4013         int                     i_subpublications;
4014         int                     i,
4015                                 ntups;
4016
4017         if (dopt->no_subscriptions || fout->remoteVersion < 100000)
4018                 return;
4019
4020         if (!is_superuser(fout))
4021         {
4022                 int                     n;
4023
4024                 res = ExecuteSqlQuery(fout,
4025                                                           "SELECT count(*) FROM pg_subscription "
4026                                                           "WHERE subdbid = (SELECT oid FROM pg_database"
4027                                                           "                 WHERE datname = current_database())",
4028                                                           PGRES_TUPLES_OK);
4029                 n = atoi(PQgetvalue(res, 0, 0));
4030                 if (n > 0)
4031                         write_msg(NULL, "WARNING: subscriptions not dumped because current user is not a superuser\n");
4032                 PQclear(res);
4033                 return;
4034         }
4035
4036         query = createPQExpBuffer();
4037
4038         resetPQExpBuffer(query);
4039
4040         /* Get the subscriptions in current database. */
4041         appendPQExpBuffer(query,
4042                                           "SELECT s.tableoid, s.oid, s.subname,"
4043                                           "(%s s.subowner) AS rolname, "
4044                                           " s.subconninfo, s.subslotname, s.subsynccommit, "
4045                                           " s.subpublications "
4046                                           "FROM pg_subscription s "
4047                                           "WHERE s.subdbid = (SELECT oid FROM pg_database"
4048                                           "                   WHERE datname = current_database())",
4049                                           username_subquery);
4050         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4051
4052         ntups = PQntuples(res);
4053
4054         i_tableoid = PQfnumber(res, "tableoid");
4055         i_oid = PQfnumber(res, "oid");
4056         i_subname = PQfnumber(res, "subname");
4057         i_rolname = PQfnumber(res, "rolname");
4058         i_subconninfo = PQfnumber(res, "subconninfo");
4059         i_subslotname = PQfnumber(res, "subslotname");
4060         i_subsynccommit = PQfnumber(res, "subsynccommit");
4061         i_subpublications = PQfnumber(res, "subpublications");
4062
4063         subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
4064
4065         for (i = 0; i < ntups; i++)
4066         {
4067                 subinfo[i].dobj.objType = DO_SUBSCRIPTION;
4068                 subinfo[i].dobj.catId.tableoid =
4069                         atooid(PQgetvalue(res, i, i_tableoid));
4070                 subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4071                 AssignDumpId(&subinfo[i].dobj);
4072                 subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
4073                 subinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4074                 subinfo[i].subconninfo = pg_strdup(PQgetvalue(res, i, i_subconninfo));
4075                 if (PQgetisnull(res, i, i_subslotname))
4076                         subinfo[i].subslotname = NULL;
4077                 else
4078                         subinfo[i].subslotname = pg_strdup(PQgetvalue(res, i, i_subslotname));
4079                 subinfo[i].subsynccommit =
4080                         pg_strdup(PQgetvalue(res, i, i_subsynccommit));
4081                 subinfo[i].subpublications =
4082                         pg_strdup(PQgetvalue(res, i, i_subpublications));
4083
4084                 if (strlen(subinfo[i].rolname) == 0)
4085                         write_msg(NULL, "WARNING: owner of subscription \"%s\" appears to be invalid\n",
4086                                           subinfo[i].dobj.name);
4087
4088                 /* Decide whether we want to dump it */
4089                 selectDumpableObject(&(subinfo[i].dobj), fout);
4090         }
4091         PQclear(res);
4092
4093         destroyPQExpBuffer(query);
4094 }
4095
4096 /*
4097  * dumpSubscription
4098  *        dump the definition of the given subscription
4099  */
4100 static void
4101 dumpSubscription(Archive *fout, SubscriptionInfo *subinfo)
4102 {
4103         PQExpBuffer delq;
4104         PQExpBuffer query;
4105         PQExpBuffer publications;
4106         char       *qsubname;
4107         char      **pubnames = NULL;
4108         int                     npubnames = 0;
4109         int                     i;
4110
4111         if (!(subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
4112                 return;
4113
4114         delq = createPQExpBuffer();
4115         query = createPQExpBuffer();
4116
4117         qsubname = pg_strdup(fmtId(subinfo->dobj.name));
4118
4119         appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
4120                                           qsubname);
4121
4122         appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
4123                                           qsubname);
4124         appendStringLiteralAH(query, subinfo->subconninfo, fout);
4125
4126         /* Build list of quoted publications and append them to query. */
4127         if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
4128         {
4129                 write_msg(NULL,
4130                                   "WARNING: could not parse subpublications array\n");
4131                 if (pubnames)
4132                         free(pubnames);
4133                 pubnames = NULL;
4134                 npubnames = 0;
4135         }
4136
4137         publications = createPQExpBuffer();
4138         for (i = 0; i < npubnames; i++)
4139         {
4140                 if (i > 0)
4141                         appendPQExpBufferStr(publications, ", ");
4142
4143                 appendPQExpBufferStr(publications, fmtId(pubnames[i]));
4144         }
4145
4146         appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
4147         if (subinfo->subslotname)
4148                 appendStringLiteralAH(query, subinfo->subslotname, fout);
4149         else
4150                 appendPQExpBufferStr(query, "NONE");
4151
4152         if (strcmp(subinfo->subsynccommit, "off") != 0)
4153                 appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
4154
4155         appendPQExpBufferStr(query, ");\n");
4156
4157         ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
4158                                  ARCHIVE_OPTS(.tag = subinfo->dobj.name,
4159                                                           .owner = subinfo->rolname,
4160                                                           .description = "SUBSCRIPTION",
4161                                                           .section = SECTION_POST_DATA,
4162                                                           .createStmt = query->data,
4163                                                           .dropStmt = delq->data));
4164
4165         if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4166                 dumpComment(fout, "SUBSCRIPTION", qsubname,
4167                                         NULL, subinfo->rolname,
4168                                         subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
4169
4170         if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
4171                 dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
4172                                          NULL, subinfo->rolname,
4173                                          subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
4174
4175         destroyPQExpBuffer(publications);
4176         if (pubnames)
4177                 free(pubnames);
4178
4179         destroyPQExpBuffer(delq);
4180         destroyPQExpBuffer(query);
4181         free(qsubname);
4182 }
4183
4184 static void
4185 binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
4186                                                                                  PQExpBuffer upgrade_buffer,
4187                                                                                  Oid pg_type_oid,
4188                                                                                  bool force_array_type)
4189 {
4190         PQExpBuffer upgrade_query = createPQExpBuffer();
4191         PGresult   *res;
4192         Oid                     pg_type_array_oid;
4193
4194         appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
4195         appendPQExpBuffer(upgrade_buffer,
4196                                           "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4197                                           pg_type_oid);
4198
4199         /* we only support old >= 8.3 for binary upgrades */
4200         appendPQExpBuffer(upgrade_query,
4201                                           "SELECT typarray "
4202                                           "FROM pg_catalog.pg_type "
4203                                           "WHERE oid = '%u'::pg_catalog.oid;",
4204                                           pg_type_oid);
4205
4206         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4207
4208         pg_type_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
4209
4210         PQclear(res);
4211
4212         if (!OidIsValid(pg_type_array_oid) && force_array_type)
4213         {
4214                 /*
4215                  * If the old version didn't assign an array type, but the new version
4216                  * does, we must select an unused type OID to assign.  This currently
4217                  * only happens for domains, when upgrading pre-v11 to v11 and up.
4218                  *
4219                  * Note: local state here is kind of ugly, but we must have some,
4220                  * since we mustn't choose the same unused OID more than once.
4221                  */
4222                 static Oid      next_possible_free_oid = FirstNormalObjectId;
4223                 bool            is_dup;
4224
4225                 do
4226                 {
4227                         ++next_possible_free_oid;
4228                         printfPQExpBuffer(upgrade_query,
4229                                                           "SELECT EXISTS(SELECT 1 "
4230                                                           "FROM pg_catalog.pg_type "
4231                                                           "WHERE oid = '%u'::pg_catalog.oid);",
4232                                                           next_possible_free_oid);
4233                         res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4234                         is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
4235                         PQclear(res);
4236                 } while (is_dup);
4237
4238                 pg_type_array_oid = next_possible_free_oid;
4239         }
4240
4241         if (OidIsValid(pg_type_array_oid))
4242         {
4243                 appendPQExpBufferStr(upgrade_buffer,
4244                                                          "\n-- For binary upgrade, must preserve pg_type array oid\n");
4245                 appendPQExpBuffer(upgrade_buffer,
4246                                                   "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4247                                                   pg_type_array_oid);
4248         }
4249
4250         destroyPQExpBuffer(upgrade_query);
4251 }
4252
4253 static bool
4254 binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
4255                                                                                 PQExpBuffer upgrade_buffer,
4256                                                                                 Oid pg_rel_oid)
4257 {
4258         PQExpBuffer upgrade_query = createPQExpBuffer();
4259         PGresult   *upgrade_res;
4260         Oid                     pg_type_oid;
4261         bool            toast_set = false;
4262
4263         /* we only support old >= 8.3 for binary upgrades */
4264         appendPQExpBuffer(upgrade_query,
4265                                           "SELECT c.reltype AS crel, t.reltype AS trel "
4266                                           "FROM pg_catalog.pg_class c "
4267                                           "LEFT JOIN pg_catalog.pg_class t ON "
4268                                           "  (c.reltoastrelid = t.oid) "
4269                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
4270                                           pg_rel_oid);
4271
4272         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4273
4274         pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
4275
4276         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
4277                                                                                          pg_type_oid, false);
4278
4279         if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
4280         {
4281                 /* Toast tables do not have pg_type array rows */
4282                 Oid                     pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
4283                                                                                                                   PQfnumber(upgrade_res, "trel")));
4284
4285                 appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
4286                 appendPQExpBuffer(upgrade_buffer,
4287                                                   "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4288                                                   pg_type_toast_oid);
4289
4290                 toast_set = true;
4291         }
4292
4293         PQclear(upgrade_res);
4294         destroyPQExpBuffer(upgrade_query);
4295
4296         return toast_set;
4297 }
4298
4299 static void
4300 binary_upgrade_set_pg_class_oids(Archive *fout,
4301                                                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid,
4302                                                                  bool is_index)
4303 {
4304         PQExpBuffer upgrade_query = createPQExpBuffer();
4305         PGresult   *upgrade_res;
4306         Oid                     pg_class_reltoastrelid;
4307         Oid                     pg_index_indexrelid;
4308
4309         appendPQExpBuffer(upgrade_query,
4310                                           "SELECT c.reltoastrelid, i.indexrelid "
4311                                           "FROM pg_catalog.pg_class c LEFT JOIN "
4312                                           "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
4313                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
4314                                           pg_class_oid);
4315
4316         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4317
4318         pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
4319         pg_index_indexrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "indexrelid")));
4320
4321         appendPQExpBufferStr(upgrade_buffer,
4322                                                  "\n-- For binary upgrade, must preserve pg_class oids\n");
4323
4324         if (!is_index)
4325         {
4326                 appendPQExpBuffer(upgrade_buffer,
4327                                                   "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
4328                                                   pg_class_oid);
4329                 /* only tables have toast tables, not indexes */
4330                 if (OidIsValid(pg_class_reltoastrelid))
4331                 {
4332                         /*
4333                          * One complexity is that the table definition might not require
4334                          * the creation of a TOAST table, and the TOAST table might have
4335                          * been created long after table creation, when the table was
4336                          * loaded with wide data.  By setting the TOAST oid we force
4337                          * creation of the TOAST heap and TOAST index by the backend so we
4338                          * can cleanly copy the files during binary upgrade.
4339                          */
4340
4341                         appendPQExpBuffer(upgrade_buffer,
4342                                                           "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
4343                                                           pg_class_reltoastrelid);
4344
4345                         /* every toast table has an index */
4346                         appendPQExpBuffer(upgrade_buffer,
4347                                                           "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
4348                                                           pg_index_indexrelid);
4349                 }
4350         }
4351         else
4352                 appendPQExpBuffer(upgrade_buffer,
4353                                                   "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
4354                                                   pg_class_oid);
4355
4356         appendPQExpBufferChar(upgrade_buffer, '\n');
4357
4358         PQclear(upgrade_res);
4359         destroyPQExpBuffer(upgrade_query);
4360 }
4361
4362 /*
4363  * If the DumpableObject is a member of an extension, add a suitable
4364  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
4365  *
4366  * For somewhat historical reasons, objname should already be quoted,
4367  * but not objnamespace (if any).
4368  */
4369 static void
4370 binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
4371                                                                 DumpableObject *dobj,
4372                                                                 const char *objtype,
4373                                                                 const char *objname,
4374                                                                 const char *objnamespace)
4375 {
4376         DumpableObject *extobj = NULL;
4377         int                     i;
4378
4379         if (!dobj->ext_member)
4380                 return;
4381
4382         /*
4383          * Find the parent extension.  We could avoid this search if we wanted to
4384          * add a link field to DumpableObject, but the space costs of that would
4385          * be considerable.  We assume that member objects could only have a
4386          * direct dependency on their own extension, not any others.
4387          */
4388         for (i = 0; i < dobj->nDeps; i++)
4389         {
4390                 extobj = findObjectByDumpId(dobj->dependencies[i]);
4391                 if (extobj && extobj->objType == DO_EXTENSION)
4392                         break;
4393                 extobj = NULL;
4394         }
4395         if (extobj == NULL)
4396                 exit_horribly(NULL, "could not find parent extension for %s %s\n",
4397                                           objtype, objname);
4398
4399         appendPQExpBufferStr(upgrade_buffer,
4400                                                  "\n-- For binary upgrade, handle extension membership the hard way\n");
4401         appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
4402                                           fmtId(extobj->name),
4403                                           objtype);
4404         if (objnamespace && *objnamespace)
4405                 appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
4406         appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
4407 }
4408
4409 /*
4410  * getNamespaces:
4411  *        read all namespaces in the system catalogs and return them in the
4412  * NamespaceInfo* structure
4413  *
4414  *      numNamespaces is set to the number of namespaces read in
4415  */
4416 NamespaceInfo *
4417 getNamespaces(Archive *fout, int *numNamespaces)
4418 {
4419         DumpOptions *dopt = fout->dopt;
4420         PGresult   *res;
4421         int                     ntups;
4422         int                     i;
4423         PQExpBuffer query;
4424         NamespaceInfo *nsinfo;
4425         int                     i_tableoid;
4426         int                     i_oid;
4427         int                     i_nspname;
4428         int                     i_rolname;
4429         int                     i_nspacl;
4430         int                     i_rnspacl;
4431         int                     i_initnspacl;
4432         int                     i_initrnspacl;
4433
4434         query = createPQExpBuffer();
4435
4436         /*
4437          * we fetch all namespaces including system ones, so that every object we
4438          * read in can be linked to a containing namespace.
4439          */
4440         if (fout->remoteVersion >= 90600)
4441         {
4442                 PQExpBuffer acl_subquery = createPQExpBuffer();
4443                 PQExpBuffer racl_subquery = createPQExpBuffer();
4444                 PQExpBuffer init_acl_subquery = createPQExpBuffer();
4445                 PQExpBuffer init_racl_subquery = createPQExpBuffer();
4446
4447                 buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
4448                                                 init_racl_subquery, "n.nspacl", "n.nspowner", "'n'",
4449                                                 dopt->binary_upgrade);
4450
4451                 appendPQExpBuffer(query, "SELECT n.tableoid, n.oid, n.nspname, "
4452                                                   "(%s nspowner) AS rolname, "
4453                                                   "%s as nspacl, "
4454                                                   "%s as rnspacl, "
4455                                                   "%s as initnspacl, "
4456                                                   "%s as initrnspacl "
4457                                                   "FROM pg_namespace n "
4458                                                   "LEFT JOIN pg_init_privs pip "
4459                                                   "ON (n.oid = pip.objoid "
4460                                                   "AND pip.classoid = 'pg_namespace'::regclass "
4461                                                   "AND pip.objsubid = 0",
4462                                                   username_subquery,
4463                                                   acl_subquery->data,
4464                                                   racl_subquery->data,
4465                                                   init_acl_subquery->data,
4466                                                   init_racl_subquery->data);
4467
4468                 appendPQExpBuffer(query, ") ");
4469
4470                 destroyPQExpBuffer(acl_subquery);
4471                 destroyPQExpBuffer(racl_subquery);
4472                 destroyPQExpBuffer(init_acl_subquery);
4473                 destroyPQExpBuffer(init_racl_subquery);
4474         }
4475         else
4476                 appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
4477                                                   "(%s nspowner) AS rolname, "
4478                                                   "nspacl, NULL as rnspacl, "
4479                                                   "NULL AS initnspacl, NULL as initrnspacl "
4480                                                   "FROM pg_namespace",
4481                                                   username_subquery);
4482
4483         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4484
4485         ntups = PQntuples(res);
4486
4487         nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
4488
4489         i_tableoid = PQfnumber(res, "tableoid");
4490         i_oid = PQfnumber(res, "oid");
4491         i_nspname = PQfnumber(res, "nspname");
4492         i_rolname = PQfnumber(res, "rolname");
4493         i_nspacl = PQfnumber(res, "nspacl");
4494         i_rnspacl = PQfnumber(res, "rnspacl");
4495         i_initnspacl = PQfnumber(res, "initnspacl");
4496         i_initrnspacl = PQfnumber(res, "initrnspacl");
4497
4498         for (i = 0; i < ntups; i++)
4499         {
4500                 nsinfo[i].dobj.objType = DO_NAMESPACE;
4501                 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4502                 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4503                 AssignDumpId(&nsinfo[i].dobj);
4504                 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
4505                 nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4506                 nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
4507                 nsinfo[i].rnspacl = pg_strdup(PQgetvalue(res, i, i_rnspacl));
4508                 nsinfo[i].initnspacl = pg_strdup(PQgetvalue(res, i, i_initnspacl));
4509                 nsinfo[i].initrnspacl = pg_strdup(PQgetvalue(res, i, i_initrnspacl));
4510
4511                 /* Decide whether to dump this namespace */
4512                 selectDumpableNamespace(&nsinfo[i], fout);
4513
4514                 /*
4515                  * Do not try to dump ACL if the ACL is empty or the default.
4516                  *
4517                  * This is useful because, for some schemas/objects, the only
4518                  * component we are going to try and dump is the ACL and if we can
4519                  * remove that then 'dump' goes to zero/false and we don't consider
4520                  * this object for dumping at all later on.
4521                  */
4522                 if (PQgetisnull(res, i, i_nspacl) && PQgetisnull(res, i, i_rnspacl) &&
4523                         PQgetisnull(res, i, i_initnspacl) &&
4524                         PQgetisnull(res, i, i_initrnspacl))
4525                         nsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4526
4527                 if (strlen(nsinfo[i].rolname) == 0)
4528                         write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
4529                                           nsinfo[i].dobj.name);
4530         }
4531
4532         PQclear(res);
4533         destroyPQExpBuffer(query);
4534
4535         *numNamespaces = ntups;
4536
4537         return nsinfo;
4538 }
4539
4540 /*
4541  * findNamespace:
4542  *              given a namespace OID, look up the info read by getNamespaces
4543  */
4544 static NamespaceInfo *
4545 findNamespace(Archive *fout, Oid nsoid)
4546 {
4547         NamespaceInfo *nsinfo;
4548
4549         nsinfo = findNamespaceByOid(nsoid);
4550         if (nsinfo == NULL)
4551                 exit_horribly(NULL, "schema with OID %u does not exist\n", nsoid);
4552         return nsinfo;
4553 }
4554
4555 /*
4556  * getExtensions:
4557  *        read all extensions in the system catalogs and return them in the
4558  * ExtensionInfo* structure
4559  *
4560  *      numExtensions is set to the number of extensions read in
4561  */
4562 ExtensionInfo *
4563 getExtensions(Archive *fout, int *numExtensions)
4564 {
4565         DumpOptions *dopt = fout->dopt;
4566         PGresult   *res;
4567         int                     ntups;
4568         int                     i;
4569         PQExpBuffer query;
4570         ExtensionInfo *extinfo;
4571         int                     i_tableoid;
4572         int                     i_oid;
4573         int                     i_extname;
4574         int                     i_nspname;
4575         int                     i_extrelocatable;
4576         int                     i_extversion;
4577         int                     i_extconfig;
4578         int                     i_extcondition;
4579
4580         /*
4581          * Before 9.1, there are no extensions.
4582          */
4583         if (fout->remoteVersion < 90100)
4584         {
4585                 *numExtensions = 0;
4586                 return NULL;
4587         }
4588
4589         query = createPQExpBuffer();
4590
4591         appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
4592                                                  "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
4593                                                  "FROM pg_extension x "
4594                                                  "JOIN pg_namespace n ON n.oid = x.extnamespace");
4595
4596         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4597
4598         ntups = PQntuples(res);
4599
4600         extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
4601
4602         i_tableoid = PQfnumber(res, "tableoid");
4603         i_oid = PQfnumber(res, "oid");
4604         i_extname = PQfnumber(res, "extname");
4605         i_nspname = PQfnumber(res, "nspname");
4606         i_extrelocatable = PQfnumber(res, "extrelocatable");
4607         i_extversion = PQfnumber(res, "extversion");
4608         i_extconfig = PQfnumber(res, "extconfig");
4609         i_extcondition = PQfnumber(res, "extcondition");
4610
4611         for (i = 0; i < ntups; i++)
4612         {
4613                 extinfo[i].dobj.objType = DO_EXTENSION;
4614                 extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4615                 extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4616                 AssignDumpId(&extinfo[i].dobj);
4617                 extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
4618                 extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
4619                 extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
4620                 extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
4621                 extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
4622                 extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
4623
4624                 /* Decide whether we want to dump it */
4625                 selectDumpableExtension(&(extinfo[i]), dopt);
4626         }
4627
4628         PQclear(res);
4629         destroyPQExpBuffer(query);
4630
4631         *numExtensions = ntups;
4632
4633         return extinfo;
4634 }
4635
4636 /*
4637  * getTypes:
4638  *        read all types in the system catalogs and return them in the
4639  * TypeInfo* structure
4640  *
4641  *      numTypes is set to the number of types read in
4642  *
4643  * NB: this must run after getFuncs() because we assume we can do
4644  * findFuncByOid().
4645  */
4646 TypeInfo *
4647 getTypes(Archive *fout, int *numTypes)
4648 {
4649         DumpOptions *dopt = fout->dopt;
4650         PGresult   *res;
4651         int                     ntups;
4652         int                     i;
4653         PQExpBuffer query = createPQExpBuffer();
4654         TypeInfo   *tyinfo;
4655         ShellTypeInfo *stinfo;
4656         int                     i_tableoid;
4657         int                     i_oid;
4658         int                     i_typname;
4659         int                     i_typnamespace;
4660         int                     i_typacl;
4661         int                     i_rtypacl;
4662         int                     i_inittypacl;
4663         int                     i_initrtypacl;
4664         int                     i_rolname;
4665         int                     i_typelem;
4666         int                     i_typrelid;
4667         int                     i_typrelkind;
4668         int                     i_typtype;
4669         int                     i_typisdefined;
4670         int                     i_isarray;
4671
4672         /*
4673          * we include even the built-in types because those may be used as array
4674          * elements by user-defined types
4675          *
4676          * we filter out the built-in types when we dump out the types
4677          *
4678          * same approach for undefined (shell) types and array types
4679          *
4680          * Note: as of 8.3 we can reliably detect whether a type is an
4681          * auto-generated array type by checking the element type's typarray.
4682          * (Before that the test is capable of generating false positives.) We
4683          * still check for name beginning with '_', though, so as to avoid the
4684          * cost of the subselect probe for all standard types.  This would have to
4685          * be revisited if the backend ever allows renaming of array types.
4686          */
4687
4688         if (fout->remoteVersion >= 90600)
4689         {
4690                 PQExpBuffer acl_subquery = createPQExpBuffer();
4691                 PQExpBuffer racl_subquery = createPQExpBuffer();
4692                 PQExpBuffer initacl_subquery = createPQExpBuffer();
4693                 PQExpBuffer initracl_subquery = createPQExpBuffer();
4694
4695                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
4696                                                 initracl_subquery, "t.typacl", "t.typowner", "'T'",
4697                                                 dopt->binary_upgrade);
4698
4699                 appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, t.typname, "
4700                                                   "t.typnamespace, "
4701                                                   "%s AS typacl, "
4702                                                   "%s AS rtypacl, "
4703                                                   "%s AS inittypacl, "
4704                                                   "%s AS initrtypacl, "
4705                                                   "(%s t.typowner) AS rolname, "
4706                                                   "t.typelem, t.typrelid, "
4707                                                   "CASE WHEN t.typrelid = 0 THEN ' '::\"char\" "
4708                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = t.typrelid) END AS typrelkind, "
4709                                                   "t.typtype, t.typisdefined, "
4710                                                   "t.typname[0] = '_' AND t.typelem != 0 AND "
4711                                                   "(SELECT typarray FROM pg_type te WHERE oid = t.typelem) = t.oid AS isarray "
4712                                                   "FROM pg_type t "
4713                                                   "LEFT JOIN pg_init_privs pip ON "
4714                                                   "(t.oid = pip.objoid "
4715                                                   "AND pip.classoid = 'pg_type'::regclass "
4716                                                   "AND pip.objsubid = 0) ",
4717                                                   acl_subquery->data,
4718                                                   racl_subquery->data,
4719                                                   initacl_subquery->data,
4720                                                   initracl_subquery->data,
4721                                                   username_subquery);
4722
4723                 destroyPQExpBuffer(acl_subquery);
4724                 destroyPQExpBuffer(racl_subquery);
4725                 destroyPQExpBuffer(initacl_subquery);
4726                 destroyPQExpBuffer(initracl_subquery);
4727         }
4728         else if (fout->remoteVersion >= 90200)
4729         {
4730                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4731                                                   "typnamespace, typacl, NULL as rtypacl, "
4732                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4733                                                   "(%s typowner) AS rolname, "
4734                                                   "typelem, typrelid, "
4735                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4736                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4737                                                   "typtype, typisdefined, "
4738                                                   "typname[0] = '_' AND typelem != 0 AND "
4739                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4740                                                   "FROM pg_type",
4741                                                   username_subquery);
4742         }
4743         else if (fout->remoteVersion >= 80300)
4744         {
4745                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4746                                                   "typnamespace, NULL AS typacl, NULL as rtypacl, "
4747                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4748                                                   "(%s typowner) AS rolname, "
4749                                                   "typelem, typrelid, "
4750                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4751                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4752                                                   "typtype, typisdefined, "
4753                                                   "typname[0] = '_' AND typelem != 0 AND "
4754                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4755                                                   "FROM pg_type",
4756                                                   username_subquery);
4757         }
4758         else
4759         {
4760                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4761                                                   "typnamespace, NULL AS typacl, NULL as rtypacl, "
4762                                                   "NULL AS inittypacl, NULL AS initrtypacl, "
4763                                                   "(%s typowner) AS rolname, "
4764                                                   "typelem, typrelid, "
4765                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4766                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4767                                                   "typtype, typisdefined, "
4768                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
4769                                                   "FROM pg_type",
4770                                                   username_subquery);
4771         }
4772
4773         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4774
4775         ntups = PQntuples(res);
4776
4777         tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
4778
4779         i_tableoid = PQfnumber(res, "tableoid");
4780         i_oid = PQfnumber(res, "oid");
4781         i_typname = PQfnumber(res, "typname");
4782         i_typnamespace = PQfnumber(res, "typnamespace");
4783         i_typacl = PQfnumber(res, "typacl");
4784         i_rtypacl = PQfnumber(res, "rtypacl");
4785         i_inittypacl = PQfnumber(res, "inittypacl");
4786         i_initrtypacl = PQfnumber(res, "initrtypacl");
4787         i_rolname = PQfnumber(res, "rolname");
4788         i_typelem = PQfnumber(res, "typelem");
4789         i_typrelid = PQfnumber(res, "typrelid");
4790         i_typrelkind = PQfnumber(res, "typrelkind");
4791         i_typtype = PQfnumber(res, "typtype");
4792         i_typisdefined = PQfnumber(res, "typisdefined");
4793         i_isarray = PQfnumber(res, "isarray");
4794
4795         for (i = 0; i < ntups; i++)
4796         {
4797                 tyinfo[i].dobj.objType = DO_TYPE;
4798                 tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4799                 tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4800                 AssignDumpId(&tyinfo[i].dobj);
4801                 tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
4802                 tyinfo[i].dobj.namespace =
4803                         findNamespace(fout,
4804                                                   atooid(PQgetvalue(res, i, i_typnamespace)));
4805                 tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4806                 tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
4807                 tyinfo[i].rtypacl = pg_strdup(PQgetvalue(res, i, i_rtypacl));
4808                 tyinfo[i].inittypacl = pg_strdup(PQgetvalue(res, i, i_inittypacl));
4809                 tyinfo[i].initrtypacl = pg_strdup(PQgetvalue(res, i, i_initrtypacl));
4810                 tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
4811                 tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
4812                 tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
4813                 tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
4814                 tyinfo[i].shellType = NULL;
4815
4816                 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
4817                         tyinfo[i].isDefined = true;
4818                 else
4819                         tyinfo[i].isDefined = false;
4820
4821                 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
4822                         tyinfo[i].isArray = true;
4823                 else
4824                         tyinfo[i].isArray = false;
4825
4826                 /* Decide whether we want to dump it */
4827                 selectDumpableType(&tyinfo[i], fout);
4828
4829                 /* Do not try to dump ACL if no ACL exists. */
4830                 if (PQgetisnull(res, i, i_typacl) && PQgetisnull(res, i, i_rtypacl) &&
4831                         PQgetisnull(res, i, i_inittypacl) &&
4832                         PQgetisnull(res, i, i_initrtypacl))
4833                         tyinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4834
4835                 /*
4836                  * If it's a domain, fetch info about its constraints, if any
4837                  */
4838                 tyinfo[i].nDomChecks = 0;
4839                 tyinfo[i].domChecks = NULL;
4840                 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4841                         tyinfo[i].typtype == TYPTYPE_DOMAIN)
4842                         getDomainConstraints(fout, &(tyinfo[i]));
4843
4844                 /*
4845                  * If it's a base type, make a DumpableObject representing a shell
4846                  * definition of the type.  We will need to dump that ahead of the I/O
4847                  * functions for the type.  Similarly, range types need a shell
4848                  * definition in case they have a canonicalize function.
4849                  *
4850                  * Note: the shell type doesn't have a catId.  You might think it
4851                  * should copy the base type's catId, but then it might capture the
4852                  * pg_depend entries for the type, which we don't want.
4853                  */
4854                 if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4855                         (tyinfo[i].typtype == TYPTYPE_BASE ||
4856                          tyinfo[i].typtype == TYPTYPE_RANGE))
4857                 {
4858                         stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
4859                         stinfo->dobj.objType = DO_SHELL_TYPE;
4860                         stinfo->dobj.catId = nilCatalogId;
4861                         AssignDumpId(&stinfo->dobj);
4862                         stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
4863                         stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
4864                         stinfo->baseType = &(tyinfo[i]);
4865                         tyinfo[i].shellType = stinfo;
4866
4867                         /*
4868                          * Initially mark the shell type as not to be dumped.  We'll only
4869                          * dump it if the I/O or canonicalize functions need to be dumped;
4870                          * this is taken care of while sorting dependencies.
4871                          */
4872                         stinfo->dobj.dump = DUMP_COMPONENT_NONE;
4873                 }
4874
4875                 if (strlen(tyinfo[i].rolname) == 0)
4876                         write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
4877                                           tyinfo[i].dobj.name);
4878         }
4879
4880         *numTypes = ntups;
4881
4882         PQclear(res);
4883
4884         destroyPQExpBuffer(query);
4885
4886         return tyinfo;
4887 }
4888
4889 /*
4890  * getOperators:
4891  *        read all operators in the system catalogs and return them in the
4892  * OprInfo* structure
4893  *
4894  *      numOprs is set to the number of operators read in
4895  */
4896 OprInfo *
4897 getOperators(Archive *fout, int *numOprs)
4898 {
4899         PGresult   *res;
4900         int                     ntups;
4901         int                     i;
4902         PQExpBuffer query = createPQExpBuffer();
4903         OprInfo    *oprinfo;
4904         int                     i_tableoid;
4905         int                     i_oid;
4906         int                     i_oprname;
4907         int                     i_oprnamespace;
4908         int                     i_rolname;
4909         int                     i_oprkind;
4910         int                     i_oprcode;
4911
4912         /*
4913          * find all operators, including builtin operators; we filter out
4914          * system-defined operators at dump-out time.
4915          */
4916
4917         appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
4918                                           "oprnamespace, "
4919                                           "(%s oprowner) AS rolname, "
4920                                           "oprkind, "
4921                                           "oprcode::oid AS oprcode "
4922                                           "FROM pg_operator",
4923                                           username_subquery);
4924
4925         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4926
4927         ntups = PQntuples(res);
4928         *numOprs = ntups;
4929
4930         oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
4931
4932         i_tableoid = PQfnumber(res, "tableoid");
4933         i_oid = PQfnumber(res, "oid");
4934         i_oprname = PQfnumber(res, "oprname");
4935         i_oprnamespace = PQfnumber(res, "oprnamespace");
4936         i_rolname = PQfnumber(res, "rolname");
4937         i_oprkind = PQfnumber(res, "oprkind");
4938         i_oprcode = PQfnumber(res, "oprcode");
4939
4940         for (i = 0; i < ntups; i++)
4941         {
4942                 oprinfo[i].dobj.objType = DO_OPERATOR;
4943                 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4944                 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4945                 AssignDumpId(&oprinfo[i].dobj);
4946                 oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
4947                 oprinfo[i].dobj.namespace =
4948                         findNamespace(fout,
4949                                                   atooid(PQgetvalue(res, i, i_oprnamespace)));
4950                 oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4951                 oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
4952                 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
4953
4954                 /* Decide whether we want to dump it */
4955                 selectDumpableObject(&(oprinfo[i].dobj), fout);
4956
4957                 /* Operators do not currently have ACLs. */
4958                 oprinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4959
4960                 if (strlen(oprinfo[i].rolname) == 0)
4961                         write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
4962                                           oprinfo[i].dobj.name);
4963         }
4964
4965         PQclear(res);
4966
4967         destroyPQExpBuffer(query);
4968
4969         return oprinfo;
4970 }
4971
4972 /*
4973  * getCollations:
4974  *        read all collations in the system catalogs and return them in the
4975  * CollInfo* structure
4976  *
4977  *      numCollations is set to the number of collations read in
4978  */
4979 CollInfo *
4980 getCollations(Archive *fout, int *numCollations)
4981 {
4982         PGresult   *res;
4983         int                     ntups;
4984         int                     i;
4985         PQExpBuffer query;
4986         CollInfo   *collinfo;
4987         int                     i_tableoid;
4988         int                     i_oid;
4989         int                     i_collname;
4990         int                     i_collnamespace;
4991         int                     i_rolname;
4992
4993         /* Collations didn't exist pre-9.1 */
4994         if (fout->remoteVersion < 90100)
4995         {
4996                 *numCollations = 0;
4997                 return NULL;
4998         }
4999
5000         query = createPQExpBuffer();
5001
5002         /*
5003          * find all collations, including builtin collations; we filter out
5004          * system-defined collations at dump-out time.
5005          */
5006
5007         appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
5008                                           "collnamespace, "
5009                                           "(%s collowner) AS rolname "
5010                                           "FROM pg_collation",
5011                                           username_subquery);
5012
5013         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5014
5015         ntups = PQntuples(res);
5016         *numCollations = ntups;
5017
5018         collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
5019
5020         i_tableoid = PQfnumber(res, "tableoid");
5021         i_oid = PQfnumber(res, "oid");
5022         i_collname = PQfnumber(res, "collname");
5023         i_collnamespace = PQfnumber(res, "collnamespace");
5024         i_rolname = PQfnumber(res, "rolname");
5025
5026         for (i = 0; i < ntups; i++)
5027         {
5028                 collinfo[i].dobj.objType = DO_COLLATION;
5029                 collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5030                 collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5031                 AssignDumpId(&collinfo[i].dobj);
5032                 collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
5033                 collinfo[i].dobj.namespace =
5034                         findNamespace(fout,
5035                                                   atooid(PQgetvalue(res, i, i_collnamespace)));
5036                 collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5037
5038                 /* Decide whether we want to dump it */
5039                 selectDumpableObject(&(collinfo[i].dobj), fout);
5040
5041                 /* Collations do not currently have ACLs. */
5042                 collinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5043         }
5044
5045         PQclear(res);
5046
5047         destroyPQExpBuffer(query);
5048
5049         return collinfo;
5050 }
5051
5052 /*
5053  * getConversions:
5054  *        read all conversions in the system catalogs and return them in the
5055  * ConvInfo* structure
5056  *
5057  *      numConversions is set to the number of conversions read in
5058  */
5059 ConvInfo *
5060 getConversions(Archive *fout, int *numConversions)
5061 {
5062         PGresult   *res;
5063         int                     ntups;
5064         int                     i;
5065         PQExpBuffer query;
5066         ConvInfo   *convinfo;
5067         int                     i_tableoid;
5068         int                     i_oid;
5069         int                     i_conname;
5070         int                     i_connamespace;
5071         int                     i_rolname;
5072
5073         query = createPQExpBuffer();
5074
5075         /*
5076          * find all conversions, including builtin conversions; we filter out
5077          * system-defined conversions at dump-out time.
5078          */
5079
5080         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5081                                           "connamespace, "
5082                                           "(%s conowner) AS rolname "
5083                                           "FROM pg_conversion",
5084                                           username_subquery);
5085
5086         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5087
5088         ntups = PQntuples(res);
5089         *numConversions = ntups;
5090
5091         convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
5092
5093         i_tableoid = PQfnumber(res, "tableoid");
5094         i_oid = PQfnumber(res, "oid");
5095         i_conname = PQfnumber(res, "conname");
5096         i_connamespace = PQfnumber(res, "connamespace");
5097         i_rolname = PQfnumber(res, "rolname");
5098
5099         for (i = 0; i < ntups; i++)
5100         {
5101                 convinfo[i].dobj.objType = DO_CONVERSION;
5102                 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5103                 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5104                 AssignDumpId(&convinfo[i].dobj);
5105                 convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
5106                 convinfo[i].dobj.namespace =
5107                         findNamespace(fout,
5108                                                   atooid(PQgetvalue(res, i, i_connamespace)));
5109                 convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5110
5111                 /* Decide whether we want to dump it */
5112                 selectDumpableObject(&(convinfo[i].dobj), fout);
5113
5114                 /* Conversions do not currently have ACLs. */
5115                 convinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5116         }
5117
5118         PQclear(res);
5119
5120         destroyPQExpBuffer(query);
5121
5122         return convinfo;
5123 }
5124
5125 /*
5126  * getAccessMethods:
5127  *        read all user-defined access methods in the system catalogs and return
5128  *        them in the AccessMethodInfo* structure
5129  *
5130  *      numAccessMethods is set to the number of access methods read in
5131  */
5132 AccessMethodInfo *
5133 getAccessMethods(Archive *fout, int *numAccessMethods)
5134 {
5135         PGresult   *res;
5136         int                     ntups;
5137         int                     i;
5138         PQExpBuffer query;
5139         AccessMethodInfo *aminfo;
5140         int                     i_tableoid;
5141         int                     i_oid;
5142         int                     i_amname;
5143         int                     i_amhandler;
5144         int                     i_amtype;
5145
5146         /* Before 9.6, there are no user-defined access methods */
5147         if (fout->remoteVersion < 90600)
5148         {
5149                 *numAccessMethods = 0;
5150                 return NULL;
5151         }
5152
5153         query = createPQExpBuffer();
5154
5155         /* Select all access methods from pg_am table */
5156         appendPQExpBuffer(query, "SELECT tableoid, oid, amname, amtype, "
5157                                           "amhandler::pg_catalog.regproc AS amhandler "
5158                                           "FROM pg_am");
5159
5160         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5161
5162         ntups = PQntuples(res);
5163         *numAccessMethods = ntups;
5164
5165         aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
5166
5167         i_tableoid = PQfnumber(res, "tableoid");
5168         i_oid = PQfnumber(res, "oid");
5169         i_amname = PQfnumber(res, "amname");
5170         i_amhandler = PQfnumber(res, "amhandler");
5171         i_amtype = PQfnumber(res, "amtype");
5172
5173         for (i = 0; i < ntups; i++)
5174         {
5175                 aminfo[i].dobj.objType = DO_ACCESS_METHOD;
5176                 aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5177                 aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5178                 AssignDumpId(&aminfo[i].dobj);
5179                 aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
5180                 aminfo[i].dobj.namespace = NULL;
5181                 aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
5182                 aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
5183
5184                 /* Decide whether we want to dump it */
5185                 selectDumpableAccessMethod(&(aminfo[i]), fout);
5186
5187                 /* Access methods do not currently have ACLs. */
5188                 aminfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5189         }
5190
5191         PQclear(res);
5192
5193         destroyPQExpBuffer(query);
5194
5195         return aminfo;
5196 }
5197
5198
5199 /*
5200  * getOpclasses:
5201  *        read all opclasses in the system catalogs and return them in the
5202  * OpclassInfo* structure
5203  *
5204  *      numOpclasses is set to the number of opclasses read in
5205  */
5206 OpclassInfo *
5207 getOpclasses(Archive *fout, int *numOpclasses)
5208 {
5209         PGresult   *res;
5210         int                     ntups;
5211         int                     i;
5212         PQExpBuffer query = createPQExpBuffer();
5213         OpclassInfo *opcinfo;
5214         int                     i_tableoid;
5215         int                     i_oid;
5216         int                     i_opcname;
5217         int                     i_opcnamespace;
5218         int                     i_rolname;
5219
5220         /*
5221          * find all opclasses, including builtin opclasses; we filter out
5222          * system-defined opclasses at dump-out time.
5223          */
5224
5225         appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
5226                                           "opcnamespace, "
5227                                           "(%s opcowner) AS rolname "
5228                                           "FROM pg_opclass",
5229                                           username_subquery);
5230
5231         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5232
5233         ntups = PQntuples(res);
5234         *numOpclasses = ntups;
5235
5236         opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
5237
5238         i_tableoid = PQfnumber(res, "tableoid");
5239         i_oid = PQfnumber(res, "oid");
5240         i_opcname = PQfnumber(res, "opcname");
5241         i_opcnamespace = PQfnumber(res, "opcnamespace");
5242         i_rolname = PQfnumber(res, "rolname");
5243
5244         for (i = 0; i < ntups; i++)
5245         {
5246                 opcinfo[i].dobj.objType = DO_OPCLASS;
5247                 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5248                 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5249                 AssignDumpId(&opcinfo[i].dobj);
5250                 opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
5251                 opcinfo[i].dobj.namespace =
5252                         findNamespace(fout,
5253                                                   atooid(PQgetvalue(res, i, i_opcnamespace)));
5254                 opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5255
5256                 /* Decide whether we want to dump it */
5257                 selectDumpableObject(&(opcinfo[i].dobj), fout);
5258
5259                 /* Op Classes do not currently have ACLs. */
5260                 opcinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5261
5262                 if (strlen(opcinfo[i].rolname) == 0)
5263                         write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
5264                                           opcinfo[i].dobj.name);
5265         }
5266
5267         PQclear(res);
5268
5269         destroyPQExpBuffer(query);
5270
5271         return opcinfo;
5272 }
5273
5274 /*
5275  * getOpfamilies:
5276  *        read all opfamilies in the system catalogs and return them in the
5277  * OpfamilyInfo* structure
5278  *
5279  *      numOpfamilies is set to the number of opfamilies read in
5280  */
5281 OpfamilyInfo *
5282 getOpfamilies(Archive *fout, int *numOpfamilies)
5283 {
5284         PGresult   *res;
5285         int                     ntups;
5286         int                     i;
5287         PQExpBuffer query;
5288         OpfamilyInfo *opfinfo;
5289         int                     i_tableoid;
5290         int                     i_oid;
5291         int                     i_opfname;
5292         int                     i_opfnamespace;
5293         int                     i_rolname;
5294
5295         /* Before 8.3, there is no separate concept of opfamilies */
5296         if (fout->remoteVersion < 80300)
5297         {
5298                 *numOpfamilies = 0;
5299                 return NULL;
5300         }
5301
5302         query = createPQExpBuffer();
5303
5304         /*
5305          * find all opfamilies, including builtin opfamilies; we filter out
5306          * system-defined opfamilies at dump-out time.
5307          */
5308
5309         appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
5310                                           "opfnamespace, "
5311                                           "(%s opfowner) AS rolname "
5312                                           "FROM pg_opfamily",
5313                                           username_subquery);
5314
5315         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5316
5317         ntups = PQntuples(res);
5318         *numOpfamilies = ntups;
5319
5320         opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
5321
5322         i_tableoid = PQfnumber(res, "tableoid");
5323         i_oid = PQfnumber(res, "oid");
5324         i_opfname = PQfnumber(res, "opfname");
5325         i_opfnamespace = PQfnumber(res, "opfnamespace");
5326         i_rolname = PQfnumber(res, "rolname");
5327
5328         for (i = 0; i < ntups; i++)
5329         {
5330                 opfinfo[i].dobj.objType = DO_OPFAMILY;
5331                 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5332                 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5333                 AssignDumpId(&opfinfo[i].dobj);
5334                 opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
5335                 opfinfo[i].dobj.namespace =
5336                         findNamespace(fout,
5337                                                   atooid(PQgetvalue(res, i, i_opfnamespace)));
5338                 opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5339
5340                 /* Decide whether we want to dump it */
5341                 selectDumpableObject(&(opfinfo[i].dobj), fout);
5342
5343                 /* Extensions do not currently have ACLs. */
5344                 opfinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5345
5346                 if (strlen(opfinfo[i].rolname) == 0)
5347                         write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
5348                                           opfinfo[i].dobj.name);
5349         }
5350
5351         PQclear(res);
5352
5353         destroyPQExpBuffer(query);
5354
5355         return opfinfo;
5356 }
5357
5358 /*
5359  * getAggregates:
5360  *        read all the user-defined aggregates in the system catalogs and
5361  * return them in the AggInfo* structure
5362  *
5363  * numAggs is set to the number of aggregates read in
5364  */
5365 AggInfo *
5366 getAggregates(Archive *fout, int *numAggs)
5367 {
5368         DumpOptions *dopt = fout->dopt;
5369         PGresult   *res;
5370         int                     ntups;
5371         int                     i;
5372         PQExpBuffer query = createPQExpBuffer();
5373         AggInfo    *agginfo;
5374         int                     i_tableoid;
5375         int                     i_oid;
5376         int                     i_aggname;
5377         int                     i_aggnamespace;
5378         int                     i_pronargs;
5379         int                     i_proargtypes;
5380         int                     i_rolname;
5381         int                     i_aggacl;
5382         int                     i_raggacl;
5383         int                     i_initaggacl;
5384         int                     i_initraggacl;
5385
5386         /*
5387          * Find all interesting aggregates.  See comment in getFuncs() for the
5388          * rationale behind the filtering logic.
5389          */
5390         if (fout->remoteVersion >= 90600)
5391         {
5392                 PQExpBuffer acl_subquery = createPQExpBuffer();
5393                 PQExpBuffer racl_subquery = createPQExpBuffer();
5394                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5395                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5396                 const char *agg_check;
5397
5398                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5399                                                 initracl_subquery, "p.proacl", "p.proowner", "'f'",
5400                                                 dopt->binary_upgrade);
5401
5402                 agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
5403                                          : "p.proisagg");
5404
5405                 appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
5406                                                   "p.proname AS aggname, "
5407                                                   "p.pronamespace AS aggnamespace, "
5408                                                   "p.pronargs, p.proargtypes, "
5409                                                   "(%s p.proowner) AS rolname, "
5410                                                   "%s AS aggacl, "
5411                                                   "%s AS raggacl, "
5412                                                   "%s AS initaggacl, "
5413                                                   "%s AS initraggacl "
5414                                                   "FROM pg_proc p "
5415                                                   "LEFT JOIN pg_init_privs pip ON "
5416                                                   "(p.oid = pip.objoid "
5417                                                   "AND pip.classoid = 'pg_proc'::regclass "
5418                                                   "AND pip.objsubid = 0) "
5419                                                   "WHERE %s AND ("
5420                                                   "p.pronamespace != "
5421                                                   "(SELECT oid FROM pg_namespace "
5422                                                   "WHERE nspname = 'pg_catalog') OR "
5423                                                   "p.proacl IS DISTINCT FROM pip.initprivs",
5424                                                   username_subquery,
5425                                                   acl_subquery->data,
5426                                                   racl_subquery->data,
5427                                                   initacl_subquery->data,
5428                                                   initracl_subquery->data,
5429                                                   agg_check);
5430                 if (dopt->binary_upgrade)
5431                         appendPQExpBufferStr(query,
5432                                                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5433                                                                  "classid = 'pg_proc'::regclass AND "
5434                                                                  "objid = p.oid AND "
5435                                                                  "refclassid = 'pg_extension'::regclass AND "
5436                                                                  "deptype = 'e')");
5437                 appendPQExpBufferChar(query, ')');
5438
5439                 destroyPQExpBuffer(acl_subquery);
5440                 destroyPQExpBuffer(racl_subquery);
5441                 destroyPQExpBuffer(initacl_subquery);
5442                 destroyPQExpBuffer(initracl_subquery);
5443         }
5444         else if (fout->remoteVersion >= 80200)
5445         {
5446                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
5447                                                   "pronamespace AS aggnamespace, "
5448                                                   "pronargs, proargtypes, "
5449                                                   "(%s proowner) AS rolname, "
5450                                                   "proacl AS aggacl, "
5451                                                   "NULL AS raggacl, "
5452                                                   "NULL AS initaggacl, NULL AS initraggacl "
5453                                                   "FROM pg_proc p "
5454                                                   "WHERE proisagg AND ("
5455                                                   "pronamespace != "
5456                                                   "(SELECT oid FROM pg_namespace "
5457                                                   "WHERE nspname = 'pg_catalog')",
5458                                                   username_subquery);
5459                 if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
5460                         appendPQExpBufferStr(query,
5461                                                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5462                                                                  "classid = 'pg_proc'::regclass AND "
5463                                                                  "objid = p.oid AND "
5464                                                                  "refclassid = 'pg_extension'::regclass AND "
5465                                                                  "deptype = 'e')");
5466                 appendPQExpBufferChar(query, ')');
5467         }
5468         else
5469         {
5470                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
5471                                                   "pronamespace AS aggnamespace, "
5472                                                   "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
5473                                                   "proargtypes, "
5474                                                   "(%s proowner) AS rolname, "
5475                                                   "proacl AS aggacl, "
5476                                                   "NULL AS raggacl, "
5477                                                   "NULL AS initaggacl, NULL AS initraggacl "
5478                                                   "FROM pg_proc "
5479                                                   "WHERE proisagg "
5480                                                   "AND pronamespace != "
5481                                                   "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
5482                                                   username_subquery);
5483         }
5484
5485         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5486
5487         ntups = PQntuples(res);
5488         *numAggs = ntups;
5489
5490         agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
5491
5492         i_tableoid = PQfnumber(res, "tableoid");
5493         i_oid = PQfnumber(res, "oid");
5494         i_aggname = PQfnumber(res, "aggname");
5495         i_aggnamespace = PQfnumber(res, "aggnamespace");
5496         i_pronargs = PQfnumber(res, "pronargs");
5497         i_proargtypes = PQfnumber(res, "proargtypes");
5498         i_rolname = PQfnumber(res, "rolname");
5499         i_aggacl = PQfnumber(res, "aggacl");
5500         i_raggacl = PQfnumber(res, "raggacl");
5501         i_initaggacl = PQfnumber(res, "initaggacl");
5502         i_initraggacl = PQfnumber(res, "initraggacl");
5503
5504         for (i = 0; i < ntups; i++)
5505         {
5506                 agginfo[i].aggfn.dobj.objType = DO_AGG;
5507                 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5508                 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5509                 AssignDumpId(&agginfo[i].aggfn.dobj);
5510                 agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
5511                 agginfo[i].aggfn.dobj.namespace =
5512                         findNamespace(fout,
5513                                                   atooid(PQgetvalue(res, i, i_aggnamespace)));
5514                 agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5515                 if (strlen(agginfo[i].aggfn.rolname) == 0)
5516                         write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
5517                                           agginfo[i].aggfn.dobj.name);
5518                 agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
5519                 agginfo[i].aggfn.prorettype = InvalidOid;       /* not saved */
5520                 agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
5521                 agginfo[i].aggfn.rproacl = pg_strdup(PQgetvalue(res, i, i_raggacl));
5522                 agginfo[i].aggfn.initproacl = pg_strdup(PQgetvalue(res, i, i_initaggacl));
5523                 agginfo[i].aggfn.initrproacl = pg_strdup(PQgetvalue(res, i, i_initraggacl));
5524                 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
5525                 if (agginfo[i].aggfn.nargs == 0)
5526                         agginfo[i].aggfn.argtypes = NULL;
5527                 else
5528                 {
5529                         agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
5530                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
5531                                                   agginfo[i].aggfn.argtypes,
5532                                                   agginfo[i].aggfn.nargs);
5533                 }
5534
5535                 /* Decide whether we want to dump it */
5536                 selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
5537
5538                 /* Do not try to dump ACL if no ACL exists. */
5539                 if (PQgetisnull(res, i, i_aggacl) && PQgetisnull(res, i, i_raggacl) &&
5540                         PQgetisnull(res, i, i_initaggacl) &&
5541                         PQgetisnull(res, i, i_initraggacl))
5542                         agginfo[i].aggfn.dobj.dump &= ~DUMP_COMPONENT_ACL;
5543         }
5544
5545         PQclear(res);
5546
5547         destroyPQExpBuffer(query);
5548
5549         return agginfo;
5550 }
5551
5552 /*
5553  * getFuncs:
5554  *        read all the user-defined functions in the system catalogs and
5555  * return them in the FuncInfo* structure
5556  *
5557  * numFuncs is set to the number of functions read in
5558  */
5559 FuncInfo *
5560 getFuncs(Archive *fout, int *numFuncs)
5561 {
5562         DumpOptions *dopt = fout->dopt;
5563         PGresult   *res;
5564         int                     ntups;
5565         int                     i;
5566         PQExpBuffer query = createPQExpBuffer();
5567         FuncInfo   *finfo;
5568         int                     i_tableoid;
5569         int                     i_oid;
5570         int                     i_proname;
5571         int                     i_pronamespace;
5572         int                     i_rolname;
5573         int                     i_prolang;
5574         int                     i_pronargs;
5575         int                     i_proargtypes;
5576         int                     i_prorettype;
5577         int                     i_proacl;
5578         int                     i_rproacl;
5579         int                     i_initproacl;
5580         int                     i_initrproacl;
5581
5582         /*
5583          * Find all interesting functions.  This is a bit complicated:
5584          *
5585          * 1. Always exclude aggregates; those are handled elsewhere.
5586          *
5587          * 2. Always exclude functions that are internally dependent on something
5588          * else, since presumably those will be created as a result of creating
5589          * the something else.  This currently acts only to suppress constructor
5590          * functions for range types (so we only need it in 9.2 and up).  Note
5591          * this is OK only because the constructors don't have any dependencies
5592          * the range type doesn't have; otherwise we might not get creation
5593          * ordering correct.
5594          *
5595          * 3. Otherwise, we normally exclude functions in pg_catalog.  However, if
5596          * they're members of extensions and we are in binary-upgrade mode then
5597          * include them, since we want to dump extension members individually in
5598          * that mode.  Also, if they are used by casts or transforms then we need
5599          * to gather the information about them, though they won't be dumped if
5600          * they are built-in.  Also, in 9.6 and up, include functions in
5601          * pg_catalog if they have an ACL different from what's shown in
5602          * pg_init_privs.
5603          */
5604         if (fout->remoteVersion >= 90600)
5605         {
5606                 PQExpBuffer acl_subquery = createPQExpBuffer();
5607                 PQExpBuffer racl_subquery = createPQExpBuffer();
5608                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5609                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5610                 const char *not_agg_check;
5611
5612                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5613                                                 initracl_subquery, "p.proacl", "p.proowner", "'f'",
5614                                                 dopt->binary_upgrade);
5615
5616                 not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
5617                                                  : "NOT p.proisagg");
5618
5619                 appendPQExpBuffer(query,
5620                                                   "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
5621                                                   "p.pronargs, p.proargtypes, p.prorettype, "
5622                                                   "%s AS proacl, "
5623                                                   "%s AS rproacl, "
5624                                                   "%s AS initproacl, "
5625                                                   "%s AS initrproacl, "
5626                                                   "p.pronamespace, "
5627                                                   "(%s p.proowner) AS rolname "
5628                                                   "FROM pg_proc p "
5629                                                   "LEFT JOIN pg_init_privs pip ON "
5630                                                   "(p.oid = pip.objoid "
5631                                                   "AND pip.classoid = 'pg_proc'::regclass "
5632                                                   "AND pip.objsubid = 0) "
5633                                                   "WHERE %s"
5634                                                   "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
5635                                                   "WHERE classid = 'pg_proc'::regclass AND "
5636                                                   "objid = p.oid AND deptype = 'i')"
5637                                                   "\n  AND ("
5638                                                   "\n  pronamespace != "
5639                                                   "(SELECT oid FROM pg_namespace "
5640                                                   "WHERE nspname = 'pg_catalog')"
5641                                                   "\n  OR EXISTS (SELECT 1 FROM pg_cast"
5642                                                   "\n  WHERE pg_cast.oid > %u "
5643                                                   "\n  AND p.oid = pg_cast.castfunc)"
5644                                                   "\n  OR EXISTS (SELECT 1 FROM pg_transform"
5645                                                   "\n  WHERE pg_transform.oid > %u AND "
5646                                                   "\n  (p.oid = pg_transform.trffromsql"
5647                                                   "\n  OR p.oid = pg_transform.trftosql))",
5648                                                   acl_subquery->data,
5649                                                   racl_subquery->data,
5650                                                   initacl_subquery->data,
5651                                                   initracl_subquery->data,
5652                                                   username_subquery,
5653                                                   not_agg_check,
5654                                                   g_last_builtin_oid,
5655                                                   g_last_builtin_oid);
5656                 if (dopt->binary_upgrade)
5657                         appendPQExpBufferStr(query,
5658                                                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5659                                                                  "classid = 'pg_proc'::regclass AND "
5660                                                                  "objid = p.oid AND "
5661                                                                  "refclassid = 'pg_extension'::regclass AND "
5662                                                                  "deptype = 'e')");
5663                 appendPQExpBufferStr(query,
5664                                                          "\n  OR p.proacl IS DISTINCT FROM pip.initprivs");
5665                 appendPQExpBufferChar(query, ')');
5666
5667                 destroyPQExpBuffer(acl_subquery);
5668                 destroyPQExpBuffer(racl_subquery);
5669                 destroyPQExpBuffer(initacl_subquery);
5670                 destroyPQExpBuffer(initracl_subquery);
5671         }
5672         else
5673         {
5674                 appendPQExpBuffer(query,
5675                                                   "SELECT tableoid, oid, proname, prolang, "
5676                                                   "pronargs, proargtypes, prorettype, proacl, "
5677                                                   "NULL as rproacl, "
5678                                                   "NULL as initproacl, NULL AS initrproacl, "
5679                                                   "pronamespace, "
5680                                                   "(%s proowner) AS rolname "
5681                                                   "FROM pg_proc p "
5682                                                   "WHERE NOT proisagg",
5683                                                   username_subquery);
5684                 if (fout->remoteVersion >= 90200)
5685                         appendPQExpBufferStr(query,
5686                                                                  "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
5687                                                                  "WHERE classid = 'pg_proc'::regclass AND "
5688                                                                  "objid = p.oid AND deptype = 'i')");
5689                 appendPQExpBuffer(query,
5690                                                   "\n  AND ("
5691                                                   "\n  pronamespace != "
5692                                                   "(SELECT oid FROM pg_namespace "
5693                                                   "WHERE nspname = 'pg_catalog')"
5694                                                   "\n  OR EXISTS (SELECT 1 FROM pg_cast"
5695                                                   "\n  WHERE pg_cast.oid > '%u'::oid"
5696                                                   "\n  AND p.oid = pg_cast.castfunc)",
5697                                                   g_last_builtin_oid);
5698
5699                 if (fout->remoteVersion >= 90500)
5700                         appendPQExpBuffer(query,
5701                                                           "\n  OR EXISTS (SELECT 1 FROM pg_transform"
5702                                                           "\n  WHERE pg_transform.oid > '%u'::oid"
5703                                                           "\n  AND (p.oid = pg_transform.trffromsql"
5704                                                           "\n  OR p.oid = pg_transform.trftosql))",
5705                                                           g_last_builtin_oid);
5706
5707                 if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
5708                         appendPQExpBufferStr(query,
5709                                                                  "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5710                                                                  "classid = 'pg_proc'::regclass AND "
5711                                                                  "objid = p.oid AND "
5712                                                                  "refclassid = 'pg_extension'::regclass AND "
5713                                                                  "deptype = 'e')");
5714                 appendPQExpBufferChar(query, ')');
5715         }
5716
5717         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5718
5719         ntups = PQntuples(res);
5720
5721         *numFuncs = ntups;
5722
5723         finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
5724
5725         i_tableoid = PQfnumber(res, "tableoid");
5726         i_oid = PQfnumber(res, "oid");
5727         i_proname = PQfnumber(res, "proname");
5728         i_pronamespace = PQfnumber(res, "pronamespace");
5729         i_rolname = PQfnumber(res, "rolname");
5730         i_prolang = PQfnumber(res, "prolang");
5731         i_pronargs = PQfnumber(res, "pronargs");
5732         i_proargtypes = PQfnumber(res, "proargtypes");
5733         i_prorettype = PQfnumber(res, "prorettype");
5734         i_proacl = PQfnumber(res, "proacl");
5735         i_rproacl = PQfnumber(res, "rproacl");
5736         i_initproacl = PQfnumber(res, "initproacl");
5737         i_initrproacl = PQfnumber(res, "initrproacl");
5738
5739         for (i = 0; i < ntups; i++)
5740         {
5741                 finfo[i].dobj.objType = DO_FUNC;
5742                 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5743                 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5744                 AssignDumpId(&finfo[i].dobj);
5745                 finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
5746                 finfo[i].dobj.namespace =
5747                         findNamespace(fout,
5748                                                   atooid(PQgetvalue(res, i, i_pronamespace)));
5749                 finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5750                 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
5751                 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
5752                 finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
5753                 finfo[i].rproacl = pg_strdup(PQgetvalue(res, i, i_rproacl));
5754                 finfo[i].initproacl = pg_strdup(PQgetvalue(res, i, i_initproacl));
5755                 finfo[i].initrproacl = pg_strdup(PQgetvalue(res, i, i_initrproacl));
5756                 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
5757                 if (finfo[i].nargs == 0)
5758                         finfo[i].argtypes = NULL;
5759                 else
5760                 {
5761                         finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
5762                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
5763                                                   finfo[i].argtypes, finfo[i].nargs);
5764                 }
5765
5766                 /* Decide whether we want to dump it */
5767                 selectDumpableObject(&(finfo[i].dobj), fout);
5768
5769                 /* Do not try to dump ACL if no ACL exists. */
5770                 if (PQgetisnull(res, i, i_proacl) && PQgetisnull(res, i, i_rproacl) &&
5771                         PQgetisnull(res, i, i_initproacl) &&
5772                         PQgetisnull(res, i, i_initrproacl))
5773                         finfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5774
5775                 if (strlen(finfo[i].rolname) == 0)
5776                         write_msg(NULL,
5777                                           "WARNING: owner of function \"%s\" appears to be invalid\n",
5778                                           finfo[i].dobj.name);
5779         }
5780
5781         PQclear(res);
5782
5783         destroyPQExpBuffer(query);
5784
5785         return finfo;
5786 }
5787
5788 /*
5789  * getTables
5790  *        read all the tables (no indexes)
5791  * in the system catalogs return them in the TableInfo* structure
5792  *
5793  * numTables is set to the number of tables read in
5794  */
5795 TableInfo *
5796 getTables(Archive *fout, int *numTables)
5797 {
5798         DumpOptions *dopt = fout->dopt;
5799         PGresult   *res;
5800         int                     ntups;
5801         int                     i;
5802         PQExpBuffer query = createPQExpBuffer();
5803         TableInfo  *tblinfo;
5804         int                     i_reltableoid;
5805         int                     i_reloid;
5806         int                     i_relname;
5807         int                     i_relnamespace;
5808         int                     i_relkind;
5809         int                     i_relacl;
5810         int                     i_rrelacl;
5811         int                     i_initrelacl;
5812         int                     i_initrrelacl;
5813         int                     i_rolname;
5814         int                     i_relchecks;
5815         int                     i_relhastriggers;
5816         int                     i_relhasindex;
5817         int                     i_relhasrules;
5818         int                     i_relrowsec;
5819         int                     i_relforcerowsec;
5820         int                     i_relhasoids;
5821         int                     i_relfrozenxid;
5822         int                     i_relminmxid;
5823         int                     i_toastoid;
5824         int                     i_toastfrozenxid;
5825         int                     i_toastminmxid;
5826         int                     i_relpersistence;
5827         int                     i_relispopulated;
5828         int                     i_relreplident;
5829         int                     i_owning_tab;
5830         int                     i_owning_col;
5831         int                     i_reltablespace;
5832         int                     i_reloptions;
5833         int                     i_checkoption;
5834         int                     i_toastreloptions;
5835         int                     i_reloftype;
5836         int                     i_relpages;
5837         int                     i_is_identity_sequence;
5838         int                     i_changed_acl;
5839         int                     i_partkeydef;
5840         int                     i_ispartition;
5841         int                     i_partbound;
5842
5843         /*
5844          * Find all the tables and table-like objects.
5845          *
5846          * We include system catalogs, so that we can work if a user table is
5847          * defined to inherit from a system catalog (pretty weird, but...)
5848          *
5849          * We ignore relations that are not ordinary tables, sequences, views,
5850          * materialized views, composite types, or foreign tables.
5851          *
5852          * Composite-type table entries won't be dumped as such, but we have to
5853          * make a DumpableObject for them so that we can track dependencies of the
5854          * composite type (pg_depend entries for columns of the composite type
5855          * link to the pg_class entry not the pg_type entry).
5856          *
5857          * Note: in this phase we should collect only a minimal amount of
5858          * information about each table, basically just enough to decide if it is
5859          * interesting. We must fetch all tables in this phase because otherwise
5860          * we cannot correctly identify inherited columns, owned sequences, etc.
5861          */
5862
5863         if (fout->remoteVersion >= 90600)
5864         {
5865                 char       *partkeydef = "NULL";
5866                 char       *ispartition = "false";
5867                 char       *partbound = "NULL";
5868                 char       *relhasoids = "c.relhasoids";
5869
5870                 PQExpBuffer acl_subquery = createPQExpBuffer();
5871                 PQExpBuffer racl_subquery = createPQExpBuffer();
5872                 PQExpBuffer initacl_subquery = createPQExpBuffer();
5873                 PQExpBuffer initracl_subquery = createPQExpBuffer();
5874
5875                 PQExpBuffer attacl_subquery = createPQExpBuffer();
5876                 PQExpBuffer attracl_subquery = createPQExpBuffer();
5877                 PQExpBuffer attinitacl_subquery = createPQExpBuffer();
5878                 PQExpBuffer attinitracl_subquery = createPQExpBuffer();
5879
5880                 /*
5881                  * Collect the information about any partitioned tables, which were
5882                  * added in PG10.
5883                  */
5884
5885                 if (fout->remoteVersion >= 100000)
5886                 {
5887                         partkeydef = "pg_get_partkeydef(c.oid)";
5888                         ispartition = "c.relispartition";
5889                         partbound = "pg_get_expr(c.relpartbound, c.oid)";
5890                 }
5891
5892                 /* In PG12 upwards WITH OIDS does not exist anymore. */
5893                 if (fout->remoteVersion >= 120000)
5894                         relhasoids = "'f'::bool";
5895
5896                 /*
5897                  * Left join to pick up dependency info linking sequences to their
5898                  * owning column, if any (note this dependency is AUTO as of 8.2)
5899                  *
5900                  * Left join to detect if any privileges are still as-set-at-init, in
5901                  * which case we won't dump out ACL commands for those.
5902                  */
5903
5904                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5905                                                 initracl_subquery, "c.relacl", "c.relowner",
5906                                                 "CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
5907                                                 " THEN 's' ELSE 'r' END::\"char\"",
5908                                                 dopt->binary_upgrade);
5909
5910                 buildACLQueries(attacl_subquery, attracl_subquery, attinitacl_subquery,
5911                                                 attinitracl_subquery, "at.attacl", "c.relowner", "'c'",
5912                                                 dopt->binary_upgrade);
5913
5914                 appendPQExpBuffer(query,
5915                                                   "SELECT c.tableoid, c.oid, c.relname, "
5916                                                   "%s AS relacl, %s as rrelacl, "
5917                                                   "%s AS initrelacl, %s as initrrelacl, "
5918                                                   "c.relkind, c.relnamespace, "
5919                                                   "(%s c.relowner) AS rolname, "
5920                                                   "c.relchecks, c.relhastriggers, "
5921                                                   "c.relhasindex, c.relhasrules, %s AS relhasoids, "
5922                                                   "c.relrowsecurity, c.relforcerowsecurity, "
5923                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
5924                                                   "tc.relfrozenxid AS tfrozenxid, "
5925                                                   "tc.relminmxid AS tminmxid, "
5926                                                   "c.relpersistence, c.relispopulated, "
5927                                                   "c.relreplident, c.relpages, "
5928                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
5929                                                   "d.refobjid AS owning_tab, "
5930                                                   "d.refobjsubid AS owning_col, "
5931                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
5932                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
5933                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
5934                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
5935                                                   "tc.reloptions AS toast_reloptions, "
5936                                                   "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, "
5937                                                   "EXISTS (SELECT 1 FROM pg_attribute at LEFT JOIN pg_init_privs pip ON "
5938                                                   "(c.oid = pip.objoid "
5939                                                   "AND pip.classoid = 'pg_class'::regclass "
5940                                                   "AND pip.objsubid = at.attnum)"
5941                                                   "WHERE at.attrelid = c.oid AND ("
5942                                                   "%s IS NOT NULL "
5943                                                   "OR %s IS NOT NULL "
5944                                                   "OR %s IS NOT NULL "
5945                                                   "OR %s IS NOT NULL"
5946                                                   "))"
5947                                                   "AS changed_acl, "
5948                                                   "%s AS partkeydef, "
5949                                                   "%s AS ispartition, "
5950                                                   "%s AS partbound "
5951                                                   "FROM pg_class c "
5952                                                   "LEFT JOIN pg_depend d ON "
5953                                                   "(c.relkind = '%c' AND "
5954                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
5955                                                   "d.objsubid = 0 AND "
5956                                                   "d.refclassid = c.tableoid AND d.deptype IN ('a', 'i')) "
5957                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
5958                                                   "LEFT JOIN pg_init_privs pip ON "
5959                                                   "(c.oid = pip.objoid "
5960                                                   "AND pip.classoid = 'pg_class'::regclass "
5961                                                   "AND pip.objsubid = 0) "
5962                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c', '%c') "
5963                                                   "ORDER BY c.oid",
5964                                                   acl_subquery->data,
5965                                                   racl_subquery->data,
5966                                                   initacl_subquery->data,
5967                                                   initracl_subquery->data,
5968                                                   username_subquery,
5969                                                   relhasoids,
5970                                                   RELKIND_SEQUENCE,
5971                                                   attacl_subquery->data,
5972                                                   attracl_subquery->data,
5973                                                   attinitacl_subquery->data,
5974                                                   attinitracl_subquery->data,
5975                                                   partkeydef,
5976                                                   ispartition,
5977                                                   partbound,
5978                                                   RELKIND_SEQUENCE,
5979                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
5980                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
5981                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
5982                                                   RELKIND_PARTITIONED_TABLE);
5983
5984                 destroyPQExpBuffer(acl_subquery);
5985                 destroyPQExpBuffer(racl_subquery);
5986                 destroyPQExpBuffer(initacl_subquery);
5987                 destroyPQExpBuffer(initracl_subquery);
5988
5989                 destroyPQExpBuffer(attacl_subquery);
5990                 destroyPQExpBuffer(attracl_subquery);
5991                 destroyPQExpBuffer(attinitacl_subquery);
5992                 destroyPQExpBuffer(attinitracl_subquery);
5993         }
5994         else if (fout->remoteVersion >= 90500)
5995         {
5996                 /*
5997                  * Left join to pick up dependency info linking sequences to their
5998                  * owning column, if any (note this dependency is AUTO as of 8.2)
5999                  */
6000                 appendPQExpBuffer(query,
6001                                                   "SELECT c.tableoid, c.oid, c.relname, "
6002                                                   "c.relacl, NULL as rrelacl, "
6003                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6004                                                   "c.relkind, "
6005                                                   "c.relnamespace, "
6006                                                   "(%s c.relowner) AS rolname, "
6007                                                   "c.relchecks, c.relhastriggers, "
6008                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6009                                                   "c.relrowsecurity, c.relforcerowsecurity, "
6010                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6011                                                   "tc.relfrozenxid AS tfrozenxid, "
6012                                                   "tc.relminmxid AS tminmxid, "
6013                                                   "c.relpersistence, c.relispopulated, "
6014                                                   "c.relreplident, c.relpages, "
6015                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6016                                                   "d.refobjid AS owning_tab, "
6017                                                   "d.refobjsubid AS owning_col, "
6018                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6019                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6020                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6021                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6022                                                   "tc.reloptions AS toast_reloptions, "
6023                                                   "NULL AS changed_acl, "
6024                                                   "NULL AS partkeydef, "
6025                                                   "false AS ispartition, "
6026                                                   "NULL AS partbound "
6027                                                   "FROM pg_class c "
6028                                                   "LEFT JOIN pg_depend d ON "
6029                                                   "(c.relkind = '%c' AND "
6030                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6031                                                   "d.objsubid = 0 AND "
6032                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6033                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6034                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6035                                                   "ORDER BY c.oid",
6036                                                   username_subquery,
6037                                                   RELKIND_SEQUENCE,
6038                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6039                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6040                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6041         }
6042         else if (fout->remoteVersion >= 90400)
6043         {
6044                 /*
6045                  * Left join to pick up dependency info linking sequences to their
6046                  * owning column, if any (note this dependency is AUTO as of 8.2)
6047                  */
6048                 appendPQExpBuffer(query,
6049                                                   "SELECT c.tableoid, c.oid, c.relname, "
6050                                                   "c.relacl, NULL as rrelacl, "
6051                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6052                                                   "c.relkind, "
6053                                                   "c.relnamespace, "
6054                                                   "(%s c.relowner) AS rolname, "
6055                                                   "c.relchecks, c.relhastriggers, "
6056                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6057                                                   "'f'::bool AS relrowsecurity, "
6058                                                   "'f'::bool AS relforcerowsecurity, "
6059                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6060                                                   "tc.relfrozenxid AS tfrozenxid, "
6061                                                   "tc.relminmxid AS tminmxid, "
6062                                                   "c.relpersistence, c.relispopulated, "
6063                                                   "c.relreplident, c.relpages, "
6064                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6065                                                   "d.refobjid AS owning_tab, "
6066                                                   "d.refobjsubid AS owning_col, "
6067                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6068                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6069                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6070                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6071                                                   "tc.reloptions AS toast_reloptions, "
6072                                                   "NULL AS changed_acl, "
6073                                                   "NULL AS partkeydef, "
6074                                                   "false AS ispartition, "
6075                                                   "NULL AS partbound "
6076                                                   "FROM pg_class c "
6077                                                   "LEFT JOIN pg_depend d ON "
6078                                                   "(c.relkind = '%c' AND "
6079                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6080                                                   "d.objsubid = 0 AND "
6081                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6082                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6083                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6084                                                   "ORDER BY c.oid",
6085                                                   username_subquery,
6086                                                   RELKIND_SEQUENCE,
6087                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6088                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6089                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6090         }
6091         else if (fout->remoteVersion >= 90300)
6092         {
6093                 /*
6094                  * Left join to pick up dependency info linking sequences to their
6095                  * owning column, if any (note this dependency is AUTO as of 8.2)
6096                  */
6097                 appendPQExpBuffer(query,
6098                                                   "SELECT c.tableoid, c.oid, c.relname, "
6099                                                   "c.relacl, NULL as rrelacl, "
6100                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6101                                                   "c.relkind, "
6102                                                   "c.relnamespace, "
6103                                                   "(%s c.relowner) AS rolname, "
6104                                                   "c.relchecks, c.relhastriggers, "
6105                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6106                                                   "'f'::bool AS relrowsecurity, "
6107                                                   "'f'::bool AS relforcerowsecurity, "
6108                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6109                                                   "tc.relfrozenxid AS tfrozenxid, "
6110                                                   "tc.relminmxid AS tminmxid, "
6111                                                   "c.relpersistence, c.relispopulated, "
6112                                                   "'d' AS relreplident, c.relpages, "
6113                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6114                                                   "d.refobjid AS owning_tab, "
6115                                                   "d.refobjsubid AS owning_col, "
6116                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6117                                                   "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6118                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6119                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6120                                                   "tc.reloptions AS toast_reloptions, "
6121                                                   "NULL AS changed_acl, "
6122                                                   "NULL AS partkeydef, "
6123                                                   "false AS ispartition, "
6124                                                   "NULL AS partbound "
6125                                                   "FROM pg_class c "
6126                                                   "LEFT JOIN pg_depend d ON "
6127                                                   "(c.relkind = '%c' AND "
6128                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6129                                                   "d.objsubid = 0 AND "
6130                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6131                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6132                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6133                                                   "ORDER BY c.oid",
6134                                                   username_subquery,
6135                                                   RELKIND_SEQUENCE,
6136                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6137                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6138                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6139         }
6140         else if (fout->remoteVersion >= 90100)
6141         {
6142                 /*
6143                  * Left join to pick up dependency info linking sequences to their
6144                  * owning column, if any (note this dependency is AUTO as of 8.2)
6145                  */
6146                 appendPQExpBuffer(query,
6147                                                   "SELECT c.tableoid, c.oid, c.relname, "
6148                                                   "c.relacl, NULL as rrelacl, "
6149                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6150                                                   "c.relkind, "
6151                                                   "c.relnamespace, "
6152                                                   "(%s c.relowner) AS rolname, "
6153                                                   "c.relchecks, c.relhastriggers, "
6154                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6155                                                   "'f'::bool AS relrowsecurity, "
6156                                                   "'f'::bool AS relforcerowsecurity, "
6157                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6158                                                   "tc.relfrozenxid AS tfrozenxid, "
6159                                                   "0 AS tminmxid, "
6160                                                   "c.relpersistence, 't' as relispopulated, "
6161                                                   "'d' AS relreplident, c.relpages, "
6162                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6163                                                   "d.refobjid AS owning_tab, "
6164                                                   "d.refobjsubid AS owning_col, "
6165                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6166                                                   "c.reloptions AS reloptions, "
6167                                                   "tc.reloptions AS toast_reloptions, "
6168                                                   "NULL AS changed_acl, "
6169                                                   "NULL AS partkeydef, "
6170                                                   "false AS ispartition, "
6171                                                   "NULL AS partbound "
6172                                                   "FROM pg_class c "
6173                                                   "LEFT JOIN pg_depend d ON "
6174                                                   "(c.relkind = '%c' AND "
6175                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6176                                                   "d.objsubid = 0 AND "
6177                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6178                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6179                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6180                                                   "ORDER BY c.oid",
6181                                                   username_subquery,
6182                                                   RELKIND_SEQUENCE,
6183                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6184                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6185                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6186         }
6187         else if (fout->remoteVersion >= 90000)
6188         {
6189                 /*
6190                  * Left join to pick up dependency info linking sequences to their
6191                  * owning column, if any (note this dependency is AUTO as of 8.2)
6192                  */
6193                 appendPQExpBuffer(query,
6194                                                   "SELECT c.tableoid, c.oid, c.relname, "
6195                                                   "c.relacl, NULL as rrelacl, "
6196                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6197                                                   "c.relkind, "
6198                                                   "c.relnamespace, "
6199                                                   "(%s c.relowner) AS rolname, "
6200                                                   "c.relchecks, c.relhastriggers, "
6201                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6202                                                   "'f'::bool AS relrowsecurity, "
6203                                                   "'f'::bool AS relforcerowsecurity, "
6204                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6205                                                   "tc.relfrozenxid AS tfrozenxid, "
6206                                                   "0 AS tminmxid, "
6207                                                   "'p' AS relpersistence, 't' as relispopulated, "
6208                                                   "'d' AS relreplident, c.relpages, "
6209                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6210                                                   "d.refobjid AS owning_tab, "
6211                                                   "d.refobjsubid AS owning_col, "
6212                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6213                                                   "c.reloptions AS reloptions, "
6214                                                   "tc.reloptions AS toast_reloptions, "
6215                                                   "NULL AS changed_acl, "
6216                                                   "NULL AS partkeydef, "
6217                                                   "false AS ispartition, "
6218                                                   "NULL AS partbound "
6219                                                   "FROM pg_class c "
6220                                                   "LEFT JOIN pg_depend d ON "
6221                                                   "(c.relkind = '%c' AND "
6222                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6223                                                   "d.objsubid = 0 AND "
6224                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6225                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6226                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6227                                                   "ORDER BY c.oid",
6228                                                   username_subquery,
6229                                                   RELKIND_SEQUENCE,
6230                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6231                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6232         }
6233         else if (fout->remoteVersion >= 80400)
6234         {
6235                 /*
6236                  * Left join to pick up dependency info linking sequences to their
6237                  * owning column, if any (note this dependency is AUTO as of 8.2)
6238                  */
6239                 appendPQExpBuffer(query,
6240                                                   "SELECT c.tableoid, c.oid, c.relname, "
6241                                                   "c.relacl, NULL as rrelacl, "
6242                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6243                                                   "c.relkind, "
6244                                                   "c.relnamespace, "
6245                                                   "(%s c.relowner) AS rolname, "
6246                                                   "c.relchecks, c.relhastriggers, "
6247                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6248                                                   "'f'::bool AS relrowsecurity, "
6249                                                   "'f'::bool AS relforcerowsecurity, "
6250                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6251                                                   "tc.relfrozenxid AS tfrozenxid, "
6252                                                   "0 AS tminmxid, "
6253                                                   "'p' AS relpersistence, 't' as relispopulated, "
6254                                                   "'d' AS relreplident, c.relpages, "
6255                                                   "NULL AS reloftype, "
6256                                                   "d.refobjid AS owning_tab, "
6257                                                   "d.refobjsubid AS owning_col, "
6258                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6259                                                   "c.reloptions AS reloptions, "
6260                                                   "tc.reloptions AS toast_reloptions, "
6261                                                   "NULL AS changed_acl, "
6262                                                   "NULL AS partkeydef, "
6263                                                   "false AS ispartition, "
6264                                                   "NULL AS partbound "
6265                                                   "FROM pg_class c "
6266                                                   "LEFT JOIN pg_depend d ON "
6267                                                   "(c.relkind = '%c' AND "
6268                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6269                                                   "d.objsubid = 0 AND "
6270                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6271                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6272                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6273                                                   "ORDER BY c.oid",
6274                                                   username_subquery,
6275                                                   RELKIND_SEQUENCE,
6276                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6277                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6278         }
6279         else if (fout->remoteVersion >= 80200)
6280         {
6281                 /*
6282                  * Left join to pick up dependency info linking sequences to their
6283                  * owning column, if any (note this dependency is AUTO as of 8.2)
6284                  */
6285                 appendPQExpBuffer(query,
6286                                                   "SELECT c.tableoid, c.oid, c.relname, "
6287                                                   "c.relacl, NULL as rrelacl, "
6288                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6289                                                   "c.relkind, "
6290                                                   "c.relnamespace, "
6291                                                   "(%s c.relowner) AS rolname, "
6292                                                   "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
6293                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
6294                                                   "'f'::bool AS relrowsecurity, "
6295                                                   "'f'::bool AS relforcerowsecurity, "
6296                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6297                                                   "tc.relfrozenxid AS tfrozenxid, "
6298                                                   "0 AS tminmxid, "
6299                                                   "'p' AS relpersistence, 't' as relispopulated, "
6300                                                   "'d' AS relreplident, c.relpages, "
6301                                                   "NULL AS reloftype, "
6302                                                   "d.refobjid AS owning_tab, "
6303                                                   "d.refobjsubid AS owning_col, "
6304                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6305                                                   "c.reloptions AS reloptions, "
6306                                                   "NULL AS toast_reloptions, "
6307                                                   "NULL AS changed_acl, "
6308                                                   "NULL AS partkeydef, "
6309                                                   "false AS ispartition, "
6310                                                   "NULL AS partbound "
6311                                                   "FROM pg_class c "
6312                                                   "LEFT JOIN pg_depend d ON "
6313                                                   "(c.relkind = '%c' AND "
6314                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6315                                                   "d.objsubid = 0 AND "
6316                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
6317                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6318                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6319                                                   "ORDER BY c.oid",
6320                                                   username_subquery,
6321                                                   RELKIND_SEQUENCE,
6322                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6323                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6324         }
6325         else
6326         {
6327                 /*
6328                  * Left join to pick up dependency info linking sequences to their
6329                  * owning column, if any
6330                  */
6331                 appendPQExpBuffer(query,
6332                                                   "SELECT c.tableoid, c.oid, relname, "
6333                                                   "relacl, NULL as rrelacl, "
6334                                                   "NULL AS initrelacl, NULL AS initrrelacl, "
6335                                                   "relkind, relnamespace, "
6336                                                   "(%s relowner) AS rolname, "
6337                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
6338                                                   "relhasindex, relhasrules, relhasoids, "
6339                                                   "'f'::bool AS relrowsecurity, "
6340                                                   "'f'::bool AS relforcerowsecurity, "
6341                                                   "0 AS relfrozenxid, 0 AS relminmxid,"
6342                                                   "0 AS toid, "
6343                                                   "0 AS tfrozenxid, 0 AS tminmxid,"
6344                                                   "'p' AS relpersistence, 't' as relispopulated, "
6345                                                   "'d' AS relreplident, relpages, "
6346                                                   "NULL AS reloftype, "
6347                                                   "d.refobjid AS owning_tab, "
6348                                                   "d.refobjsubid AS owning_col, "
6349                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6350                                                   "NULL AS reloptions, "
6351                                                   "NULL AS toast_reloptions, "
6352                                                   "NULL AS changed_acl, "
6353                                                   "NULL AS partkeydef, "
6354                                                   "false AS ispartition, "
6355                                                   "NULL AS partbound "
6356                                                   "FROM pg_class c "
6357                                                   "LEFT JOIN pg_depend d ON "
6358                                                   "(c.relkind = '%c' AND "
6359                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
6360                                                   "d.objsubid = 0 AND "
6361                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
6362                                                   "WHERE relkind in ('%c', '%c', '%c', '%c') "
6363                                                   "ORDER BY c.oid",
6364                                                   username_subquery,
6365                                                   RELKIND_SEQUENCE,
6366                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
6367                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6368         }
6369
6370         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6371
6372         ntups = PQntuples(res);
6373
6374         *numTables = ntups;
6375
6376         /*
6377          * Extract data from result and lock dumpable tables.  We do the locking
6378          * before anything else, to minimize the window wherein a table could
6379          * disappear under us.
6380          *
6381          * Note that we have to save info about all tables here, even when dumping
6382          * only one, because we don't yet know which tables might be inheritance
6383          * ancestors of the target table.
6384          */
6385         tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
6386
6387         i_reltableoid = PQfnumber(res, "tableoid");
6388         i_reloid = PQfnumber(res, "oid");
6389         i_relname = PQfnumber(res, "relname");
6390         i_relnamespace = PQfnumber(res, "relnamespace");
6391         i_relacl = PQfnumber(res, "relacl");
6392         i_rrelacl = PQfnumber(res, "rrelacl");
6393         i_initrelacl = PQfnumber(res, "initrelacl");
6394         i_initrrelacl = PQfnumber(res, "initrrelacl");
6395         i_relkind = PQfnumber(res, "relkind");
6396         i_rolname = PQfnumber(res, "rolname");
6397         i_relchecks = PQfnumber(res, "relchecks");
6398         i_relhastriggers = PQfnumber(res, "relhastriggers");
6399         i_relhasindex = PQfnumber(res, "relhasindex");
6400         i_relhasrules = PQfnumber(res, "relhasrules");
6401         i_relrowsec = PQfnumber(res, "relrowsecurity");
6402         i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
6403         i_relhasoids = PQfnumber(res, "relhasoids");
6404         i_relfrozenxid = PQfnumber(res, "relfrozenxid");
6405         i_relminmxid = PQfnumber(res, "relminmxid");
6406         i_toastoid = PQfnumber(res, "toid");
6407         i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
6408         i_toastminmxid = PQfnumber(res, "tminmxid");
6409         i_relpersistence = PQfnumber(res, "relpersistence");
6410         i_relispopulated = PQfnumber(res, "relispopulated");
6411         i_relreplident = PQfnumber(res, "relreplident");
6412         i_relpages = PQfnumber(res, "relpages");
6413         i_owning_tab = PQfnumber(res, "owning_tab");
6414         i_owning_col = PQfnumber(res, "owning_col");
6415         i_reltablespace = PQfnumber(res, "reltablespace");
6416         i_reloptions = PQfnumber(res, "reloptions");
6417         i_checkoption = PQfnumber(res, "checkoption");
6418         i_toastreloptions = PQfnumber(res, "toast_reloptions");
6419         i_reloftype = PQfnumber(res, "reloftype");
6420         i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
6421         i_changed_acl = PQfnumber(res, "changed_acl");
6422         i_partkeydef = PQfnumber(res, "partkeydef");
6423         i_ispartition = PQfnumber(res, "ispartition");
6424         i_partbound = PQfnumber(res, "partbound");
6425
6426         if (dopt->lockWaitTimeout)
6427         {
6428                 /*
6429                  * Arrange to fail instead of waiting forever for a table lock.
6430                  *
6431                  * NB: this coding assumes that the only queries issued within the
6432                  * following loop are LOCK TABLEs; else the timeout may be undesirably
6433                  * applied to other things too.
6434                  */
6435                 resetPQExpBuffer(query);
6436                 appendPQExpBufferStr(query, "SET statement_timeout = ");
6437                 appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
6438                 ExecuteSqlStatement(fout, query->data);
6439         }
6440
6441         for (i = 0; i < ntups; i++)
6442         {
6443                 tblinfo[i].dobj.objType = DO_TABLE;
6444                 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
6445                 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
6446                 AssignDumpId(&tblinfo[i].dobj);
6447                 tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
6448                 tblinfo[i].dobj.namespace =
6449                         findNamespace(fout,
6450                                                   atooid(PQgetvalue(res, i, i_relnamespace)));
6451                 tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6452                 tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
6453                 tblinfo[i].rrelacl = pg_strdup(PQgetvalue(res, i, i_rrelacl));
6454                 tblinfo[i].initrelacl = pg_strdup(PQgetvalue(res, i, i_initrelacl));
6455                 tblinfo[i].initrrelacl = pg_strdup(PQgetvalue(res, i, i_initrrelacl));
6456                 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
6457                 tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
6458                 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
6459                 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
6460                 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
6461                 tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
6462                 tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
6463                 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
6464                 tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
6465                 tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
6466                 tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
6467                 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
6468                 tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
6469                 tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
6470                 tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
6471                 tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
6472                 if (PQgetisnull(res, i, i_reloftype))
6473                         tblinfo[i].reloftype = NULL;
6474                 else
6475                         tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
6476                 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
6477                 if (PQgetisnull(res, i, i_owning_tab))
6478                 {
6479                         tblinfo[i].owning_tab = InvalidOid;
6480                         tblinfo[i].owning_col = 0;
6481                 }
6482                 else
6483                 {
6484                         tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
6485                         tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
6486                 }
6487                 tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
6488                 tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
6489                 if (i_checkoption == -1 || PQgetisnull(res, i, i_checkoption))
6490                         tblinfo[i].checkoption = NULL;
6491                 else
6492                         tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
6493                 tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
6494
6495                 /* other fields were zeroed above */
6496
6497                 /*
6498                  * Decide whether we want to dump this table.
6499                  */
6500                 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
6501                         tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
6502                 else
6503                         selectDumpableTable(&tblinfo[i], fout);
6504
6505                 /*
6506                  * If the table-level and all column-level ACLs for this table are
6507                  * unchanged, then we don't need to worry about including the ACLs for
6508                  * this table.  If any column-level ACLs have been changed, the
6509                  * 'changed_acl' column from the query will indicate that.
6510                  *
6511                  * This can result in a significant performance improvement in cases
6512                  * where we are only looking to dump out the ACL (eg: pg_catalog).
6513                  */
6514                 if (PQgetisnull(res, i, i_relacl) && PQgetisnull(res, i, i_rrelacl) &&
6515                         PQgetisnull(res, i, i_initrelacl) &&
6516                         PQgetisnull(res, i, i_initrrelacl) &&
6517                         strcmp(PQgetvalue(res, i, i_changed_acl), "f") == 0)
6518                         tblinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
6519
6520                 tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
6521                 tblinfo[i].dummy_view = false;  /* might get set during sort */
6522                 tblinfo[i].postponed_def = false;       /* might get set during sort */
6523
6524                 tblinfo[i].is_identity_sequence = (i_is_identity_sequence >= 0 &&
6525                                                                                    strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
6526
6527                 /* Partition key string or NULL */
6528                 tblinfo[i].partkeydef = pg_strdup(PQgetvalue(res, i, i_partkeydef));
6529                 tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
6530                 tblinfo[i].partbound = pg_strdup(PQgetvalue(res, i, i_partbound));
6531
6532                 /*
6533                  * Read-lock target tables to make sure they aren't DROPPED or altered
6534                  * in schema before we get around to dumping them.
6535                  *
6536                  * Note that we don't explicitly lock parents of the target tables; we
6537                  * assume our lock on the child is enough to prevent schema
6538                  * alterations to parent tables.
6539                  *
6540                  * NOTE: it'd be kinda nice to lock other relations too, not only
6541                  * plain or partitioned tables, but the backend doesn't presently
6542                  * allow that.
6543                  *
6544                  * We only need to lock the table for certain components; see
6545                  * pg_dump.h
6546                  */
6547                 if (tblinfo[i].dobj.dump &&
6548                         (tblinfo[i].relkind == RELKIND_RELATION ||
6549                          tblinfo->relkind == RELKIND_PARTITIONED_TABLE) &&
6550                         (tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK))
6551                 {
6552                         resetPQExpBuffer(query);
6553                         appendPQExpBuffer(query,
6554                                                           "LOCK TABLE %s IN ACCESS SHARE MODE",
6555                                                           fmtQualifiedDumpable(&tblinfo[i]));
6556                         ExecuteSqlStatement(fout, query->data);
6557                 }
6558
6559                 /* Emit notice if join for owner failed */
6560                 if (strlen(tblinfo[i].rolname) == 0)
6561                         write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
6562                                           tblinfo[i].dobj.name);
6563         }
6564
6565         if (dopt->lockWaitTimeout)
6566         {
6567                 ExecuteSqlStatement(fout, "SET statement_timeout = 0");
6568         }
6569
6570         PQclear(res);
6571
6572         destroyPQExpBuffer(query);
6573
6574         return tblinfo;
6575 }
6576
6577 /*
6578  * getOwnedSeqs
6579  *        identify owned sequences and mark them as dumpable if owning table is
6580  *
6581  * We used to do this in getTables(), but it's better to do it after the
6582  * index used by findTableByOid() has been set up.
6583  */
6584 void
6585 getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
6586 {
6587         int                     i;
6588
6589         /*
6590          * Force sequences that are "owned" by table columns to be dumped whenever
6591          * their owning table is being dumped.
6592          */
6593         for (i = 0; i < numTables; i++)
6594         {
6595                 TableInfo  *seqinfo = &tblinfo[i];
6596                 TableInfo  *owning_tab;
6597
6598                 if (!OidIsValid(seqinfo->owning_tab))
6599                         continue;                       /* not an owned sequence */
6600
6601                 owning_tab = findTableByOid(seqinfo->owning_tab);
6602                 if (owning_tab == NULL)
6603                         exit_horribly(NULL, "failed sanity check, parent table with OID %u of sequence with OID %u not found\n",
6604                                                   seqinfo->owning_tab, seqinfo->dobj.catId.oid);
6605
6606                 /*
6607                  * Only dump identity sequences if we're going to dump the table that
6608                  * it belongs to.
6609                  */
6610                 if (owning_tab->dobj.dump == DUMP_COMPONENT_NONE &&
6611                         seqinfo->is_identity_sequence)
6612                 {
6613                         seqinfo->dobj.dump = DUMP_COMPONENT_NONE;
6614                         continue;
6615                 }
6616
6617                 /*
6618                  * Otherwise we need to dump the components that are being dumped for
6619                  * the table and any components which the sequence is explicitly
6620                  * marked with.
6621                  *
6622                  * We can't simply use the set of components which are being dumped
6623                  * for the table as the table might be in an extension (and only the
6624                  * non-extension components, eg: ACLs if changed, security labels, and
6625                  * policies, are being dumped) while the sequence is not (and
6626                  * therefore the definition and other components should also be
6627                  * dumped).
6628                  *
6629                  * If the sequence is part of the extension then it should be properly
6630                  * marked by checkExtensionMembership() and this will be a no-op as
6631                  * the table will be equivalently marked.
6632                  */
6633                 seqinfo->dobj.dump = seqinfo->dobj.dump | owning_tab->dobj.dump;
6634
6635                 if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
6636                         seqinfo->interesting = true;
6637         }
6638 }
6639
6640 /*
6641  * getInherits
6642  *        read all the inheritance information
6643  * from the system catalogs return them in the InhInfo* structure
6644  *
6645  * numInherits is set to the number of pairs read in
6646  */
6647 InhInfo *
6648 getInherits(Archive *fout, int *numInherits)
6649 {
6650         PGresult   *res;
6651         int                     ntups;
6652         int                     i;
6653         PQExpBuffer query = createPQExpBuffer();
6654         InhInfo    *inhinfo;
6655
6656         int                     i_inhrelid;
6657         int                     i_inhparent;
6658
6659         /*
6660          * Find all the inheritance information, excluding implicit inheritance
6661          * via partitioning.  We handle that case using getPartitions(), because
6662          * we want more information about partitions than just the parent-child
6663          * relationship.
6664          */
6665         appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
6666
6667         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6668
6669         ntups = PQntuples(res);
6670
6671         *numInherits = ntups;
6672
6673         inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
6674
6675         i_inhrelid = PQfnumber(res, "inhrelid");
6676         i_inhparent = PQfnumber(res, "inhparent");
6677
6678         for (i = 0; i < ntups; i++)
6679         {
6680                 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
6681                 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
6682         }
6683
6684         PQclear(res);
6685
6686         destroyPQExpBuffer(query);
6687
6688         return inhinfo;
6689 }
6690
6691 /*
6692  * getIndexes
6693  *        get information about every index on a dumpable table
6694  *
6695  * Note: index data is not returned directly to the caller, but it
6696  * does get entered into the DumpableObject tables.
6697  */
6698 void
6699 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
6700 {
6701         int                     i,
6702                                 j;
6703         PQExpBuffer query = createPQExpBuffer();
6704         PGresult   *res;
6705         IndxInfo   *indxinfo;
6706         ConstraintInfo *constrinfo;
6707         int                     i_tableoid,
6708                                 i_oid,
6709                                 i_indexname,
6710                                 i_parentidx,
6711                                 i_indexdef,
6712                                 i_indnkeyatts,
6713                                 i_indnatts,
6714                                 i_indkey,
6715                                 i_indisclustered,
6716                                 i_indisreplident,
6717                                 i_contype,
6718                                 i_conname,
6719                                 i_condeferrable,
6720                                 i_condeferred,
6721                                 i_contableoid,
6722                                 i_conoid,
6723                                 i_condef,
6724                                 i_tablespace,
6725                                 i_indreloptions,
6726                                 i_indstatcols,
6727                                 i_indstatvals;
6728         int                     ntups;
6729
6730         for (i = 0; i < numTables; i++)
6731         {
6732                 TableInfo  *tbinfo = &tblinfo[i];
6733
6734                 if (!tbinfo->hasindex)
6735                         continue;
6736
6737                 /*
6738                  * Ignore indexes of tables whose definitions are not to be dumped.
6739                  *
6740                  * We also need indexes on partitioned tables which have partitions to
6741                  * be dumped, in order to dump the indexes on the partitions.
6742                  */
6743                 if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION) &&
6744                         !tbinfo->interesting)
6745                         continue;
6746
6747                 if (g_verbose)
6748                         write_msg(NULL, "reading indexes for table \"%s.%s\"\n",
6749                                           tbinfo->dobj.namespace->dobj.name,
6750                                           tbinfo->dobj.name);
6751
6752                 /*
6753                  * The point of the messy-looking outer join is to find a constraint
6754                  * that is related by an internal dependency link to the index. If we
6755                  * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
6756                  * assume an index won't have more than one internal dependency.
6757                  *
6758                  * As of 9.0 we don't need to look at pg_depend but can check for a
6759                  * match to pg_constraint.conindid.  The check on conrelid is
6760                  * redundant but useful because that column is indexed while conindid
6761                  * is not.
6762                  */
6763                 resetPQExpBuffer(query);
6764                 if (fout->remoteVersion >= 110000)
6765                 {
6766                         appendPQExpBuffer(query,
6767                                                           "SELECT t.tableoid, t.oid, "
6768                                                           "t.relname AS indexname, "
6769                                                           "inh.inhparent AS parentidx, "
6770                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6771                                                           "i.indnkeyatts AS indnkeyatts, "
6772                                                           "i.indnatts AS indnatts, "
6773                                                           "i.indkey, i.indisclustered, "
6774                                                           "i.indisreplident, "
6775                                                           "c.contype, c.conname, "
6776                                                           "c.condeferrable, c.condeferred, "
6777                                                           "c.tableoid AS contableoid, "
6778                                                           "c.oid AS conoid, "
6779                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6780                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6781                                                           "t.reloptions AS indreloptions, "
6782                                                           "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
6783                                                           "  FROM pg_catalog.pg_attribute "
6784                                                           "  WHERE attrelid = i.indexrelid AND "
6785                                                           "    attstattarget >= 0) AS indstatcols,"
6786                                                           "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
6787                                                           "  FROM pg_catalog.pg_attribute "
6788                                                           "  WHERE attrelid = i.indexrelid AND "
6789                                                           "    attstattarget >= 0) AS indstatvals "
6790                                                           "FROM pg_catalog.pg_index i "
6791                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6792                                                           "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
6793                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6794                                                           "ON (i.indrelid = c.conrelid AND "
6795                                                           "i.indexrelid = c.conindid AND "
6796                                                           "c.contype IN ('p','u','x')) "
6797                                                           "LEFT JOIN pg_catalog.pg_inherits inh "
6798                                                           "ON (inh.inhrelid = indexrelid) "
6799                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6800                                                           "AND (i.indisvalid OR t2.relkind = 'p') "
6801                                                           "AND i.indisready "
6802                                                           "ORDER BY indexname",
6803                                                           tbinfo->dobj.catId.oid);
6804                 }
6805                 else if (fout->remoteVersion >= 90400)
6806                 {
6807                         /*
6808                          * the test on indisready is necessary in 9.2, and harmless in
6809                          * earlier/later versions
6810                          */
6811                         appendPQExpBuffer(query,
6812                                                           "SELECT t.tableoid, t.oid, "
6813                                                           "t.relname AS indexname, "
6814                                                           "0 AS parentidx, "
6815                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6816                                                           "i.indnatts AS indnkeyatts, "
6817                                                           "i.indnatts AS indnatts, "
6818                                                           "i.indkey, i.indisclustered, "
6819                                                           "i.indisreplident, "
6820                                                           "c.contype, c.conname, "
6821                                                           "c.condeferrable, c.condeferred, "
6822                                                           "c.tableoid AS contableoid, "
6823                                                           "c.oid AS conoid, "
6824                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6825                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6826                                                           "t.reloptions AS indreloptions, "
6827                                                           "'' AS indstatcols, "
6828                                                           "'' AS indstatvals "
6829                                                           "FROM pg_catalog.pg_index i "
6830                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6831                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6832                                                           "ON (i.indrelid = c.conrelid AND "
6833                                                           "i.indexrelid = c.conindid AND "
6834                                                           "c.contype IN ('p','u','x')) "
6835                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6836                                                           "AND i.indisvalid AND i.indisready "
6837                                                           "ORDER BY indexname",
6838                                                           tbinfo->dobj.catId.oid);
6839                 }
6840                 else if (fout->remoteVersion >= 90000)
6841                 {
6842                         /*
6843                          * the test on indisready is necessary in 9.2, and harmless in
6844                          * earlier/later versions
6845                          */
6846                         appendPQExpBuffer(query,
6847                                                           "SELECT t.tableoid, t.oid, "
6848                                                           "t.relname AS indexname, "
6849                                                           "0 AS parentidx, "
6850                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6851                                                           "i.indnatts AS indnkeyatts, "
6852                                                           "i.indnatts AS indnatts, "
6853                                                           "i.indkey, i.indisclustered, "
6854                                                           "false AS indisreplident, "
6855                                                           "c.contype, c.conname, "
6856                                                           "c.condeferrable, c.condeferred, "
6857                                                           "c.tableoid AS contableoid, "
6858                                                           "c.oid AS conoid, "
6859                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6860                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6861                                                           "t.reloptions AS indreloptions, "
6862                                                           "'' AS indstatcols, "
6863                                                           "'' AS indstatvals "
6864                                                           "FROM pg_catalog.pg_index i "
6865                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6866                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6867                                                           "ON (i.indrelid = c.conrelid AND "
6868                                                           "i.indexrelid = c.conindid AND "
6869                                                           "c.contype IN ('p','u','x')) "
6870                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6871                                                           "AND i.indisvalid AND i.indisready "
6872                                                           "ORDER BY indexname",
6873                                                           tbinfo->dobj.catId.oid);
6874                 }
6875                 else if (fout->remoteVersion >= 80200)
6876                 {
6877                         appendPQExpBuffer(query,
6878                                                           "SELECT t.tableoid, t.oid, "
6879                                                           "t.relname AS indexname, "
6880                                                           "0 AS parentidx, "
6881                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6882                                                           "i.indnatts AS indnkeyatts, "
6883                                                           "i.indnatts AS indnatts, "
6884                                                           "i.indkey, i.indisclustered, "
6885                                                           "false AS indisreplident, "
6886                                                           "c.contype, c.conname, "
6887                                                           "c.condeferrable, c.condeferred, "
6888                                                           "c.tableoid AS contableoid, "
6889                                                           "c.oid AS conoid, "
6890                                                           "null AS condef, "
6891                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6892                                                           "t.reloptions AS indreloptions, "
6893                                                           "'' AS indstatcols, "
6894                                                           "'' AS indstatvals "
6895                                                           "FROM pg_catalog.pg_index i "
6896                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6897                                                           "LEFT JOIN pg_catalog.pg_depend d "
6898                                                           "ON (d.classid = t.tableoid "
6899                                                           "AND d.objid = t.oid "
6900                                                           "AND d.deptype = 'i') "
6901                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6902                                                           "ON (d.refclassid = c.tableoid "
6903                                                           "AND d.refobjid = c.oid) "
6904                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6905                                                           "AND i.indisvalid "
6906                                                           "ORDER BY indexname",
6907                                                           tbinfo->dobj.catId.oid);
6908                 }
6909                 else
6910                 {
6911                         appendPQExpBuffer(query,
6912                                                           "SELECT t.tableoid, t.oid, "
6913                                                           "t.relname AS indexname, "
6914                                                           "0 AS parentidx, "
6915                                                           "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6916                                                           "t.relnatts AS indnkeyatts, "
6917                                                           "t.relnatts AS indnatts, "
6918                                                           "i.indkey, i.indisclustered, "
6919                                                           "false AS indisreplident, "
6920                                                           "c.contype, c.conname, "
6921                                                           "c.condeferrable, c.condeferred, "
6922                                                           "c.tableoid AS contableoid, "
6923                                                           "c.oid AS conoid, "
6924                                                           "null AS condef, "
6925                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6926                                                           "null AS indreloptions, "
6927                                                           "'' AS indstatcols, "
6928                                                           "'' AS indstatvals "
6929                                                           "FROM pg_catalog.pg_index i "
6930                                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6931                                                           "LEFT JOIN pg_catalog.pg_depend d "
6932                                                           "ON (d.classid = t.tableoid "
6933                                                           "AND d.objid = t.oid "
6934                                                           "AND d.deptype = 'i') "
6935                                                           "LEFT JOIN pg_catalog.pg_constraint c "
6936                                                           "ON (d.refclassid = c.tableoid "
6937                                                           "AND d.refobjid = c.oid) "
6938                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
6939                                                           "ORDER BY indexname",
6940                                                           tbinfo->dobj.catId.oid);
6941                 }
6942
6943                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6944
6945                 ntups = PQntuples(res);
6946
6947                 i_tableoid = PQfnumber(res, "tableoid");
6948                 i_oid = PQfnumber(res, "oid");
6949                 i_indexname = PQfnumber(res, "indexname");
6950                 i_parentidx = PQfnumber(res, "parentidx");
6951                 i_indexdef = PQfnumber(res, "indexdef");
6952                 i_indnkeyatts = PQfnumber(res, "indnkeyatts");
6953                 i_indnatts = PQfnumber(res, "indnatts");
6954                 i_indkey = PQfnumber(res, "indkey");
6955                 i_indisclustered = PQfnumber(res, "indisclustered");
6956                 i_indisreplident = PQfnumber(res, "indisreplident");
6957                 i_contype = PQfnumber(res, "contype");
6958                 i_conname = PQfnumber(res, "conname");
6959                 i_condeferrable = PQfnumber(res, "condeferrable");
6960                 i_condeferred = PQfnumber(res, "condeferred");
6961                 i_contableoid = PQfnumber(res, "contableoid");
6962                 i_conoid = PQfnumber(res, "conoid");
6963                 i_condef = PQfnumber(res, "condef");
6964                 i_tablespace = PQfnumber(res, "tablespace");
6965                 i_indreloptions = PQfnumber(res, "indreloptions");
6966                 i_indstatcols = PQfnumber(res, "indstatcols");
6967                 i_indstatvals = PQfnumber(res, "indstatvals");
6968
6969                 tbinfo->indexes = indxinfo =
6970                         (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
6971                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
6972                 tbinfo->numIndexes = ntups;
6973
6974                 for (j = 0; j < ntups; j++)
6975                 {
6976                         char            contype;
6977
6978                         indxinfo[j].dobj.objType = DO_INDEX;
6979                         indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
6980                         indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
6981                         AssignDumpId(&indxinfo[j].dobj);
6982                         indxinfo[j].dobj.dump = tbinfo->dobj.dump;
6983                         indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
6984                         indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
6985                         indxinfo[j].indextable = tbinfo;
6986                         indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
6987                         indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
6988                         indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
6989                         indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
6990                         indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
6991                         indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
6992                         indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
6993                         indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
6994                         parseOidArray(PQgetvalue(res, j, i_indkey),
6995                                                   indxinfo[j].indkeys, indxinfo[j].indnattrs);
6996                         indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
6997                         indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
6998                         indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
6999                         contype = *(PQgetvalue(res, j, i_contype));
7000
7001                         if (contype == 'p' || contype == 'u' || contype == 'x')
7002                         {
7003                                 /*
7004                                  * If we found a constraint matching the index, create an
7005                                  * entry for it.
7006                                  */
7007                                 constrinfo[j].dobj.objType = DO_CONSTRAINT;
7008                                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7009                                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7010                                 AssignDumpId(&constrinfo[j].dobj);
7011                                 constrinfo[j].dobj.dump = tbinfo->dobj.dump;
7012                                 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7013                                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7014                                 constrinfo[j].contable = tbinfo;
7015                                 constrinfo[j].condomain = NULL;
7016                                 constrinfo[j].contype = contype;
7017                                 if (contype == 'x')
7018                                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
7019                                 else
7020                                         constrinfo[j].condef = NULL;
7021                                 constrinfo[j].confrelid = InvalidOid;
7022                                 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
7023                                 constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
7024                                 constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
7025                                 constrinfo[j].conislocal = true;
7026                                 constrinfo[j].separate = true;
7027
7028                                 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
7029                         }
7030                         else
7031                         {
7032                                 /* Plain secondary index */
7033                                 indxinfo[j].indexconstraint = 0;
7034                         }
7035                 }
7036
7037                 PQclear(res);
7038         }
7039
7040         destroyPQExpBuffer(query);
7041 }
7042
7043 /*
7044  * getExtendedStatistics
7045  *        get information about extended-statistics objects.
7046  *
7047  * Note: extended statistics data is not returned directly to the caller, but
7048  * it does get entered into the DumpableObject tables.
7049  */
7050 void
7051 getExtendedStatistics(Archive *fout)
7052 {
7053         PQExpBuffer query;
7054         PGresult   *res;
7055         StatsExtInfo *statsextinfo;
7056         int                     ntups;
7057         int                     i_tableoid;
7058         int                     i_oid;
7059         int                     i_stxname;
7060         int                     i_stxnamespace;
7061         int                     i_rolname;
7062         int                     i;
7063
7064         /* Extended statistics were new in v10 */
7065         if (fout->remoteVersion < 100000)
7066                 return;
7067
7068         query = createPQExpBuffer();
7069
7070         appendPQExpBuffer(query, "SELECT tableoid, oid, stxname, "
7071                                           "stxnamespace, (%s stxowner) AS rolname "
7072                                           "FROM pg_catalog.pg_statistic_ext",
7073                                           username_subquery);
7074
7075         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7076
7077         ntups = PQntuples(res);
7078
7079         i_tableoid = PQfnumber(res, "tableoid");
7080         i_oid = PQfnumber(res, "oid");
7081         i_stxname = PQfnumber(res, "stxname");
7082         i_stxnamespace = PQfnumber(res, "stxnamespace");
7083         i_rolname = PQfnumber(res, "rolname");
7084
7085         statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
7086
7087         for (i = 0; i < ntups; i++)
7088         {
7089                 statsextinfo[i].dobj.objType = DO_STATSEXT;
7090                 statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7091                 statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7092                 AssignDumpId(&statsextinfo[i].dobj);
7093                 statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
7094                 statsextinfo[i].dobj.namespace =
7095                         findNamespace(fout,
7096                                                   atooid(PQgetvalue(res, i, i_stxnamespace)));
7097                 statsextinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7098
7099                 /* Decide whether we want to dump it */
7100                 selectDumpableObject(&(statsextinfo[i].dobj), fout);
7101
7102                 /* Stats objects do not currently have ACLs. */
7103                 statsextinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7104         }
7105
7106         PQclear(res);
7107         destroyPQExpBuffer(query);
7108 }
7109
7110 /*
7111  * getConstraints
7112  *
7113  * Get info about constraints on dumpable tables.
7114  *
7115  * Currently handles foreign keys only.
7116  * Unique and primary key constraints are handled with indexes,
7117  * while check constraints are processed in getTableAttrs().
7118  */
7119 void
7120 getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
7121 {
7122         int                     i,
7123                                 j;
7124         ConstraintInfo *constrinfo;
7125         PQExpBuffer query;
7126         PGresult   *res;
7127         int                     i_contableoid,
7128                                 i_conoid,
7129                                 i_conname,
7130                                 i_confrelid,
7131                                 i_condef;
7132         int                     ntups;
7133
7134         query = createPQExpBuffer();
7135
7136         for (i = 0; i < numTables; i++)
7137         {
7138                 TableInfo  *tbinfo = &tblinfo[i];
7139
7140                 /*
7141                  * For partitioned tables, foreign keys have no triggers so they must
7142                  * be included anyway in case some foreign keys are defined.
7143                  */
7144                 if ((!tbinfo->hastriggers &&
7145                          tbinfo->relkind != RELKIND_PARTITIONED_TABLE) ||
7146                         !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7147                         continue;
7148
7149                 if (g_verbose)
7150                         write_msg(NULL, "reading foreign key constraints for table \"%s.%s\"\n",
7151                                           tbinfo->dobj.namespace->dobj.name,
7152                                           tbinfo->dobj.name);
7153
7154                 resetPQExpBuffer(query);
7155                 if (fout->remoteVersion >= 110000)
7156                         appendPQExpBuffer(query,
7157                                                           "SELECT tableoid, oid, conname, confrelid, "
7158                                                           "pg_catalog.pg_get_constraintdef(oid) AS condef "
7159                                                           "FROM pg_catalog.pg_constraint "
7160                                                           "WHERE conrelid = '%u'::pg_catalog.oid "
7161                                                           "AND conparentid = 0 "
7162                                                           "AND contype = 'f'",
7163                                                           tbinfo->dobj.catId.oid);
7164                 else
7165                         appendPQExpBuffer(query,
7166                                                           "SELECT tableoid, oid, conname, confrelid, "
7167                                                           "pg_catalog.pg_get_constraintdef(oid) AS condef "
7168                                                           "FROM pg_catalog.pg_constraint "
7169                                                           "WHERE conrelid = '%u'::pg_catalog.oid "
7170                                                           "AND contype = 'f'",
7171                                                           tbinfo->dobj.catId.oid);
7172                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7173
7174                 ntups = PQntuples(res);
7175
7176                 i_contableoid = PQfnumber(res, "tableoid");
7177                 i_conoid = PQfnumber(res, "oid");
7178                 i_conname = PQfnumber(res, "conname");
7179                 i_confrelid = PQfnumber(res, "confrelid");
7180                 i_condef = PQfnumber(res, "condef");
7181
7182                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7183
7184                 for (j = 0; j < ntups; j++)
7185                 {
7186                         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
7187                         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7188                         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7189                         AssignDumpId(&constrinfo[j].dobj);
7190                         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7191                         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7192                         constrinfo[j].contable = tbinfo;
7193                         constrinfo[j].condomain = NULL;
7194                         constrinfo[j].contype = 'f';
7195                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
7196                         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
7197                         constrinfo[j].conindex = 0;
7198                         constrinfo[j].condeferrable = false;
7199                         constrinfo[j].condeferred = false;
7200                         constrinfo[j].conislocal = true;
7201                         constrinfo[j].separate = true;
7202                 }
7203
7204                 PQclear(res);
7205         }
7206
7207         destroyPQExpBuffer(query);
7208 }
7209
7210 /*
7211  * getDomainConstraints
7212  *
7213  * Get info about constraints on a domain.
7214  */
7215 static void
7216 getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
7217 {
7218         int                     i;
7219         ConstraintInfo *constrinfo;
7220         PQExpBuffer query;
7221         PGresult   *res;
7222         int                     i_tableoid,
7223                                 i_oid,
7224                                 i_conname,
7225                                 i_consrc;
7226         int                     ntups;
7227
7228         query = createPQExpBuffer();
7229
7230         if (fout->remoteVersion >= 90100)
7231                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
7232                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7233                                                   "convalidated "
7234                                                   "FROM pg_catalog.pg_constraint "
7235                                                   "WHERE contypid = '%u'::pg_catalog.oid "
7236                                                   "ORDER BY conname",
7237                                                   tyinfo->dobj.catId.oid);
7238
7239         else
7240                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
7241                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7242                                                   "true as convalidated "
7243                                                   "FROM pg_catalog.pg_constraint "
7244                                                   "WHERE contypid = '%u'::pg_catalog.oid "
7245                                                   "ORDER BY conname",
7246                                                   tyinfo->dobj.catId.oid);
7247
7248         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7249
7250         ntups = PQntuples(res);
7251
7252         i_tableoid = PQfnumber(res, "tableoid");
7253         i_oid = PQfnumber(res, "oid");
7254         i_conname = PQfnumber(res, "conname");
7255         i_consrc = PQfnumber(res, "consrc");
7256
7257         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7258
7259         tyinfo->nDomChecks = ntups;
7260         tyinfo->domChecks = constrinfo;
7261
7262         for (i = 0; i < ntups; i++)
7263         {
7264                 bool            validated = PQgetvalue(res, i, 4)[0] == 't';
7265
7266                 constrinfo[i].dobj.objType = DO_CONSTRAINT;
7267                 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7268                 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7269                 AssignDumpId(&constrinfo[i].dobj);
7270                 constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
7271                 constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
7272                 constrinfo[i].contable = NULL;
7273                 constrinfo[i].condomain = tyinfo;
7274                 constrinfo[i].contype = 'c';
7275                 constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
7276                 constrinfo[i].confrelid = InvalidOid;
7277                 constrinfo[i].conindex = 0;
7278                 constrinfo[i].condeferrable = false;
7279                 constrinfo[i].condeferred = false;
7280                 constrinfo[i].conislocal = true;
7281
7282                 constrinfo[i].separate = !validated;
7283
7284                 /*
7285                  * Make the domain depend on the constraint, ensuring it won't be
7286                  * output till any constraint dependencies are OK.  If the constraint
7287                  * has not been validated, it's going to be dumped after the domain
7288                  * anyway, so this doesn't matter.
7289                  */
7290                 if (validated)
7291                         addObjectDependency(&tyinfo->dobj,
7292                                                                 constrinfo[i].dobj.dumpId);
7293         }
7294
7295         PQclear(res);
7296
7297         destroyPQExpBuffer(query);
7298 }
7299
7300 /*
7301  * getRules
7302  *        get basic information about every rule in the system
7303  *
7304  * numRules is set to the number of rules read in
7305  */
7306 RuleInfo *
7307 getRules(Archive *fout, int *numRules)
7308 {
7309         PGresult   *res;
7310         int                     ntups;
7311         int                     i;
7312         PQExpBuffer query = createPQExpBuffer();
7313         RuleInfo   *ruleinfo;
7314         int                     i_tableoid;
7315         int                     i_oid;
7316         int                     i_rulename;
7317         int                     i_ruletable;
7318         int                     i_ev_type;
7319         int                     i_is_instead;
7320         int                     i_ev_enabled;
7321
7322         if (fout->remoteVersion >= 80300)
7323         {
7324                 appendPQExpBufferStr(query, "SELECT "
7325                                                          "tableoid, oid, rulename, "
7326                                                          "ev_class AS ruletable, ev_type, is_instead, "
7327                                                          "ev_enabled "
7328                                                          "FROM pg_rewrite "
7329                                                          "ORDER BY oid");
7330         }
7331         else
7332         {
7333                 appendPQExpBufferStr(query, "SELECT "
7334                                                          "tableoid, oid, rulename, "
7335                                                          "ev_class AS ruletable, ev_type, is_instead, "
7336                                                          "'O'::char AS ev_enabled "
7337                                                          "FROM pg_rewrite "
7338                                                          "ORDER BY oid");
7339         }
7340
7341         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7342
7343         ntups = PQntuples(res);
7344
7345         *numRules = ntups;
7346
7347         ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
7348
7349         i_tableoid = PQfnumber(res, "tableoid");
7350         i_oid = PQfnumber(res, "oid");
7351         i_rulename = PQfnumber(res, "rulename");
7352         i_ruletable = PQfnumber(res, "ruletable");
7353         i_ev_type = PQfnumber(res, "ev_type");
7354         i_is_instead = PQfnumber(res, "is_instead");
7355         i_ev_enabled = PQfnumber(res, "ev_enabled");
7356
7357         for (i = 0; i < ntups; i++)
7358         {
7359                 Oid                     ruletableoid;
7360
7361                 ruleinfo[i].dobj.objType = DO_RULE;
7362                 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7363                 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7364                 AssignDumpId(&ruleinfo[i].dobj);
7365                 ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
7366                 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
7367                 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
7368                 if (ruleinfo[i].ruletable == NULL)
7369                         exit_horribly(NULL, "failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found\n",
7370                                                   ruletableoid, ruleinfo[i].dobj.catId.oid);
7371                 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
7372                 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
7373                 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
7374                 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
7375                 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
7376                 if (ruleinfo[i].ruletable)
7377                 {
7378                         /*
7379                          * If the table is a view or materialized view, force its ON
7380                          * SELECT rule to be sorted before the view itself --- this
7381                          * ensures that any dependencies for the rule affect the table's
7382                          * positioning. Other rules are forced to appear after their
7383                          * table.
7384                          */
7385                         if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
7386                                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
7387                                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
7388                         {
7389                                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
7390                                                                         ruleinfo[i].dobj.dumpId);
7391                                 /* We'll merge the rule into CREATE VIEW, if possible */
7392                                 ruleinfo[i].separate = false;
7393                         }
7394                         else
7395                         {
7396                                 addObjectDependency(&ruleinfo[i].dobj,
7397                                                                         ruleinfo[i].ruletable->dobj.dumpId);
7398                                 ruleinfo[i].separate = true;
7399                         }
7400                 }
7401                 else
7402                         ruleinfo[i].separate = true;
7403         }
7404
7405         PQclear(res);
7406
7407         destroyPQExpBuffer(query);
7408
7409         return ruleinfo;
7410 }
7411
7412 /*
7413  * getTriggers
7414  *        get information about every trigger on a dumpable table
7415  *
7416  * Note: trigger data is not returned directly to the caller, but it
7417  * does get entered into the DumpableObject tables.
7418  */
7419 void
7420 getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
7421 {
7422         int                     i,
7423                                 j;
7424         PQExpBuffer query = createPQExpBuffer();
7425         PGresult   *res;
7426         TriggerInfo *tginfo;
7427         int                     i_tableoid,
7428                                 i_oid,
7429                                 i_tgname,
7430                                 i_tgfname,
7431                                 i_tgtype,
7432                                 i_tgnargs,
7433                                 i_tgargs,
7434                                 i_tgisconstraint,
7435                                 i_tgconstrname,
7436                                 i_tgconstrrelid,
7437                                 i_tgconstrrelname,
7438                                 i_tgenabled,
7439                                 i_tgdeferrable,
7440                                 i_tginitdeferred,
7441                                 i_tgdef;
7442         int                     ntups;
7443
7444         for (i = 0; i < numTables; i++)
7445         {
7446                 TableInfo  *tbinfo = &tblinfo[i];
7447
7448                 if (!tbinfo->hastriggers ||
7449                         !(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7450                         continue;
7451
7452                 if (g_verbose)
7453                         write_msg(NULL, "reading triggers for table \"%s.%s\"\n",
7454                                           tbinfo->dobj.namespace->dobj.name,
7455                                           tbinfo->dobj.name);
7456
7457                 resetPQExpBuffer(query);
7458                 if (fout->remoteVersion >= 90000)
7459                 {
7460                         /*
7461                          * NB: think not to use pretty=true in pg_get_triggerdef.  It
7462                          * could result in non-forward-compatible dumps of WHEN clauses
7463                          * due to under-parenthesization.
7464                          */
7465                         appendPQExpBuffer(query,
7466                                                           "SELECT tgname, "
7467                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7468                                                           "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
7469                                                           "tgenabled, tableoid, oid "
7470                                                           "FROM pg_catalog.pg_trigger t "
7471                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7472                                                           "AND NOT tgisinternal",
7473                                                           tbinfo->dobj.catId.oid);
7474                 }
7475                 else if (fout->remoteVersion >= 80300)
7476                 {
7477                         /*
7478                          * We ignore triggers that are tied to a foreign-key constraint
7479                          */
7480                         appendPQExpBuffer(query,
7481                                                           "SELECT tgname, "
7482                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7483                                                           "tgtype, tgnargs, tgargs, tgenabled, "
7484                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
7485                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
7486                                                           "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
7487                                                           "FROM pg_catalog.pg_trigger t "
7488                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7489                                                           "AND tgconstraint = 0",
7490                                                           tbinfo->dobj.catId.oid);
7491                 }
7492                 else
7493                 {
7494                         /*
7495                          * We ignore triggers that are tied to a foreign-key constraint,
7496                          * but in these versions we have to grovel through pg_constraint
7497                          * to find out
7498                          */
7499                         appendPQExpBuffer(query,
7500                                                           "SELECT tgname, "
7501                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
7502                                                           "tgtype, tgnargs, tgargs, tgenabled, "
7503                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
7504                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
7505                                                           "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
7506                                                           "FROM pg_catalog.pg_trigger t "
7507                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
7508                                                           "AND (NOT tgisconstraint "
7509                                                           " OR NOT EXISTS"
7510                                                           "  (SELECT 1 FROM pg_catalog.pg_depend d "
7511                                                           "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
7512                                                           "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
7513                                                           tbinfo->dobj.catId.oid);
7514                 }
7515
7516                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7517
7518                 ntups = PQntuples(res);
7519
7520                 i_tableoid = PQfnumber(res, "tableoid");
7521                 i_oid = PQfnumber(res, "oid");
7522                 i_tgname = PQfnumber(res, "tgname");
7523                 i_tgfname = PQfnumber(res, "tgfname");
7524                 i_tgtype = PQfnumber(res, "tgtype");
7525                 i_tgnargs = PQfnumber(res, "tgnargs");
7526                 i_tgargs = PQfnumber(res, "tgargs");
7527                 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
7528                 i_tgconstrname = PQfnumber(res, "tgconstrname");
7529                 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
7530                 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
7531                 i_tgenabled = PQfnumber(res, "tgenabled");
7532                 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
7533                 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
7534                 i_tgdef = PQfnumber(res, "tgdef");
7535
7536                 tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
7537
7538                 tbinfo->numTriggers = ntups;
7539                 tbinfo->triggers = tginfo;
7540
7541                 for (j = 0; j < ntups; j++)
7542                 {
7543                         tginfo[j].dobj.objType = DO_TRIGGER;
7544                         tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
7545                         tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7546                         AssignDumpId(&tginfo[j].dobj);
7547                         tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
7548                         tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
7549                         tginfo[j].tgtable = tbinfo;
7550                         tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
7551                         if (i_tgdef >= 0)
7552                         {
7553                                 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
7554
7555                                 /* remaining fields are not valid if we have tgdef */
7556                                 tginfo[j].tgfname = NULL;
7557                                 tginfo[j].tgtype = 0;
7558                                 tginfo[j].tgnargs = 0;
7559                                 tginfo[j].tgargs = NULL;
7560                                 tginfo[j].tgisconstraint = false;
7561                                 tginfo[j].tgdeferrable = false;
7562                                 tginfo[j].tginitdeferred = false;
7563                                 tginfo[j].tgconstrname = NULL;
7564                                 tginfo[j].tgconstrrelid = InvalidOid;
7565                                 tginfo[j].tgconstrrelname = NULL;
7566                         }
7567                         else
7568                         {
7569                                 tginfo[j].tgdef = NULL;
7570
7571                                 tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
7572                                 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
7573                                 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
7574                                 tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
7575                                 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
7576                                 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
7577                                 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
7578
7579                                 if (tginfo[j].tgisconstraint)
7580                                 {
7581                                         tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
7582                                         tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
7583                                         if (OidIsValid(tginfo[j].tgconstrrelid))
7584                                         {
7585                                                 if (PQgetisnull(res, j, i_tgconstrrelname))
7586                                                         exit_horribly(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
7587                                                                                   tginfo[j].dobj.name,
7588                                                                                   tbinfo->dobj.name,
7589                                                                                   tginfo[j].tgconstrrelid);
7590                                                 tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
7591                                         }
7592                                         else
7593                                                 tginfo[j].tgconstrrelname = NULL;
7594                                 }
7595                                 else
7596                                 {
7597                                         tginfo[j].tgconstrname = NULL;
7598                                         tginfo[j].tgconstrrelid = InvalidOid;
7599                                         tginfo[j].tgconstrrelname = NULL;
7600                                 }
7601                         }
7602                 }
7603
7604                 PQclear(res);
7605         }
7606
7607         destroyPQExpBuffer(query);
7608 }
7609
7610 /*
7611  * getEventTriggers
7612  *        get information about event triggers
7613  */
7614 EventTriggerInfo *
7615 getEventTriggers(Archive *fout, int *numEventTriggers)
7616 {
7617         int                     i;
7618         PQExpBuffer query;
7619         PGresult   *res;
7620         EventTriggerInfo *evtinfo;
7621         int                     i_tableoid,
7622                                 i_oid,
7623                                 i_evtname,
7624                                 i_evtevent,
7625                                 i_evtowner,
7626                                 i_evttags,
7627                                 i_evtfname,
7628                                 i_evtenabled;
7629         int                     ntups;
7630
7631         /* Before 9.3, there are no event triggers */
7632         if (fout->remoteVersion < 90300)
7633         {
7634                 *numEventTriggers = 0;
7635                 return NULL;
7636         }
7637
7638         query = createPQExpBuffer();
7639
7640         appendPQExpBuffer(query,
7641                                           "SELECT e.tableoid, e.oid, evtname, evtenabled, "
7642                                           "evtevent, (%s evtowner) AS evtowner, "
7643                                           "array_to_string(array("
7644                                           "select quote_literal(x) "
7645                                           " from unnest(evttags) as t(x)), ', ') as evttags, "
7646                                           "e.evtfoid::regproc as evtfname "
7647                                           "FROM pg_event_trigger e "
7648                                           "ORDER BY e.oid",
7649                                           username_subquery);
7650
7651         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7652
7653         ntups = PQntuples(res);
7654
7655         *numEventTriggers = ntups;
7656
7657         evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
7658
7659         i_tableoid = PQfnumber(res, "tableoid");
7660         i_oid = PQfnumber(res, "oid");
7661         i_evtname = PQfnumber(res, "evtname");
7662         i_evtevent = PQfnumber(res, "evtevent");
7663         i_evtowner = PQfnumber(res, "evtowner");
7664         i_evttags = PQfnumber(res, "evttags");
7665         i_evtfname = PQfnumber(res, "evtfname");
7666         i_evtenabled = PQfnumber(res, "evtenabled");
7667
7668         for (i = 0; i < ntups; i++)
7669         {
7670                 evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
7671                 evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7672                 evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7673                 AssignDumpId(&evtinfo[i].dobj);
7674                 evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
7675                 evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
7676                 evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
7677                 evtinfo[i].evtowner = pg_strdup(PQgetvalue(res, i, i_evtowner));
7678                 evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
7679                 evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
7680                 evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
7681
7682                 /* Decide whether we want to dump it */
7683                 selectDumpableObject(&(evtinfo[i].dobj), fout);
7684
7685                 /* Event Triggers do not currently have ACLs. */
7686                 evtinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7687         }
7688
7689         PQclear(res);
7690
7691         destroyPQExpBuffer(query);
7692
7693         return evtinfo;
7694 }
7695
7696 /*
7697  * getProcLangs
7698  *        get basic information about every procedural language in the system
7699  *
7700  * numProcLangs is set to the number of langs read in
7701  *
7702  * NB: this must run after getFuncs() because we assume we can do
7703  * findFuncByOid().
7704  */
7705 ProcLangInfo *
7706 getProcLangs(Archive *fout, int *numProcLangs)
7707 {
7708         DumpOptions *dopt = fout->dopt;
7709         PGresult   *res;
7710         int                     ntups;
7711         int                     i;
7712         PQExpBuffer query = createPQExpBuffer();
7713         ProcLangInfo *planginfo;
7714         int                     i_tableoid;
7715         int                     i_oid;
7716         int                     i_lanname;
7717         int                     i_lanpltrusted;
7718         int                     i_lanplcallfoid;
7719         int                     i_laninline;
7720         int                     i_lanvalidator;
7721         int                     i_lanacl;
7722         int                     i_rlanacl;
7723         int                     i_initlanacl;
7724         int                     i_initrlanacl;
7725         int                     i_lanowner;
7726
7727         if (fout->remoteVersion >= 90600)
7728         {
7729                 PQExpBuffer acl_subquery = createPQExpBuffer();
7730                 PQExpBuffer racl_subquery = createPQExpBuffer();
7731                 PQExpBuffer initacl_subquery = createPQExpBuffer();
7732                 PQExpBuffer initracl_subquery = createPQExpBuffer();
7733
7734                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
7735                                                 initracl_subquery, "l.lanacl", "l.lanowner", "'l'",
7736                                                 dopt->binary_upgrade);
7737
7738                 /* pg_language has a laninline column */
7739                 appendPQExpBuffer(query, "SELECT l.tableoid, l.oid, "
7740                                                   "l.lanname, l.lanpltrusted, l.lanplcallfoid, "
7741                                                   "l.laninline, l.lanvalidator, "
7742                                                   "%s AS lanacl, "
7743                                                   "%s AS rlanacl, "
7744                                                   "%s AS initlanacl, "
7745                                                   "%s AS initrlanacl, "
7746                                                   "(%s l.lanowner) AS lanowner "
7747                                                   "FROM pg_language l "
7748                                                   "LEFT JOIN pg_init_privs pip ON "
7749                                                   "(l.oid = pip.objoid "
7750                                                   "AND pip.classoid = 'pg_language'::regclass "
7751                                                   "AND pip.objsubid = 0) "
7752                                                   "WHERE l.lanispl "
7753                                                   "ORDER BY l.oid",
7754                                                   acl_subquery->data,
7755                                                   racl_subquery->data,
7756                                                   initacl_subquery->data,
7757                                                   initracl_subquery->data,
7758                                                   username_subquery);
7759
7760                 destroyPQExpBuffer(acl_subquery);
7761                 destroyPQExpBuffer(racl_subquery);
7762                 destroyPQExpBuffer(initacl_subquery);
7763                 destroyPQExpBuffer(initracl_subquery);
7764         }
7765         else if (fout->remoteVersion >= 90000)
7766         {
7767                 /* pg_language has a laninline column */
7768                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7769                                                   "lanname, lanpltrusted, lanplcallfoid, "
7770                                                   "laninline, lanvalidator, lanacl, NULL AS rlanacl, "
7771                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7772                                                   "(%s lanowner) AS lanowner "
7773                                                   "FROM pg_language "
7774                                                   "WHERE lanispl "
7775                                                   "ORDER BY oid",
7776                                                   username_subquery);
7777         }
7778         else if (fout->remoteVersion >= 80300)
7779         {
7780                 /* pg_language has a lanowner column */
7781                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7782                                                   "lanname, lanpltrusted, lanplcallfoid, "
7783                                                   "0 AS laninline, lanvalidator, lanacl, "
7784                                                   "NULL AS rlanacl, "
7785                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7786                                                   "(%s lanowner) AS lanowner "
7787                                                   "FROM pg_language "
7788                                                   "WHERE lanispl "
7789                                                   "ORDER BY oid",
7790                                                   username_subquery);
7791         }
7792         else if (fout->remoteVersion >= 80100)
7793         {
7794                 /* Languages are owned by the bootstrap superuser, OID 10 */
7795                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7796                                                   "lanname, lanpltrusted, lanplcallfoid, "
7797                                                   "0 AS laninline, lanvalidator, lanacl, "
7798                                                   "NULL AS rlanacl, "
7799                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7800                                                   "(%s '10') AS lanowner "
7801                                                   "FROM pg_language "
7802                                                   "WHERE lanispl "
7803                                                   "ORDER BY oid",
7804                                                   username_subquery);
7805         }
7806         else
7807         {
7808                 /* Languages are owned by the bootstrap superuser, sysid 1 */
7809                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
7810                                                   "lanname, lanpltrusted, lanplcallfoid, "
7811                                                   "0 AS laninline, lanvalidator, lanacl, "
7812                                                   "NULL AS rlanacl, "
7813                                                   "NULL AS initlanacl, NULL AS initrlanacl, "
7814                                                   "(%s '1') AS lanowner "
7815                                                   "FROM pg_language "
7816                                                   "WHERE lanispl "
7817                                                   "ORDER BY oid",
7818                                                   username_subquery);
7819         }
7820
7821         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7822
7823         ntups = PQntuples(res);
7824
7825         *numProcLangs = ntups;
7826
7827         planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
7828
7829         i_tableoid = PQfnumber(res, "tableoid");
7830         i_oid = PQfnumber(res, "oid");
7831         i_lanname = PQfnumber(res, "lanname");
7832         i_lanpltrusted = PQfnumber(res, "lanpltrusted");
7833         i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
7834         i_laninline = PQfnumber(res, "laninline");
7835         i_lanvalidator = PQfnumber(res, "lanvalidator");
7836         i_lanacl = PQfnumber(res, "lanacl");
7837         i_rlanacl = PQfnumber(res, "rlanacl");
7838         i_initlanacl = PQfnumber(res, "initlanacl");
7839         i_initrlanacl = PQfnumber(res, "initrlanacl");
7840         i_lanowner = PQfnumber(res, "lanowner");
7841
7842         for (i = 0; i < ntups; i++)
7843         {
7844                 planginfo[i].dobj.objType = DO_PROCLANG;
7845                 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7846                 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7847                 AssignDumpId(&planginfo[i].dobj);
7848
7849                 planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
7850                 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
7851                 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
7852                 planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
7853                 planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
7854                 planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
7855                 planginfo[i].rlanacl = pg_strdup(PQgetvalue(res, i, i_rlanacl));
7856                 planginfo[i].initlanacl = pg_strdup(PQgetvalue(res, i, i_initlanacl));
7857                 planginfo[i].initrlanacl = pg_strdup(PQgetvalue(res, i, i_initrlanacl));
7858                 planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
7859
7860                 /* Decide whether we want to dump it */
7861                 selectDumpableProcLang(&(planginfo[i]), fout);
7862
7863                 /* Do not try to dump ACL if no ACL exists. */
7864                 if (PQgetisnull(res, i, i_lanacl) && PQgetisnull(res, i, i_rlanacl) &&
7865                         PQgetisnull(res, i, i_initlanacl) &&
7866                         PQgetisnull(res, i, i_initrlanacl))
7867                         planginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7868         }
7869
7870         PQclear(res);
7871
7872         destroyPQExpBuffer(query);
7873
7874         return planginfo;
7875 }
7876
7877 /*
7878  * getCasts
7879  *        get basic information about every cast in the system
7880  *
7881  * numCasts is set to the number of casts read in
7882  */
7883 CastInfo *
7884 getCasts(Archive *fout, int *numCasts)
7885 {
7886         PGresult   *res;
7887         int                     ntups;
7888         int                     i;
7889         PQExpBuffer query = createPQExpBuffer();
7890         CastInfo   *castinfo;
7891         int                     i_tableoid;
7892         int                     i_oid;
7893         int                     i_castsource;
7894         int                     i_casttarget;
7895         int                     i_castfunc;
7896         int                     i_castcontext;
7897         int                     i_castmethod;
7898
7899         if (fout->remoteVersion >= 80400)
7900         {
7901                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
7902                                                          "castsource, casttarget, castfunc, castcontext, "
7903                                                          "castmethod "
7904                                                          "FROM pg_cast ORDER BY 3,4");
7905         }
7906         else
7907         {
7908                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
7909                                                          "castsource, casttarget, castfunc, castcontext, "
7910                                                          "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
7911                                                          "FROM pg_cast ORDER BY 3,4");
7912         }
7913
7914         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7915
7916         ntups = PQntuples(res);
7917
7918         *numCasts = ntups;
7919
7920         castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
7921
7922         i_tableoid = PQfnumber(res, "tableoid");
7923         i_oid = PQfnumber(res, "oid");
7924         i_castsource = PQfnumber(res, "castsource");
7925         i_casttarget = PQfnumber(res, "casttarget");
7926         i_castfunc = PQfnumber(res, "castfunc");
7927         i_castcontext = PQfnumber(res, "castcontext");
7928         i_castmethod = PQfnumber(res, "castmethod");
7929
7930         for (i = 0; i < ntups; i++)
7931         {
7932                 PQExpBufferData namebuf;
7933                 TypeInfo   *sTypeInfo;
7934                 TypeInfo   *tTypeInfo;
7935
7936                 castinfo[i].dobj.objType = DO_CAST;
7937                 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7938                 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7939                 AssignDumpId(&castinfo[i].dobj);
7940                 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
7941                 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
7942                 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
7943                 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
7944                 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
7945
7946                 /*
7947                  * Try to name cast as concatenation of typnames.  This is only used
7948                  * for purposes of sorting.  If we fail to find either type, the name
7949                  * will be an empty string.
7950                  */
7951                 initPQExpBuffer(&namebuf);
7952                 sTypeInfo = findTypeByOid(castinfo[i].castsource);
7953                 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
7954                 if (sTypeInfo && tTypeInfo)
7955                         appendPQExpBuffer(&namebuf, "%s %s",
7956                                                           sTypeInfo->dobj.name, tTypeInfo->dobj.name);
7957                 castinfo[i].dobj.name = namebuf.data;
7958
7959                 /* Decide whether we want to dump it */
7960                 selectDumpableCast(&(castinfo[i]), fout);
7961
7962                 /* Casts do not currently have ACLs. */
7963                 castinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7964         }
7965
7966         PQclear(res);
7967
7968         destroyPQExpBuffer(query);
7969
7970         return castinfo;
7971 }
7972
7973 static char *
7974 get_language_name(Archive *fout, Oid langid)
7975 {
7976         PQExpBuffer query;
7977         PGresult   *res;
7978         char       *lanname;
7979
7980         query = createPQExpBuffer();
7981         appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
7982         res = ExecuteSqlQueryForSingleRow(fout, query->data);
7983         lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
7984         destroyPQExpBuffer(query);
7985         PQclear(res);
7986
7987         return lanname;
7988 }
7989
7990 /*
7991  * getTransforms
7992  *        get basic information about every transform in the system
7993  *
7994  * numTransforms is set to the number of transforms read in
7995  */
7996 TransformInfo *
7997 getTransforms(Archive *fout, int *numTransforms)
7998 {
7999         PGresult   *res;
8000         int                     ntups;
8001         int                     i;
8002         PQExpBuffer query;
8003         TransformInfo *transforminfo;
8004         int                     i_tableoid;
8005         int                     i_oid;
8006         int                     i_trftype;
8007         int                     i_trflang;
8008         int                     i_trffromsql;
8009         int                     i_trftosql;
8010
8011         /* Transforms didn't exist pre-9.5 */
8012         if (fout->remoteVersion < 90500)
8013         {
8014                 *numTransforms = 0;
8015                 return NULL;
8016         }
8017
8018         query = createPQExpBuffer();
8019
8020         appendPQExpBuffer(query, "SELECT tableoid, oid, "
8021                                           "trftype, trflang, trffromsql::oid, trftosql::oid "
8022                                           "FROM pg_transform "
8023                                           "ORDER BY 3,4");
8024
8025         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8026
8027         ntups = PQntuples(res);
8028
8029         *numTransforms = ntups;
8030
8031         transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
8032
8033         i_tableoid = PQfnumber(res, "tableoid");
8034         i_oid = PQfnumber(res, "oid");
8035         i_trftype = PQfnumber(res, "trftype");
8036         i_trflang = PQfnumber(res, "trflang");
8037         i_trffromsql = PQfnumber(res, "trffromsql");
8038         i_trftosql = PQfnumber(res, "trftosql");
8039
8040         for (i = 0; i < ntups; i++)
8041         {
8042                 PQExpBufferData namebuf;
8043                 TypeInfo   *typeInfo;
8044                 char       *lanname;
8045
8046                 transforminfo[i].dobj.objType = DO_TRANSFORM;
8047                 transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8048                 transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8049                 AssignDumpId(&transforminfo[i].dobj);
8050                 transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
8051                 transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
8052                 transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
8053                 transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
8054
8055                 /*
8056                  * Try to name transform as concatenation of type and language name.
8057                  * This is only used for purposes of sorting.  If we fail to find
8058                  * either, the name will be an empty string.
8059                  */
8060                 initPQExpBuffer(&namebuf);
8061                 typeInfo = findTypeByOid(transforminfo[i].trftype);
8062                 lanname = get_language_name(fout, transforminfo[i].trflang);
8063                 if (typeInfo && lanname)
8064                         appendPQExpBuffer(&namebuf, "%s %s",
8065                                                           typeInfo->dobj.name, lanname);
8066                 transforminfo[i].dobj.name = namebuf.data;
8067                 free(lanname);
8068
8069                 /* Decide whether we want to dump it */
8070                 selectDumpableObject(&(transforminfo[i].dobj), fout);
8071         }
8072
8073         PQclear(res);
8074
8075         destroyPQExpBuffer(query);
8076
8077         return transforminfo;
8078 }
8079
8080 /*
8081  * getTableAttrs -
8082  *        for each interesting table, read info about its attributes
8083  *        (names, types, default values, CHECK constraints, etc)
8084  *
8085  * This is implemented in a very inefficient way right now, looping
8086  * through the tblinfo and doing a join per table to find the attrs and their
8087  * types.  However, because we want type names and so forth to be named
8088  * relative to the schema of each table, we couldn't do it in just one
8089  * query.  (Maybe one query per schema?)
8090  *
8091  *      modifies tblinfo
8092  */
8093 void
8094 getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
8095 {
8096         DumpOptions *dopt = fout->dopt;
8097         int                     i,
8098                                 j;
8099         PQExpBuffer q = createPQExpBuffer();
8100         int                     i_attnum;
8101         int                     i_attname;
8102         int                     i_atttypname;
8103         int                     i_atttypmod;
8104         int                     i_attstattarget;
8105         int                     i_attstorage;
8106         int                     i_typstorage;
8107         int                     i_attnotnull;
8108         int                     i_atthasdef;
8109         int                     i_attidentity;
8110         int                     i_attisdropped;
8111         int                     i_attlen;
8112         int                     i_attalign;
8113         int                     i_attislocal;
8114         int                     i_attoptions;
8115         int                     i_attcollation;
8116         int                     i_attfdwoptions;
8117         int                     i_attmissingval;
8118         PGresult   *res;
8119         int                     ntups;
8120         bool            hasdefaults;
8121
8122         for (i = 0; i < numTables; i++)
8123         {
8124                 TableInfo  *tbinfo = &tblinfo[i];
8125
8126                 /* Don't bother to collect info for sequences */
8127                 if (tbinfo->relkind == RELKIND_SEQUENCE)
8128                         continue;
8129
8130                 /* Don't bother with uninteresting tables, either */
8131                 if (!tbinfo->interesting)
8132                         continue;
8133
8134                 /* find all the user attributes and their types */
8135
8136                 /*
8137                  * we must read the attribute names in attribute number order! because
8138                  * we will use the attnum to index into the attnames array later.
8139                  */
8140                 if (g_verbose)
8141                         write_msg(NULL, "finding the columns and types of table \"%s.%s\"\n",
8142                                           tbinfo->dobj.namespace->dobj.name,
8143                                           tbinfo->dobj.name);
8144
8145                 resetPQExpBuffer(q);
8146
8147                 appendPQExpBuffer(q,
8148                                                   "SELECT\n"
8149                                                   "a.attnum,\n"
8150                                                   "a.attname,\n"
8151                                                   "a.atttypmod,\n"
8152                                                   "a.attstattarget,\n"
8153                                                   "a.attstorage,\n"
8154                                                   "t.typstorage,\n"
8155                                                   "a.attnotnull,\n"
8156                                                   "a.atthasdef,\n"
8157                                                   "a.attisdropped,\n"
8158                                                   "a.attlen,\n"
8159                                                   "a.attalign,\n"
8160                                                   "a.attislocal,\n"
8161                                                   "pg_catalog.format_type(t.oid, a.atttypmod) AS atttypname,\n");
8162
8163                 if (fout->remoteVersion >= 110000)
8164                         appendPQExpBuffer(q,
8165                                                           "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
8166                                                           "THEN a.attmissingval ELSE null END AS attmissingval,\n");
8167                 else
8168                         appendPQExpBuffer(q,
8169                                                           "NULL AS attmissingval,\n");
8170
8171                 if (fout->remoteVersion >= 100000)
8172                         appendPQExpBuffer(q,
8173                                                           "a.attidentity,\n");
8174                 else
8175                         appendPQExpBuffer(q,
8176                                                           "'' AS attidentity,\n");
8177
8178                 if (fout->remoteVersion >= 90200)
8179                         appendPQExpBuffer(q,
8180                                                           "pg_catalog.array_to_string(ARRAY("
8181                                                           "SELECT pg_catalog.quote_ident(option_name) || "
8182                                                           "' ' || pg_catalog.quote_literal(option_value) "
8183                                                           "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
8184                                                           "ORDER BY option_name"
8185                                                           "), E',\n    ') AS attfdwoptions,\n");
8186                 else
8187                         appendPQExpBuffer(q,
8188                                                           "'' AS attfdwoptions,\n");
8189
8190                 if (fout->remoteVersion >= 90100)
8191                 {
8192                         /*
8193                          * Since we only want to dump COLLATE clauses for attributes whose
8194                          * collation is different from their type's default, we use a CASE
8195                          * here to suppress uninteresting attcollations cheaply.
8196                          */
8197                         appendPQExpBuffer(q,
8198                                                           "CASE WHEN a.attcollation <> t.typcollation "
8199                                                           "THEN a.attcollation ELSE 0 END AS attcollation,\n");
8200                 }
8201                 else
8202                         appendPQExpBuffer(q,
8203                                                           "0 AS attcollation,\n");
8204
8205                 if (fout->remoteVersion >= 90000)
8206                         appendPQExpBuffer(q,
8207                                                           "array_to_string(a.attoptions, ', ') AS attoptions\n");
8208                 else
8209                         appendPQExpBuffer(q,
8210                                                           "'' AS attoptions\n");
8211
8212                 /* need left join here to not fail on dropped columns ... */
8213                 appendPQExpBuffer(q,
8214                                                   "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
8215                                                   "ON a.atttypid = t.oid\n"
8216                                                   "WHERE a.attrelid = '%u'::pg_catalog.oid "
8217                                                   "AND a.attnum > 0::pg_catalog.int2\n"
8218                                                   "ORDER BY a.attnum",
8219                                                   tbinfo->dobj.catId.oid);
8220
8221                 res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8222
8223                 ntups = PQntuples(res);
8224
8225                 i_attnum = PQfnumber(res, "attnum");
8226                 i_attname = PQfnumber(res, "attname");
8227                 i_atttypname = PQfnumber(res, "atttypname");
8228                 i_atttypmod = PQfnumber(res, "atttypmod");
8229                 i_attstattarget = PQfnumber(res, "attstattarget");
8230                 i_attstorage = PQfnumber(res, "attstorage");
8231                 i_typstorage = PQfnumber(res, "typstorage");
8232                 i_attnotnull = PQfnumber(res, "attnotnull");
8233                 i_atthasdef = PQfnumber(res, "atthasdef");
8234                 i_attidentity = PQfnumber(res, "attidentity");
8235                 i_attisdropped = PQfnumber(res, "attisdropped");
8236                 i_attlen = PQfnumber(res, "attlen");
8237                 i_attalign = PQfnumber(res, "attalign");
8238                 i_attislocal = PQfnumber(res, "attislocal");
8239                 i_attoptions = PQfnumber(res, "attoptions");
8240                 i_attcollation = PQfnumber(res, "attcollation");
8241                 i_attfdwoptions = PQfnumber(res, "attfdwoptions");
8242                 i_attmissingval = PQfnumber(res, "attmissingval");
8243
8244                 tbinfo->numatts = ntups;
8245                 tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
8246                 tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
8247                 tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
8248                 tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
8249                 tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
8250                 tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
8251                 tbinfo->attidentity = (char *) pg_malloc(ntups * sizeof(char));
8252                 tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
8253                 tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
8254                 tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
8255                 tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
8256                 tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
8257                 tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
8258                 tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
8259                 tbinfo->attmissingval = (char **) pg_malloc(ntups * sizeof(char *));
8260                 tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
8261                 tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
8262                 tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
8263                 hasdefaults = false;
8264
8265                 for (j = 0; j < ntups; j++)
8266                 {
8267                         if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
8268                                 exit_horribly(NULL,
8269                                                           "invalid column numbering in table \"%s\"\n",
8270                                                           tbinfo->dobj.name);
8271                         tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
8272                         tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
8273                         tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
8274                         tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
8275                         tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
8276                         tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
8277                         tbinfo->attidentity[j] = *(PQgetvalue(res, j, i_attidentity));
8278                         tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
8279                         tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
8280                         tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
8281                         tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
8282                         tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
8283                         tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
8284                         tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
8285                         tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
8286                         tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
8287                         tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, j, i_attmissingval));
8288                         tbinfo->attrdefs[j] = NULL; /* fix below */
8289                         if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
8290                                 hasdefaults = true;
8291                         /* these flags will be set in flagInhAttrs() */
8292                         tbinfo->inhNotNull[j] = false;
8293                 }
8294
8295                 PQclear(res);
8296
8297                 /*
8298                  * Get info about column defaults
8299                  */
8300                 if (hasdefaults)
8301                 {
8302                         AttrDefInfo *attrdefs;
8303                         int                     numDefaults;
8304
8305                         if (g_verbose)
8306                                 write_msg(NULL, "finding default expressions of table \"%s.%s\"\n",
8307                                                   tbinfo->dobj.namespace->dobj.name,
8308                                                   tbinfo->dobj.name);
8309
8310                         printfPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
8311                                                           "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
8312                                                           "FROM pg_catalog.pg_attrdef "
8313                                                           "WHERE adrelid = '%u'::pg_catalog.oid",
8314                                                           tbinfo->dobj.catId.oid);
8315
8316                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8317
8318                         numDefaults = PQntuples(res);
8319                         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
8320
8321                         for (j = 0; j < numDefaults; j++)
8322                         {
8323                                 int                     adnum;
8324
8325                                 adnum = atoi(PQgetvalue(res, j, 2));
8326
8327                                 if (adnum <= 0 || adnum > ntups)
8328                                         exit_horribly(NULL,
8329                                                                   "invalid adnum value %d for table \"%s\"\n",
8330                                                                   adnum, tbinfo->dobj.name);
8331
8332                                 /*
8333                                  * dropped columns shouldn't have defaults, but just in case,
8334                                  * ignore 'em
8335                                  */
8336                                 if (tbinfo->attisdropped[adnum - 1])
8337                                         continue;
8338
8339                                 attrdefs[j].dobj.objType = DO_ATTRDEF;
8340                                 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
8341                                 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
8342                                 AssignDumpId(&attrdefs[j].dobj);
8343                                 attrdefs[j].adtable = tbinfo;
8344                                 attrdefs[j].adnum = adnum;
8345                                 attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
8346
8347                                 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
8348                                 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
8349
8350                                 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
8351
8352                                 /*
8353                                  * Defaults on a VIEW must always be dumped as separate ALTER
8354                                  * TABLE commands.  Defaults on regular tables are dumped as
8355                                  * part of the CREATE TABLE if possible, which it won't be if
8356                                  * the column is not going to be emitted explicitly.
8357                                  */
8358                                 if (tbinfo->relkind == RELKIND_VIEW)
8359                                 {
8360                                         attrdefs[j].separate = true;
8361                                 }
8362                                 else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
8363                                 {
8364                                         /* column will be suppressed, print default separately */
8365                                         attrdefs[j].separate = true;
8366                                 }
8367                                 else
8368                                 {
8369                                         attrdefs[j].separate = false;
8370
8371                                         /*
8372                                          * Mark the default as needing to appear before the table,
8373                                          * so that any dependencies it has must be emitted before
8374                                          * the CREATE TABLE.  If this is not possible, we'll
8375                                          * change to "separate" mode while sorting dependencies.
8376                                          */
8377                                         addObjectDependency(&tbinfo->dobj,
8378                                                                                 attrdefs[j].dobj.dumpId);
8379                                 }
8380
8381                                 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
8382                         }
8383                         PQclear(res);
8384                 }
8385
8386                 /*
8387                  * Get info about table CHECK constraints
8388                  */
8389                 if (tbinfo->ncheck > 0)
8390                 {
8391                         ConstraintInfo *constrs;
8392                         int                     numConstrs;
8393
8394                         if (g_verbose)
8395                                 write_msg(NULL, "finding check constraints for table \"%s.%s\"\n",
8396                                                   tbinfo->dobj.namespace->dobj.name,
8397                                                   tbinfo->dobj.name);
8398
8399                         resetPQExpBuffer(q);
8400                         if (fout->remoteVersion >= 90200)
8401                         {
8402                                 /*
8403                                  * convalidated is new in 9.2 (actually, it is there in 9.1,
8404                                  * but it wasn't ever false for check constraints until 9.2).
8405                                  */
8406                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8407                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8408                                                                   "conislocal, convalidated "
8409                                                                   "FROM pg_catalog.pg_constraint "
8410                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8411                                                                   "   AND contype = 'c' "
8412                                                                   "ORDER BY conname",
8413                                                                   tbinfo->dobj.catId.oid);
8414                         }
8415                         else if (fout->remoteVersion >= 80400)
8416                         {
8417                                 /* conislocal is new in 8.4 */
8418                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8419                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8420                                                                   "conislocal, true AS convalidated "
8421                                                                   "FROM pg_catalog.pg_constraint "
8422                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8423                                                                   "   AND contype = 'c' "
8424                                                                   "ORDER BY conname",
8425                                                                   tbinfo->dobj.catId.oid);
8426                         }
8427                         else
8428                         {
8429                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8430                                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8431                                                                   "true AS conislocal, true AS convalidated "
8432                                                                   "FROM pg_catalog.pg_constraint "
8433                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
8434                                                                   "   AND contype = 'c' "
8435                                                                   "ORDER BY conname",
8436                                                                   tbinfo->dobj.catId.oid);
8437                         }
8438
8439                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8440
8441                         numConstrs = PQntuples(res);
8442                         if (numConstrs != tbinfo->ncheck)
8443                         {
8444                                 write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
8445                                                                                  "expected %d check constraints on table \"%s\" but found %d\n",
8446                                                                                  tbinfo->ncheck),
8447                                                   tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
8448                                 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
8449                                 exit_nicely(1);
8450                         }
8451
8452                         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
8453                         tbinfo->checkexprs = constrs;
8454
8455                         for (j = 0; j < numConstrs; j++)
8456                         {
8457                                 bool            validated = PQgetvalue(res, j, 5)[0] == 't';
8458
8459                                 constrs[j].dobj.objType = DO_CONSTRAINT;
8460                                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
8461                                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
8462                                 AssignDumpId(&constrs[j].dobj);
8463                                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
8464                                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
8465                                 constrs[j].contable = tbinfo;
8466                                 constrs[j].condomain = NULL;
8467                                 constrs[j].contype = 'c';
8468                                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
8469                                 constrs[j].confrelid = InvalidOid;
8470                                 constrs[j].conindex = 0;
8471                                 constrs[j].condeferrable = false;
8472                                 constrs[j].condeferred = false;
8473                                 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
8474
8475                                 /*
8476                                  * An unvalidated constraint needs to be dumped separately, so
8477                                  * that potentially-violating existing data is loaded before
8478                                  * the constraint.
8479                                  */
8480                                 constrs[j].separate = !validated;
8481
8482                                 constrs[j].dobj.dump = tbinfo->dobj.dump;
8483
8484                                 /*
8485                                  * Mark the constraint as needing to appear before the table
8486                                  * --- this is so that any other dependencies of the
8487                                  * constraint will be emitted before we try to create the
8488                                  * table.  If the constraint is to be dumped separately, it
8489                                  * will be dumped after data is loaded anyway, so don't do it.
8490                                  * (There's an automatic dependency in the opposite direction
8491                                  * anyway, so don't need to add one manually here.)
8492                                  */
8493                                 if (!constrs[j].separate)
8494                                         addObjectDependency(&tbinfo->dobj,
8495                                                                                 constrs[j].dobj.dumpId);
8496
8497                                 /*
8498                                  * If the constraint is inherited, this will be detected later
8499                                  * (in pre-8.4 databases).  We also detect later if the
8500                                  * constraint must be split out from the table definition.
8501                                  */
8502                         }
8503                         PQclear(res);
8504                 }
8505         }
8506
8507         destroyPQExpBuffer(q);
8508 }
8509
8510 /*
8511  * Test whether a column should be printed as part of table's CREATE TABLE.
8512  * Column number is zero-based.
8513  *
8514  * Normally this is always true, but it's false for dropped columns, as well
8515  * as those that were inherited without any local definition.  (If we print
8516  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
8517  * However, in binary_upgrade mode, we must print all such columns anyway and
8518  * fix the attislocal/attisdropped state later, so as to keep control of the
8519  * physical column order.
8520  *
8521  * This function exists because there are scattered nonobvious places that
8522  * must be kept in sync with this decision.
8523  */
8524 bool
8525 shouldPrintColumn(DumpOptions *dopt, TableInfo *tbinfo, int colno)
8526 {
8527         if (dopt->binary_upgrade)
8528                 return true;
8529         return (tbinfo->attislocal[colno] && !tbinfo->attisdropped[colno]);
8530 }
8531
8532
8533 /*
8534  * getTSParsers:
8535  *        read all text search parsers in the system catalogs and return them
8536  *        in the TSParserInfo* structure
8537  *
8538  *      numTSParsers is set to the number of parsers read in
8539  */
8540 TSParserInfo *
8541 getTSParsers(Archive *fout, int *numTSParsers)
8542 {
8543         PGresult   *res;
8544         int                     ntups;
8545         int                     i;
8546         PQExpBuffer query;
8547         TSParserInfo *prsinfo;
8548         int                     i_tableoid;
8549         int                     i_oid;
8550         int                     i_prsname;
8551         int                     i_prsnamespace;
8552         int                     i_prsstart;
8553         int                     i_prstoken;
8554         int                     i_prsend;
8555         int                     i_prsheadline;
8556         int                     i_prslextype;
8557
8558         /* Before 8.3, there is no built-in text search support */
8559         if (fout->remoteVersion < 80300)
8560         {
8561                 *numTSParsers = 0;
8562                 return NULL;
8563         }
8564
8565         query = createPQExpBuffer();
8566
8567         /*
8568          * find all text search objects, including builtin ones; we filter out
8569          * system-defined objects at dump-out time.
8570          */
8571
8572         appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
8573                                                  "prsstart::oid, prstoken::oid, "
8574                                                  "prsend::oid, prsheadline::oid, prslextype::oid "
8575                                                  "FROM pg_ts_parser");
8576
8577         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8578
8579         ntups = PQntuples(res);
8580         *numTSParsers = ntups;
8581
8582         prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
8583
8584         i_tableoid = PQfnumber(res, "tableoid");
8585         i_oid = PQfnumber(res, "oid");
8586         i_prsname = PQfnumber(res, "prsname");
8587         i_prsnamespace = PQfnumber(res, "prsnamespace");
8588         i_prsstart = PQfnumber(res, "prsstart");
8589         i_prstoken = PQfnumber(res, "prstoken");
8590         i_prsend = PQfnumber(res, "prsend");
8591         i_prsheadline = PQfnumber(res, "prsheadline");
8592         i_prslextype = PQfnumber(res, "prslextype");
8593
8594         for (i = 0; i < ntups; i++)
8595         {
8596                 prsinfo[i].dobj.objType = DO_TSPARSER;
8597                 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8598                 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8599                 AssignDumpId(&prsinfo[i].dobj);
8600                 prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
8601                 prsinfo[i].dobj.namespace =
8602                         findNamespace(fout,
8603                                                   atooid(PQgetvalue(res, i, i_prsnamespace)));
8604                 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
8605                 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
8606                 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
8607                 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
8608                 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
8609
8610                 /* Decide whether we want to dump it */
8611                 selectDumpableObject(&(prsinfo[i].dobj), fout);
8612
8613                 /* Text Search Parsers do not currently have ACLs. */
8614                 prsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8615         }
8616
8617         PQclear(res);
8618
8619         destroyPQExpBuffer(query);
8620
8621         return prsinfo;
8622 }
8623
8624 /*
8625  * getTSDictionaries:
8626  *        read all text search dictionaries in the system catalogs and return them
8627  *        in the TSDictInfo* structure
8628  *
8629  *      numTSDicts is set to the number of dictionaries read in
8630  */
8631 TSDictInfo *
8632 getTSDictionaries(Archive *fout, int *numTSDicts)
8633 {
8634         PGresult   *res;
8635         int                     ntups;
8636         int                     i;
8637         PQExpBuffer query;
8638         TSDictInfo *dictinfo;
8639         int                     i_tableoid;
8640         int                     i_oid;
8641         int                     i_dictname;
8642         int                     i_dictnamespace;
8643         int                     i_rolname;
8644         int                     i_dicttemplate;
8645         int                     i_dictinitoption;
8646
8647         /* Before 8.3, there is no built-in text search support */
8648         if (fout->remoteVersion < 80300)
8649         {
8650                 *numTSDicts = 0;
8651                 return NULL;
8652         }
8653
8654         query = createPQExpBuffer();
8655
8656         appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
8657                                           "dictnamespace, (%s dictowner) AS rolname, "
8658                                           "dicttemplate, dictinitoption "
8659                                           "FROM pg_ts_dict",
8660                                           username_subquery);
8661
8662         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8663
8664         ntups = PQntuples(res);
8665         *numTSDicts = ntups;
8666
8667         dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
8668
8669         i_tableoid = PQfnumber(res, "tableoid");
8670         i_oid = PQfnumber(res, "oid");
8671         i_dictname = PQfnumber(res, "dictname");
8672         i_dictnamespace = PQfnumber(res, "dictnamespace");
8673         i_rolname = PQfnumber(res, "rolname");
8674         i_dictinitoption = PQfnumber(res, "dictinitoption");
8675         i_dicttemplate = PQfnumber(res, "dicttemplate");
8676
8677         for (i = 0; i < ntups; i++)
8678         {
8679                 dictinfo[i].dobj.objType = DO_TSDICT;
8680                 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8681                 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8682                 AssignDumpId(&dictinfo[i].dobj);
8683                 dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
8684                 dictinfo[i].dobj.namespace =
8685                         findNamespace(fout,
8686                                                   atooid(PQgetvalue(res, i, i_dictnamespace)));
8687                 dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8688                 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
8689                 if (PQgetisnull(res, i, i_dictinitoption))
8690                         dictinfo[i].dictinitoption = NULL;
8691                 else
8692                         dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
8693
8694                 /* Decide whether we want to dump it */
8695                 selectDumpableObject(&(dictinfo[i].dobj), fout);
8696
8697                 /* Text Search Dictionaries do not currently have ACLs. */
8698                 dictinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8699         }
8700
8701         PQclear(res);
8702
8703         destroyPQExpBuffer(query);
8704
8705         return dictinfo;
8706 }
8707
8708 /*
8709  * getTSTemplates:
8710  *        read all text search templates in the system catalogs and return them
8711  *        in the TSTemplateInfo* structure
8712  *
8713  *      numTSTemplates is set to the number of templates read in
8714  */
8715 TSTemplateInfo *
8716 getTSTemplates(Archive *fout, int *numTSTemplates)
8717 {
8718         PGresult   *res;
8719         int                     ntups;
8720         int                     i;
8721         PQExpBuffer query;
8722         TSTemplateInfo *tmplinfo;
8723         int                     i_tableoid;
8724         int                     i_oid;
8725         int                     i_tmplname;
8726         int                     i_tmplnamespace;
8727         int                     i_tmplinit;
8728         int                     i_tmpllexize;
8729
8730         /* Before 8.3, there is no built-in text search support */
8731         if (fout->remoteVersion < 80300)
8732         {
8733                 *numTSTemplates = 0;
8734                 return NULL;
8735         }
8736
8737         query = createPQExpBuffer();
8738
8739         appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
8740                                                  "tmplnamespace, tmplinit::oid, tmpllexize::oid "
8741                                                  "FROM pg_ts_template");
8742
8743         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8744
8745         ntups = PQntuples(res);
8746         *numTSTemplates = ntups;
8747
8748         tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
8749
8750         i_tableoid = PQfnumber(res, "tableoid");
8751         i_oid = PQfnumber(res, "oid");
8752         i_tmplname = PQfnumber(res, "tmplname");
8753         i_tmplnamespace = PQfnumber(res, "tmplnamespace");
8754         i_tmplinit = PQfnumber(res, "tmplinit");
8755         i_tmpllexize = PQfnumber(res, "tmpllexize");
8756
8757         for (i = 0; i < ntups; i++)
8758         {
8759                 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
8760                 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8761                 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8762                 AssignDumpId(&tmplinfo[i].dobj);
8763                 tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
8764                 tmplinfo[i].dobj.namespace =
8765                         findNamespace(fout,
8766                                                   atooid(PQgetvalue(res, i, i_tmplnamespace)));
8767                 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
8768                 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
8769
8770                 /* Decide whether we want to dump it */
8771                 selectDumpableObject(&(tmplinfo[i].dobj), fout);
8772
8773                 /* Text Search Templates do not currently have ACLs. */
8774                 tmplinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8775         }
8776
8777         PQclear(res);
8778
8779         destroyPQExpBuffer(query);
8780
8781         return tmplinfo;
8782 }
8783
8784 /*
8785  * getTSConfigurations:
8786  *        read all text search configurations in the system catalogs and return
8787  *        them in the TSConfigInfo* structure
8788  *
8789  *      numTSConfigs is set to the number of configurations read in
8790  */
8791 TSConfigInfo *
8792 getTSConfigurations(Archive *fout, int *numTSConfigs)
8793 {
8794         PGresult   *res;
8795         int                     ntups;
8796         int                     i;
8797         PQExpBuffer query;
8798         TSConfigInfo *cfginfo;
8799         int                     i_tableoid;
8800         int                     i_oid;
8801         int                     i_cfgname;
8802         int                     i_cfgnamespace;
8803         int                     i_rolname;
8804         int                     i_cfgparser;
8805
8806         /* Before 8.3, there is no built-in text search support */
8807         if (fout->remoteVersion < 80300)
8808         {
8809                 *numTSConfigs = 0;
8810                 return NULL;
8811         }
8812
8813         query = createPQExpBuffer();
8814
8815         appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
8816                                           "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
8817                                           "FROM pg_ts_config",
8818                                           username_subquery);
8819
8820         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8821
8822         ntups = PQntuples(res);
8823         *numTSConfigs = ntups;
8824
8825         cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
8826
8827         i_tableoid = PQfnumber(res, "tableoid");
8828         i_oid = PQfnumber(res, "oid");
8829         i_cfgname = PQfnumber(res, "cfgname");
8830         i_cfgnamespace = PQfnumber(res, "cfgnamespace");
8831         i_rolname = PQfnumber(res, "rolname");
8832         i_cfgparser = PQfnumber(res, "cfgparser");
8833
8834         for (i = 0; i < ntups; i++)
8835         {
8836                 cfginfo[i].dobj.objType = DO_TSCONFIG;
8837                 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8838                 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8839                 AssignDumpId(&cfginfo[i].dobj);
8840                 cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
8841                 cfginfo[i].dobj.namespace =
8842                         findNamespace(fout,
8843                                                   atooid(PQgetvalue(res, i, i_cfgnamespace)));
8844                 cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8845                 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
8846
8847                 /* Decide whether we want to dump it */
8848                 selectDumpableObject(&(cfginfo[i].dobj), fout);
8849
8850                 /* Text Search Configurations do not currently have ACLs. */
8851                 cfginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8852         }
8853
8854         PQclear(res);
8855
8856         destroyPQExpBuffer(query);
8857
8858         return cfginfo;
8859 }
8860
8861 /*
8862  * getForeignDataWrappers:
8863  *        read all foreign-data wrappers in the system catalogs and return
8864  *        them in the FdwInfo* structure
8865  *
8866  *      numForeignDataWrappers is set to the number of fdws read in
8867  */
8868 FdwInfo *
8869 getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
8870 {
8871         DumpOptions *dopt = fout->dopt;
8872         PGresult   *res;
8873         int                     ntups;
8874         int                     i;
8875         PQExpBuffer query;
8876         FdwInfo    *fdwinfo;
8877         int                     i_tableoid;
8878         int                     i_oid;
8879         int                     i_fdwname;
8880         int                     i_rolname;
8881         int                     i_fdwhandler;
8882         int                     i_fdwvalidator;
8883         int                     i_fdwacl;
8884         int                     i_rfdwacl;
8885         int                     i_initfdwacl;
8886         int                     i_initrfdwacl;
8887         int                     i_fdwoptions;
8888
8889         /* Before 8.4, there are no foreign-data wrappers */
8890         if (fout->remoteVersion < 80400)
8891         {
8892                 *numForeignDataWrappers = 0;
8893                 return NULL;
8894         }
8895
8896         query = createPQExpBuffer();
8897
8898         if (fout->remoteVersion >= 90600)
8899         {
8900                 PQExpBuffer acl_subquery = createPQExpBuffer();
8901                 PQExpBuffer racl_subquery = createPQExpBuffer();
8902                 PQExpBuffer initacl_subquery = createPQExpBuffer();
8903                 PQExpBuffer initracl_subquery = createPQExpBuffer();
8904
8905                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
8906                                                 initracl_subquery, "f.fdwacl", "f.fdwowner", "'F'",
8907                                                 dopt->binary_upgrade);
8908
8909                 appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.fdwname, "
8910                                                   "(%s f.fdwowner) AS rolname, "
8911                                                   "f.fdwhandler::pg_catalog.regproc, "
8912                                                   "f.fdwvalidator::pg_catalog.regproc, "
8913                                                   "%s AS fdwacl, "
8914                                                   "%s AS rfdwacl, "
8915                                                   "%s AS initfdwacl, "
8916                                                   "%s AS initrfdwacl, "
8917                                                   "array_to_string(ARRAY("
8918                                                   "SELECT quote_ident(option_name) || ' ' || "
8919                                                   "quote_literal(option_value) "
8920                                                   "FROM pg_options_to_table(f.fdwoptions) "
8921                                                   "ORDER BY option_name"
8922                                                   "), E',\n    ') AS fdwoptions "
8923                                                   "FROM pg_foreign_data_wrapper f "
8924                                                   "LEFT JOIN pg_init_privs pip ON "
8925                                                   "(f.oid = pip.objoid "
8926                                                   "AND pip.classoid = 'pg_foreign_data_wrapper'::regclass "
8927                                                   "AND pip.objsubid = 0) ",
8928                                                   username_subquery,
8929                                                   acl_subquery->data,
8930                                                   racl_subquery->data,
8931                                                   initacl_subquery->data,
8932                                                   initracl_subquery->data);
8933
8934                 destroyPQExpBuffer(acl_subquery);
8935                 destroyPQExpBuffer(racl_subquery);
8936                 destroyPQExpBuffer(initacl_subquery);
8937                 destroyPQExpBuffer(initracl_subquery);
8938         }
8939         else if (fout->remoteVersion >= 90100)
8940         {
8941                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
8942                                                   "(%s fdwowner) AS rolname, "
8943                                                   "fdwhandler::pg_catalog.regproc, "
8944                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
8945                                                   "NULL as rfdwacl, "
8946                                                   "NULL as initfdwacl, NULL AS initrfdwacl, "
8947                                                   "array_to_string(ARRAY("
8948                                                   "SELECT quote_ident(option_name) || ' ' || "
8949                                                   "quote_literal(option_value) "
8950                                                   "FROM pg_options_to_table(fdwoptions) "
8951                                                   "ORDER BY option_name"
8952                                                   "), E',\n    ') AS fdwoptions "
8953                                                   "FROM pg_foreign_data_wrapper",
8954                                                   username_subquery);
8955         }
8956         else
8957         {
8958                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
8959                                                   "(%s fdwowner) AS rolname, "
8960                                                   "'-' AS fdwhandler, "
8961                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
8962                                                   "NULL as rfdwacl, "
8963                                                   "NULL as initfdwacl, NULL AS initrfdwacl, "
8964                                                   "array_to_string(ARRAY("
8965                                                   "SELECT quote_ident(option_name) || ' ' || "
8966                                                   "quote_literal(option_value) "
8967                                                   "FROM pg_options_to_table(fdwoptions) "
8968                                                   "ORDER BY option_name"
8969                                                   "), E',\n    ') AS fdwoptions "
8970                                                   "FROM pg_foreign_data_wrapper",
8971                                                   username_subquery);
8972         }
8973
8974         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8975
8976         ntups = PQntuples(res);
8977         *numForeignDataWrappers = ntups;
8978
8979         fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
8980
8981         i_tableoid = PQfnumber(res, "tableoid");
8982         i_oid = PQfnumber(res, "oid");
8983         i_fdwname = PQfnumber(res, "fdwname");
8984         i_rolname = PQfnumber(res, "rolname");
8985         i_fdwhandler = PQfnumber(res, "fdwhandler");
8986         i_fdwvalidator = PQfnumber(res, "fdwvalidator");
8987         i_fdwacl = PQfnumber(res, "fdwacl");
8988         i_rfdwacl = PQfnumber(res, "rfdwacl");
8989         i_initfdwacl = PQfnumber(res, "initfdwacl");
8990         i_initrfdwacl = PQfnumber(res, "initrfdwacl");
8991         i_fdwoptions = PQfnumber(res, "fdwoptions");
8992
8993         for (i = 0; i < ntups; i++)
8994         {
8995                 fdwinfo[i].dobj.objType = DO_FDW;
8996                 fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8997                 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8998                 AssignDumpId(&fdwinfo[i].dobj);
8999                 fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
9000                 fdwinfo[i].dobj.namespace = NULL;
9001                 fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
9002                 fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
9003                 fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
9004                 fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
9005                 fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
9006                 fdwinfo[i].rfdwacl = pg_strdup(PQgetvalue(res, i, i_rfdwacl));
9007                 fdwinfo[i].initfdwacl = pg_strdup(PQgetvalue(res, i, i_initfdwacl));
9008                 fdwinfo[i].initrfdwacl = pg_strdup(PQgetvalue(res, i, i_initrfdwacl));
9009
9010                 /* Decide whether we want to dump it */
9011                 selectDumpableObject(&(fdwinfo[i].dobj), fout);
9012
9013                 /* Do not try to dump ACL if no ACL exists. */
9014                 if (PQgetisnull(res, i, i_fdwacl) && PQgetisnull(res, i, i_rfdwacl) &&
9015                         PQgetisnull(res, i, i_initfdwacl) &&
9016                         PQgetisnull(res, i, i_initrfdwacl))
9017                         fdwinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
9018         }
9019
9020         PQclear(res);
9021
9022         destroyPQExpBuffer(query);
9023
9024         return fdwinfo;
9025 }
9026
9027 /*
9028  * getForeignServers:
9029  *        read all foreign servers in the system catalogs and return
9030  *        them in the ForeignServerInfo * structure
9031  *
9032  *      numForeignServers is set to the number of servers read in
9033  */
9034 ForeignServerInfo *
9035 getForeignServers(Archive *fout, int *numForeignServers)
9036 {
9037         DumpOptions *dopt = fout->dopt;
9038         PGresult   *res;
9039         int                     ntups;
9040         int                     i;
9041         PQExpBuffer query;
9042         ForeignServerInfo *srvinfo;
9043         int                     i_tableoid;
9044         int                     i_oid;
9045         int                     i_srvname;
9046         int                     i_rolname;
9047         int                     i_srvfdw;
9048         int                     i_srvtype;
9049         int                     i_srvversion;
9050         int                     i_srvacl;
9051         int                     i_rsrvacl;
9052         int                     i_initsrvacl;
9053         int                     i_initrsrvacl;
9054         int                     i_srvoptions;
9055
9056         /* Before 8.4, there are no foreign servers */
9057         if (fout->remoteVersion < 80400)
9058         {
9059                 *numForeignServers = 0;
9060                 return NULL;
9061         }
9062
9063         query = createPQExpBuffer();
9064
9065         if (fout->remoteVersion >= 90600)
9066         {
9067                 PQExpBuffer acl_subquery = createPQExpBuffer();
9068                 PQExpBuffer racl_subquery = createPQExpBuffer();
9069                 PQExpBuffer initacl_subquery = createPQExpBuffer();
9070                 PQExpBuffer initracl_subquery = createPQExpBuffer();
9071
9072                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9073                                                 initracl_subquery, "f.srvacl", "f.srvowner", "'S'",
9074                                                 dopt->binary_upgrade);
9075
9076                 appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.srvname, "
9077                                                   "(%s f.srvowner) AS rolname, "
9078                                                   "f.srvfdw, f.srvtype, f.srvversion, "
9079                                                   "%s AS srvacl, "
9080                                                   "%s AS rsrvacl, "
9081                                                   "%s AS initsrvacl, "
9082                                                   "%s AS initrsrvacl, "
9083                                                   "array_to_string(ARRAY("
9084                                                   "SELECT quote_ident(option_name) || ' ' || "
9085                                                   "quote_literal(option_value) "
9086                                                   "FROM pg_options_to_table(f.srvoptions) "
9087                                                   "ORDER BY option_name"
9088                                                   "), E',\n    ') AS srvoptions "
9089                                                   "FROM pg_foreign_server f "
9090                                                   "LEFT JOIN pg_init_privs pip "
9091                                                   "ON (f.oid = pip.objoid "
9092                                                   "AND pip.classoid = 'pg_foreign_server'::regclass "
9093                                                   "AND pip.objsubid = 0) ",
9094                                                   username_subquery,
9095                                                   acl_subquery->data,
9096                                                   racl_subquery->data,
9097                                                   initacl_subquery->data,
9098                                                   initracl_subquery->data);
9099
9100                 destroyPQExpBuffer(acl_subquery);
9101                 destroyPQExpBuffer(racl_subquery);
9102                 destroyPQExpBuffer(initacl_subquery);
9103                 destroyPQExpBuffer(initracl_subquery);
9104         }
9105         else
9106         {
9107                 appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
9108                                                   "(%s srvowner) AS rolname, "
9109                                                   "srvfdw, srvtype, srvversion, srvacl, "
9110                                                   "NULL AS rsrvacl, "
9111                                                   "NULL AS initsrvacl, NULL AS initrsrvacl, "
9112                                                   "array_to_string(ARRAY("
9113                                                   "SELECT quote_ident(option_name) || ' ' || "
9114                                                   "quote_literal(option_value) "
9115                                                   "FROM pg_options_to_table(srvoptions) "
9116                                                   "ORDER BY option_name"
9117                                                   "), E',\n    ') AS srvoptions "
9118                                                   "FROM pg_foreign_server",
9119                                                   username_subquery);
9120         }
9121
9122         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9123
9124         ntups = PQntuples(res);
9125         *numForeignServers = ntups;
9126
9127         srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
9128
9129         i_tableoid = PQfnumber(res, "tableoid");
9130         i_oid = PQfnumber(res, "oid");
9131         i_srvname = PQfnumber(res, "srvname");
9132         i_rolname = PQfnumber(res, "rolname");
9133         i_srvfdw = PQfnumber(res, "srvfdw");
9134         i_srvtype = PQfnumber(res, "srvtype");
9135         i_srvversion = PQfnumber(res, "srvversion");
9136         i_srvacl = PQfnumber(res, "srvacl");
9137         i_rsrvacl = PQfnumber(res, "rsrvacl");
9138         i_initsrvacl = PQfnumber(res, "initsrvacl");
9139         i_initrsrvacl = PQfnumber(res, "initrsrvacl");
9140         i_srvoptions = PQfnumber(res, "srvoptions");
9141
9142         for (i = 0; i < ntups; i++)
9143         {
9144                 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
9145                 srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9146                 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9147                 AssignDumpId(&srvinfo[i].dobj);
9148                 srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
9149                 srvinfo[i].dobj.namespace = NULL;
9150                 srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
9151                 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
9152                 srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
9153                 srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
9154                 srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
9155                 srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
9156                 srvinfo[i].rsrvacl = pg_strdup(PQgetvalue(res, i, i_rsrvacl));
9157                 srvinfo[i].initsrvacl = pg_strdup(PQgetvalue(res, i, i_initsrvacl));
9158                 srvinfo[i].initrsrvacl = pg_strdup(PQgetvalue(res, i, i_initrsrvacl));
9159
9160                 /* Decide whether we want to dump it */
9161                 selectDumpableObject(&(srvinfo[i].dobj), fout);
9162
9163                 /* Do not try to dump ACL if no ACL exists. */
9164                 if (PQgetisnull(res, i, i_srvacl) && PQgetisnull(res, i, i_rsrvacl) &&
9165                         PQgetisnull(res, i, i_initsrvacl) &&
9166                         PQgetisnull(res, i, i_initrsrvacl))
9167                         srvinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
9168         }
9169
9170         PQclear(res);
9171
9172         destroyPQExpBuffer(query);
9173
9174         return srvinfo;
9175 }
9176
9177 /*
9178  * getDefaultACLs:
9179  *        read all default ACL information in the system catalogs and return
9180  *        them in the DefaultACLInfo structure
9181  *
9182  *      numDefaultACLs is set to the number of ACLs read in
9183  */
9184 DefaultACLInfo *
9185 getDefaultACLs(Archive *fout, int *numDefaultACLs)
9186 {
9187         DumpOptions *dopt = fout->dopt;
9188         DefaultACLInfo *daclinfo;
9189         PQExpBuffer query;
9190         PGresult   *res;
9191         int                     i_oid;
9192         int                     i_tableoid;
9193         int                     i_defaclrole;
9194         int                     i_defaclnamespace;
9195         int                     i_defaclobjtype;
9196         int                     i_defaclacl;
9197         int                     i_rdefaclacl;
9198         int                     i_initdefaclacl;
9199         int                     i_initrdefaclacl;
9200         int                     i,
9201                                 ntups;
9202
9203         if (fout->remoteVersion < 90000)
9204         {
9205                 *numDefaultACLs = 0;
9206                 return NULL;
9207         }
9208
9209         query = createPQExpBuffer();
9210
9211         if (fout->remoteVersion >= 90600)
9212         {
9213                 PQExpBuffer acl_subquery = createPQExpBuffer();
9214                 PQExpBuffer racl_subquery = createPQExpBuffer();
9215                 PQExpBuffer initacl_subquery = createPQExpBuffer();
9216                 PQExpBuffer initracl_subquery = createPQExpBuffer();
9217
9218                 buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9219                                                 initracl_subquery, "defaclacl", "defaclrole",
9220                                                 "CASE WHEN defaclobjtype = 'S' THEN 's' ELSE defaclobjtype END::\"char\"",
9221                                                 dopt->binary_upgrade);
9222
9223                 appendPQExpBuffer(query, "SELECT d.oid, d.tableoid, "
9224                                                   "(%s d.defaclrole) AS defaclrole, "
9225                                                   "d.defaclnamespace, "
9226                                                   "d.defaclobjtype, "
9227                                                   "%s AS defaclacl, "
9228                                                   "%s AS rdefaclacl, "
9229                                                   "%s AS initdefaclacl, "
9230                                                   "%s AS initrdefaclacl "
9231                                                   "FROM pg_default_acl d "
9232                                                   "LEFT JOIN pg_init_privs pip ON "
9233                                                   "(d.oid = pip.objoid "
9234                                                   "AND pip.classoid = 'pg_default_acl'::regclass "
9235                                                   "AND pip.objsubid = 0) ",
9236                                                   username_subquery,
9237                                                   acl_subquery->data,
9238                                                   racl_subquery->data,
9239                                                   initacl_subquery->data,
9240                                                   initracl_subquery->data);
9241         }
9242         else
9243         {
9244                 appendPQExpBuffer(query, "SELECT oid, tableoid, "
9245                                                   "(%s defaclrole) AS defaclrole, "
9246                                                   "defaclnamespace, "
9247                                                   "defaclobjtype, "
9248                                                   "defaclacl, "
9249                                                   "NULL AS rdefaclacl, "
9250                                                   "NULL AS initdefaclacl, "
9251                                                   "NULL AS initrdefaclacl "
9252                                                   "FROM pg_default_acl",
9253                                                   username_subquery);
9254         }
9255
9256         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9257
9258         ntups = PQntuples(res);
9259         *numDefaultACLs = ntups;
9260
9261         daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
9262
9263         i_oid = PQfnumber(res, "oid");
9264         i_tableoid = PQfnumber(res, "tableoid");
9265         i_defaclrole = PQfnumber(res, "defaclrole");
9266         i_defaclnamespace = PQfnumber(res, "defaclnamespace");
9267         i_defaclobjtype = PQfnumber(res, "defaclobjtype");
9268         i_defaclacl = PQfnumber(res, "defaclacl");
9269         i_rdefaclacl = PQfnumber(res, "rdefaclacl");
9270         i_initdefaclacl = PQfnumber(res, "initdefaclacl");
9271         i_initrdefaclacl = PQfnumber(res, "initrdefaclacl");
9272
9273         for (i = 0; i < ntups; i++)
9274         {
9275                 Oid                     nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
9276
9277                 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
9278                 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9279                 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9280                 AssignDumpId(&daclinfo[i].dobj);
9281                 /* cheesy ... is it worth coming up with a better object name? */
9282                 daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
9283
9284                 if (nspid != InvalidOid)
9285                         daclinfo[i].dobj.namespace = findNamespace(fout, nspid);
9286                 else
9287                         daclinfo[i].dobj.namespace = NULL;
9288
9289                 daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
9290                 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
9291                 daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
9292                 daclinfo[i].rdefaclacl = pg_strdup(PQgetvalue(res, i, i_rdefaclacl));
9293                 daclinfo[i].initdefaclacl = pg_strdup(PQgetvalue(res, i, i_initdefaclacl));
9294                 daclinfo[i].initrdefaclacl = pg_strdup(PQgetvalue(res, i, i_initrdefaclacl));
9295
9296                 /* Decide whether we want to dump it */
9297                 selectDumpableDefaultACL(&(daclinfo[i]), dopt);
9298         }
9299
9300         PQclear(res);
9301
9302         destroyPQExpBuffer(query);
9303
9304         return daclinfo;
9305 }
9306
9307 /*
9308  * dumpComment --
9309  *
9310  * This routine is used to dump any comments associated with the
9311  * object handed to this routine. The routine takes the object type
9312  * and object name (ready to print, except for schema decoration), plus
9313  * the namespace and owner of the object (for labeling the ArchiveEntry),
9314  * plus catalog ID and subid which are the lookup key for pg_description,
9315  * plus the dump ID for the object (for setting a dependency).
9316  * If a matching pg_description entry is found, it is dumped.
9317  *
9318  * Note: in some cases, such as comments for triggers and rules, the "type"
9319  * string really looks like, e.g., "TRIGGER name ON".  This is a bit of a hack
9320  * but it doesn't seem worth complicating the API for all callers to make
9321  * it cleaner.
9322  *
9323  * Note: although this routine takes a dumpId for dependency purposes,
9324  * that purpose is just to mark the dependency in the emitted dump file
9325  * for possible future use by pg_restore.  We do NOT use it for determining
9326  * ordering of the comment in the dump file, because this routine is called
9327  * after dependency sorting occurs.  This routine should be called just after
9328  * calling ArchiveEntry() for the specified object.
9329  */
9330 static void
9331 dumpComment(Archive *fout, const char *type, const char *name,
9332                         const char *namespace, const char *owner,
9333                         CatalogId catalogId, int subid, DumpId dumpId)
9334 {
9335         DumpOptions *dopt = fout->dopt;
9336         CommentItem *comments;
9337         int                     ncomments;
9338
9339         /* do nothing, if --no-comments is supplied */
9340         if (dopt->no_comments)
9341                 return;
9342
9343         /* Comments are schema not data ... except blob comments are data */
9344         if (strcmp(type, "LARGE OBJECT") != 0)
9345         {
9346                 if (dopt->dataOnly)
9347                         return;
9348         }
9349         else
9350         {
9351                 /* We do dump blob comments in binary-upgrade mode */
9352                 if (dopt->schemaOnly && !dopt->binary_upgrade)
9353                         return;
9354         }
9355
9356         /* Search for comments associated with catalogId, using table */
9357         ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
9358                                                          &comments);
9359
9360         /* Is there one matching the subid? */
9361         while (ncomments > 0)
9362         {
9363                 if (comments->objsubid == subid)
9364                         break;
9365                 comments++;
9366                 ncomments--;
9367         }
9368
9369         /* If a comment exists, build COMMENT ON statement */
9370         if (ncomments > 0)
9371         {
9372                 PQExpBuffer query = createPQExpBuffer();
9373                 PQExpBuffer tag = createPQExpBuffer();
9374
9375                 appendPQExpBuffer(query, "COMMENT ON %s ", type);
9376                 if (namespace && *namespace)
9377                         appendPQExpBuffer(query, "%s.", fmtId(namespace));
9378                 appendPQExpBuffer(query, "%s IS ", name);
9379                 appendStringLiteralAH(query, comments->descr, fout);
9380                 appendPQExpBufferStr(query, ";\n");
9381
9382                 appendPQExpBuffer(tag, "%s %s", type, name);
9383
9384                 /*
9385                  * We mark comments as SECTION_NONE because they really belong in the
9386                  * same section as their parent, whether that is pre-data or
9387                  * post-data.
9388                  */
9389                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
9390                                          ARCHIVE_OPTS(.tag = tag->data,
9391                                                                   .namespace = namespace,
9392                                                                   .owner = owner,
9393                                                                   .description = "COMMENT",
9394                                                                   .section = SECTION_NONE,
9395                                                                   .createStmt = query->data,
9396                                                                   .deps = &dumpId,
9397                                                                   .nDeps = 1));
9398
9399                 destroyPQExpBuffer(query);
9400                 destroyPQExpBuffer(tag);
9401         }
9402 }
9403
9404 /*
9405  * dumpTableComment --
9406  *
9407  * As above, but dump comments for both the specified table (or view)
9408  * and its columns.
9409  */
9410 static void
9411 dumpTableComment(Archive *fout, TableInfo *tbinfo,
9412                                  const char *reltypename)
9413 {
9414         DumpOptions *dopt = fout->dopt;
9415         CommentItem *comments;
9416         int                     ncomments;
9417         PQExpBuffer query;
9418         PQExpBuffer tag;
9419
9420         /* do nothing, if --no-comments is supplied */
9421         if (dopt->no_comments)
9422                 return;
9423
9424         /* Comments are SCHEMA not data */
9425         if (dopt->dataOnly)
9426                 return;
9427
9428         /* Search for comments associated with relation, using table */
9429         ncomments = findComments(fout,
9430                                                          tbinfo->dobj.catId.tableoid,
9431                                                          tbinfo->dobj.catId.oid,
9432                                                          &comments);
9433
9434         /* If comments exist, build COMMENT ON statements */
9435         if (ncomments <= 0)
9436                 return;
9437
9438         query = createPQExpBuffer();
9439         tag = createPQExpBuffer();
9440
9441         while (ncomments > 0)
9442         {
9443                 const char *descr = comments->descr;
9444                 int                     objsubid = comments->objsubid;
9445
9446                 if (objsubid == 0)
9447                 {
9448                         resetPQExpBuffer(tag);
9449                         appendPQExpBuffer(tag, "%s %s", reltypename,
9450                                                           fmtId(tbinfo->dobj.name));
9451
9452                         resetPQExpBuffer(query);
9453                         appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
9454                                                           fmtQualifiedDumpable(tbinfo));
9455                         appendStringLiteralAH(query, descr, fout);
9456                         appendPQExpBufferStr(query, ";\n");
9457
9458                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
9459                                                  ARCHIVE_OPTS(.tag = tag->data,
9460                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
9461                                                                           .owner = tbinfo->rolname,
9462                                                                           .description = "COMMENT",
9463                                                                           .section = SECTION_NONE,
9464                                                                           .createStmt = query->data,
9465                                                                           .deps = &(tbinfo->dobj.dumpId),
9466                                                                           .nDeps = 1));
9467                 }
9468                 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
9469                 {
9470                         resetPQExpBuffer(tag);
9471                         appendPQExpBuffer(tag, "COLUMN %s.",
9472                                                           fmtId(tbinfo->dobj.name));
9473                         appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
9474
9475                         resetPQExpBuffer(query);
9476                         appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
9477                                                           fmtQualifiedDumpable(tbinfo));
9478                         appendPQExpBuffer(query, "%s IS ",
9479                                                           fmtId(tbinfo->attnames[objsubid - 1]));
9480                         appendStringLiteralAH(query, descr, fout);
9481                         appendPQExpBufferStr(query, ";\n");
9482
9483                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
9484                                                  ARCHIVE_OPTS(.tag = tag->data,
9485                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
9486                                                                           .owner = tbinfo->rolname,
9487                                                                           .description = "COMMENT",
9488                                                                           .section = SECTION_NONE,
9489                                                                           .createStmt = query->data,
9490                                                                           .deps = &(tbinfo->dobj.dumpId),
9491                                                                           .nDeps = 1));
9492                 }
9493
9494                 comments++;
9495                 ncomments--;
9496         }
9497
9498         destroyPQExpBuffer(query);
9499         destroyPQExpBuffer(tag);
9500 }
9501
9502 /*
9503  * findComments --
9504  *
9505  * Find the comment(s), if any, associated with the given object.  All the
9506  * objsubid values associated with the given classoid/objoid are found with
9507  * one search.
9508  */
9509 static int
9510 findComments(Archive *fout, Oid classoid, Oid objoid,
9511                          CommentItem **items)
9512 {
9513         /* static storage for table of comments */
9514         static CommentItem *comments = NULL;
9515         static int      ncomments = -1;
9516
9517         CommentItem *middle = NULL;
9518         CommentItem *low;
9519         CommentItem *high;
9520         int                     nmatch;
9521
9522         /* Get comments if we didn't already */
9523         if (ncomments < 0)
9524                 ncomments = collectComments(fout, &comments);
9525
9526         /*
9527          * Do binary search to find some item matching the object.
9528          */
9529         low = &comments[0];
9530         high = &comments[ncomments - 1];
9531         while (low <= high)
9532         {
9533                 middle = low + (high - low) / 2;
9534
9535                 if (classoid < middle->classoid)
9536                         high = middle - 1;
9537                 else if (classoid > middle->classoid)
9538                         low = middle + 1;
9539                 else if (objoid < middle->objoid)
9540                         high = middle - 1;
9541                 else if (objoid > middle->objoid)
9542                         low = middle + 1;
9543                 else
9544                         break;                          /* found a match */
9545         }
9546
9547         if (low > high)                         /* no matches */
9548         {
9549                 *items = NULL;
9550                 return 0;
9551         }
9552
9553         /*
9554          * Now determine how many items match the object.  The search loop
9555          * invariant still holds: only items between low and high inclusive could
9556          * match.
9557          */
9558         nmatch = 1;
9559         while (middle > low)
9560         {
9561                 if (classoid != middle[-1].classoid ||
9562                         objoid != middle[-1].objoid)
9563                         break;
9564                 middle--;
9565                 nmatch++;
9566         }
9567
9568         *items = middle;
9569
9570         middle += nmatch;
9571         while (middle <= high)
9572         {
9573                 if (classoid != middle->classoid ||
9574                         objoid != middle->objoid)
9575                         break;
9576                 middle++;
9577                 nmatch++;
9578         }
9579
9580         return nmatch;
9581 }
9582
9583 /*
9584  * collectComments --
9585  *
9586  * Construct a table of all comments available for database objects.
9587  * We used to do per-object queries for the comments, but it's much faster
9588  * to pull them all over at once, and on most databases the memory cost
9589  * isn't high.
9590  *
9591  * The table is sorted by classoid/objid/objsubid for speed in lookup.
9592  */
9593 static int
9594 collectComments(Archive *fout, CommentItem **items)
9595 {
9596         PGresult   *res;
9597         PQExpBuffer query;
9598         int                     i_description;
9599         int                     i_classoid;
9600         int                     i_objoid;
9601         int                     i_objsubid;
9602         int                     ntups;
9603         int                     i;
9604         CommentItem *comments;
9605
9606         query = createPQExpBuffer();
9607
9608         appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
9609                                                  "FROM pg_catalog.pg_description "
9610                                                  "ORDER BY classoid, objoid, objsubid");
9611
9612         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9613
9614         /* Construct lookup table containing OIDs in numeric form */
9615
9616         i_description = PQfnumber(res, "description");
9617         i_classoid = PQfnumber(res, "classoid");
9618         i_objoid = PQfnumber(res, "objoid");
9619         i_objsubid = PQfnumber(res, "objsubid");
9620
9621         ntups = PQntuples(res);
9622
9623         comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
9624
9625         for (i = 0; i < ntups; i++)
9626         {
9627                 comments[i].descr = PQgetvalue(res, i, i_description);
9628                 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
9629                 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
9630                 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
9631         }
9632
9633         /* Do NOT free the PGresult since we are keeping pointers into it */
9634         destroyPQExpBuffer(query);
9635
9636         *items = comments;
9637         return ntups;
9638 }
9639
9640 /*
9641  * dumpDumpableObject
9642  *
9643  * This routine and its subsidiaries are responsible for creating
9644  * ArchiveEntries (TOC objects) for each object to be dumped.
9645  */
9646 static void
9647 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
9648 {
9649         switch (dobj->objType)
9650         {
9651                 case DO_NAMESPACE:
9652                         dumpNamespace(fout, (NamespaceInfo *) dobj);
9653                         break;
9654                 case DO_EXTENSION:
9655                         dumpExtension(fout, (ExtensionInfo *) dobj);
9656                         break;
9657                 case DO_TYPE:
9658                         dumpType(fout, (TypeInfo *) dobj);
9659                         break;
9660                 case DO_SHELL_TYPE:
9661                         dumpShellType(fout, (ShellTypeInfo *) dobj);
9662                         break;
9663                 case DO_FUNC:
9664                         dumpFunc(fout, (FuncInfo *) dobj);
9665                         break;
9666                 case DO_AGG:
9667                         dumpAgg(fout, (AggInfo *) dobj);
9668                         break;
9669                 case DO_OPERATOR:
9670                         dumpOpr(fout, (OprInfo *) dobj);
9671                         break;
9672                 case DO_ACCESS_METHOD:
9673                         dumpAccessMethod(fout, (AccessMethodInfo *) dobj);
9674                         break;
9675                 case DO_OPCLASS:
9676                         dumpOpclass(fout, (OpclassInfo *) dobj);
9677                         break;
9678                 case DO_OPFAMILY:
9679                         dumpOpfamily(fout, (OpfamilyInfo *) dobj);
9680                         break;
9681                 case DO_COLLATION:
9682                         dumpCollation(fout, (CollInfo *) dobj);
9683                         break;
9684                 case DO_CONVERSION:
9685                         dumpConversion(fout, (ConvInfo *) dobj);
9686                         break;
9687                 case DO_TABLE:
9688                         dumpTable(fout, (TableInfo *) dobj);
9689                         break;
9690                 case DO_ATTRDEF:
9691                         dumpAttrDef(fout, (AttrDefInfo *) dobj);
9692                         break;
9693                 case DO_INDEX:
9694                         dumpIndex(fout, (IndxInfo *) dobj);
9695                         break;
9696                 case DO_INDEX_ATTACH:
9697                         dumpIndexAttach(fout, (IndexAttachInfo *) dobj);
9698                         break;
9699                 case DO_STATSEXT:
9700                         dumpStatisticsExt(fout, (StatsExtInfo *) dobj);
9701                         break;
9702                 case DO_REFRESH_MATVIEW:
9703                         refreshMatViewData(fout, (TableDataInfo *) dobj);
9704                         break;
9705                 case DO_RULE:
9706                         dumpRule(fout, (RuleInfo *) dobj);
9707                         break;
9708                 case DO_TRIGGER:
9709                         dumpTrigger(fout, (TriggerInfo *) dobj);
9710                         break;
9711                 case DO_EVENT_TRIGGER:
9712                         dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
9713                         break;
9714                 case DO_CONSTRAINT:
9715                         dumpConstraint(fout, (ConstraintInfo *) dobj);
9716                         break;
9717                 case DO_FK_CONSTRAINT:
9718                         dumpConstraint(fout, (ConstraintInfo *) dobj);
9719                         break;
9720                 case DO_PROCLANG:
9721                         dumpProcLang(fout, (ProcLangInfo *) dobj);
9722                         break;
9723                 case DO_CAST:
9724                         dumpCast(fout, (CastInfo *) dobj);
9725                         break;
9726                 case DO_TRANSFORM:
9727                         dumpTransform(fout, (TransformInfo *) dobj);
9728                         break;
9729                 case DO_SEQUENCE_SET:
9730                         dumpSequenceData(fout, (TableDataInfo *) dobj);
9731                         break;
9732                 case DO_TABLE_DATA:
9733                         dumpTableData(fout, (TableDataInfo *) dobj);
9734                         break;
9735                 case DO_DUMMY_TYPE:
9736                         /* table rowtypes and array types are never dumped separately */
9737                         break;
9738                 case DO_TSPARSER:
9739                         dumpTSParser(fout, (TSParserInfo *) dobj);
9740                         break;
9741                 case DO_TSDICT:
9742                         dumpTSDictionary(fout, (TSDictInfo *) dobj);
9743                         break;
9744                 case DO_TSTEMPLATE:
9745                         dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
9746                         break;
9747                 case DO_TSCONFIG:
9748                         dumpTSConfig(fout, (TSConfigInfo *) dobj);
9749                         break;
9750                 case DO_FDW:
9751                         dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
9752                         break;
9753                 case DO_FOREIGN_SERVER:
9754                         dumpForeignServer(fout, (ForeignServerInfo *) dobj);
9755                         break;
9756                 case DO_DEFAULT_ACL:
9757                         dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
9758                         break;
9759                 case DO_BLOB:
9760                         dumpBlob(fout, (BlobInfo *) dobj);
9761                         break;
9762                 case DO_BLOB_DATA:
9763                         if (dobj->dump & DUMP_COMPONENT_DATA)
9764                         {
9765                                 TocEntry   *te;
9766
9767                                 te = ArchiveEntry(fout, dobj->catId, dobj->dumpId,
9768                                                                   ARCHIVE_OPTS(.tag = dobj->name,
9769                                                                                            .description = "BLOBS",
9770                                                                                            .section = SECTION_DATA,
9771                                                                                            .dumpFn = dumpBlobs));
9772
9773                                 /*
9774                                  * Set the TocEntry's dataLength in case we are doing a
9775                                  * parallel dump and want to order dump jobs by table size.
9776                                  * (We need some size estimate for every TocEntry with a
9777                                  * DataDumper function.)  We don't currently have any cheap
9778                                  * way to estimate the size of blobs, but it doesn't matter;
9779                                  * let's just set the size to a large value so parallel dumps
9780                                  * will launch this job first.  If there's lots of blobs, we
9781                                  * win, and if there aren't, we don't lose much.  (If you want
9782                                  * to improve on this, really what you should be thinking
9783                                  * about is allowing blob dumping to be parallelized, not just
9784                                  * getting a smarter estimate for the single TOC entry.)
9785                                  */
9786                                 te->dataLength = MaxBlockNumber;
9787                         }
9788                         break;
9789                 case DO_POLICY:
9790                         dumpPolicy(fout, (PolicyInfo *) dobj);
9791                         break;
9792                 case DO_PUBLICATION:
9793                         dumpPublication(fout, (PublicationInfo *) dobj);
9794                         break;
9795                 case DO_PUBLICATION_REL:
9796                         dumpPublicationTable(fout, (PublicationRelInfo *) dobj);
9797                         break;
9798                 case DO_SUBSCRIPTION:
9799                         dumpSubscription(fout, (SubscriptionInfo *) dobj);
9800                         break;
9801                 case DO_PRE_DATA_BOUNDARY:
9802                 case DO_POST_DATA_BOUNDARY:
9803                         /* never dumped, nothing to do */
9804                         break;
9805         }
9806 }
9807
9808 /*
9809  * dumpNamespace
9810  *        writes out to fout the queries to recreate a user-defined namespace
9811  */
9812 static void
9813 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
9814 {
9815         DumpOptions *dopt = fout->dopt;
9816         PQExpBuffer q;
9817         PQExpBuffer delq;
9818         char       *qnspname;
9819
9820         /* Skip if not to be dumped */
9821         if (!nspinfo->dobj.dump || dopt->dataOnly)
9822                 return;
9823
9824         q = createPQExpBuffer();
9825         delq = createPQExpBuffer();
9826
9827         qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
9828
9829         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
9830
9831         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
9832
9833         if (dopt->binary_upgrade)
9834                 binary_upgrade_extension_member(q, &nspinfo->dobj,
9835                                                                                 "SCHEMA", qnspname, NULL);
9836
9837         if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
9838                 ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
9839                                          ARCHIVE_OPTS(.tag = nspinfo->dobj.name,
9840                                                                   .owner = nspinfo->rolname,
9841                                                                   .description = "SCHEMA",
9842                                                                   .section = SECTION_PRE_DATA,
9843                                                                   .createStmt = q->data,
9844                                                                   .dropStmt = delq->data));
9845
9846         /* Dump Schema Comments and Security Labels */
9847         if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
9848                 dumpComment(fout, "SCHEMA", qnspname,
9849                                         NULL, nspinfo->rolname,
9850                                         nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
9851
9852         if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
9853                 dumpSecLabel(fout, "SCHEMA", qnspname,
9854                                          NULL, nspinfo->rolname,
9855                                          nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
9856
9857         if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
9858                 dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
9859                                 qnspname, NULL, NULL,
9860                                 nspinfo->rolname, nspinfo->nspacl, nspinfo->rnspacl,
9861                                 nspinfo->initnspacl, nspinfo->initrnspacl);
9862
9863         free(qnspname);
9864
9865         destroyPQExpBuffer(q);
9866         destroyPQExpBuffer(delq);
9867 }
9868
9869 /*
9870  * dumpExtension
9871  *        writes out to fout the queries to recreate an extension
9872  */
9873 static void
9874 dumpExtension(Archive *fout, ExtensionInfo *extinfo)
9875 {
9876         DumpOptions *dopt = fout->dopt;
9877         PQExpBuffer q;
9878         PQExpBuffer delq;
9879         char       *qextname;
9880
9881         /* Skip if not to be dumped */
9882         if (!extinfo->dobj.dump || dopt->dataOnly)
9883                 return;
9884
9885         q = createPQExpBuffer();
9886         delq = createPQExpBuffer();
9887
9888         qextname = pg_strdup(fmtId(extinfo->dobj.name));
9889
9890         appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
9891
9892         if (!dopt->binary_upgrade)
9893         {
9894                 /*
9895                  * In a regular dump, we simply create the extension, intentionally
9896                  * not specifying a version, so that the destination installation's
9897                  * default version is used.
9898                  *
9899                  * Use of IF NOT EXISTS here is unlike our behavior for other object
9900                  * types; but there are various scenarios in which it's convenient to
9901                  * manually create the desired extension before restoring, so we
9902                  * prefer to allow it to exist already.
9903                  */
9904                 appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
9905                                                   qextname, fmtId(extinfo->namespace));
9906         }
9907         else
9908         {
9909                 /*
9910                  * In binary-upgrade mode, it's critical to reproduce the state of the
9911                  * database exactly, so our procedure is to create an empty extension,
9912                  * restore all the contained objects normally, and add them to the
9913                  * extension one by one.  This function performs just the first of
9914                  * those steps.  binary_upgrade_extension_member() takes care of
9915                  * adding member objects as they're created.
9916                  */
9917                 int                     i;
9918                 int                     n;
9919
9920                 appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
9921
9922                 /*
9923                  * We unconditionally create the extension, so we must drop it if it
9924                  * exists.  This could happen if the user deleted 'plpgsql' and then
9925                  * readded it, causing its oid to be greater than g_last_builtin_oid.
9926                  */
9927                 appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
9928
9929                 appendPQExpBufferStr(q,
9930                                                          "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
9931                 appendStringLiteralAH(q, extinfo->dobj.name, fout);
9932                 appendPQExpBufferStr(q, ", ");
9933                 appendStringLiteralAH(q, extinfo->namespace, fout);
9934                 appendPQExpBufferStr(q, ", ");
9935                 appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
9936                 appendStringLiteralAH(q, extinfo->extversion, fout);
9937                 appendPQExpBufferStr(q, ", ");
9938
9939                 /*
9940                  * Note that we're pushing extconfig (an OID array) back into
9941                  * pg_extension exactly as-is.  This is OK because pg_class OIDs are
9942                  * preserved in binary upgrade.
9943                  */
9944                 if (strlen(extinfo->extconfig) > 2)
9945                         appendStringLiteralAH(q, extinfo->extconfig, fout);
9946                 else
9947                         appendPQExpBufferStr(q, "NULL");
9948                 appendPQExpBufferStr(q, ", ");
9949                 if (strlen(extinfo->extcondition) > 2)
9950                         appendStringLiteralAH(q, extinfo->extcondition, fout);
9951                 else
9952                         appendPQExpBufferStr(q, "NULL");
9953                 appendPQExpBufferStr(q, ", ");
9954                 appendPQExpBufferStr(q, "ARRAY[");
9955                 n = 0;
9956                 for (i = 0; i < extinfo->dobj.nDeps; i++)
9957                 {
9958                         DumpableObject *extobj;
9959
9960                         extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
9961                         if (extobj && extobj->objType == DO_EXTENSION)
9962                         {
9963                                 if (n++ > 0)
9964                                         appendPQExpBufferChar(q, ',');
9965                                 appendStringLiteralAH(q, extobj->name, fout);
9966                         }
9967                 }
9968                 appendPQExpBufferStr(q, "]::pg_catalog.text[]");
9969                 appendPQExpBufferStr(q, ");\n");
9970         }
9971
9972         if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
9973                 ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
9974                                          ARCHIVE_OPTS(.tag = extinfo->dobj.name,
9975                                                                   .description = "EXTENSION",
9976                                                                   .section = SECTION_PRE_DATA,
9977                                                                   .createStmt = q->data,
9978                                                                   .dropStmt = delq->data));
9979
9980         /* Dump Extension Comments and Security Labels */
9981         if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
9982                 dumpComment(fout, "EXTENSION", qextname,
9983                                         NULL, "",
9984                                         extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
9985
9986         if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
9987                 dumpSecLabel(fout, "EXTENSION", qextname,
9988                                          NULL, "",
9989                                          extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
9990
9991         free(qextname);
9992
9993         destroyPQExpBuffer(q);
9994         destroyPQExpBuffer(delq);
9995 }
9996
9997 /*
9998  * dumpType
9999  *        writes out to fout the queries to recreate a user-defined type
10000  */
10001 static void
10002 dumpType(Archive *fout, TypeInfo *tyinfo)
10003 {
10004         DumpOptions *dopt = fout->dopt;
10005
10006         /* Skip if not to be dumped */
10007         if (!tyinfo->dobj.dump || dopt->dataOnly)
10008                 return;
10009
10010         /* Dump out in proper style */
10011         if (tyinfo->typtype == TYPTYPE_BASE)
10012                 dumpBaseType(fout, tyinfo);
10013         else if (tyinfo->typtype == TYPTYPE_DOMAIN)
10014                 dumpDomain(fout, tyinfo);
10015         else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
10016                 dumpCompositeType(fout, tyinfo);
10017         else if (tyinfo->typtype == TYPTYPE_ENUM)
10018                 dumpEnumType(fout, tyinfo);
10019         else if (tyinfo->typtype == TYPTYPE_RANGE)
10020                 dumpRangeType(fout, tyinfo);
10021         else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
10022                 dumpUndefinedType(fout, tyinfo);
10023         else
10024                 write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
10025                                   tyinfo->dobj.name);
10026 }
10027
10028 /*
10029  * dumpEnumType
10030  *        writes out to fout the queries to recreate a user-defined enum type
10031  */
10032 static void
10033 dumpEnumType(Archive *fout, TypeInfo *tyinfo)
10034 {
10035         DumpOptions *dopt = fout->dopt;
10036         PQExpBuffer q = createPQExpBuffer();
10037         PQExpBuffer delq = createPQExpBuffer();
10038         PQExpBuffer query = createPQExpBuffer();
10039         PGresult   *res;
10040         int                     num,
10041                                 i;
10042         Oid                     enum_oid;
10043         char       *qtypname;
10044         char       *qualtypname;
10045         char       *label;
10046
10047         if (fout->remoteVersion >= 90100)
10048                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
10049                                                   "FROM pg_catalog.pg_enum "
10050                                                   "WHERE enumtypid = '%u'"
10051                                                   "ORDER BY enumsortorder",
10052                                                   tyinfo->dobj.catId.oid);
10053         else
10054                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
10055                                                   "FROM pg_catalog.pg_enum "
10056                                                   "WHERE enumtypid = '%u'"
10057                                                   "ORDER BY oid",
10058                                                   tyinfo->dobj.catId.oid);
10059
10060         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10061
10062         num = PQntuples(res);
10063
10064         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10065         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10066
10067         /*
10068          * CASCADE shouldn't be required here as for normal types since the I/O
10069          * functions are generic and do not get dropped.
10070          */
10071         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10072
10073         if (dopt->binary_upgrade)
10074                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10075                                                                                                  tyinfo->dobj.catId.oid,
10076                                                                                                  false);
10077
10078         appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
10079                                           qualtypname);
10080
10081         if (!dopt->binary_upgrade)
10082         {
10083                 /* Labels with server-assigned oids */
10084                 for (i = 0; i < num; i++)
10085                 {
10086                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
10087                         if (i > 0)
10088                                 appendPQExpBufferChar(q, ',');
10089                         appendPQExpBufferStr(q, "\n    ");
10090                         appendStringLiteralAH(q, label, fout);
10091                 }
10092         }
10093
10094         appendPQExpBufferStr(q, "\n);\n");
10095
10096         if (dopt->binary_upgrade)
10097         {
10098                 /* Labels with dump-assigned (preserved) oids */
10099                 for (i = 0; i < num; i++)
10100                 {
10101                         enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
10102                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
10103
10104                         if (i == 0)
10105                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
10106                         appendPQExpBuffer(q,
10107                                                           "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
10108                                                           enum_oid);
10109                         appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
10110                         appendStringLiteralAH(q, label, fout);
10111                         appendPQExpBufferStr(q, ";\n\n");
10112                 }
10113         }
10114
10115         if (dopt->binary_upgrade)
10116                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10117                                                                                 "TYPE", qtypname,
10118                                                                                 tyinfo->dobj.namespace->dobj.name);
10119
10120         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10121                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10122                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10123                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10124                                                                   .owner = tyinfo->rolname,
10125                                                                   .description = "TYPE",
10126                                                                   .section = SECTION_PRE_DATA,
10127                                                                   .createStmt = q->data,
10128                                                                   .dropStmt = delq->data));
10129
10130         /* Dump Type Comments and Security Labels */
10131         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10132                 dumpComment(fout, "TYPE", qtypname,
10133                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10134                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10135
10136         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10137                 dumpSecLabel(fout, "TYPE", qtypname,
10138                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10139                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10140
10141         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10142                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10143                                 qtypname, NULL,
10144                                 tyinfo->dobj.namespace->dobj.name,
10145                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10146                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10147
10148         PQclear(res);
10149         destroyPQExpBuffer(q);
10150         destroyPQExpBuffer(delq);
10151         destroyPQExpBuffer(query);
10152         free(qtypname);
10153         free(qualtypname);
10154 }
10155
10156 /*
10157  * dumpRangeType
10158  *        writes out to fout the queries to recreate a user-defined range type
10159  */
10160 static void
10161 dumpRangeType(Archive *fout, TypeInfo *tyinfo)
10162 {
10163         DumpOptions *dopt = fout->dopt;
10164         PQExpBuffer q = createPQExpBuffer();
10165         PQExpBuffer delq = createPQExpBuffer();
10166         PQExpBuffer query = createPQExpBuffer();
10167         PGresult   *res;
10168         Oid                     collationOid;
10169         char       *qtypname;
10170         char       *qualtypname;
10171         char       *procname;
10172
10173         appendPQExpBuffer(query,
10174                                           "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
10175                                           "opc.opcname AS opcname, "
10176                                           "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
10177                                           "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
10178                                           "opc.opcdefault, "
10179                                           "CASE WHEN rngcollation = st.typcollation THEN 0 "
10180                                           "     ELSE rngcollation END AS collation, "
10181                                           "rngcanonical, rngsubdiff "
10182                                           "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
10183                                           "     pg_catalog.pg_opclass opc "
10184                                           "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
10185                                           "rngtypid = '%u'",
10186                                           tyinfo->dobj.catId.oid);
10187
10188         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10189
10190         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10191         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10192
10193         /*
10194          * CASCADE shouldn't be required here as for normal types since the I/O
10195          * functions are generic and do not get dropped.
10196          */
10197         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10198
10199         if (dopt->binary_upgrade)
10200                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10201                                                                                                  tyinfo->dobj.catId.oid,
10202                                                                                                  false);
10203
10204         appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
10205                                           qualtypname);
10206
10207         appendPQExpBuffer(q, "\n    subtype = %s",
10208                                           PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
10209
10210         /* print subtype_opclass only if not default for subtype */
10211         if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
10212         {
10213                 char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
10214                 char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
10215
10216                 appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
10217                                                   fmtId(nspname));
10218                 appendPQExpBufferStr(q, fmtId(opcname));
10219         }
10220
10221         collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
10222         if (OidIsValid(collationOid))
10223         {
10224                 CollInfo   *coll = findCollationByOid(collationOid);
10225
10226                 if (coll)
10227                         appendPQExpBuffer(q, ",\n    collation = %s",
10228                                                           fmtQualifiedDumpable(coll));
10229         }
10230
10231         procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
10232         if (strcmp(procname, "-") != 0)
10233                 appendPQExpBuffer(q, ",\n    canonical = %s", procname);
10234
10235         procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
10236         if (strcmp(procname, "-") != 0)
10237                 appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
10238
10239         appendPQExpBufferStr(q, "\n);\n");
10240
10241         if (dopt->binary_upgrade)
10242                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10243                                                                                 "TYPE", qtypname,
10244                                                                                 tyinfo->dobj.namespace->dobj.name);
10245
10246         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10247                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10248                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10249                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10250                                                                   .owner = tyinfo->rolname,
10251                                                                   .description = "TYPE",
10252                                                                   .section = SECTION_PRE_DATA,
10253                                                                   .createStmt = q->data,
10254                                                                   .dropStmt = delq->data));
10255
10256         /* Dump Type Comments and Security Labels */
10257         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10258                 dumpComment(fout, "TYPE", qtypname,
10259                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10260                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10261
10262         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10263                 dumpSecLabel(fout, "TYPE", qtypname,
10264                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10265                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10266
10267         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10268                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10269                                 qtypname, NULL,
10270                                 tyinfo->dobj.namespace->dobj.name,
10271                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10272                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10273
10274         PQclear(res);
10275         destroyPQExpBuffer(q);
10276         destroyPQExpBuffer(delq);
10277         destroyPQExpBuffer(query);
10278         free(qtypname);
10279         free(qualtypname);
10280 }
10281
10282 /*
10283  * dumpUndefinedType
10284  *        writes out to fout the queries to recreate a !typisdefined type
10285  *
10286  * This is a shell type, but we use different terminology to distinguish
10287  * this case from where we have to emit a shell type definition to break
10288  * circular dependencies.  An undefined type shouldn't ever have anything
10289  * depending on it.
10290  */
10291 static void
10292 dumpUndefinedType(Archive *fout, TypeInfo *tyinfo)
10293 {
10294         DumpOptions *dopt = fout->dopt;
10295         PQExpBuffer q = createPQExpBuffer();
10296         PQExpBuffer delq = createPQExpBuffer();
10297         char       *qtypname;
10298         char       *qualtypname;
10299
10300         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10301         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10302
10303         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10304
10305         if (dopt->binary_upgrade)
10306                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10307                                                                                                  tyinfo->dobj.catId.oid,
10308                                                                                                  false);
10309
10310         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
10311                                           qualtypname);
10312
10313         if (dopt->binary_upgrade)
10314                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10315                                                                                 "TYPE", qtypname,
10316                                                                                 tyinfo->dobj.namespace->dobj.name);
10317
10318         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10319                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10320                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10321                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10322                                                                   .owner = tyinfo->rolname,
10323                                                                   .description = "TYPE",
10324                                                                   .section = SECTION_PRE_DATA,
10325                                                                   .createStmt = q->data,
10326                                                                   .dropStmt = delq->data));
10327
10328         /* Dump Type Comments and Security Labels */
10329         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10330                 dumpComment(fout, "TYPE", qtypname,
10331                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10332                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10333
10334         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10335                 dumpSecLabel(fout, "TYPE", qtypname,
10336                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10337                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10338
10339         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10340                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10341                                 qtypname, NULL,
10342                                 tyinfo->dobj.namespace->dobj.name,
10343                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10344                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10345
10346         destroyPQExpBuffer(q);
10347         destroyPQExpBuffer(delq);
10348         free(qtypname);
10349         free(qualtypname);
10350 }
10351
10352 /*
10353  * dumpBaseType
10354  *        writes out to fout the queries to recreate a user-defined base type
10355  */
10356 static void
10357 dumpBaseType(Archive *fout, TypeInfo *tyinfo)
10358 {
10359         DumpOptions *dopt = fout->dopt;
10360         PQExpBuffer q = createPQExpBuffer();
10361         PQExpBuffer delq = createPQExpBuffer();
10362         PQExpBuffer query = createPQExpBuffer();
10363         PGresult   *res;
10364         char       *qtypname;
10365         char       *qualtypname;
10366         char       *typlen;
10367         char       *typinput;
10368         char       *typoutput;
10369         char       *typreceive;
10370         char       *typsend;
10371         char       *typmodin;
10372         char       *typmodout;
10373         char       *typanalyze;
10374         Oid                     typreceiveoid;
10375         Oid                     typsendoid;
10376         Oid                     typmodinoid;
10377         Oid                     typmodoutoid;
10378         Oid                     typanalyzeoid;
10379         char       *typcategory;
10380         char       *typispreferred;
10381         char       *typdelim;
10382         char       *typbyval;
10383         char       *typalign;
10384         char       *typstorage;
10385         char       *typcollatable;
10386         char       *typdefault;
10387         bool            typdefault_is_literal = false;
10388
10389         /* Fetch type-specific details */
10390         if (fout->remoteVersion >= 90100)
10391         {
10392                 appendPQExpBuffer(query, "SELECT typlen, "
10393                                                   "typinput, typoutput, typreceive, typsend, "
10394                                                   "typmodin, typmodout, typanalyze, "
10395                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10396                                                   "typsend::pg_catalog.oid AS typsendoid, "
10397                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10398                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10399                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10400                                                   "typcategory, typispreferred, "
10401                                                   "typdelim, typbyval, typalign, typstorage, "
10402                                                   "(typcollation <> 0) AS typcollatable, "
10403                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
10404                                                   "FROM pg_catalog.pg_type "
10405                                                   "WHERE oid = '%u'::pg_catalog.oid",
10406                                                   tyinfo->dobj.catId.oid);
10407         }
10408         else if (fout->remoteVersion >= 80400)
10409         {
10410                 appendPQExpBuffer(query, "SELECT typlen, "
10411                                                   "typinput, typoutput, typreceive, typsend, "
10412                                                   "typmodin, typmodout, typanalyze, "
10413                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10414                                                   "typsend::pg_catalog.oid AS typsendoid, "
10415                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10416                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10417                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10418                                                   "typcategory, typispreferred, "
10419                                                   "typdelim, typbyval, typalign, typstorage, "
10420                                                   "false AS typcollatable, "
10421                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
10422                                                   "FROM pg_catalog.pg_type "
10423                                                   "WHERE oid = '%u'::pg_catalog.oid",
10424                                                   tyinfo->dobj.catId.oid);
10425         }
10426         else if (fout->remoteVersion >= 80300)
10427         {
10428                 /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
10429                 appendPQExpBuffer(query, "SELECT typlen, "
10430                                                   "typinput, typoutput, typreceive, typsend, "
10431                                                   "typmodin, typmodout, typanalyze, "
10432                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10433                                                   "typsend::pg_catalog.oid AS typsendoid, "
10434                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
10435                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
10436                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10437                                                   "'U' AS typcategory, false AS typispreferred, "
10438                                                   "typdelim, typbyval, typalign, typstorage, "
10439                                                   "false AS typcollatable, "
10440                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10441                                                   "FROM pg_catalog.pg_type "
10442                                                   "WHERE oid = '%u'::pg_catalog.oid",
10443                                                   tyinfo->dobj.catId.oid);
10444         }
10445         else
10446         {
10447                 appendPQExpBuffer(query, "SELECT typlen, "
10448                                                   "typinput, typoutput, typreceive, typsend, "
10449                                                   "'-' AS typmodin, '-' AS typmodout, "
10450                                                   "typanalyze, "
10451                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
10452                                                   "typsend::pg_catalog.oid AS typsendoid, "
10453                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
10454                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10455                                                   "'U' AS typcategory, false AS typispreferred, "
10456                                                   "typdelim, typbyval, typalign, typstorage, "
10457                                                   "false AS typcollatable, "
10458                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10459                                                   "FROM pg_catalog.pg_type "
10460                                                   "WHERE oid = '%u'::pg_catalog.oid",
10461                                                   tyinfo->dobj.catId.oid);
10462         }
10463
10464         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10465
10466         typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
10467         typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
10468         typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
10469         typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
10470         typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
10471         typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
10472         typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
10473         typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
10474         typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
10475         typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
10476         typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
10477         typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
10478         typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
10479         typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
10480         typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
10481         typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
10482         typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
10483         typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
10484         typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
10485         typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
10486         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
10487                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
10488         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
10489         {
10490                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
10491                 typdefault_is_literal = true;   /* it needs quotes */
10492         }
10493         else
10494                 typdefault = NULL;
10495
10496         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10497         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10498
10499         /*
10500          * The reason we include CASCADE is that the circular dependency between
10501          * the type and its I/O functions makes it impossible to drop the type any
10502          * other way.
10503          */
10504         appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
10505
10506         /*
10507          * We might already have a shell type, but setting pg_type_oid is
10508          * harmless, and in any case we'd better set the array type OID.
10509          */
10510         if (dopt->binary_upgrade)
10511                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10512                                                                                                  tyinfo->dobj.catId.oid,
10513                                                                                                  false);
10514
10515         appendPQExpBuffer(q,
10516                                           "CREATE TYPE %s (\n"
10517                                           "    INTERNALLENGTH = %s",
10518                                           qualtypname,
10519                                           (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
10520
10521         /* regproc result is sufficiently quoted already */
10522         appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
10523         appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
10524         if (OidIsValid(typreceiveoid))
10525                 appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
10526         if (OidIsValid(typsendoid))
10527                 appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
10528         if (OidIsValid(typmodinoid))
10529                 appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
10530         if (OidIsValid(typmodoutoid))
10531                 appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
10532         if (OidIsValid(typanalyzeoid))
10533                 appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
10534
10535         if (strcmp(typcollatable, "t") == 0)
10536                 appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
10537
10538         if (typdefault != NULL)
10539         {
10540                 appendPQExpBufferStr(q, ",\n    DEFAULT = ");
10541                 if (typdefault_is_literal)
10542                         appendStringLiteralAH(q, typdefault, fout);
10543                 else
10544                         appendPQExpBufferStr(q, typdefault);
10545         }
10546
10547         if (OidIsValid(tyinfo->typelem))
10548         {
10549                 char       *elemType;
10550
10551                 elemType = getFormattedTypeName(fout, tyinfo->typelem, zeroAsOpaque);
10552                 appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
10553                 free(elemType);
10554         }
10555
10556         if (strcmp(typcategory, "U") != 0)
10557         {
10558                 appendPQExpBufferStr(q, ",\n    CATEGORY = ");
10559                 appendStringLiteralAH(q, typcategory, fout);
10560         }
10561
10562         if (strcmp(typispreferred, "t") == 0)
10563                 appendPQExpBufferStr(q, ",\n    PREFERRED = true");
10564
10565         if (typdelim && strcmp(typdelim, ",") != 0)
10566         {
10567                 appendPQExpBufferStr(q, ",\n    DELIMITER = ");
10568                 appendStringLiteralAH(q, typdelim, fout);
10569         }
10570
10571         if (strcmp(typalign, "c") == 0)
10572                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
10573         else if (strcmp(typalign, "s") == 0)
10574                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
10575         else if (strcmp(typalign, "i") == 0)
10576                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
10577         else if (strcmp(typalign, "d") == 0)
10578                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
10579
10580         if (strcmp(typstorage, "p") == 0)
10581                 appendPQExpBufferStr(q, ",\n    STORAGE = plain");
10582         else if (strcmp(typstorage, "e") == 0)
10583                 appendPQExpBufferStr(q, ",\n    STORAGE = external");
10584         else if (strcmp(typstorage, "x") == 0)
10585                 appendPQExpBufferStr(q, ",\n    STORAGE = extended");
10586         else if (strcmp(typstorage, "m") == 0)
10587                 appendPQExpBufferStr(q, ",\n    STORAGE = main");
10588
10589         if (strcmp(typbyval, "t") == 0)
10590                 appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
10591
10592         appendPQExpBufferStr(q, "\n);\n");
10593
10594         if (dopt->binary_upgrade)
10595                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10596                                                                                 "TYPE", qtypname,
10597                                                                                 tyinfo->dobj.namespace->dobj.name);
10598
10599         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10600                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10601                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10602                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10603                                                                   .owner = tyinfo->rolname,
10604                                                                   .description = "TYPE",
10605                                                                   .section = SECTION_PRE_DATA,
10606                                                                   .createStmt = q->data,
10607                                                                   .dropStmt = delq->data));
10608
10609         /* Dump Type Comments and Security Labels */
10610         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10611                 dumpComment(fout, "TYPE", qtypname,
10612                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10613                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10614
10615         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10616                 dumpSecLabel(fout, "TYPE", qtypname,
10617                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10618                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10619
10620         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10621                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10622                                 qtypname, NULL,
10623                                 tyinfo->dobj.namespace->dobj.name,
10624                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10625                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10626
10627         PQclear(res);
10628         destroyPQExpBuffer(q);
10629         destroyPQExpBuffer(delq);
10630         destroyPQExpBuffer(query);
10631         free(qtypname);
10632         free(qualtypname);
10633 }
10634
10635 /*
10636  * dumpDomain
10637  *        writes out to fout the queries to recreate a user-defined domain
10638  */
10639 static void
10640 dumpDomain(Archive *fout, TypeInfo *tyinfo)
10641 {
10642         DumpOptions *dopt = fout->dopt;
10643         PQExpBuffer q = createPQExpBuffer();
10644         PQExpBuffer delq = createPQExpBuffer();
10645         PQExpBuffer query = createPQExpBuffer();
10646         PGresult   *res;
10647         int                     i;
10648         char       *qtypname;
10649         char       *qualtypname;
10650         char       *typnotnull;
10651         char       *typdefn;
10652         char       *typdefault;
10653         Oid                     typcollation;
10654         bool            typdefault_is_literal = false;
10655
10656         /* Fetch domain specific details */
10657         if (fout->remoteVersion >= 90100)
10658         {
10659                 /* typcollation is new in 9.1 */
10660                 appendPQExpBuffer(query, "SELECT t.typnotnull, "
10661                                                   "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
10662                                                   "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
10663                                                   "t.typdefault, "
10664                                                   "CASE WHEN t.typcollation <> u.typcollation "
10665                                                   "THEN t.typcollation ELSE 0 END AS typcollation "
10666                                                   "FROM pg_catalog.pg_type t "
10667                                                   "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
10668                                                   "WHERE t.oid = '%u'::pg_catalog.oid",
10669                                                   tyinfo->dobj.catId.oid);
10670         }
10671         else
10672         {
10673                 appendPQExpBuffer(query, "SELECT typnotnull, "
10674                                                   "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
10675                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
10676                                                   "typdefault, 0 AS typcollation "
10677                                                   "FROM pg_catalog.pg_type "
10678                                                   "WHERE oid = '%u'::pg_catalog.oid",
10679                                                   tyinfo->dobj.catId.oid);
10680         }
10681
10682         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10683
10684         typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
10685         typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
10686         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
10687                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
10688         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
10689         {
10690                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
10691                 typdefault_is_literal = true;   /* it needs quotes */
10692         }
10693         else
10694                 typdefault = NULL;
10695         typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
10696
10697         if (dopt->binary_upgrade)
10698                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10699                                                                                                  tyinfo->dobj.catId.oid,
10700                                                                                                  true); /* force array type */
10701
10702         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10703         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10704
10705         appendPQExpBuffer(q,
10706                                           "CREATE DOMAIN %s AS %s",
10707                                           qualtypname,
10708                                           typdefn);
10709
10710         /* Print collation only if different from base type's collation */
10711         if (OidIsValid(typcollation))
10712         {
10713                 CollInfo   *coll;
10714
10715                 coll = findCollationByOid(typcollation);
10716                 if (coll)
10717                         appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
10718         }
10719
10720         if (typnotnull[0] == 't')
10721                 appendPQExpBufferStr(q, " NOT NULL");
10722
10723         if (typdefault != NULL)
10724         {
10725                 appendPQExpBufferStr(q, " DEFAULT ");
10726                 if (typdefault_is_literal)
10727                         appendStringLiteralAH(q, typdefault, fout);
10728                 else
10729                         appendPQExpBufferStr(q, typdefault);
10730         }
10731
10732         PQclear(res);
10733
10734         /*
10735          * Add any CHECK constraints for the domain
10736          */
10737         for (i = 0; i < tyinfo->nDomChecks; i++)
10738         {
10739                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
10740
10741                 if (!domcheck->separate)
10742                         appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
10743                                                           fmtId(domcheck->dobj.name), domcheck->condef);
10744         }
10745
10746         appendPQExpBufferStr(q, ";\n");
10747
10748         appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
10749
10750         if (dopt->binary_upgrade)
10751                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10752                                                                                 "DOMAIN", qtypname,
10753                                                                                 tyinfo->dobj.namespace->dobj.name);
10754
10755         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10756                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10757                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10758                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10759                                                                   .owner = tyinfo->rolname,
10760                                                                   .description = "DOMAIN",
10761                                                                   .section = SECTION_PRE_DATA,
10762                                                                   .createStmt = q->data,
10763                                                                   .dropStmt = delq->data));
10764
10765         /* Dump Domain Comments and Security Labels */
10766         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10767                 dumpComment(fout, "DOMAIN", qtypname,
10768                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10769                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10770
10771         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10772                 dumpSecLabel(fout, "DOMAIN", qtypname,
10773                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10774                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10775
10776         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10777                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
10778                                 qtypname, NULL,
10779                                 tyinfo->dobj.namespace->dobj.name,
10780                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10781                                 tyinfo->inittypacl, tyinfo->initrtypacl);
10782
10783         /* Dump any per-constraint comments */
10784         for (i = 0; i < tyinfo->nDomChecks; i++)
10785         {
10786                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
10787                 PQExpBuffer conprefix = createPQExpBuffer();
10788
10789                 appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
10790                                                   fmtId(domcheck->dobj.name));
10791
10792                 if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10793                         dumpComment(fout, conprefix->data, qtypname,
10794                                                 tyinfo->dobj.namespace->dobj.name,
10795                                                 tyinfo->rolname,
10796                                                 domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
10797
10798                 destroyPQExpBuffer(conprefix);
10799         }
10800
10801         destroyPQExpBuffer(q);
10802         destroyPQExpBuffer(delq);
10803         destroyPQExpBuffer(query);
10804         free(qtypname);
10805         free(qualtypname);
10806 }
10807
10808 /*
10809  * dumpCompositeType
10810  *        writes out to fout the queries to recreate a user-defined stand-alone
10811  *        composite type
10812  */
10813 static void
10814 dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
10815 {
10816         DumpOptions *dopt = fout->dopt;
10817         PQExpBuffer q = createPQExpBuffer();
10818         PQExpBuffer dropped = createPQExpBuffer();
10819         PQExpBuffer delq = createPQExpBuffer();
10820         PQExpBuffer query = createPQExpBuffer();
10821         PGresult   *res;
10822         char       *qtypname;
10823         char       *qualtypname;
10824         int                     ntups;
10825         int                     i_attname;
10826         int                     i_atttypdefn;
10827         int                     i_attlen;
10828         int                     i_attalign;
10829         int                     i_attisdropped;
10830         int                     i_attcollation;
10831         int                     i;
10832         int                     actual_atts;
10833
10834         /* Fetch type specific details */
10835         if (fout->remoteVersion >= 90100)
10836         {
10837                 /*
10838                  * attcollation is new in 9.1.  Since we only want to dump COLLATE
10839                  * clauses for attributes whose collation is different from their
10840                  * type's default, we use a CASE here to suppress uninteresting
10841                  * attcollations cheaply.  atttypid will be 0 for dropped columns;
10842                  * collation does not matter for those.
10843                  */
10844                 appendPQExpBuffer(query, "SELECT a.attname, "
10845                                                   "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
10846                                                   "a.attlen, a.attalign, a.attisdropped, "
10847                                                   "CASE WHEN a.attcollation <> at.typcollation "
10848                                                   "THEN a.attcollation ELSE 0 END AS attcollation "
10849                                                   "FROM pg_catalog.pg_type ct "
10850                                                   "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
10851                                                   "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
10852                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
10853                                                   "ORDER BY a.attnum ",
10854                                                   tyinfo->dobj.catId.oid);
10855         }
10856         else
10857         {
10858                 /*
10859                  * Since ALTER TYPE could not drop columns until 9.1, attisdropped
10860                  * should always be false.
10861                  */
10862                 appendPQExpBuffer(query, "SELECT a.attname, "
10863                                                   "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
10864                                                   "a.attlen, a.attalign, a.attisdropped, "
10865                                                   "0 AS attcollation "
10866                                                   "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
10867                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
10868                                                   "AND a.attrelid = ct.typrelid "
10869                                                   "ORDER BY a.attnum ",
10870                                                   tyinfo->dobj.catId.oid);
10871         }
10872
10873         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10874
10875         ntups = PQntuples(res);
10876
10877         i_attname = PQfnumber(res, "attname");
10878         i_atttypdefn = PQfnumber(res, "atttypdefn");
10879         i_attlen = PQfnumber(res, "attlen");
10880         i_attalign = PQfnumber(res, "attalign");
10881         i_attisdropped = PQfnumber(res, "attisdropped");
10882         i_attcollation = PQfnumber(res, "attcollation");
10883
10884         if (dopt->binary_upgrade)
10885         {
10886                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
10887                                                                                                  tyinfo->dobj.catId.oid,
10888                                                                                                  false);
10889                 binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid, false);
10890         }
10891
10892         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10893         qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10894
10895         appendPQExpBuffer(q, "CREATE TYPE %s AS (",
10896                                           qualtypname);
10897
10898         actual_atts = 0;
10899         for (i = 0; i < ntups; i++)
10900         {
10901                 char       *attname;
10902                 char       *atttypdefn;
10903                 char       *attlen;
10904                 char       *attalign;
10905                 bool            attisdropped;
10906                 Oid                     attcollation;
10907
10908                 attname = PQgetvalue(res, i, i_attname);
10909                 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
10910                 attlen = PQgetvalue(res, i, i_attlen);
10911                 attalign = PQgetvalue(res, i, i_attalign);
10912                 attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
10913                 attcollation = atooid(PQgetvalue(res, i, i_attcollation));
10914
10915                 if (attisdropped && !dopt->binary_upgrade)
10916                         continue;
10917
10918                 /* Format properly if not first attr */
10919                 if (actual_atts++ > 0)
10920                         appendPQExpBufferChar(q, ',');
10921                 appendPQExpBufferStr(q, "\n\t");
10922
10923                 if (!attisdropped)
10924                 {
10925                         appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
10926
10927                         /* Add collation if not default for the column type */
10928                         if (OidIsValid(attcollation))
10929                         {
10930                                 CollInfo   *coll;
10931
10932                                 coll = findCollationByOid(attcollation);
10933                                 if (coll)
10934                                         appendPQExpBuffer(q, " COLLATE %s",
10935                                                                           fmtQualifiedDumpable(coll));
10936                         }
10937                 }
10938                 else
10939                 {
10940                         /*
10941                          * This is a dropped attribute and we're in binary_upgrade mode.
10942                          * Insert a placeholder for it in the CREATE TYPE command, and set
10943                          * length and alignment with direct UPDATE to the catalogs
10944                          * afterwards. See similar code in dumpTableSchema().
10945                          */
10946                         appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
10947
10948                         /* stash separately for insertion after the CREATE TYPE */
10949                         appendPQExpBufferStr(dropped,
10950                                                                  "\n-- For binary upgrade, recreate dropped column.\n");
10951                         appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
10952                                                           "SET attlen = %s, "
10953                                                           "attalign = '%s', attbyval = false\n"
10954                                                           "WHERE attname = ", attlen, attalign);
10955                         appendStringLiteralAH(dropped, attname, fout);
10956                         appendPQExpBufferStr(dropped, "\n  AND attrelid = ");
10957                         appendStringLiteralAH(dropped, qualtypname, fout);
10958                         appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
10959
10960                         appendPQExpBuffer(dropped, "ALTER TYPE %s ",
10961                                                           qualtypname);
10962                         appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
10963                                                           fmtId(attname));
10964                 }
10965         }
10966         appendPQExpBufferStr(q, "\n);\n");
10967         appendPQExpBufferStr(q, dropped->data);
10968
10969         appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10970
10971         if (dopt->binary_upgrade)
10972                 binary_upgrade_extension_member(q, &tyinfo->dobj,
10973                                                                                 "TYPE", qtypname,
10974                                                                                 tyinfo->dobj.namespace->dobj.name);
10975
10976         if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10977                 ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10978                                          ARCHIVE_OPTS(.tag = tyinfo->dobj.name,
10979                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
10980                                                                   .owner = tyinfo->rolname,
10981                                                                   .description = "TYPE",
10982                                                                   .section = SECTION_PRE_DATA,
10983                                                                   .createStmt = q->data,
10984                                                                   .dropStmt = delq->data));
10985
10986
10987         /* Dump Type Comments and Security Labels */
10988         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10989                 dumpComment(fout, "TYPE", qtypname,
10990                                         tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10991                                         tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10992
10993         if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10994                 dumpSecLabel(fout, "TYPE", qtypname,
10995                                          tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10996                                          tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10997
10998         if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10999                 dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
11000                                 qtypname, NULL,
11001                                 tyinfo->dobj.namespace->dobj.name,
11002                                 tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
11003                                 tyinfo->inittypacl, tyinfo->initrtypacl);
11004
11005         PQclear(res);
11006         destroyPQExpBuffer(q);
11007         destroyPQExpBuffer(dropped);
11008         destroyPQExpBuffer(delq);
11009         destroyPQExpBuffer(query);
11010         free(qtypname);
11011         free(qualtypname);
11012
11013         /* Dump any per-column comments */
11014         if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11015                 dumpCompositeTypeColComments(fout, tyinfo);
11016 }
11017
11018 /*
11019  * dumpCompositeTypeColComments
11020  *        writes out to fout the queries to recreate comments on the columns of
11021  *        a user-defined stand-alone composite type
11022  */
11023 static void
11024 dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
11025 {
11026         CommentItem *comments;
11027         int                     ncomments;
11028         PGresult   *res;
11029         PQExpBuffer query;
11030         PQExpBuffer target;
11031         Oid                     pgClassOid;
11032         int                     i;
11033         int                     ntups;
11034         int                     i_attname;
11035         int                     i_attnum;
11036
11037         /* do nothing, if --no-comments is supplied */
11038         if (fout->dopt->no_comments)
11039                 return;
11040
11041         query = createPQExpBuffer();
11042
11043         appendPQExpBuffer(query,
11044                                           "SELECT c.tableoid, a.attname, a.attnum "
11045                                           "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
11046                                           "WHERE c.oid = '%u' AND c.oid = a.attrelid "
11047                                           "  AND NOT a.attisdropped "
11048                                           "ORDER BY a.attnum ",
11049                                           tyinfo->typrelid);
11050
11051         /* Fetch column attnames */
11052         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11053
11054         ntups = PQntuples(res);
11055         if (ntups < 1)
11056         {
11057                 PQclear(res);
11058                 destroyPQExpBuffer(query);
11059                 return;
11060         }
11061
11062         pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
11063
11064         /* Search for comments associated with type's pg_class OID */
11065         ncomments = findComments(fout,
11066                                                          pgClassOid,
11067                                                          tyinfo->typrelid,
11068                                                          &comments);
11069
11070         /* If no comments exist, we're done */
11071         if (ncomments <= 0)
11072         {
11073                 PQclear(res);
11074                 destroyPQExpBuffer(query);
11075                 return;
11076         }
11077
11078         /* Build COMMENT ON statements */
11079         target = createPQExpBuffer();
11080
11081         i_attnum = PQfnumber(res, "attnum");
11082         i_attname = PQfnumber(res, "attname");
11083         while (ncomments > 0)
11084         {
11085                 const char *attname;
11086
11087                 attname = NULL;
11088                 for (i = 0; i < ntups; i++)
11089                 {
11090                         if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
11091                         {
11092                                 attname = PQgetvalue(res, i, i_attname);
11093                                 break;
11094                         }
11095                 }
11096                 if (attname)                    /* just in case we don't find it */
11097                 {
11098                         const char *descr = comments->descr;
11099
11100                         resetPQExpBuffer(target);
11101                         appendPQExpBuffer(target, "COLUMN %s.",
11102                                                           fmtId(tyinfo->dobj.name));
11103                         appendPQExpBufferStr(target, fmtId(attname));
11104
11105                         resetPQExpBuffer(query);
11106                         appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
11107                                                           fmtQualifiedDumpable(tyinfo));
11108                         appendPQExpBuffer(query, "%s IS ", fmtId(attname));
11109                         appendStringLiteralAH(query, descr, fout);
11110                         appendPQExpBufferStr(query, ";\n");
11111
11112                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
11113                                                  ARCHIVE_OPTS(.tag = target->data,
11114                                                                           .namespace = tyinfo->dobj.namespace->dobj.name,
11115                                                                           .owner = tyinfo->rolname,
11116                                                                           .description = "COMMENT",
11117                                                                           .section = SECTION_NONE,
11118                                                                           .createStmt = query->data,
11119                                                                           .deps = &(tyinfo->dobj.dumpId),
11120                                                                           .nDeps = 1));
11121                 }
11122
11123                 comments++;
11124                 ncomments--;
11125         }
11126
11127         PQclear(res);
11128         destroyPQExpBuffer(query);
11129         destroyPQExpBuffer(target);
11130 }
11131
11132 /*
11133  * dumpShellType
11134  *        writes out to fout the queries to create a shell type
11135  *
11136  * We dump a shell definition in advance of the I/O functions for the type.
11137  */
11138 static void
11139 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
11140 {
11141         DumpOptions *dopt = fout->dopt;
11142         PQExpBuffer q;
11143
11144         /* Skip if not to be dumped */
11145         if (!stinfo->dobj.dump || dopt->dataOnly)
11146                 return;
11147
11148         q = createPQExpBuffer();
11149
11150         /*
11151          * Note the lack of a DROP command for the shell type; any required DROP
11152          * is driven off the base type entry, instead.  This interacts with
11153          * _printTocEntry()'s use of the presence of a DROP command to decide
11154          * whether an entry needs an ALTER OWNER command.  We don't want to alter
11155          * the shell type's owner immediately on creation; that should happen only
11156          * after it's filled in, otherwise the backend complains.
11157          */
11158
11159         if (dopt->binary_upgrade)
11160                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
11161                                                                                                  stinfo->baseType->dobj.catId.oid,
11162                                                                                                  false);
11163
11164         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
11165                                           fmtQualifiedDumpable(stinfo));
11166
11167         if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11168                 ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
11169                                          ARCHIVE_OPTS(.tag = stinfo->dobj.name,
11170                                                                   .namespace = stinfo->dobj.namespace->dobj.name,
11171                                                                   .owner = stinfo->baseType->rolname,
11172                                                                   .description = "SHELL TYPE",
11173                                                                   .section = SECTION_PRE_DATA,
11174                                                                   .createStmt = q->data));
11175
11176         destroyPQExpBuffer(q);
11177 }
11178
11179 /*
11180  * dumpProcLang
11181  *                writes out to fout the queries to recreate a user-defined
11182  *                procedural language
11183  */
11184 static void
11185 dumpProcLang(Archive *fout, ProcLangInfo *plang)
11186 {
11187         DumpOptions *dopt = fout->dopt;
11188         PQExpBuffer defqry;
11189         PQExpBuffer delqry;
11190         bool            useParams;
11191         char       *qlanname;
11192         FuncInfo   *funcInfo;
11193         FuncInfo   *inlineInfo = NULL;
11194         FuncInfo   *validatorInfo = NULL;
11195
11196         /* Skip if not to be dumped */
11197         if (!plang->dobj.dump || dopt->dataOnly)
11198                 return;
11199
11200         /*
11201          * Try to find the support function(s).  It is not an error if we don't
11202          * find them --- if the functions are in the pg_catalog schema, as is
11203          * standard in 8.1 and up, then we won't have loaded them. (In this case
11204          * we will emit a parameterless CREATE LANGUAGE command, which will
11205          * require PL template knowledge in the backend to reload.)
11206          */
11207
11208         funcInfo = findFuncByOid(plang->lanplcallfoid);
11209         if (funcInfo != NULL && !funcInfo->dobj.dump)
11210                 funcInfo = NULL;                /* treat not-dumped same as not-found */
11211
11212         if (OidIsValid(plang->laninline))
11213         {
11214                 inlineInfo = findFuncByOid(plang->laninline);
11215                 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
11216                         inlineInfo = NULL;
11217         }
11218
11219         if (OidIsValid(plang->lanvalidator))
11220         {
11221                 validatorInfo = findFuncByOid(plang->lanvalidator);
11222                 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
11223                         validatorInfo = NULL;
11224         }
11225
11226         /*
11227          * If the functions are dumpable then emit a traditional CREATE LANGUAGE
11228          * with parameters.  Otherwise, we'll write a parameterless command, which
11229          * will rely on data from pg_pltemplate.
11230          */
11231         useParams = (funcInfo != NULL &&
11232                                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
11233                                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
11234
11235         defqry = createPQExpBuffer();
11236         delqry = createPQExpBuffer();
11237
11238         qlanname = pg_strdup(fmtId(plang->dobj.name));
11239
11240         appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
11241                                           qlanname);
11242
11243         if (useParams)
11244         {
11245                 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
11246                                                   plang->lanpltrusted ? "TRUSTED " : "",
11247                                                   qlanname);
11248                 appendPQExpBuffer(defqry, " HANDLER %s",
11249                                                   fmtQualifiedDumpable(funcInfo));
11250                 if (OidIsValid(plang->laninline))
11251                         appendPQExpBuffer(defqry, " INLINE %s",
11252                                                           fmtQualifiedDumpable(inlineInfo));
11253                 if (OidIsValid(plang->lanvalidator))
11254                         appendPQExpBuffer(defqry, " VALIDATOR %s",
11255                                                           fmtQualifiedDumpable(validatorInfo));
11256         }
11257         else
11258         {
11259                 /*
11260                  * If not dumping parameters, then use CREATE OR REPLACE so that the
11261                  * command will not fail if the language is preinstalled in the target
11262                  * database.  We restrict the use of REPLACE to this case so as to
11263                  * eliminate the risk of replacing a language with incompatible
11264                  * parameter settings: this command will only succeed at all if there
11265                  * is a pg_pltemplate entry, and if there is one, the existing entry
11266                  * must match it too.
11267                  */
11268                 appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
11269                                                   qlanname);
11270         }
11271         appendPQExpBufferStr(defqry, ";\n");
11272
11273         if (dopt->binary_upgrade)
11274                 binary_upgrade_extension_member(defqry, &plang->dobj,
11275                                                                                 "LANGUAGE", qlanname, NULL);
11276
11277         if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
11278                 ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
11279                                          ARCHIVE_OPTS(.tag = plang->dobj.name,
11280                                                                   .owner = plang->lanowner,
11281                                                                   .description = "PROCEDURAL LANGUAGE",
11282                                                                   .section = SECTION_PRE_DATA,
11283                                                                   .createStmt = defqry->data,
11284                                                                   .dropStmt = delqry->data,
11285                                                                   ));
11286
11287         /* Dump Proc Lang Comments and Security Labels */
11288         if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
11289                 dumpComment(fout, "LANGUAGE", qlanname,
11290                                         NULL, plang->lanowner,
11291                                         plang->dobj.catId, 0, plang->dobj.dumpId);
11292
11293         if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
11294                 dumpSecLabel(fout, "LANGUAGE", qlanname,
11295                                          NULL, plang->lanowner,
11296                                          plang->dobj.catId, 0, plang->dobj.dumpId);
11297
11298         if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
11299                 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
11300                                 qlanname, NULL, NULL,
11301                                 plang->lanowner, plang->lanacl, plang->rlanacl,
11302                                 plang->initlanacl, plang->initrlanacl);
11303
11304         free(qlanname);
11305
11306         destroyPQExpBuffer(defqry);
11307         destroyPQExpBuffer(delqry);
11308 }
11309
11310 /*
11311  * format_function_arguments: generate function name and argument list
11312  *
11313  * This is used when we can rely on pg_get_function_arguments to format
11314  * the argument list.  Note, however, that pg_get_function_arguments
11315  * does not special-case zero-argument aggregates.
11316  */
11317 static char *
11318 format_function_arguments(FuncInfo *finfo, char *funcargs, bool is_agg)
11319 {
11320         PQExpBufferData fn;
11321
11322         initPQExpBuffer(&fn);
11323         appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
11324         if (is_agg && finfo->nargs == 0)
11325                 appendPQExpBufferStr(&fn, "(*)");
11326         else
11327                 appendPQExpBuffer(&fn, "(%s)", funcargs);
11328         return fn.data;
11329 }
11330
11331 /*
11332  * format_function_arguments_old: generate function name and argument list
11333  *
11334  * The argument type names are qualified if needed.  The function name
11335  * is never qualified.
11336  *
11337  * This is used only with pre-8.4 servers, so we aren't expecting to see
11338  * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
11339  *
11340  * Any or all of allargtypes, argmodes, argnames may be NULL.
11341  */
11342 static char *
11343 format_function_arguments_old(Archive *fout,
11344                                                           FuncInfo *finfo, int nallargs,
11345                                                           char **allargtypes,
11346                                                           char **argmodes,
11347                                                           char **argnames)
11348 {
11349         PQExpBufferData fn;
11350         int                     j;
11351
11352         initPQExpBuffer(&fn);
11353         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11354         for (j = 0; j < nallargs; j++)
11355         {
11356                 Oid                     typid;
11357                 char       *typname;
11358                 const char *argmode;
11359                 const char *argname;
11360
11361                 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
11362                 typname = getFormattedTypeName(fout, typid, zeroAsOpaque);
11363
11364                 if (argmodes)
11365                 {
11366                         switch (argmodes[j][0])
11367                         {
11368                                 case PROARGMODE_IN:
11369                                         argmode = "";
11370                                         break;
11371                                 case PROARGMODE_OUT:
11372                                         argmode = "OUT ";
11373                                         break;
11374                                 case PROARGMODE_INOUT:
11375                                         argmode = "INOUT ";
11376                                         break;
11377                                 default:
11378                                         write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
11379                                         argmode = "";
11380                                         break;
11381                         }
11382                 }
11383                 else
11384                         argmode = "";
11385
11386                 argname = argnames ? argnames[j] : (char *) NULL;
11387                 if (argname && argname[0] == '\0')
11388                         argname = NULL;
11389
11390                 appendPQExpBuffer(&fn, "%s%s%s%s%s",
11391                                                   (j > 0) ? ", " : "",
11392                                                   argmode,
11393                                                   argname ? fmtId(argname) : "",
11394                                                   argname ? " " : "",
11395                                                   typname);
11396                 free(typname);
11397         }
11398         appendPQExpBufferChar(&fn, ')');
11399         return fn.data;
11400 }
11401
11402 /*
11403  * format_function_signature: generate function name and argument list
11404  *
11405  * This is like format_function_arguments_old except that only a minimal
11406  * list of input argument types is generated; this is sufficient to
11407  * reference the function, but not to define it.
11408  *
11409  * If honor_quotes is false then the function name is never quoted.
11410  * This is appropriate for use in TOC tags, but not in SQL commands.
11411  */
11412 static char *
11413 format_function_signature(Archive *fout, FuncInfo *finfo, bool honor_quotes)
11414 {
11415         PQExpBufferData fn;
11416         int                     j;
11417
11418         initPQExpBuffer(&fn);
11419         if (honor_quotes)
11420                 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11421         else
11422                 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
11423         for (j = 0; j < finfo->nargs; j++)
11424         {
11425                 char       *typname;
11426
11427                 if (j > 0)
11428                         appendPQExpBufferStr(&fn, ", ");
11429
11430                 typname = getFormattedTypeName(fout, finfo->argtypes[j],
11431                                                                            zeroAsOpaque);
11432                 appendPQExpBufferStr(&fn, typname);
11433                 free(typname);
11434         }
11435         appendPQExpBufferChar(&fn, ')');
11436         return fn.data;
11437 }
11438
11439
11440 /*
11441  * dumpFunc:
11442  *        dump out one function
11443  */
11444 static void
11445 dumpFunc(Archive *fout, FuncInfo *finfo)
11446 {
11447         DumpOptions *dopt = fout->dopt;
11448         PQExpBuffer query;
11449         PQExpBuffer q;
11450         PQExpBuffer delqry;
11451         PQExpBuffer asPart;
11452         PGresult   *res;
11453         char       *funcsig;            /* identity signature */
11454         char       *funcfullsig = NULL; /* full signature */
11455         char       *funcsig_tag;
11456         char       *proretset;
11457         char       *prosrc;
11458         char       *probin;
11459         char       *funcargs;
11460         char       *funciargs;
11461         char       *funcresult;
11462         char       *proallargtypes;
11463         char       *proargmodes;
11464         char       *proargnames;
11465         char       *protrftypes;
11466         char       *prokind;
11467         char       *provolatile;
11468         char       *proisstrict;
11469         char       *prosecdef;
11470         char       *proleakproof;
11471         char       *proconfig;
11472         char       *procost;
11473         char       *prorows;
11474         char       *prosupport;
11475         char       *proparallel;
11476         char       *lanname;
11477         char       *rettypename;
11478         int                     nallargs;
11479         char      **allargtypes = NULL;
11480         char      **argmodes = NULL;
11481         char      **argnames = NULL;
11482         char      **configitems = NULL;
11483         int                     nconfigitems = 0;
11484         const char *keyword;
11485         int                     i;
11486
11487         /* Skip if not to be dumped */
11488         if (!finfo->dobj.dump || dopt->dataOnly)
11489                 return;
11490
11491         query = createPQExpBuffer();
11492         q = createPQExpBuffer();
11493         delqry = createPQExpBuffer();
11494         asPart = createPQExpBuffer();
11495
11496         /* Fetch function-specific details */
11497         if (fout->remoteVersion >= 120000)
11498         {
11499                 /*
11500                  * prosupport was added in 12
11501                  */
11502                 appendPQExpBuffer(query,
11503                                                   "SELECT proretset, prosrc, probin, "
11504                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11505                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11506                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11507                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11508                                                   "prokind, provolatile, proisstrict, prosecdef, "
11509                                                   "proleakproof, proconfig, procost, prorows, "
11510                                                   "prosupport, proparallel, "
11511                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11512                                                   "FROM pg_catalog.pg_proc "
11513                                                   "WHERE oid = '%u'::pg_catalog.oid",
11514                                                   finfo->dobj.catId.oid);
11515         }
11516         else if (fout->remoteVersion >= 110000)
11517         {
11518                 /*
11519                  * prokind was added in 11
11520                  */
11521                 appendPQExpBuffer(query,
11522                                                   "SELECT proretset, prosrc, probin, "
11523                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11524                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11525                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11526                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11527                                                   "prokind, provolatile, proisstrict, prosecdef, "
11528                                                   "proleakproof, proconfig, procost, prorows, "
11529                                                   "'-' AS prosupport, proparallel, "
11530                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11531                                                   "FROM pg_catalog.pg_proc "
11532                                                   "WHERE oid = '%u'::pg_catalog.oid",
11533                                                   finfo->dobj.catId.oid);
11534         }
11535         else if (fout->remoteVersion >= 90600)
11536         {
11537                 /*
11538                  * proparallel was added in 9.6
11539                  */
11540                 appendPQExpBuffer(query,
11541                                                   "SELECT proretset, prosrc, probin, "
11542                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11543                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11544                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11545                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11546                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11547                                                   "provolatile, proisstrict, prosecdef, "
11548                                                   "proleakproof, proconfig, procost, prorows, "
11549                                                   "'-' AS prosupport, proparallel, "
11550                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11551                                                   "FROM pg_catalog.pg_proc "
11552                                                   "WHERE oid = '%u'::pg_catalog.oid",
11553                                                   finfo->dobj.catId.oid);
11554         }
11555         else if (fout->remoteVersion >= 90500)
11556         {
11557                 /*
11558                  * protrftypes was added in 9.5
11559                  */
11560                 appendPQExpBuffer(query,
11561                                                   "SELECT proretset, prosrc, probin, "
11562                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11563                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11564                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11565                                                   "array_to_string(protrftypes, ' ') AS protrftypes, "
11566                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11567                                                   "provolatile, proisstrict, prosecdef, "
11568                                                   "proleakproof, proconfig, procost, prorows, "
11569                                                   "'-' AS prosupport, "
11570                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11571                                                   "FROM pg_catalog.pg_proc "
11572                                                   "WHERE oid = '%u'::pg_catalog.oid",
11573                                                   finfo->dobj.catId.oid);
11574         }
11575         else if (fout->remoteVersion >= 90200)
11576         {
11577                 /*
11578                  * proleakproof was added in 9.2
11579                  */
11580                 appendPQExpBuffer(query,
11581                                                   "SELECT proretset, prosrc, probin, "
11582                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11583                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11584                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11585                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11586                                                   "provolatile, proisstrict, prosecdef, "
11587                                                   "proleakproof, proconfig, procost, prorows, "
11588                                                   "'-' AS prosupport, "
11589                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11590                                                   "FROM pg_catalog.pg_proc "
11591                                                   "WHERE oid = '%u'::pg_catalog.oid",
11592                                                   finfo->dobj.catId.oid);
11593         }
11594         else if (fout->remoteVersion >= 80400)
11595         {
11596                 /*
11597                  * In 8.4 and up we rely on pg_get_function_arguments and
11598                  * pg_get_function_result instead of examining proallargtypes etc.
11599                  */
11600                 appendPQExpBuffer(query,
11601                                                   "SELECT proretset, prosrc, probin, "
11602                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11603                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11604                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11605                                                   "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11606                                                   "provolatile, proisstrict, prosecdef, "
11607                                                   "false AS proleakproof, "
11608                                                   " proconfig, procost, prorows, "
11609                                                   "'-' AS prosupport, "
11610                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11611                                                   "FROM pg_catalog.pg_proc "
11612                                                   "WHERE oid = '%u'::pg_catalog.oid",
11613                                                   finfo->dobj.catId.oid);
11614         }
11615         else if (fout->remoteVersion >= 80300)
11616         {
11617                 appendPQExpBuffer(query,
11618                                                   "SELECT proretset, prosrc, probin, "
11619                                                   "proallargtypes, proargmodes, proargnames, "
11620                                                   "'f' AS prokind, "
11621                                                   "provolatile, proisstrict, prosecdef, "
11622                                                   "false AS proleakproof, "
11623                                                   "proconfig, procost, prorows, "
11624                                                   "'-' AS prosupport, "
11625                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11626                                                   "FROM pg_catalog.pg_proc "
11627                                                   "WHERE oid = '%u'::pg_catalog.oid",
11628                                                   finfo->dobj.catId.oid);
11629         }
11630         else if (fout->remoteVersion >= 80100)
11631         {
11632                 appendPQExpBuffer(query,
11633                                                   "SELECT proretset, prosrc, probin, "
11634                                                   "proallargtypes, proargmodes, proargnames, "
11635                                                   "'f' AS prokind, "
11636                                                   "provolatile, proisstrict, prosecdef, "
11637                                                   "false AS proleakproof, "
11638                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
11639                                                   "'-' AS prosupport, "
11640                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11641                                                   "FROM pg_catalog.pg_proc "
11642                                                   "WHERE oid = '%u'::pg_catalog.oid",
11643                                                   finfo->dobj.catId.oid);
11644         }
11645         else
11646         {
11647                 appendPQExpBuffer(query,
11648                                                   "SELECT proretset, prosrc, probin, "
11649                                                   "null AS proallargtypes, "
11650                                                   "null AS proargmodes, "
11651                                                   "proargnames, "
11652                                                   "'f' AS prokind, "
11653                                                   "provolatile, proisstrict, prosecdef, "
11654                                                   "false AS proleakproof, "
11655                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
11656                                                   "'-' AS prosupport, "
11657                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11658                                                   "FROM pg_catalog.pg_proc "
11659                                                   "WHERE oid = '%u'::pg_catalog.oid",
11660                                                   finfo->dobj.catId.oid);
11661         }
11662
11663         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11664
11665         proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
11666         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
11667         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
11668         if (fout->remoteVersion >= 80400)
11669         {
11670                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
11671                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
11672                 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
11673                 proallargtypes = proargmodes = proargnames = NULL;
11674         }
11675         else
11676         {
11677                 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
11678                 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
11679                 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
11680                 funcargs = funciargs = funcresult = NULL;
11681         }
11682         if (PQfnumber(res, "protrftypes") != -1)
11683                 protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
11684         else
11685                 protrftypes = NULL;
11686         prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
11687         provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
11688         proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
11689         prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
11690         proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
11691         proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
11692         procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
11693         prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
11694         prosupport = PQgetvalue(res, 0, PQfnumber(res, "prosupport"));
11695
11696         if (PQfnumber(res, "proparallel") != -1)
11697                 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
11698         else
11699                 proparallel = NULL;
11700
11701         lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
11702
11703         /*
11704          * See backend/commands/functioncmds.c for details of how the 'AS' clause
11705          * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
11706          * versions would set it to "-".  There are no known cases in which prosrc
11707          * is unused, so the tests below for "-" are probably useless.
11708          */
11709         if (probin[0] != '\0' && strcmp(probin, "-") != 0)
11710         {
11711                 appendPQExpBufferStr(asPart, "AS ");
11712                 appendStringLiteralAH(asPart, probin, fout);
11713                 if (strcmp(prosrc, "-") != 0)
11714                 {
11715                         appendPQExpBufferStr(asPart, ", ");
11716
11717                         /*
11718                          * where we have bin, use dollar quoting if allowed and src
11719                          * contains quote or backslash; else use regular quoting.
11720                          */
11721                         if (dopt->disable_dollar_quoting ||
11722                                 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
11723                                 appendStringLiteralAH(asPart, prosrc, fout);
11724                         else
11725                                 appendStringLiteralDQ(asPart, prosrc, NULL);
11726                 }
11727         }
11728         else
11729         {
11730                 if (strcmp(prosrc, "-") != 0)
11731                 {
11732                         appendPQExpBufferStr(asPart, "AS ");
11733                         /* with no bin, dollar quote src unconditionally if allowed */
11734                         if (dopt->disable_dollar_quoting)
11735                                 appendStringLiteralAH(asPart, prosrc, fout);
11736                         else
11737                                 appendStringLiteralDQ(asPart, prosrc, NULL);
11738                 }
11739         }
11740
11741         nallargs = finfo->nargs;        /* unless we learn different from allargs */
11742
11743         if (proallargtypes && *proallargtypes)
11744         {
11745                 int                     nitems = 0;
11746
11747                 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
11748                         nitems < finfo->nargs)
11749                 {
11750                         write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
11751                         if (allargtypes)
11752                                 free(allargtypes);
11753                         allargtypes = NULL;
11754                 }
11755                 else
11756                         nallargs = nitems;
11757         }
11758
11759         if (proargmodes && *proargmodes)
11760         {
11761                 int                     nitems = 0;
11762
11763                 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
11764                         nitems != nallargs)
11765                 {
11766                         write_msg(NULL, "WARNING: could not parse proargmodes array\n");
11767                         if (argmodes)
11768                                 free(argmodes);
11769                         argmodes = NULL;
11770                 }
11771         }
11772
11773         if (proargnames && *proargnames)
11774         {
11775                 int                     nitems = 0;
11776
11777                 if (!parsePGArray(proargnames, &argnames, &nitems) ||
11778                         nitems != nallargs)
11779                 {
11780                         write_msg(NULL, "WARNING: could not parse proargnames array\n");
11781                         if (argnames)
11782                                 free(argnames);
11783                         argnames = NULL;
11784                 }
11785         }
11786
11787         if (proconfig && *proconfig)
11788         {
11789                 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
11790                 {
11791                         write_msg(NULL, "WARNING: could not parse proconfig array\n");
11792                         if (configitems)
11793                                 free(configitems);
11794                         configitems = NULL;
11795                         nconfigitems = 0;
11796                 }
11797         }
11798
11799         if (funcargs)
11800         {
11801                 /* 8.4 or later; we rely on server-side code for most of the work */
11802                 funcfullsig = format_function_arguments(finfo, funcargs, false);
11803                 funcsig = format_function_arguments(finfo, funciargs, false);
11804         }
11805         else
11806                 /* pre-8.4, do it ourselves */
11807                 funcsig = format_function_arguments_old(fout,
11808                                                                                                 finfo, nallargs, allargtypes,
11809                                                                                                 argmodes, argnames);
11810
11811         funcsig_tag = format_function_signature(fout, finfo, false);
11812
11813         if (prokind[0] == PROKIND_PROCEDURE)
11814                 keyword = "PROCEDURE";
11815         else
11816                 keyword = "FUNCTION";   /* works for window functions too */
11817
11818         appendPQExpBuffer(delqry, "DROP %s %s.%s;\n",
11819                                           keyword,
11820                                           fmtId(finfo->dobj.namespace->dobj.name),
11821                                           funcsig);
11822
11823         appendPQExpBuffer(q, "CREATE %s %s.%s",
11824                                           keyword,
11825                                           fmtId(finfo->dobj.namespace->dobj.name),
11826                                           funcfullsig ? funcfullsig :
11827                                           funcsig);
11828
11829         if (prokind[0] == PROKIND_PROCEDURE)
11830                  /* no result type to output */ ;
11831         else if (funcresult)
11832                 appendPQExpBuffer(q, " RETURNS %s", funcresult);
11833         else
11834         {
11835                 rettypename = getFormattedTypeName(fout, finfo->prorettype,
11836                                                                                    zeroAsOpaque);
11837                 appendPQExpBuffer(q, " RETURNS %s%s",
11838                                                   (proretset[0] == 't') ? "SETOF " : "",
11839                                                   rettypename);
11840                 free(rettypename);
11841         }
11842
11843         appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
11844
11845         if (protrftypes != NULL && strcmp(protrftypes, "") != 0)
11846         {
11847                 Oid                *typeids = palloc(FUNC_MAX_ARGS * sizeof(Oid));
11848                 int                     i;
11849
11850                 appendPQExpBufferStr(q, " TRANSFORM ");
11851                 parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
11852                 for (i = 0; typeids[i]; i++)
11853                 {
11854                         if (i != 0)
11855                                 appendPQExpBufferStr(q, ", ");
11856                         appendPQExpBuffer(q, "FOR TYPE %s",
11857                                                           getFormattedTypeName(fout, typeids[i], zeroAsNone));
11858                 }
11859         }
11860
11861         if (prokind[0] == PROKIND_WINDOW)
11862                 appendPQExpBufferStr(q, " WINDOW");
11863
11864         if (provolatile[0] != PROVOLATILE_VOLATILE)
11865         {
11866                 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
11867                         appendPQExpBufferStr(q, " IMMUTABLE");
11868                 else if (provolatile[0] == PROVOLATILE_STABLE)
11869                         appendPQExpBufferStr(q, " STABLE");
11870                 else if (provolatile[0] != PROVOLATILE_VOLATILE)
11871                         exit_horribly(NULL, "unrecognized provolatile value for function \"%s\"\n",
11872                                                   finfo->dobj.name);
11873         }
11874
11875         if (proisstrict[0] == 't')
11876                 appendPQExpBufferStr(q, " STRICT");
11877
11878         if (prosecdef[0] == 't')
11879                 appendPQExpBufferStr(q, " SECURITY DEFINER");
11880
11881         if (proleakproof[0] == 't')
11882                 appendPQExpBufferStr(q, " LEAKPROOF");
11883
11884         /*
11885          * COST and ROWS are emitted only if present and not default, so as not to
11886          * break backwards-compatibility of the dump without need.  Keep this code
11887          * in sync with the defaults in functioncmds.c.
11888          */
11889         if (strcmp(procost, "0") != 0)
11890         {
11891                 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
11892                 {
11893                         /* default cost is 1 */
11894                         if (strcmp(procost, "1") != 0)
11895                                 appendPQExpBuffer(q, " COST %s", procost);
11896                 }
11897                 else
11898                 {
11899                         /* default cost is 100 */
11900                         if (strcmp(procost, "100") != 0)
11901                                 appendPQExpBuffer(q, " COST %s", procost);
11902                 }
11903         }
11904         if (proretset[0] == 't' &&
11905                 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
11906                 appendPQExpBuffer(q, " ROWS %s", prorows);
11907
11908         if (strcmp(prosupport, "-") != 0)
11909         {
11910                 /* We rely on regprocout to provide quoting and qualification */
11911                 appendPQExpBuffer(q, " SUPPORT %s", prosupport);
11912         }
11913
11914         if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
11915         {
11916                 if (proparallel[0] == PROPARALLEL_SAFE)
11917                         appendPQExpBufferStr(q, " PARALLEL SAFE");
11918                 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
11919                         appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
11920                 else if (proparallel[0] != PROPARALLEL_UNSAFE)
11921                         exit_horribly(NULL, "unrecognized proparallel value for function \"%s\"\n",
11922                                                   finfo->dobj.name);
11923         }
11924
11925         for (i = 0; i < nconfigitems; i++)
11926         {
11927                 /* we feel free to scribble on configitems[] here */
11928                 char       *configitem = configitems[i];
11929                 char       *pos;
11930
11931                 pos = strchr(configitem, '=');
11932                 if (pos == NULL)
11933                         continue;
11934                 *pos++ = '\0';
11935                 appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
11936
11937                 /*
11938                  * Variables that are marked GUC_LIST_QUOTE were already fully quoted
11939                  * by flatten_set_variable_args() before they were put into the
11940                  * proconfig array.  However, because the quoting rules used there
11941                  * aren't exactly like SQL's, we have to break the list value apart
11942                  * and then quote the elements as string literals.  (The elements may
11943                  * be double-quoted as-is, but we can't just feed them to the SQL
11944                  * parser; it would do the wrong thing with elements that are
11945                  * zero-length or longer than NAMEDATALEN.)
11946                  *
11947                  * Variables that are not so marked should just be emitted as simple
11948                  * string literals.  If the variable is not known to
11949                  * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
11950                  * to use GUC_LIST_QUOTE for extension variables.
11951                  */
11952                 if (variable_is_guc_list_quote(configitem))
11953                 {
11954                         char      **namelist;
11955                         char      **nameptr;
11956
11957                         /* Parse string into list of identifiers */
11958                         /* this shouldn't fail really */
11959                         if (SplitGUCList(pos, ',', &namelist))
11960                         {
11961                                 for (nameptr = namelist; *nameptr; nameptr++)
11962                                 {
11963                                         if (nameptr != namelist)
11964                                                 appendPQExpBufferStr(q, ", ");
11965                                         appendStringLiteralAH(q, *nameptr, fout);
11966                                 }
11967                         }
11968                         pg_free(namelist);
11969                 }
11970                 else
11971                         appendStringLiteralAH(q, pos, fout);
11972         }
11973
11974         appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
11975
11976         if (dopt->binary_upgrade)
11977                 binary_upgrade_extension_member(q, &finfo->dobj,
11978                                                                                 keyword, funcsig,
11979                                                                                 finfo->dobj.namespace->dobj.name);
11980
11981         if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11982                 ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
11983                                          ARCHIVE_OPTS(.tag = funcsig_tag,
11984                                                                   .namespace = finfo->dobj.namespace->dobj.name,
11985                                                                   .owner = finfo->rolname,
11986                                                                   .description = keyword,
11987                                                                   .section = SECTION_PRE_DATA,
11988                                                                   .createStmt = q->data,
11989                                                                   .dropStmt = delqry->data));
11990
11991         /* Dump Function Comments and Security Labels */
11992         if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11993                 dumpComment(fout, keyword, funcsig,
11994                                         finfo->dobj.namespace->dobj.name, finfo->rolname,
11995                                         finfo->dobj.catId, 0, finfo->dobj.dumpId);
11996
11997         if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11998                 dumpSecLabel(fout, keyword, funcsig,
11999                                          finfo->dobj.namespace->dobj.name, finfo->rolname,
12000                                          finfo->dobj.catId, 0, finfo->dobj.dumpId);
12001
12002         if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
12003                 dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, keyword,
12004                                 funcsig, NULL,
12005                                 finfo->dobj.namespace->dobj.name,
12006                                 finfo->rolname, finfo->proacl, finfo->rproacl,
12007                                 finfo->initproacl, finfo->initrproacl);
12008
12009         PQclear(res);
12010
12011         destroyPQExpBuffer(query);
12012         destroyPQExpBuffer(q);
12013         destroyPQExpBuffer(delqry);
12014         destroyPQExpBuffer(asPart);
12015         free(funcsig);
12016         if (funcfullsig)
12017                 free(funcfullsig);
12018         free(funcsig_tag);
12019         if (allargtypes)
12020                 free(allargtypes);
12021         if (argmodes)
12022                 free(argmodes);
12023         if (argnames)
12024                 free(argnames);
12025         if (configitems)
12026                 free(configitems);
12027 }
12028
12029
12030 /*
12031  * Dump a user-defined cast
12032  */
12033 static void
12034 dumpCast(Archive *fout, CastInfo *cast)
12035 {
12036         DumpOptions *dopt = fout->dopt;
12037         PQExpBuffer defqry;
12038         PQExpBuffer delqry;
12039         PQExpBuffer labelq;
12040         PQExpBuffer castargs;
12041         FuncInfo   *funcInfo = NULL;
12042         char       *sourceType;
12043         char       *targetType;
12044
12045         /* Skip if not to be dumped */
12046         if (!cast->dobj.dump || dopt->dataOnly)
12047                 return;
12048
12049         /* Cannot dump if we don't have the cast function's info */
12050         if (OidIsValid(cast->castfunc))
12051         {
12052                 funcInfo = findFuncByOid(cast->castfunc);
12053                 if (funcInfo == NULL)
12054                         exit_horribly(NULL, "could not find function definition for function with OID %u\n",
12055                                                   cast->castfunc);
12056         }
12057
12058         defqry = createPQExpBuffer();
12059         delqry = createPQExpBuffer();
12060         labelq = createPQExpBuffer();
12061         castargs = createPQExpBuffer();
12062
12063         sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
12064         targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
12065         appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
12066                                           sourceType, targetType);
12067
12068         appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
12069                                           sourceType, targetType);
12070
12071         switch (cast->castmethod)
12072         {
12073                 case COERCION_METHOD_BINARY:
12074                         appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
12075                         break;
12076                 case COERCION_METHOD_INOUT:
12077                         appendPQExpBufferStr(defqry, "WITH INOUT");
12078                         break;
12079                 case COERCION_METHOD_FUNCTION:
12080                         if (funcInfo)
12081                         {
12082                                 char       *fsig = format_function_signature(fout, funcInfo, true);
12083
12084                                 /*
12085                                  * Always qualify the function name (format_function_signature
12086                                  * won't qualify it).
12087                                  */
12088                                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
12089                                                                   fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
12090                                 free(fsig);
12091                         }
12092                         else
12093                                 write_msg(NULL, "WARNING: bogus value in pg_cast.castfunc or pg_cast.castmethod field\n");
12094                         break;
12095                 default:
12096                         write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
12097         }
12098
12099         if (cast->castcontext == 'a')
12100                 appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
12101         else if (cast->castcontext == 'i')
12102                 appendPQExpBufferStr(defqry, " AS IMPLICIT");
12103         appendPQExpBufferStr(defqry, ";\n");
12104
12105         appendPQExpBuffer(labelq, "CAST (%s AS %s)",
12106                                           sourceType, targetType);
12107
12108         appendPQExpBuffer(castargs, "(%s AS %s)",
12109                                           sourceType, targetType);
12110
12111         if (dopt->binary_upgrade)
12112                 binary_upgrade_extension_member(defqry, &cast->dobj,
12113                                                                                 "CAST", castargs->data, NULL);
12114
12115         if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
12116                 ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
12117                                          ARCHIVE_OPTS(.tag = labelq->data,
12118                                                                   .description = "CAST",
12119                                                                   .section = SECTION_PRE_DATA,
12120                                                                   .createStmt = defqry->data,
12121                                                                   .dropStmt = delqry->data));
12122
12123         /* Dump Cast Comments */
12124         if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
12125                 dumpComment(fout, "CAST", castargs->data,
12126                                         NULL, "",
12127                                         cast->dobj.catId, 0, cast->dobj.dumpId);
12128
12129         free(sourceType);
12130         free(targetType);
12131
12132         destroyPQExpBuffer(defqry);
12133         destroyPQExpBuffer(delqry);
12134         destroyPQExpBuffer(labelq);
12135         destroyPQExpBuffer(castargs);
12136 }
12137
12138 /*
12139  * Dump a transform
12140  */
12141 static void
12142 dumpTransform(Archive *fout, TransformInfo *transform)
12143 {
12144         DumpOptions *dopt = fout->dopt;
12145         PQExpBuffer defqry;
12146         PQExpBuffer delqry;
12147         PQExpBuffer labelq;
12148         PQExpBuffer transformargs;
12149         FuncInfo   *fromsqlFuncInfo = NULL;
12150         FuncInfo   *tosqlFuncInfo = NULL;
12151         char       *lanname;
12152         char       *transformType;
12153
12154         /* Skip if not to be dumped */
12155         if (!transform->dobj.dump || dopt->dataOnly)
12156                 return;
12157
12158         /* Cannot dump if we don't have the transform functions' info */
12159         if (OidIsValid(transform->trffromsql))
12160         {
12161                 fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
12162                 if (fromsqlFuncInfo == NULL)
12163                         exit_horribly(NULL, "could not find function definition for function with OID %u\n",
12164                                                   transform->trffromsql);
12165         }
12166         if (OidIsValid(transform->trftosql))
12167         {
12168                 tosqlFuncInfo = findFuncByOid(transform->trftosql);
12169                 if (tosqlFuncInfo == NULL)
12170                         exit_horribly(NULL, "could not find function definition for function with OID %u\n",
12171                                                   transform->trftosql);
12172         }
12173
12174         defqry = createPQExpBuffer();
12175         delqry = createPQExpBuffer();
12176         labelq = createPQExpBuffer();
12177         transformargs = createPQExpBuffer();
12178
12179         lanname = get_language_name(fout, transform->trflang);
12180         transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
12181
12182         appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
12183                                           transformType, lanname);
12184
12185         appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
12186                                           transformType, lanname);
12187
12188         if (!transform->trffromsql && !transform->trftosql)
12189                 write_msg(NULL, "WARNING: bogus transform definition, at least one of trffromsql and trftosql should be nonzero\n");
12190
12191         if (transform->trffromsql)
12192         {
12193                 if (fromsqlFuncInfo)
12194                 {
12195                         char       *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
12196
12197                         /*
12198                          * Always qualify the function name (format_function_signature
12199                          * won't qualify it).
12200                          */
12201                         appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
12202                                                           fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
12203                         free(fsig);
12204                 }
12205                 else
12206                         write_msg(NULL, "WARNING: bogus value in pg_transform.trffromsql field\n");
12207         }
12208
12209         if (transform->trftosql)
12210         {
12211                 if (transform->trffromsql)
12212                         appendPQExpBuffer(defqry, ", ");
12213
12214                 if (tosqlFuncInfo)
12215                 {
12216                         char       *fsig = format_function_signature(fout, tosqlFuncInfo, true);
12217
12218                         /*
12219                          * Always qualify the function name (format_function_signature
12220                          * won't qualify it).
12221                          */
12222                         appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
12223                                                           fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
12224                         free(fsig);
12225                 }
12226                 else
12227                         write_msg(NULL, "WARNING: bogus value in pg_transform.trftosql field\n");
12228         }
12229
12230         appendPQExpBuffer(defqry, ");\n");
12231
12232         appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
12233                                           transformType, lanname);
12234
12235         appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
12236                                           transformType, lanname);
12237
12238         if (dopt->binary_upgrade)
12239                 binary_upgrade_extension_member(defqry, &transform->dobj,
12240                                                                                 "TRANSFORM", transformargs->data, NULL);
12241
12242         if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
12243                 ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
12244                                          ARCHIVE_OPTS(.tag = labelq->data,
12245                                                                   .description = "TRANSFORM",
12246                                                                   .section = SECTION_PRE_DATA,
12247                                                                   .createStmt = defqry->data,
12248                                                                   .dropStmt = delqry->data,
12249                                                                   .deps = transform->dobj.dependencies,
12250                                                                   .nDeps = transform->dobj.nDeps));
12251
12252         /* Dump Transform Comments */
12253         if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
12254                 dumpComment(fout, "TRANSFORM", transformargs->data,
12255                                         NULL, "",
12256                                         transform->dobj.catId, 0, transform->dobj.dumpId);
12257
12258         free(lanname);
12259         free(transformType);
12260         destroyPQExpBuffer(defqry);
12261         destroyPQExpBuffer(delqry);
12262         destroyPQExpBuffer(labelq);
12263         destroyPQExpBuffer(transformargs);
12264 }
12265
12266
12267 /*
12268  * dumpOpr
12269  *        write out a single operator definition
12270  */
12271 static void
12272 dumpOpr(Archive *fout, OprInfo *oprinfo)
12273 {
12274         DumpOptions *dopt = fout->dopt;
12275         PQExpBuffer query;
12276         PQExpBuffer q;
12277         PQExpBuffer delq;
12278         PQExpBuffer oprid;
12279         PQExpBuffer details;
12280         PGresult   *res;
12281         int                     i_oprkind;
12282         int                     i_oprcode;
12283         int                     i_oprleft;
12284         int                     i_oprright;
12285         int                     i_oprcom;
12286         int                     i_oprnegate;
12287         int                     i_oprrest;
12288         int                     i_oprjoin;
12289         int                     i_oprcanmerge;
12290         int                     i_oprcanhash;
12291         char       *oprkind;
12292         char       *oprcode;
12293         char       *oprleft;
12294         char       *oprright;
12295         char       *oprcom;
12296         char       *oprnegate;
12297         char       *oprrest;
12298         char       *oprjoin;
12299         char       *oprcanmerge;
12300         char       *oprcanhash;
12301         char       *oprregproc;
12302         char       *oprref;
12303
12304         /* Skip if not to be dumped */
12305         if (!oprinfo->dobj.dump || dopt->dataOnly)
12306                 return;
12307
12308         /*
12309          * some operators are invalid because they were the result of user
12310          * defining operators before commutators exist
12311          */
12312         if (!OidIsValid(oprinfo->oprcode))
12313                 return;
12314
12315         query = createPQExpBuffer();
12316         q = createPQExpBuffer();
12317         delq = createPQExpBuffer();
12318         oprid = createPQExpBuffer();
12319         details = createPQExpBuffer();
12320
12321         if (fout->remoteVersion >= 80300)
12322         {
12323                 appendPQExpBuffer(query, "SELECT oprkind, "
12324                                                   "oprcode::pg_catalog.regprocedure, "
12325                                                   "oprleft::pg_catalog.regtype, "
12326                                                   "oprright::pg_catalog.regtype, "
12327                                                   "oprcom, "
12328                                                   "oprnegate, "
12329                                                   "oprrest::pg_catalog.regprocedure, "
12330                                                   "oprjoin::pg_catalog.regprocedure, "
12331                                                   "oprcanmerge, oprcanhash "
12332                                                   "FROM pg_catalog.pg_operator "
12333                                                   "WHERE oid = '%u'::pg_catalog.oid",
12334                                                   oprinfo->dobj.catId.oid);
12335         }
12336         else
12337         {
12338                 appendPQExpBuffer(query, "SELECT oprkind, "
12339                                                   "oprcode::pg_catalog.regprocedure, "
12340                                                   "oprleft::pg_catalog.regtype, "
12341                                                   "oprright::pg_catalog.regtype, "
12342                                                   "oprcom, "
12343                                                   "oprnegate, "
12344                                                   "oprrest::pg_catalog.regprocedure, "
12345                                                   "oprjoin::pg_catalog.regprocedure, "
12346                                                   "(oprlsortop != 0) AS oprcanmerge, "
12347                                                   "oprcanhash "
12348                                                   "FROM pg_catalog.pg_operator "
12349                                                   "WHERE oid = '%u'::pg_catalog.oid",
12350                                                   oprinfo->dobj.catId.oid);
12351         }
12352
12353         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12354
12355         i_oprkind = PQfnumber(res, "oprkind");
12356         i_oprcode = PQfnumber(res, "oprcode");
12357         i_oprleft = PQfnumber(res, "oprleft");
12358         i_oprright = PQfnumber(res, "oprright");
12359         i_oprcom = PQfnumber(res, "oprcom");
12360         i_oprnegate = PQfnumber(res, "oprnegate");
12361         i_oprrest = PQfnumber(res, "oprrest");
12362         i_oprjoin = PQfnumber(res, "oprjoin");
12363         i_oprcanmerge = PQfnumber(res, "oprcanmerge");
12364         i_oprcanhash = PQfnumber(res, "oprcanhash");
12365
12366         oprkind = PQgetvalue(res, 0, i_oprkind);
12367         oprcode = PQgetvalue(res, 0, i_oprcode);
12368         oprleft = PQgetvalue(res, 0, i_oprleft);
12369         oprright = PQgetvalue(res, 0, i_oprright);
12370         oprcom = PQgetvalue(res, 0, i_oprcom);
12371         oprnegate = PQgetvalue(res, 0, i_oprnegate);
12372         oprrest = PQgetvalue(res, 0, i_oprrest);
12373         oprjoin = PQgetvalue(res, 0, i_oprjoin);
12374         oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
12375         oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
12376
12377         oprregproc = convertRegProcReference(fout, oprcode);
12378         if (oprregproc)
12379         {
12380                 appendPQExpBuffer(details, "    FUNCTION = %s", oprregproc);
12381                 free(oprregproc);
12382         }
12383
12384         appendPQExpBuffer(oprid, "%s (",
12385                                           oprinfo->dobj.name);
12386
12387         /*
12388          * right unary means there's a left arg and left unary means there's a
12389          * right arg
12390          */
12391         if (strcmp(oprkind, "r") == 0 ||
12392                 strcmp(oprkind, "b") == 0)
12393         {
12394                 appendPQExpBuffer(details, ",\n    LEFTARG = %s", oprleft);
12395                 appendPQExpBufferStr(oprid, oprleft);
12396         }
12397         else
12398                 appendPQExpBufferStr(oprid, "NONE");
12399
12400         if (strcmp(oprkind, "l") == 0 ||
12401                 strcmp(oprkind, "b") == 0)
12402         {
12403                 appendPQExpBuffer(details, ",\n    RIGHTARG = %s", oprright);
12404                 appendPQExpBuffer(oprid, ", %s)", oprright);
12405         }
12406         else
12407                 appendPQExpBufferStr(oprid, ", NONE)");
12408
12409         oprref = getFormattedOperatorName(fout, oprcom);
12410         if (oprref)
12411         {
12412                 appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", oprref);
12413                 free(oprref);
12414         }
12415
12416         oprref = getFormattedOperatorName(fout, oprnegate);
12417         if (oprref)
12418         {
12419                 appendPQExpBuffer(details, ",\n    NEGATOR = %s", oprref);
12420                 free(oprref);
12421         }
12422
12423         if (strcmp(oprcanmerge, "t") == 0)
12424                 appendPQExpBufferStr(details, ",\n    MERGES");
12425
12426         if (strcmp(oprcanhash, "t") == 0)
12427                 appendPQExpBufferStr(details, ",\n    HASHES");
12428
12429         oprregproc = convertRegProcReference(fout, oprrest);
12430         if (oprregproc)
12431         {
12432                 appendPQExpBuffer(details, ",\n    RESTRICT = %s", oprregproc);
12433                 free(oprregproc);
12434         }
12435
12436         oprregproc = convertRegProcReference(fout, oprjoin);
12437         if (oprregproc)
12438         {
12439                 appendPQExpBuffer(details, ",\n    JOIN = %s", oprregproc);
12440                 free(oprregproc);
12441         }
12442
12443         appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
12444                                           fmtId(oprinfo->dobj.namespace->dobj.name),
12445                                           oprid->data);
12446
12447         appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
12448                                           fmtId(oprinfo->dobj.namespace->dobj.name),
12449                                           oprinfo->dobj.name, details->data);
12450
12451         if (dopt->binary_upgrade)
12452                 binary_upgrade_extension_member(q, &oprinfo->dobj,
12453                                                                                 "OPERATOR", oprid->data,
12454                                                                                 oprinfo->dobj.namespace->dobj.name);
12455
12456         if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12457                 ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
12458                                          ARCHIVE_OPTS(.tag = oprinfo->dobj.name,
12459                                                                   .namespace = oprinfo->dobj.namespace->dobj.name,
12460                                                                   .owner = oprinfo->rolname,
12461                                                                   .description = "OPERATOR",
12462                                                                   .section = SECTION_PRE_DATA,
12463                                                                   .createStmt = q->data,
12464                                                                   .dropStmt = delq->data));
12465
12466         /* Dump Operator Comments */
12467         if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12468                 dumpComment(fout, "OPERATOR", oprid->data,
12469                                         oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
12470                                         oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
12471
12472         PQclear(res);
12473
12474         destroyPQExpBuffer(query);
12475         destroyPQExpBuffer(q);
12476         destroyPQExpBuffer(delq);
12477         destroyPQExpBuffer(oprid);
12478         destroyPQExpBuffer(details);
12479 }
12480
12481 /*
12482  * Convert a function reference obtained from pg_operator
12483  *
12484  * Returns allocated string of what to print, or NULL if function references
12485  * is InvalidOid. Returned string is expected to be free'd by the caller.
12486  *
12487  * The input is a REGPROCEDURE display; we have to strip the argument-types
12488  * part.
12489  */
12490 static char *
12491 convertRegProcReference(Archive *fout, const char *proc)
12492 {
12493         char       *name;
12494         char       *paren;
12495         bool            inquote;
12496
12497         /* In all cases "-" means a null reference */
12498         if (strcmp(proc, "-") == 0)
12499                 return NULL;
12500
12501         name = pg_strdup(proc);
12502         /* find non-double-quoted left paren */
12503         inquote = false;
12504         for (paren = name; *paren; paren++)
12505         {
12506                 if (*paren == '(' && !inquote)
12507                 {
12508                         *paren = '\0';
12509                         break;
12510                 }
12511                 if (*paren == '"')
12512                         inquote = !inquote;
12513         }
12514         return name;
12515 }
12516
12517 /*
12518  * getFormattedOperatorName - retrieve the operator name for the
12519  * given operator OID (presented in string form).
12520  *
12521  * Returns an allocated string, or NULL if the given OID is invalid.
12522  * Caller is responsible for free'ing result string.
12523  *
12524  * What we produce has the format "OPERATOR(schema.oprname)".  This is only
12525  * useful in commands where the operator's argument types can be inferred from
12526  * context.  We always schema-qualify the name, though.  The predecessor to
12527  * this code tried to skip the schema qualification if possible, but that led
12528  * to wrong results in corner cases, such as if an operator and its negator
12529  * are in different schemas.
12530  */
12531 static char *
12532 getFormattedOperatorName(Archive *fout, const char *oproid)
12533 {
12534         OprInfo    *oprInfo;
12535
12536         /* In all cases "0" means a null reference */
12537         if (strcmp(oproid, "0") == 0)
12538                 return NULL;
12539
12540         oprInfo = findOprByOid(atooid(oproid));
12541         if (oprInfo == NULL)
12542         {
12543                 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
12544                                   oproid);
12545                 return NULL;
12546         }
12547
12548         return psprintf("OPERATOR(%s.%s)",
12549                                         fmtId(oprInfo->dobj.namespace->dobj.name),
12550                                         oprInfo->dobj.name);
12551 }
12552
12553 /*
12554  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
12555  *
12556  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
12557  * argument lists of these functions are predetermined.  Note that the
12558  * caller should ensure we are in the proper schema, because the results
12559  * are search path dependent!
12560  */
12561 static char *
12562 convertTSFunction(Archive *fout, Oid funcOid)
12563 {
12564         char       *result;
12565         char            query[128];
12566         PGresult   *res;
12567
12568         snprintf(query, sizeof(query),
12569                          "SELECT '%u'::pg_catalog.regproc", funcOid);
12570         res = ExecuteSqlQueryForSingleRow(fout, query);
12571
12572         result = pg_strdup(PQgetvalue(res, 0, 0));
12573
12574         PQclear(res);
12575
12576         return result;
12577 }
12578
12579 /*
12580  * dumpAccessMethod
12581  *        write out a single access method definition
12582  */
12583 static void
12584 dumpAccessMethod(Archive *fout, AccessMethodInfo *aminfo)
12585 {
12586         DumpOptions *dopt = fout->dopt;
12587         PQExpBuffer q;
12588         PQExpBuffer delq;
12589         char       *qamname;
12590
12591         /* Skip if not to be dumped */
12592         if (!aminfo->dobj.dump || dopt->dataOnly)
12593                 return;
12594
12595         q = createPQExpBuffer();
12596         delq = createPQExpBuffer();
12597
12598         qamname = pg_strdup(fmtId(aminfo->dobj.name));
12599
12600         appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
12601
12602         switch (aminfo->amtype)
12603         {
12604                 case AMTYPE_INDEX:
12605                         appendPQExpBuffer(q, "TYPE INDEX ");
12606                         break;
12607                 default:
12608                         write_msg(NULL, "WARNING: invalid type \"%c\" of access method \"%s\"\n",
12609                                           aminfo->amtype, qamname);
12610                         destroyPQExpBuffer(q);
12611                         destroyPQExpBuffer(delq);
12612                         free(qamname);
12613                         return;
12614         }
12615
12616         appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
12617
12618         appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
12619                                           qamname);
12620
12621         if (dopt->binary_upgrade)
12622                 binary_upgrade_extension_member(q, &aminfo->dobj,
12623                                                                                 "ACCESS METHOD", qamname, NULL);
12624
12625         if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12626                 ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
12627                                          ARCHIVE_OPTS(.tag = aminfo->dobj.name,
12628                                                                   .description = "ACCESS METHOD",
12629                                                                   .section = SECTION_PRE_DATA,
12630                                                                   .createStmt = q->data,
12631                                                                   .dropStmt = delq->data));
12632
12633         /* Dump Access Method Comments */
12634         if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12635                 dumpComment(fout, "ACCESS METHOD", qamname,
12636                                         NULL, "",
12637                                         aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
12638
12639         destroyPQExpBuffer(q);
12640         destroyPQExpBuffer(delq);
12641         free(qamname);
12642 }
12643
12644 /*
12645  * dumpOpclass
12646  *        write out a single operator class definition
12647  */
12648 static void
12649 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
12650 {
12651         DumpOptions *dopt = fout->dopt;
12652         PQExpBuffer query;
12653         PQExpBuffer q;
12654         PQExpBuffer delq;
12655         PQExpBuffer nameusing;
12656         PGresult   *res;
12657         int                     ntups;
12658         int                     i_opcintype;
12659         int                     i_opckeytype;
12660         int                     i_opcdefault;
12661         int                     i_opcfamily;
12662         int                     i_opcfamilyname;
12663         int                     i_opcfamilynsp;
12664         int                     i_amname;
12665         int                     i_amopstrategy;
12666         int                     i_amopreqcheck;
12667         int                     i_amopopr;
12668         int                     i_sortfamily;
12669         int                     i_sortfamilynsp;
12670         int                     i_amprocnum;
12671         int                     i_amproc;
12672         int                     i_amproclefttype;
12673         int                     i_amprocrighttype;
12674         char       *opcintype;
12675         char       *opckeytype;
12676         char       *opcdefault;
12677         char       *opcfamily;
12678         char       *opcfamilyname;
12679         char       *opcfamilynsp;
12680         char       *amname;
12681         char       *amopstrategy;
12682         char       *amopreqcheck;
12683         char       *amopopr;
12684         char       *sortfamily;
12685         char       *sortfamilynsp;
12686         char       *amprocnum;
12687         char       *amproc;
12688         char       *amproclefttype;
12689         char       *amprocrighttype;
12690         bool            needComma;
12691         int                     i;
12692
12693         /* Skip if not to be dumped */
12694         if (!opcinfo->dobj.dump || dopt->dataOnly)
12695                 return;
12696
12697         query = createPQExpBuffer();
12698         q = createPQExpBuffer();
12699         delq = createPQExpBuffer();
12700         nameusing = createPQExpBuffer();
12701
12702         /* Get additional fields from the pg_opclass row */
12703         if (fout->remoteVersion >= 80300)
12704         {
12705                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
12706                                                   "opckeytype::pg_catalog.regtype, "
12707                                                   "opcdefault, opcfamily, "
12708                                                   "opfname AS opcfamilyname, "
12709                                                   "nspname AS opcfamilynsp, "
12710                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
12711                                                   "FROM pg_catalog.pg_opclass c "
12712                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
12713                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12714                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
12715                                                   opcinfo->dobj.catId.oid);
12716         }
12717         else
12718         {
12719                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
12720                                                   "opckeytype::pg_catalog.regtype, "
12721                                                   "opcdefault, NULL AS opcfamily, "
12722                                                   "NULL AS opcfamilyname, "
12723                                                   "NULL AS opcfamilynsp, "
12724                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
12725                                                   "FROM pg_catalog.pg_opclass "
12726                                                   "WHERE oid = '%u'::pg_catalog.oid",
12727                                                   opcinfo->dobj.catId.oid);
12728         }
12729
12730         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12731
12732         i_opcintype = PQfnumber(res, "opcintype");
12733         i_opckeytype = PQfnumber(res, "opckeytype");
12734         i_opcdefault = PQfnumber(res, "opcdefault");
12735         i_opcfamily = PQfnumber(res, "opcfamily");
12736         i_opcfamilyname = PQfnumber(res, "opcfamilyname");
12737         i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
12738         i_amname = PQfnumber(res, "amname");
12739
12740         /* opcintype may still be needed after we PQclear res */
12741         opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
12742         opckeytype = PQgetvalue(res, 0, i_opckeytype);
12743         opcdefault = PQgetvalue(res, 0, i_opcdefault);
12744         /* opcfamily will still be needed after we PQclear res */
12745         opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
12746         opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
12747         opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
12748         /* amname will still be needed after we PQclear res */
12749         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
12750
12751         appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
12752                                           fmtQualifiedDumpable(opcinfo));
12753         appendPQExpBuffer(delq, " USING %s;\n",
12754                                           fmtId(amname));
12755
12756         /* Build the fixed portion of the CREATE command */
12757         appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
12758                                           fmtQualifiedDumpable(opcinfo));
12759         if (strcmp(opcdefault, "t") == 0)
12760                 appendPQExpBufferStr(q, "DEFAULT ");
12761         appendPQExpBuffer(q, "FOR TYPE %s USING %s",
12762                                           opcintype,
12763                                           fmtId(amname));
12764         if (strlen(opcfamilyname) > 0)
12765         {
12766                 appendPQExpBufferStr(q, " FAMILY ");
12767                 appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
12768                 appendPQExpBufferStr(q, fmtId(opcfamilyname));
12769         }
12770         appendPQExpBufferStr(q, " AS\n    ");
12771
12772         needComma = false;
12773
12774         if (strcmp(opckeytype, "-") != 0)
12775         {
12776                 appendPQExpBuffer(q, "STORAGE %s",
12777                                                   opckeytype);
12778                 needComma = true;
12779         }
12780
12781         PQclear(res);
12782
12783         /*
12784          * Now fetch and print the OPERATOR entries (pg_amop rows).
12785          *
12786          * Print only those opfamily members that are tied to the opclass by
12787          * pg_depend entries.
12788          *
12789          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
12790          * older server's opclass in which it is used.  This is to avoid
12791          * hard-to-detect breakage if a newer pg_dump is used to dump from an
12792          * older server and then reload into that old version.  This can go away
12793          * once 8.3 is so old as to not be of interest to anyone.
12794          */
12795         resetPQExpBuffer(query);
12796
12797         if (fout->remoteVersion >= 90100)
12798         {
12799                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12800                                                   "amopopr::pg_catalog.regoperator, "
12801                                                   "opfname AS sortfamily, "
12802                                                   "nspname AS sortfamilynsp "
12803                                                   "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
12804                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
12805                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
12806                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12807                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12808                                                   "AND refobjid = '%u'::pg_catalog.oid "
12809                                                   "AND amopfamily = '%s'::pg_catalog.oid "
12810                                                   "ORDER BY amopstrategy",
12811                                                   opcinfo->dobj.catId.oid,
12812                                                   opcfamily);
12813         }
12814         else if (fout->remoteVersion >= 80400)
12815         {
12816                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
12817                                                   "amopopr::pg_catalog.regoperator, "
12818                                                   "NULL AS sortfamily, "
12819                                                   "NULL AS sortfamilynsp "
12820                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12821                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12822                                                   "AND refobjid = '%u'::pg_catalog.oid "
12823                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12824                                                   "AND objid = ao.oid "
12825                                                   "ORDER BY amopstrategy",
12826                                                   opcinfo->dobj.catId.oid);
12827         }
12828         else if (fout->remoteVersion >= 80300)
12829         {
12830                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
12831                                                   "amopopr::pg_catalog.regoperator, "
12832                                                   "NULL AS sortfamily, "
12833                                                   "NULL AS sortfamilynsp "
12834                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
12835                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12836                                                   "AND refobjid = '%u'::pg_catalog.oid "
12837                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
12838                                                   "AND objid = ao.oid "
12839                                                   "ORDER BY amopstrategy",
12840                                                   opcinfo->dobj.catId.oid);
12841         }
12842         else
12843         {
12844                 /*
12845                  * Here, we print all entries since there are no opfamilies and hence
12846                  * no loose operators to worry about.
12847                  */
12848                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
12849                                                   "amopopr::pg_catalog.regoperator, "
12850                                                   "NULL AS sortfamily, "
12851                                                   "NULL AS sortfamilynsp "
12852                                                   "FROM pg_catalog.pg_amop "
12853                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
12854                                                   "ORDER BY amopstrategy",
12855                                                   opcinfo->dobj.catId.oid);
12856         }
12857
12858         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12859
12860         ntups = PQntuples(res);
12861
12862         i_amopstrategy = PQfnumber(res, "amopstrategy");
12863         i_amopreqcheck = PQfnumber(res, "amopreqcheck");
12864         i_amopopr = PQfnumber(res, "amopopr");
12865         i_sortfamily = PQfnumber(res, "sortfamily");
12866         i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
12867
12868         for (i = 0; i < ntups; i++)
12869         {
12870                 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
12871                 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
12872                 amopopr = PQgetvalue(res, i, i_amopopr);
12873                 sortfamily = PQgetvalue(res, i, i_sortfamily);
12874                 sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
12875
12876                 if (needComma)
12877                         appendPQExpBufferStr(q, " ,\n    ");
12878
12879                 appendPQExpBuffer(q, "OPERATOR %s %s",
12880                                                   amopstrategy, amopopr);
12881
12882                 if (strlen(sortfamily) > 0)
12883                 {
12884                         appendPQExpBufferStr(q, " FOR ORDER BY ");
12885                         appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
12886                         appendPQExpBufferStr(q, fmtId(sortfamily));
12887                 }
12888
12889                 if (strcmp(amopreqcheck, "t") == 0)
12890                         appendPQExpBufferStr(q, " RECHECK");
12891
12892                 needComma = true;
12893         }
12894
12895         PQclear(res);
12896
12897         /*
12898          * Now fetch and print the FUNCTION entries (pg_amproc rows).
12899          *
12900          * Print only those opfamily members that are tied to the opclass by
12901          * pg_depend entries.
12902          *
12903          * We print the amproclefttype/amprocrighttype even though in most cases
12904          * the backend could deduce the right values, because of the corner case
12905          * of a btree sort support function for a cross-type comparison.  That's
12906          * only allowed in 9.2 and later, but for simplicity print them in all
12907          * versions that have the columns.
12908          */
12909         resetPQExpBuffer(query);
12910
12911         if (fout->remoteVersion >= 80300)
12912         {
12913                 appendPQExpBuffer(query, "SELECT amprocnum, "
12914                                                   "amproc::pg_catalog.regprocedure, "
12915                                                   "amproclefttype::pg_catalog.regtype, "
12916                                                   "amprocrighttype::pg_catalog.regtype "
12917                                                   "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
12918                                                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
12919                                                   "AND refobjid = '%u'::pg_catalog.oid "
12920                                                   "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
12921                                                   "AND objid = ap.oid "
12922                                                   "ORDER BY amprocnum",
12923                                                   opcinfo->dobj.catId.oid);
12924         }
12925         else
12926         {
12927                 appendPQExpBuffer(query, "SELECT amprocnum, "
12928                                                   "amproc::pg_catalog.regprocedure, "
12929                                                   "'' AS amproclefttype, "
12930                                                   "'' AS amprocrighttype "
12931                                                   "FROM pg_catalog.pg_amproc "
12932                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
12933                                                   "ORDER BY amprocnum",
12934                                                   opcinfo->dobj.catId.oid);
12935         }
12936
12937         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12938
12939         ntups = PQntuples(res);
12940
12941         i_amprocnum = PQfnumber(res, "amprocnum");
12942         i_amproc = PQfnumber(res, "amproc");
12943         i_amproclefttype = PQfnumber(res, "amproclefttype");
12944         i_amprocrighttype = PQfnumber(res, "amprocrighttype");
12945
12946         for (i = 0; i < ntups; i++)
12947         {
12948                 amprocnum = PQgetvalue(res, i, i_amprocnum);
12949                 amproc = PQgetvalue(res, i, i_amproc);
12950                 amproclefttype = PQgetvalue(res, i, i_amproclefttype);
12951                 amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
12952
12953                 if (needComma)
12954                         appendPQExpBufferStr(q, " ,\n    ");
12955
12956                 appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
12957
12958                 if (*amproclefttype && *amprocrighttype)
12959                         appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
12960
12961                 appendPQExpBuffer(q, " %s", amproc);
12962
12963                 needComma = true;
12964         }
12965
12966         PQclear(res);
12967
12968         /*
12969          * If needComma is still false it means we haven't added anything after
12970          * the AS keyword.  To avoid printing broken SQL, append a dummy STORAGE
12971          * clause with the same datatype.  This isn't sanctioned by the
12972          * documentation, but actually DefineOpClass will treat it as a no-op.
12973          */
12974         if (!needComma)
12975                 appendPQExpBuffer(q, "STORAGE %s", opcintype);
12976
12977         appendPQExpBufferStr(q, ";\n");
12978
12979         appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
12980         appendPQExpBuffer(nameusing, " USING %s",
12981                                           fmtId(amname));
12982
12983         if (dopt->binary_upgrade)
12984                 binary_upgrade_extension_member(q, &opcinfo->dobj,
12985                                                                                 "OPERATOR CLASS", nameusing->data,
12986                                                                                 opcinfo->dobj.namespace->dobj.name);
12987
12988         if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12989                 ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
12990                                          ARCHIVE_OPTS(.tag = opcinfo->dobj.name,
12991                                                                   .namespace = opcinfo->dobj.namespace->dobj.name,
12992                                                                   .owner = opcinfo->rolname,
12993                                                                   .description = "OPERATOR CLASS",
12994                                                                   .section = SECTION_PRE_DATA,
12995                                                                   .createStmt = q->data,
12996                                                                   .dropStmt = delq->data));
12997
12998         /* Dump Operator Class Comments */
12999         if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13000                 dumpComment(fout, "OPERATOR CLASS", nameusing->data,
13001                                         opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
13002                                         opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
13003
13004         free(opcintype);
13005         free(opcfamily);
13006         free(amname);
13007         destroyPQExpBuffer(query);
13008         destroyPQExpBuffer(q);
13009         destroyPQExpBuffer(delq);
13010         destroyPQExpBuffer(nameusing);
13011 }
13012
13013 /*
13014  * dumpOpfamily
13015  *        write out a single operator family definition
13016  *
13017  * Note: this also dumps any "loose" operator members that aren't bound to a
13018  * specific opclass within the opfamily.
13019  */
13020 static void
13021 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
13022 {
13023         DumpOptions *dopt = fout->dopt;
13024         PQExpBuffer query;
13025         PQExpBuffer q;
13026         PQExpBuffer delq;
13027         PQExpBuffer nameusing;
13028         PGresult   *res;
13029         PGresult   *res_ops;
13030         PGresult   *res_procs;
13031         int                     ntups;
13032         int                     i_amname;
13033         int                     i_amopstrategy;
13034         int                     i_amopreqcheck;
13035         int                     i_amopopr;
13036         int                     i_sortfamily;
13037         int                     i_sortfamilynsp;
13038         int                     i_amprocnum;
13039         int                     i_amproc;
13040         int                     i_amproclefttype;
13041         int                     i_amprocrighttype;
13042         char       *amname;
13043         char       *amopstrategy;
13044         char       *amopreqcheck;
13045         char       *amopopr;
13046         char       *sortfamily;
13047         char       *sortfamilynsp;
13048         char       *amprocnum;
13049         char       *amproc;
13050         char       *amproclefttype;
13051         char       *amprocrighttype;
13052         bool            needComma;
13053         int                     i;
13054
13055         /* Skip if not to be dumped */
13056         if (!opfinfo->dobj.dump || dopt->dataOnly)
13057                 return;
13058
13059         query = createPQExpBuffer();
13060         q = createPQExpBuffer();
13061         delq = createPQExpBuffer();
13062         nameusing = createPQExpBuffer();
13063
13064         /*
13065          * Fetch only those opfamily members that are tied directly to the
13066          * opfamily by pg_depend entries.
13067          *
13068          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
13069          * older server's opclass in which it is used.  This is to avoid
13070          * hard-to-detect breakage if a newer pg_dump is used to dump from an
13071          * older server and then reload into that old version.  This can go away
13072          * once 8.3 is so old as to not be of interest to anyone.
13073          */
13074         if (fout->remoteVersion >= 90100)
13075         {
13076                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
13077                                                   "amopopr::pg_catalog.regoperator, "
13078                                                   "opfname AS sortfamily, "
13079                                                   "nspname AS sortfamilynsp "
13080                                                   "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
13081                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
13082                                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
13083                                                   "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
13084                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13085                                                   "AND refobjid = '%u'::pg_catalog.oid "
13086                                                   "AND amopfamily = '%u'::pg_catalog.oid "
13087                                                   "ORDER BY amopstrategy",
13088                                                   opfinfo->dobj.catId.oid,
13089                                                   opfinfo->dobj.catId.oid);
13090         }
13091         else if (fout->remoteVersion >= 80400)
13092         {
13093                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
13094                                                   "amopopr::pg_catalog.regoperator, "
13095                                                   "NULL AS sortfamily, "
13096                                                   "NULL AS sortfamilynsp "
13097                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
13098                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13099                                                   "AND refobjid = '%u'::pg_catalog.oid "
13100                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
13101                                                   "AND objid = ao.oid "
13102                                                   "ORDER BY amopstrategy",
13103                                                   opfinfo->dobj.catId.oid);
13104         }
13105         else
13106         {
13107                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
13108                                                   "amopopr::pg_catalog.regoperator, "
13109                                                   "NULL AS sortfamily, "
13110                                                   "NULL AS sortfamilynsp "
13111                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
13112                                                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13113                                                   "AND refobjid = '%u'::pg_catalog.oid "
13114                                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
13115                                                   "AND objid = ao.oid "
13116                                                   "ORDER BY amopstrategy",
13117                                                   opfinfo->dobj.catId.oid);
13118         }
13119
13120         res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13121
13122         resetPQExpBuffer(query);
13123
13124         appendPQExpBuffer(query, "SELECT amprocnum, "
13125                                           "amproc::pg_catalog.regprocedure, "
13126                                           "amproclefttype::pg_catalog.regtype, "
13127                                           "amprocrighttype::pg_catalog.regtype "
13128                                           "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
13129                                           "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13130                                           "AND refobjid = '%u'::pg_catalog.oid "
13131                                           "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
13132                                           "AND objid = ap.oid "
13133                                           "ORDER BY amprocnum",
13134                                           opfinfo->dobj.catId.oid);
13135
13136         res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13137
13138         /* Get additional fields from the pg_opfamily row */
13139         resetPQExpBuffer(query);
13140
13141         appendPQExpBuffer(query, "SELECT "
13142                                           "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
13143                                           "FROM pg_catalog.pg_opfamily "
13144                                           "WHERE oid = '%u'::pg_catalog.oid",
13145                                           opfinfo->dobj.catId.oid);
13146
13147         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13148
13149         i_amname = PQfnumber(res, "amname");
13150
13151         /* amname will still be needed after we PQclear res */
13152         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
13153
13154         appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
13155                                           fmtQualifiedDumpable(opfinfo));
13156         appendPQExpBuffer(delq, " USING %s;\n",
13157                                           fmtId(amname));
13158
13159         /* Build the fixed portion of the CREATE command */
13160         appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
13161                                           fmtQualifiedDumpable(opfinfo));
13162         appendPQExpBuffer(q, " USING %s;\n",
13163                                           fmtId(amname));
13164
13165         PQclear(res);
13166
13167         /* Do we need an ALTER to add loose members? */
13168         if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
13169         {
13170                 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
13171                                                   fmtQualifiedDumpable(opfinfo));
13172                 appendPQExpBuffer(q, " USING %s ADD\n    ",
13173                                                   fmtId(amname));
13174
13175                 needComma = false;
13176
13177                 /*
13178                  * Now fetch and print the OPERATOR entries (pg_amop rows).
13179                  */
13180                 ntups = PQntuples(res_ops);
13181
13182                 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
13183                 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
13184                 i_amopopr = PQfnumber(res_ops, "amopopr");
13185                 i_sortfamily = PQfnumber(res_ops, "sortfamily");
13186                 i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
13187
13188                 for (i = 0; i < ntups; i++)
13189                 {
13190                         amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
13191                         amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
13192                         amopopr = PQgetvalue(res_ops, i, i_amopopr);
13193                         sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
13194                         sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
13195
13196                         if (needComma)
13197                                 appendPQExpBufferStr(q, " ,\n    ");
13198
13199                         appendPQExpBuffer(q, "OPERATOR %s %s",
13200                                                           amopstrategy, amopopr);
13201
13202                         if (strlen(sortfamily) > 0)
13203                         {
13204                                 appendPQExpBufferStr(q, " FOR ORDER BY ");
13205                                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
13206                                 appendPQExpBufferStr(q, fmtId(sortfamily));
13207                         }
13208
13209                         if (strcmp(amopreqcheck, "t") == 0)
13210                                 appendPQExpBufferStr(q, " RECHECK");
13211
13212                         needComma = true;
13213                 }
13214
13215                 /*
13216                  * Now fetch and print the FUNCTION entries (pg_amproc rows).
13217                  */
13218                 ntups = PQntuples(res_procs);
13219
13220                 i_amprocnum = PQfnumber(res_procs, "amprocnum");
13221                 i_amproc = PQfnumber(res_procs, "amproc");
13222                 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
13223                 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
13224
13225                 for (i = 0; i < ntups; i++)
13226                 {
13227                         amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
13228                         amproc = PQgetvalue(res_procs, i, i_amproc);
13229                         amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
13230                         amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
13231
13232                         if (needComma)
13233                                 appendPQExpBufferStr(q, " ,\n    ");
13234
13235                         appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
13236                                                           amprocnum, amproclefttype, amprocrighttype,
13237                                                           amproc);
13238
13239                         needComma = true;
13240                 }
13241
13242                 appendPQExpBufferStr(q, ";\n");
13243         }
13244
13245         appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
13246         appendPQExpBuffer(nameusing, " USING %s",
13247                                           fmtId(amname));
13248
13249         if (dopt->binary_upgrade)
13250                 binary_upgrade_extension_member(q, &opfinfo->dobj,
13251                                                                                 "OPERATOR FAMILY", nameusing->data,
13252                                                                                 opfinfo->dobj.namespace->dobj.name);
13253
13254         if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13255                 ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
13256                                          ARCHIVE_OPTS(.tag = opfinfo->dobj.name,
13257                                                                   .namespace = opfinfo->dobj.namespace->dobj.name,
13258                                                                   .owner = opfinfo->rolname,
13259                                                                   .description = "OPERATOR FAMILY",
13260                                                                   .section = SECTION_PRE_DATA,
13261                                                                   .createStmt = q->data,
13262                                                                   .dropStmt = delq->data));
13263
13264         /* Dump Operator Family Comments */
13265         if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13266                 dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
13267                                         opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
13268                                         opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
13269
13270         free(amname);
13271         PQclear(res_ops);
13272         PQclear(res_procs);
13273         destroyPQExpBuffer(query);
13274         destroyPQExpBuffer(q);
13275         destroyPQExpBuffer(delq);
13276         destroyPQExpBuffer(nameusing);
13277 }
13278
13279 /*
13280  * dumpCollation
13281  *        write out a single collation definition
13282  */
13283 static void
13284 dumpCollation(Archive *fout, CollInfo *collinfo)
13285 {
13286         DumpOptions *dopt = fout->dopt;
13287         PQExpBuffer query;
13288         PQExpBuffer q;
13289         PQExpBuffer delq;
13290         char       *qcollname;
13291         PGresult   *res;
13292         int                     i_collprovider;
13293         int                     i_collcollate;
13294         int                     i_collctype;
13295         const char *collprovider;
13296         const char *collcollate;
13297         const char *collctype;
13298
13299         /* Skip if not to be dumped */
13300         if (!collinfo->dobj.dump || dopt->dataOnly)
13301                 return;
13302
13303         query = createPQExpBuffer();
13304         q = createPQExpBuffer();
13305         delq = createPQExpBuffer();
13306
13307         qcollname = pg_strdup(fmtId(collinfo->dobj.name));
13308
13309         /* Get collation-specific details */
13310         if (fout->remoteVersion >= 100000)
13311                 appendPQExpBuffer(query, "SELECT "
13312                                                   "collprovider, "
13313                                                   "collcollate, "
13314                                                   "collctype, "
13315                                                   "collversion "
13316                                                   "FROM pg_catalog.pg_collation c "
13317                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
13318                                                   collinfo->dobj.catId.oid);
13319         else
13320                 appendPQExpBuffer(query, "SELECT "
13321                                                   "'c' AS collprovider, "
13322                                                   "collcollate, "
13323                                                   "collctype, "
13324                                                   "NULL AS collversion "
13325                                                   "FROM pg_catalog.pg_collation c "
13326                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
13327                                                   collinfo->dobj.catId.oid);
13328
13329         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13330
13331         i_collprovider = PQfnumber(res, "collprovider");
13332         i_collcollate = PQfnumber(res, "collcollate");
13333         i_collctype = PQfnumber(res, "collctype");
13334
13335         collprovider = PQgetvalue(res, 0, i_collprovider);
13336         collcollate = PQgetvalue(res, 0, i_collcollate);
13337         collctype = PQgetvalue(res, 0, i_collctype);
13338
13339         appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
13340                                           fmtQualifiedDumpable(collinfo));
13341
13342         appendPQExpBuffer(q, "CREATE COLLATION %s (",
13343                                           fmtQualifiedDumpable(collinfo));
13344
13345         appendPQExpBufferStr(q, "provider = ");
13346         if (collprovider[0] == 'c')
13347                 appendPQExpBufferStr(q, "libc");
13348         else if (collprovider[0] == 'i')
13349                 appendPQExpBufferStr(q, "icu");
13350         else if (collprovider[0] == 'd')
13351                 /* to allow dumping pg_catalog; not accepted on input */
13352                 appendPQExpBufferStr(q, "default");
13353         else
13354                 exit_horribly(NULL,
13355                                           "unrecognized collation provider: %s\n",
13356                                           collprovider);
13357
13358         if (strcmp(collcollate, collctype) == 0)
13359         {
13360                 appendPQExpBufferStr(q, ", locale = ");
13361                 appendStringLiteralAH(q, collcollate, fout);
13362         }
13363         else
13364         {
13365                 appendPQExpBufferStr(q, ", lc_collate = ");
13366                 appendStringLiteralAH(q, collcollate, fout);
13367                 appendPQExpBufferStr(q, ", lc_ctype = ");
13368                 appendStringLiteralAH(q, collctype, fout);
13369         }
13370
13371         /*
13372          * For binary upgrade, carry over the collation version.  For normal
13373          * dump/restore, omit the version, so that it is computed upon restore.
13374          */
13375         if (dopt->binary_upgrade)
13376         {
13377                 int                     i_collversion;
13378
13379                 i_collversion = PQfnumber(res, "collversion");
13380                 if (!PQgetisnull(res, 0, i_collversion))
13381                 {
13382                         appendPQExpBufferStr(q, ", version = ");
13383                         appendStringLiteralAH(q,
13384                                                                   PQgetvalue(res, 0, i_collversion),
13385                                                                   fout);
13386                 }
13387         }
13388
13389         appendPQExpBufferStr(q, ");\n");
13390
13391         if (dopt->binary_upgrade)
13392                 binary_upgrade_extension_member(q, &collinfo->dobj,
13393                                                                                 "COLLATION", qcollname,
13394                                                                                 collinfo->dobj.namespace->dobj.name);
13395
13396         if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13397                 ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
13398                                          ARCHIVE_OPTS(.tag = collinfo->dobj.name,
13399                                                                   .namespace = collinfo->dobj.namespace->dobj.name,
13400                                                                   .owner = collinfo->rolname,
13401                                                                   .description = "COLLATION",
13402                                                                   .section = SECTION_PRE_DATA,
13403                                                                   .createStmt = q->data,
13404                                                                   .dropStmt = delq->data));
13405
13406         /* Dump Collation Comments */
13407         if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13408                 dumpComment(fout, "COLLATION", qcollname,
13409                                         collinfo->dobj.namespace->dobj.name, collinfo->rolname,
13410                                         collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
13411
13412         PQclear(res);
13413
13414         destroyPQExpBuffer(query);
13415         destroyPQExpBuffer(q);
13416         destroyPQExpBuffer(delq);
13417         free(qcollname);
13418 }
13419
13420 /*
13421  * dumpConversion
13422  *        write out a single conversion definition
13423  */
13424 static void
13425 dumpConversion(Archive *fout, ConvInfo *convinfo)
13426 {
13427         DumpOptions *dopt = fout->dopt;
13428         PQExpBuffer query;
13429         PQExpBuffer q;
13430         PQExpBuffer delq;
13431         char       *qconvname;
13432         PGresult   *res;
13433         int                     i_conforencoding;
13434         int                     i_contoencoding;
13435         int                     i_conproc;
13436         int                     i_condefault;
13437         const char *conforencoding;
13438         const char *contoencoding;
13439         const char *conproc;
13440         bool            condefault;
13441
13442         /* Skip if not to be dumped */
13443         if (!convinfo->dobj.dump || dopt->dataOnly)
13444                 return;
13445
13446         query = createPQExpBuffer();
13447         q = createPQExpBuffer();
13448         delq = createPQExpBuffer();
13449
13450         qconvname = pg_strdup(fmtId(convinfo->dobj.name));
13451
13452         /* Get conversion-specific details */
13453         appendPQExpBuffer(query, "SELECT "
13454                                           "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
13455                                           "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
13456                                           "conproc, condefault "
13457                                           "FROM pg_catalog.pg_conversion c "
13458                                           "WHERE c.oid = '%u'::pg_catalog.oid",
13459                                           convinfo->dobj.catId.oid);
13460
13461         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13462
13463         i_conforencoding = PQfnumber(res, "conforencoding");
13464         i_contoencoding = PQfnumber(res, "contoencoding");
13465         i_conproc = PQfnumber(res, "conproc");
13466         i_condefault = PQfnumber(res, "condefault");
13467
13468         conforencoding = PQgetvalue(res, 0, i_conforencoding);
13469         contoencoding = PQgetvalue(res, 0, i_contoencoding);
13470         conproc = PQgetvalue(res, 0, i_conproc);
13471         condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
13472
13473         appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
13474                                           fmtQualifiedDumpable(convinfo));
13475
13476         appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
13477                                           (condefault) ? "DEFAULT " : "",
13478                                           fmtQualifiedDumpable(convinfo));
13479         appendStringLiteralAH(q, conforencoding, fout);
13480         appendPQExpBufferStr(q, " TO ");
13481         appendStringLiteralAH(q, contoencoding, fout);
13482         /* regproc output is already sufficiently quoted */
13483         appendPQExpBuffer(q, " FROM %s;\n", conproc);
13484
13485         if (dopt->binary_upgrade)
13486                 binary_upgrade_extension_member(q, &convinfo->dobj,
13487                                                                                 "CONVERSION", qconvname,
13488                                                                                 convinfo->dobj.namespace->dobj.name);
13489
13490         if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13491                 ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
13492                                          ARCHIVE_OPTS(.tag = convinfo->dobj.name,
13493                                                                   .namespace = convinfo->dobj.namespace->dobj.name,
13494                                                                   .owner = convinfo->rolname,
13495                                                                   .description = "CONVERSION",
13496                                                                   .section = SECTION_PRE_DATA,
13497                                                                   .createStmt = q->data,
13498                                                                   .dropStmt = delq->data));
13499
13500         /* Dump Conversion Comments */
13501         if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13502                 dumpComment(fout, "CONVERSION", qconvname,
13503                                         convinfo->dobj.namespace->dobj.name, convinfo->rolname,
13504                                         convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
13505
13506         PQclear(res);
13507
13508         destroyPQExpBuffer(query);
13509         destroyPQExpBuffer(q);
13510         destroyPQExpBuffer(delq);
13511         free(qconvname);
13512 }
13513
13514 /*
13515  * format_aggregate_signature: generate aggregate name and argument list
13516  *
13517  * The argument type names are qualified if needed.  The aggregate name
13518  * is never qualified.
13519  */
13520 static char *
13521 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
13522 {
13523         PQExpBufferData buf;
13524         int                     j;
13525
13526         initPQExpBuffer(&buf);
13527         if (honor_quotes)
13528                 appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
13529         else
13530                 appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
13531
13532         if (agginfo->aggfn.nargs == 0)
13533                 appendPQExpBuffer(&buf, "(*)");
13534         else
13535         {
13536                 appendPQExpBufferChar(&buf, '(');
13537                 for (j = 0; j < agginfo->aggfn.nargs; j++)
13538                 {
13539                         char       *typname;
13540
13541                         typname = getFormattedTypeName(fout, agginfo->aggfn.argtypes[j],
13542                                                                                    zeroAsOpaque);
13543
13544                         appendPQExpBuffer(&buf, "%s%s",
13545                                                           (j > 0) ? ", " : "",
13546                                                           typname);
13547                         free(typname);
13548                 }
13549                 appendPQExpBufferChar(&buf, ')');
13550         }
13551         return buf.data;
13552 }
13553
13554 /*
13555  * dumpAgg
13556  *        write out a single aggregate definition
13557  */
13558 static void
13559 dumpAgg(Archive *fout, AggInfo *agginfo)
13560 {
13561         DumpOptions *dopt = fout->dopt;
13562         PQExpBuffer query;
13563         PQExpBuffer q;
13564         PQExpBuffer delq;
13565         PQExpBuffer details;
13566         char       *aggsig;                     /* identity signature */
13567         char       *aggfullsig = NULL;  /* full signature */
13568         char       *aggsig_tag;
13569         PGresult   *res;
13570         int                     i_aggtransfn;
13571         int                     i_aggfinalfn;
13572         int                     i_aggcombinefn;
13573         int                     i_aggserialfn;
13574         int                     i_aggdeserialfn;
13575         int                     i_aggmtransfn;
13576         int                     i_aggminvtransfn;
13577         int                     i_aggmfinalfn;
13578         int                     i_aggfinalextra;
13579         int                     i_aggmfinalextra;
13580         int                     i_aggfinalmodify;
13581         int                     i_aggmfinalmodify;
13582         int                     i_aggsortop;
13583         int                     i_aggkind;
13584         int                     i_aggtranstype;
13585         int                     i_aggtransspace;
13586         int                     i_aggmtranstype;
13587         int                     i_aggmtransspace;
13588         int                     i_agginitval;
13589         int                     i_aggminitval;
13590         int                     i_convertok;
13591         int                     i_proparallel;
13592         const char *aggtransfn;
13593         const char *aggfinalfn;
13594         const char *aggcombinefn;
13595         const char *aggserialfn;
13596         const char *aggdeserialfn;
13597         const char *aggmtransfn;
13598         const char *aggminvtransfn;
13599         const char *aggmfinalfn;
13600         bool            aggfinalextra;
13601         bool            aggmfinalextra;
13602         char            aggfinalmodify;
13603         char            aggmfinalmodify;
13604         const char *aggsortop;
13605         char       *aggsortconvop;
13606         char            aggkind;
13607         const char *aggtranstype;
13608         const char *aggtransspace;
13609         const char *aggmtranstype;
13610         const char *aggmtransspace;
13611         const char *agginitval;
13612         const char *aggminitval;
13613         bool            convertok;
13614         const char *proparallel;
13615         char            defaultfinalmodify;
13616
13617         /* Skip if not to be dumped */
13618         if (!agginfo->aggfn.dobj.dump || dopt->dataOnly)
13619                 return;
13620
13621         query = createPQExpBuffer();
13622         q = createPQExpBuffer();
13623         delq = createPQExpBuffer();
13624         details = createPQExpBuffer();
13625
13626         /* Get aggregate-specific details */
13627         if (fout->remoteVersion >= 110000)
13628         {
13629                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13630                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13631                                                   "aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
13632                                                   "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13633                                                   "aggfinalextra, aggmfinalextra, "
13634                                                   "aggfinalmodify, aggmfinalmodify, "
13635                                                   "aggsortop, "
13636                                                   "aggkind, "
13637                                                   "aggtransspace, agginitval, "
13638                                                   "aggmtransspace, aggminitval, "
13639                                                   "true AS convertok, "
13640                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13641                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs, "
13642                                                   "p.proparallel "
13643                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13644                                                   "WHERE a.aggfnoid = p.oid "
13645                                                   "AND p.oid = '%u'::pg_catalog.oid",
13646                                                   agginfo->aggfn.dobj.catId.oid);
13647         }
13648         else if (fout->remoteVersion >= 90600)
13649         {
13650                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13651                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13652                                                   "aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
13653                                                   "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13654                                                   "aggfinalextra, aggmfinalextra, "
13655                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13656                                                   "aggsortop, "
13657                                                   "aggkind, "
13658                                                   "aggtransspace, agginitval, "
13659                                                   "aggmtransspace, aggminitval, "
13660                                                   "true AS convertok, "
13661                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13662                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs, "
13663                                                   "p.proparallel "
13664                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13665                                                   "WHERE a.aggfnoid = p.oid "
13666                                                   "AND p.oid = '%u'::pg_catalog.oid",
13667                                                   agginfo->aggfn.dobj.catId.oid);
13668         }
13669         else if (fout->remoteVersion >= 90400)
13670         {
13671                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13672                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13673                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13674                                                   "'-' AS aggdeserialfn, aggmtransfn, aggminvtransfn, "
13675                                                   "aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13676                                                   "aggfinalextra, aggmfinalextra, "
13677                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13678                                                   "aggsortop, "
13679                                                   "aggkind, "
13680                                                   "aggtransspace, agginitval, "
13681                                                   "aggmtransspace, aggminitval, "
13682                                                   "true AS convertok, "
13683                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13684                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
13685                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13686                                                   "WHERE a.aggfnoid = p.oid "
13687                                                   "AND p.oid = '%u'::pg_catalog.oid",
13688                                                   agginfo->aggfn.dobj.catId.oid);
13689         }
13690         else if (fout->remoteVersion >= 80400)
13691         {
13692                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13693                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13694                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13695                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13696                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13697                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13698                                                   "false AS aggmfinalextra, "
13699                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13700                                                   "aggsortop, "
13701                                                   "'n' AS aggkind, "
13702                                                   "0 AS aggtransspace, agginitval, "
13703                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13704                                                   "true AS convertok, "
13705                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13706                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
13707                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13708                                                   "WHERE a.aggfnoid = p.oid "
13709                                                   "AND p.oid = '%u'::pg_catalog.oid",
13710                                                   agginfo->aggfn.dobj.catId.oid);
13711         }
13712         else if (fout->remoteVersion >= 80100)
13713         {
13714                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13715                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13716                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13717                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13718                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13719                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13720                                                   "false AS aggmfinalextra, "
13721                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13722                                                   "aggsortop, "
13723                                                   "'n' AS aggkind, "
13724                                                   "0 AS aggtransspace, agginitval, "
13725                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13726                                                   "true AS convertok "
13727                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13728                                                   "WHERE a.aggfnoid = p.oid "
13729                                                   "AND p.oid = '%u'::pg_catalog.oid",
13730                                                   agginfo->aggfn.dobj.catId.oid);
13731         }
13732         else
13733         {
13734                 appendPQExpBuffer(query, "SELECT aggtransfn, "
13735                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13736                                                   "'-' AS aggcombinefn, '-' AS aggserialfn, "
13737                                                   "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13738                                                   "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13739                                                   "0 AS aggmtranstype, false AS aggfinalextra, "
13740                                                   "false AS aggmfinalextra, "
13741                                                   "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13742                                                   "0 AS aggsortop, "
13743                                                   "'n' AS aggkind, "
13744                                                   "0 AS aggtransspace, agginitval, "
13745                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
13746                                                   "true AS convertok "
13747                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13748                                                   "WHERE a.aggfnoid = p.oid "
13749                                                   "AND p.oid = '%u'::pg_catalog.oid",
13750                                                   agginfo->aggfn.dobj.catId.oid);
13751         }
13752
13753         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13754
13755         i_aggtransfn = PQfnumber(res, "aggtransfn");
13756         i_aggfinalfn = PQfnumber(res, "aggfinalfn");
13757         i_aggcombinefn = PQfnumber(res, "aggcombinefn");
13758         i_aggserialfn = PQfnumber(res, "aggserialfn");
13759         i_aggdeserialfn = PQfnumber(res, "aggdeserialfn");
13760         i_aggmtransfn = PQfnumber(res, "aggmtransfn");
13761         i_aggminvtransfn = PQfnumber(res, "aggminvtransfn");
13762         i_aggmfinalfn = PQfnumber(res, "aggmfinalfn");
13763         i_aggfinalextra = PQfnumber(res, "aggfinalextra");
13764         i_aggmfinalextra = PQfnumber(res, "aggmfinalextra");
13765         i_aggfinalmodify = PQfnumber(res, "aggfinalmodify");
13766         i_aggmfinalmodify = PQfnumber(res, "aggmfinalmodify");
13767         i_aggsortop = PQfnumber(res, "aggsortop");
13768         i_aggkind = PQfnumber(res, "aggkind");
13769         i_aggtranstype = PQfnumber(res, "aggtranstype");
13770         i_aggtransspace = PQfnumber(res, "aggtransspace");
13771         i_aggmtranstype = PQfnumber(res, "aggmtranstype");
13772         i_aggmtransspace = PQfnumber(res, "aggmtransspace");
13773         i_agginitval = PQfnumber(res, "agginitval");
13774         i_aggminitval = PQfnumber(res, "aggminitval");
13775         i_convertok = PQfnumber(res, "convertok");
13776         i_proparallel = PQfnumber(res, "proparallel");
13777
13778         aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
13779         aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
13780         aggcombinefn = PQgetvalue(res, 0, i_aggcombinefn);
13781         aggserialfn = PQgetvalue(res, 0, i_aggserialfn);
13782         aggdeserialfn = PQgetvalue(res, 0, i_aggdeserialfn);
13783         aggmtransfn = PQgetvalue(res, 0, i_aggmtransfn);
13784         aggminvtransfn = PQgetvalue(res, 0, i_aggminvtransfn);
13785         aggmfinalfn = PQgetvalue(res, 0, i_aggmfinalfn);
13786         aggfinalextra = (PQgetvalue(res, 0, i_aggfinalextra)[0] == 't');
13787         aggmfinalextra = (PQgetvalue(res, 0, i_aggmfinalextra)[0] == 't');
13788         aggfinalmodify = PQgetvalue(res, 0, i_aggfinalmodify)[0];
13789         aggmfinalmodify = PQgetvalue(res, 0, i_aggmfinalmodify)[0];
13790         aggsortop = PQgetvalue(res, 0, i_aggsortop);
13791         aggkind = PQgetvalue(res, 0, i_aggkind)[0];
13792         aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
13793         aggtransspace = PQgetvalue(res, 0, i_aggtransspace);
13794         aggmtranstype = PQgetvalue(res, 0, i_aggmtranstype);
13795         aggmtransspace = PQgetvalue(res, 0, i_aggmtransspace);
13796         agginitval = PQgetvalue(res, 0, i_agginitval);
13797         aggminitval = PQgetvalue(res, 0, i_aggminitval);
13798         convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
13799
13800         if (fout->remoteVersion >= 80400)
13801         {
13802                 /* 8.4 or later; we rely on server-side code for most of the work */
13803                 char       *funcargs;
13804                 char       *funciargs;
13805
13806                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
13807                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
13808                 aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
13809                 aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
13810         }
13811         else
13812                 /* pre-8.4, do it ourselves */
13813                 aggsig = format_aggregate_signature(agginfo, fout, true);
13814
13815         aggsig_tag = format_aggregate_signature(agginfo, fout, false);
13816
13817         if (i_proparallel != -1)
13818                 proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
13819         else
13820                 proparallel = NULL;
13821
13822         if (!convertok)
13823         {
13824                 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
13825                                   aggsig);
13826
13827                 if (aggfullsig)
13828                         free(aggfullsig);
13829
13830                 free(aggsig);
13831
13832                 return;
13833         }
13834
13835         /* identify default modify flag for aggkind (must match DefineAggregate) */
13836         defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
13837         /* replace omitted flags for old versions */
13838         if (aggfinalmodify == '0')
13839                 aggfinalmodify = defaultfinalmodify;
13840         if (aggmfinalmodify == '0')
13841                 aggmfinalmodify = defaultfinalmodify;
13842
13843         /* regproc and regtype output is already sufficiently quoted */
13844         appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
13845                                           aggtransfn, aggtranstype);
13846
13847         if (strcmp(aggtransspace, "0") != 0)
13848         {
13849                 appendPQExpBuffer(details, ",\n    SSPACE = %s",
13850                                                   aggtransspace);
13851         }
13852
13853         if (!PQgetisnull(res, 0, i_agginitval))
13854         {
13855                 appendPQExpBufferStr(details, ",\n    INITCOND = ");
13856                 appendStringLiteralAH(details, agginitval, fout);
13857         }
13858
13859         if (strcmp(aggfinalfn, "-") != 0)
13860         {
13861                 appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
13862                                                   aggfinalfn);
13863                 if (aggfinalextra)
13864                         appendPQExpBufferStr(details, ",\n    FINALFUNC_EXTRA");
13865                 if (aggfinalmodify != defaultfinalmodify)
13866                 {
13867                         switch (aggfinalmodify)
13868                         {
13869                                 case AGGMODIFY_READ_ONLY:
13870                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_ONLY");
13871                                         break;
13872                                 case AGGMODIFY_SHAREABLE:
13873                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = SHAREABLE");
13874                                         break;
13875                                 case AGGMODIFY_READ_WRITE:
13876                                         appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_WRITE");
13877                                         break;
13878                                 default:
13879                                         exit_horribly(NULL, "unrecognized aggfinalmodify value for aggregate \"%s\"\n",
13880                                                                   agginfo->aggfn.dobj.name);
13881                                         break;
13882                         }
13883                 }
13884         }
13885
13886         if (strcmp(aggcombinefn, "-") != 0)
13887                 appendPQExpBuffer(details, ",\n    COMBINEFUNC = %s", aggcombinefn);
13888
13889         if (strcmp(aggserialfn, "-") != 0)
13890                 appendPQExpBuffer(details, ",\n    SERIALFUNC = %s", aggserialfn);
13891
13892         if (strcmp(aggdeserialfn, "-") != 0)
13893                 appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s", aggdeserialfn);
13894
13895         if (strcmp(aggmtransfn, "-") != 0)
13896         {
13897                 appendPQExpBuffer(details, ",\n    MSFUNC = %s,\n    MINVFUNC = %s,\n    MSTYPE = %s",
13898                                                   aggmtransfn,
13899                                                   aggminvtransfn,
13900                                                   aggmtranstype);
13901         }
13902
13903         if (strcmp(aggmtransspace, "0") != 0)
13904         {
13905                 appendPQExpBuffer(details, ",\n    MSSPACE = %s",
13906                                                   aggmtransspace);
13907         }
13908
13909         if (!PQgetisnull(res, 0, i_aggminitval))
13910         {
13911                 appendPQExpBufferStr(details, ",\n    MINITCOND = ");
13912                 appendStringLiteralAH(details, aggminitval, fout);
13913         }
13914
13915         if (strcmp(aggmfinalfn, "-") != 0)
13916         {
13917                 appendPQExpBuffer(details, ",\n    MFINALFUNC = %s",
13918                                                   aggmfinalfn);
13919                 if (aggmfinalextra)
13920                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_EXTRA");
13921                 if (aggmfinalmodify != defaultfinalmodify)
13922                 {
13923                         switch (aggmfinalmodify)
13924                         {
13925                                 case AGGMODIFY_READ_ONLY:
13926                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_ONLY");
13927                                         break;
13928                                 case AGGMODIFY_SHAREABLE:
13929                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = SHAREABLE");
13930                                         break;
13931                                 case AGGMODIFY_READ_WRITE:
13932                                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_WRITE");
13933                                         break;
13934                                 default:
13935                                         exit_horribly(NULL, "unrecognized aggmfinalmodify value for aggregate \"%s\"\n",
13936                                                                   agginfo->aggfn.dobj.name);
13937                                         break;
13938                         }
13939                 }
13940         }
13941
13942         aggsortconvop = getFormattedOperatorName(fout, aggsortop);
13943         if (aggsortconvop)
13944         {
13945                 appendPQExpBuffer(details, ",\n    SORTOP = %s",
13946                                                   aggsortconvop);
13947                 free(aggsortconvop);
13948         }
13949
13950         if (aggkind == AGGKIND_HYPOTHETICAL)
13951                 appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
13952
13953         if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
13954         {
13955                 if (proparallel[0] == PROPARALLEL_SAFE)
13956                         appendPQExpBufferStr(details, ",\n    PARALLEL = safe");
13957                 else if (proparallel[0] == PROPARALLEL_RESTRICTED)
13958                         appendPQExpBufferStr(details, ",\n    PARALLEL = restricted");
13959                 else if (proparallel[0] != PROPARALLEL_UNSAFE)
13960                         exit_horribly(NULL, "unrecognized proparallel value for function \"%s\"\n",
13961                                                   agginfo->aggfn.dobj.name);
13962         }
13963
13964         appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
13965                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
13966                                           aggsig);
13967
13968         appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
13969                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
13970                                           aggfullsig ? aggfullsig : aggsig, details->data);
13971
13972         if (dopt->binary_upgrade)
13973                 binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
13974                                                                                 "AGGREGATE", aggsig,
13975                                                                                 agginfo->aggfn.dobj.namespace->dobj.name);
13976
13977         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
13978                 ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
13979                                          agginfo->aggfn.dobj.dumpId,
13980                                          ARCHIVE_OPTS(.tag = aggsig_tag,
13981                                                                   .namespace = agginfo->aggfn.dobj.namespace->dobj.name,
13982                                                                   .owner = agginfo->aggfn.rolname,
13983                                                                   .description = "AGGREGATE",
13984                                                                   .section = SECTION_PRE_DATA,
13985                                                                   .createStmt = q->data,
13986                                                                   .dropStmt = delq->data));
13987
13988         /* Dump Aggregate Comments */
13989         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
13990                 dumpComment(fout, "AGGREGATE", aggsig,
13991                                         agginfo->aggfn.dobj.namespace->dobj.name,
13992                                         agginfo->aggfn.rolname,
13993                                         agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
13994
13995         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
13996                 dumpSecLabel(fout, "AGGREGATE", aggsig,
13997                                          agginfo->aggfn.dobj.namespace->dobj.name,
13998                                          agginfo->aggfn.rolname,
13999                                          agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
14000
14001         /*
14002          * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
14003          * command look like a function's GRANT; in particular this affects the
14004          * syntax for zero-argument aggregates and ordered-set aggregates.
14005          */
14006         free(aggsig);
14007
14008         aggsig = format_function_signature(fout, &agginfo->aggfn, true);
14009
14010         if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
14011                 dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
14012                                 "FUNCTION", aggsig, NULL,
14013                                 agginfo->aggfn.dobj.namespace->dobj.name,
14014                                 agginfo->aggfn.rolname, agginfo->aggfn.proacl,
14015                                 agginfo->aggfn.rproacl,
14016                                 agginfo->aggfn.initproacl, agginfo->aggfn.initrproacl);
14017
14018         free(aggsig);
14019         if (aggfullsig)
14020                 free(aggfullsig);
14021         free(aggsig_tag);
14022
14023         PQclear(res);
14024
14025         destroyPQExpBuffer(query);
14026         destroyPQExpBuffer(q);
14027         destroyPQExpBuffer(delq);
14028         destroyPQExpBuffer(details);
14029 }
14030
14031 /*
14032  * dumpTSParser
14033  *        write out a single text search parser
14034  */
14035 static void
14036 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
14037 {
14038         DumpOptions *dopt = fout->dopt;
14039         PQExpBuffer q;
14040         PQExpBuffer delq;
14041         char       *qprsname;
14042
14043         /* Skip if not to be dumped */
14044         if (!prsinfo->dobj.dump || dopt->dataOnly)
14045                 return;
14046
14047         q = createPQExpBuffer();
14048         delq = createPQExpBuffer();
14049
14050         qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
14051
14052         appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
14053                                           fmtQualifiedDumpable(prsinfo));
14054
14055         appendPQExpBuffer(q, "    START = %s,\n",
14056                                           convertTSFunction(fout, prsinfo->prsstart));
14057         appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
14058                                           convertTSFunction(fout, prsinfo->prstoken));
14059         appendPQExpBuffer(q, "    END = %s,\n",
14060                                           convertTSFunction(fout, prsinfo->prsend));
14061         if (prsinfo->prsheadline != InvalidOid)
14062                 appendPQExpBuffer(q, "    HEADLINE = %s,\n",
14063                                                   convertTSFunction(fout, prsinfo->prsheadline));
14064         appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
14065                                           convertTSFunction(fout, prsinfo->prslextype));
14066
14067         appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
14068                                           fmtQualifiedDumpable(prsinfo));
14069
14070         if (dopt->binary_upgrade)
14071                 binary_upgrade_extension_member(q, &prsinfo->dobj,
14072                                                                                 "TEXT SEARCH PARSER", qprsname,
14073                                                                                 prsinfo->dobj.namespace->dobj.name);
14074
14075         if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14076                 ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
14077                                          ARCHIVE_OPTS(.tag = prsinfo->dobj.name,
14078                                                                   .namespace = prsinfo->dobj.namespace->dobj.name,
14079                                                                   .description = "TEXT SEARCH PARSER",
14080                                                                   .section = SECTION_PRE_DATA,
14081                                                                   .createStmt = q->data,
14082                                                                   .dropStmt = delq->data));
14083
14084         /* Dump Parser Comments */
14085         if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14086                 dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
14087                                         prsinfo->dobj.namespace->dobj.name, "",
14088                                         prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
14089
14090         destroyPQExpBuffer(q);
14091         destroyPQExpBuffer(delq);
14092         free(qprsname);
14093 }
14094
14095 /*
14096  * dumpTSDictionary
14097  *        write out a single text search dictionary
14098  */
14099 static void
14100 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
14101 {
14102         DumpOptions *dopt = fout->dopt;
14103         PQExpBuffer q;
14104         PQExpBuffer delq;
14105         PQExpBuffer query;
14106         char       *qdictname;
14107         PGresult   *res;
14108         char       *nspname;
14109         char       *tmplname;
14110
14111         /* Skip if not to be dumped */
14112         if (!dictinfo->dobj.dump || dopt->dataOnly)
14113                 return;
14114
14115         q = createPQExpBuffer();
14116         delq = createPQExpBuffer();
14117         query = createPQExpBuffer();
14118
14119         qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
14120
14121         /* Fetch name and namespace of the dictionary's template */
14122         appendPQExpBuffer(query, "SELECT nspname, tmplname "
14123                                           "FROM pg_ts_template p, pg_namespace n "
14124                                           "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
14125                                           dictinfo->dicttemplate);
14126         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14127         nspname = PQgetvalue(res, 0, 0);
14128         tmplname = PQgetvalue(res, 0, 1);
14129
14130         appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
14131                                           fmtQualifiedDumpable(dictinfo));
14132
14133         appendPQExpBufferStr(q, "    TEMPLATE = ");
14134         appendPQExpBuffer(q, "%s.", fmtId(nspname));
14135         appendPQExpBufferStr(q, fmtId(tmplname));
14136
14137         PQclear(res);
14138
14139         /* the dictinitoption can be dumped straight into the command */
14140         if (dictinfo->dictinitoption)
14141                 appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
14142
14143         appendPQExpBufferStr(q, " );\n");
14144
14145         appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
14146                                           fmtQualifiedDumpable(dictinfo));
14147
14148         if (dopt->binary_upgrade)
14149                 binary_upgrade_extension_member(q, &dictinfo->dobj,
14150                                                                                 "TEXT SEARCH DICTIONARY", qdictname,
14151                                                                                 dictinfo->dobj.namespace->dobj.name);
14152
14153         if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14154                 ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
14155                                          ARCHIVE_OPTS(.tag = dictinfo->dobj.name,
14156                                                                   .namespace = dictinfo->dobj.namespace->dobj.name,
14157                                                                   .owner = dictinfo->rolname,
14158                                                                   .description = "TEXT SEARCH DICTIONARY",
14159                                                                   .section = SECTION_PRE_DATA,
14160                                                                   .createStmt = q->data,
14161                                                                   .dropStmt = delq->data));
14162
14163         /* Dump Dictionary Comments */
14164         if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14165                 dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
14166                                         dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
14167                                         dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
14168
14169         destroyPQExpBuffer(q);
14170         destroyPQExpBuffer(delq);
14171         destroyPQExpBuffer(query);
14172         free(qdictname);
14173 }
14174
14175 /*
14176  * dumpTSTemplate
14177  *        write out a single text search template
14178  */
14179 static void
14180 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
14181 {
14182         DumpOptions *dopt = fout->dopt;
14183         PQExpBuffer q;
14184         PQExpBuffer delq;
14185         char       *qtmplname;
14186
14187         /* Skip if not to be dumped */
14188         if (!tmplinfo->dobj.dump || dopt->dataOnly)
14189                 return;
14190
14191         q = createPQExpBuffer();
14192         delq = createPQExpBuffer();
14193
14194         qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
14195
14196         appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
14197                                           fmtQualifiedDumpable(tmplinfo));
14198
14199         if (tmplinfo->tmplinit != InvalidOid)
14200                 appendPQExpBuffer(q, "    INIT = %s,\n",
14201                                                   convertTSFunction(fout, tmplinfo->tmplinit));
14202         appendPQExpBuffer(q, "    LEXIZE = %s );\n",
14203                                           convertTSFunction(fout, tmplinfo->tmpllexize));
14204
14205         appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
14206                                           fmtQualifiedDumpable(tmplinfo));
14207
14208         if (dopt->binary_upgrade)
14209                 binary_upgrade_extension_member(q, &tmplinfo->dobj,
14210                                                                                 "TEXT SEARCH TEMPLATE", qtmplname,
14211                                                                                 tmplinfo->dobj.namespace->dobj.name);
14212
14213         if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14214                 ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
14215                                          ARCHIVE_OPTS(.tag = tmplinfo->dobj.name,
14216                                                                   .namespace = tmplinfo->dobj.namespace->dobj.name,
14217                                                                   .description = "TEXT SEARCH TEMPLATE",
14218                                                                   .section = SECTION_PRE_DATA,
14219                                                                   .createStmt = q->data,
14220                                                                   .dropStmt = delq->data));
14221
14222         /* Dump Template Comments */
14223         if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14224                 dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
14225                                         tmplinfo->dobj.namespace->dobj.name, "",
14226                                         tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
14227
14228         destroyPQExpBuffer(q);
14229         destroyPQExpBuffer(delq);
14230         free(qtmplname);
14231 }
14232
14233 /*
14234  * dumpTSConfig
14235  *        write out a single text search configuration
14236  */
14237 static void
14238 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
14239 {
14240         DumpOptions *dopt = fout->dopt;
14241         PQExpBuffer q;
14242         PQExpBuffer delq;
14243         PQExpBuffer query;
14244         char       *qcfgname;
14245         PGresult   *res;
14246         char       *nspname;
14247         char       *prsname;
14248         int                     ntups,
14249                                 i;
14250         int                     i_tokenname;
14251         int                     i_dictname;
14252
14253         /* Skip if not to be dumped */
14254         if (!cfginfo->dobj.dump || dopt->dataOnly)
14255                 return;
14256
14257         q = createPQExpBuffer();
14258         delq = createPQExpBuffer();
14259         query = createPQExpBuffer();
14260
14261         qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
14262
14263         /* Fetch name and namespace of the config's parser */
14264         appendPQExpBuffer(query, "SELECT nspname, prsname "
14265                                           "FROM pg_ts_parser p, pg_namespace n "
14266                                           "WHERE p.oid = '%u' AND n.oid = prsnamespace",
14267                                           cfginfo->cfgparser);
14268         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14269         nspname = PQgetvalue(res, 0, 0);
14270         prsname = PQgetvalue(res, 0, 1);
14271
14272         appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
14273                                           fmtQualifiedDumpable(cfginfo));
14274
14275         appendPQExpBuffer(q, "    PARSER = %s.", fmtId(nspname));
14276         appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
14277
14278         PQclear(res);
14279
14280         resetPQExpBuffer(query);
14281         appendPQExpBuffer(query,
14282                                           "SELECT\n"
14283                                           "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
14284                                           "    WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
14285                                           "  m.mapdict::pg_catalog.regdictionary AS dictname\n"
14286                                           "FROM pg_catalog.pg_ts_config_map AS m\n"
14287                                           "WHERE m.mapcfg = '%u'\n"
14288                                           "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
14289                                           cfginfo->cfgparser, cfginfo->dobj.catId.oid);
14290
14291         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14292         ntups = PQntuples(res);
14293
14294         i_tokenname = PQfnumber(res, "tokenname");
14295         i_dictname = PQfnumber(res, "dictname");
14296
14297         for (i = 0; i < ntups; i++)
14298         {
14299                 char       *tokenname = PQgetvalue(res, i, i_tokenname);
14300                 char       *dictname = PQgetvalue(res, i, i_dictname);
14301
14302                 if (i == 0 ||
14303                         strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
14304                 {
14305                         /* starting a new token type, so start a new command */
14306                         if (i > 0)
14307                                 appendPQExpBufferStr(q, ";\n");
14308                         appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
14309                                                           fmtQualifiedDumpable(cfginfo));
14310                         /* tokenname needs quoting, dictname does NOT */
14311                         appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
14312                                                           fmtId(tokenname), dictname);
14313                 }
14314                 else
14315                         appendPQExpBuffer(q, ", %s", dictname);
14316         }
14317
14318         if (ntups > 0)
14319                 appendPQExpBufferStr(q, ";\n");
14320
14321         PQclear(res);
14322
14323         appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
14324                                           fmtQualifiedDumpable(cfginfo));
14325
14326         if (dopt->binary_upgrade)
14327                 binary_upgrade_extension_member(q, &cfginfo->dobj,
14328                                                                                 "TEXT SEARCH CONFIGURATION", qcfgname,
14329                                                                                 cfginfo->dobj.namespace->dobj.name);
14330
14331         if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14332                 ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
14333                                          ARCHIVE_OPTS(.tag = cfginfo->dobj.name,
14334                                                                   .namespace = cfginfo->dobj.namespace->dobj.name,
14335                                                                   .owner = cfginfo->rolname,
14336                                                                   .description = "TEXT SEARCH CONFIGURATION",
14337                                                                   .section = SECTION_PRE_DATA,
14338                                                                   .createStmt = q->data,
14339                                                                   .dropStmt = delq->data));
14340
14341         /* Dump Configuration Comments */
14342         if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14343                 dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
14344                                         cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
14345                                         cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
14346
14347         destroyPQExpBuffer(q);
14348         destroyPQExpBuffer(delq);
14349         destroyPQExpBuffer(query);
14350         free(qcfgname);
14351 }
14352
14353 /*
14354  * dumpForeignDataWrapper
14355  *        write out a single foreign-data wrapper definition
14356  */
14357 static void
14358 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
14359 {
14360         DumpOptions *dopt = fout->dopt;
14361         PQExpBuffer q;
14362         PQExpBuffer delq;
14363         char       *qfdwname;
14364
14365         /* Skip if not to be dumped */
14366         if (!fdwinfo->dobj.dump || dopt->dataOnly)
14367                 return;
14368
14369         q = createPQExpBuffer();
14370         delq = createPQExpBuffer();
14371
14372         qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
14373
14374         appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
14375                                           qfdwname);
14376
14377         if (strcmp(fdwinfo->fdwhandler, "-") != 0)
14378                 appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
14379
14380         if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
14381                 appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
14382
14383         if (strlen(fdwinfo->fdwoptions) > 0)
14384                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
14385
14386         appendPQExpBufferStr(q, ";\n");
14387
14388         appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
14389                                           qfdwname);
14390
14391         if (dopt->binary_upgrade)
14392                 binary_upgrade_extension_member(q, &fdwinfo->dobj,
14393                                                                                 "FOREIGN DATA WRAPPER", qfdwname,
14394                                                                                 NULL);
14395
14396         if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14397                 ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14398                                          ARCHIVE_OPTS(.tag = fdwinfo->dobj.name,
14399                                                                   .owner = fdwinfo->rolname,
14400                                                                   .description = "FOREIGN DATA WRAPPER",
14401                                                                   .section = SECTION_PRE_DATA,
14402                                                                   .createStmt = q->data,
14403                                                                   .dropStmt = delq->data));
14404
14405         /* Dump Foreign Data Wrapper Comments */
14406         if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14407                 dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
14408                                         NULL, fdwinfo->rolname,
14409                                         fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
14410
14411         /* Handle the ACL */
14412         if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
14413                 dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14414                                 "FOREIGN DATA WRAPPER", qfdwname, NULL,
14415                                 NULL, fdwinfo->rolname,
14416                                 fdwinfo->fdwacl, fdwinfo->rfdwacl,
14417                                 fdwinfo->initfdwacl, fdwinfo->initrfdwacl);
14418
14419         free(qfdwname);
14420
14421         destroyPQExpBuffer(q);
14422         destroyPQExpBuffer(delq);
14423 }
14424
14425 /*
14426  * dumpForeignServer
14427  *        write out a foreign server definition
14428  */
14429 static void
14430 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
14431 {
14432         DumpOptions *dopt = fout->dopt;
14433         PQExpBuffer q;
14434         PQExpBuffer delq;
14435         PQExpBuffer query;
14436         PGresult   *res;
14437         char       *qsrvname;
14438         char       *fdwname;
14439
14440         /* Skip if not to be dumped */
14441         if (!srvinfo->dobj.dump || dopt->dataOnly)
14442                 return;
14443
14444         q = createPQExpBuffer();
14445         delq = createPQExpBuffer();
14446         query = createPQExpBuffer();
14447
14448         qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
14449
14450         /* look up the foreign-data wrapper */
14451         appendPQExpBuffer(query, "SELECT fdwname "
14452                                           "FROM pg_foreign_data_wrapper w "
14453                                           "WHERE w.oid = '%u'",
14454                                           srvinfo->srvfdw);
14455         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14456         fdwname = PQgetvalue(res, 0, 0);
14457
14458         appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
14459         if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
14460         {
14461                 appendPQExpBufferStr(q, " TYPE ");
14462                 appendStringLiteralAH(q, srvinfo->srvtype, fout);
14463         }
14464         if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
14465         {
14466                 appendPQExpBufferStr(q, " VERSION ");
14467                 appendStringLiteralAH(q, srvinfo->srvversion, fout);
14468         }
14469
14470         appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
14471         appendPQExpBufferStr(q, fmtId(fdwname));
14472
14473         if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
14474                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
14475
14476         appendPQExpBufferStr(q, ";\n");
14477
14478         appendPQExpBuffer(delq, "DROP SERVER %s;\n",
14479                                           qsrvname);
14480
14481         if (dopt->binary_upgrade)
14482                 binary_upgrade_extension_member(q, &srvinfo->dobj,
14483                                                                                 "SERVER", qsrvname, NULL);
14484
14485         if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14486                 ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14487                                          ARCHIVE_OPTS(.tag = srvinfo->dobj.name,
14488                                                                   .owner = srvinfo->rolname,
14489                                                                   .description = "SERVER",
14490                                                                   .section = SECTION_PRE_DATA,
14491                                                                   .createStmt = q->data,
14492                                                                   .dropStmt = delq->data));
14493
14494         /* Dump Foreign Server Comments */
14495         if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14496                 dumpComment(fout, "SERVER", qsrvname,
14497                                         NULL, srvinfo->rolname,
14498                                         srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
14499
14500         /* Handle the ACL */
14501         if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
14502                 dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14503                                 "FOREIGN SERVER", qsrvname, NULL,
14504                                 NULL, srvinfo->rolname,
14505                                 srvinfo->srvacl, srvinfo->rsrvacl,
14506                                 srvinfo->initsrvacl, srvinfo->initrsrvacl);
14507
14508         /* Dump user mappings */
14509         if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
14510                 dumpUserMappings(fout,
14511                                                  srvinfo->dobj.name, NULL,
14512                                                  srvinfo->rolname,
14513                                                  srvinfo->dobj.catId, srvinfo->dobj.dumpId);
14514
14515         free(qsrvname);
14516
14517         destroyPQExpBuffer(q);
14518         destroyPQExpBuffer(delq);
14519         destroyPQExpBuffer(query);
14520 }
14521
14522 /*
14523  * dumpUserMappings
14524  *
14525  * This routine is used to dump any user mappings associated with the
14526  * server handed to this routine. Should be called after ArchiveEntry()
14527  * for the server.
14528  */
14529 static void
14530 dumpUserMappings(Archive *fout,
14531                                  const char *servername, const char *namespace,
14532                                  const char *owner,
14533                                  CatalogId catalogId, DumpId dumpId)
14534 {
14535         PQExpBuffer q;
14536         PQExpBuffer delq;
14537         PQExpBuffer query;
14538         PQExpBuffer tag;
14539         PGresult   *res;
14540         int                     ntups;
14541         int                     i_usename;
14542         int                     i_umoptions;
14543         int                     i;
14544
14545         q = createPQExpBuffer();
14546         tag = createPQExpBuffer();
14547         delq = createPQExpBuffer();
14548         query = createPQExpBuffer();
14549
14550         /*
14551          * We read from the publicly accessible view pg_user_mappings, so as not
14552          * to fail if run by a non-superuser.  Note that the view will show
14553          * umoptions as null if the user hasn't got privileges for the associated
14554          * server; this means that pg_dump will dump such a mapping, but with no
14555          * OPTIONS clause.  A possible alternative is to skip such mappings
14556          * altogether, but it's not clear that that's an improvement.
14557          */
14558         appendPQExpBuffer(query,
14559                                           "SELECT usename, "
14560                                           "array_to_string(ARRAY("
14561                                           "SELECT quote_ident(option_name) || ' ' || "
14562                                           "quote_literal(option_value) "
14563                                           "FROM pg_options_to_table(umoptions) "
14564                                           "ORDER BY option_name"
14565                                           "), E',\n    ') AS umoptions "
14566                                           "FROM pg_user_mappings "
14567                                           "WHERE srvid = '%u' "
14568                                           "ORDER BY usename",
14569                                           catalogId.oid);
14570
14571         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14572
14573         ntups = PQntuples(res);
14574         i_usename = PQfnumber(res, "usename");
14575         i_umoptions = PQfnumber(res, "umoptions");
14576
14577         for (i = 0; i < ntups; i++)
14578         {
14579                 char       *usename;
14580                 char       *umoptions;
14581
14582                 usename = PQgetvalue(res, i, i_usename);
14583                 umoptions = PQgetvalue(res, i, i_umoptions);
14584
14585                 resetPQExpBuffer(q);
14586                 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
14587                 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
14588
14589                 if (umoptions && strlen(umoptions) > 0)
14590                         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
14591
14592                 appendPQExpBufferStr(q, ";\n");
14593
14594                 resetPQExpBuffer(delq);
14595                 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
14596                 appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
14597
14598                 resetPQExpBuffer(tag);
14599                 appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
14600                                                   usename, servername);
14601
14602                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14603                                          ARCHIVE_OPTS(.tag = tag->data,
14604                                                                   .namespace = namespace,
14605                                                                   .owner = owner,
14606                                                                   .description = "USER MAPPING",
14607                                                                   .section = SECTION_PRE_DATA,
14608                                                                   .createStmt = q->data,
14609                                                                   .dropStmt = delq->data));
14610         }
14611
14612         PQclear(res);
14613
14614         destroyPQExpBuffer(query);
14615         destroyPQExpBuffer(delq);
14616         destroyPQExpBuffer(tag);
14617         destroyPQExpBuffer(q);
14618 }
14619
14620 /*
14621  * Write out default privileges information
14622  */
14623 static void
14624 dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
14625 {
14626         DumpOptions *dopt = fout->dopt;
14627         PQExpBuffer q;
14628         PQExpBuffer tag;
14629         const char *type;
14630
14631         /* Skip if not to be dumped */
14632         if (!daclinfo->dobj.dump || dopt->dataOnly || dopt->aclsSkip)
14633                 return;
14634
14635         q = createPQExpBuffer();
14636         tag = createPQExpBuffer();
14637
14638         switch (daclinfo->defaclobjtype)
14639         {
14640                 case DEFACLOBJ_RELATION:
14641                         type = "TABLES";
14642                         break;
14643                 case DEFACLOBJ_SEQUENCE:
14644                         type = "SEQUENCES";
14645                         break;
14646                 case DEFACLOBJ_FUNCTION:
14647                         type = "FUNCTIONS";
14648                         break;
14649                 case DEFACLOBJ_TYPE:
14650                         type = "TYPES";
14651                         break;
14652                 case DEFACLOBJ_NAMESPACE:
14653                         type = "SCHEMAS";
14654                         break;
14655                 default:
14656                         /* shouldn't get here */
14657                         exit_horribly(NULL,
14658                                                   "unrecognized object type in default privileges: %d\n",
14659                                                   (int) daclinfo->defaclobjtype);
14660                         type = "";                      /* keep compiler quiet */
14661         }
14662
14663         appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
14664
14665         /* build the actual command(s) for this tuple */
14666         if (!buildDefaultACLCommands(type,
14667                                                                  daclinfo->dobj.namespace != NULL ?
14668                                                                  daclinfo->dobj.namespace->dobj.name : NULL,
14669                                                                  daclinfo->defaclacl,
14670                                                                  daclinfo->rdefaclacl,
14671                                                                  daclinfo->initdefaclacl,
14672                                                                  daclinfo->initrdefaclacl,
14673                                                                  daclinfo->defaclrole,
14674                                                                  fout->remoteVersion,
14675                                                                  q))
14676                 exit_horribly(NULL, "could not parse default ACL list (%s)\n",
14677                                           daclinfo->defaclacl);
14678
14679         if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
14680                 ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
14681                                          ARCHIVE_OPTS(.tag = tag->data,
14682                                                                   .namespace = daclinfo->dobj.namespace ?
14683                                                                   daclinfo->dobj.namespace->dobj.name : NULL,
14684                                                                   .owner = daclinfo->defaclrole,
14685                                                                   .description = "DEFAULT ACL",
14686                                                                   .section = SECTION_POST_DATA,
14687                                                                   .createStmt = q->data));
14688
14689         destroyPQExpBuffer(tag);
14690         destroyPQExpBuffer(q);
14691 }
14692
14693 /*----------
14694  * Write out grant/revoke information
14695  *
14696  * 'objCatId' is the catalog ID of the underlying object.
14697  * 'objDumpId' is the dump ID of the underlying object.
14698  * 'type' must be one of
14699  *              TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
14700  *              FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
14701  * 'name' is the formatted name of the object.  Must be quoted etc. already.
14702  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
14703  *              (Currently we assume that subname is only provided for table columns.)
14704  * 'nspname' is the namespace the object is in (NULL if none).
14705  * 'owner' is the owner, NULL if there is no owner (for languages).
14706  * 'acls' contains the ACL string of the object from the appropriate system
14707  *              catalog field; it will be passed to buildACLCommands for building the
14708  *              appropriate GRANT commands.
14709  * 'racls' contains the ACL string of any initial-but-now-revoked ACLs of the
14710  *              object; it will be passed to buildACLCommands for building the
14711  *              appropriate REVOKE commands.
14712  * 'initacls' In binary-upgrade mode, ACL string of the object's initial
14713  *              privileges, to be recorded into pg_init_privs
14714  * 'initracls' In binary-upgrade mode, ACL string of the object's
14715  *              revoked-from-default privileges, to be recorded into pg_init_privs
14716  *
14717  * NB: initacls/initracls are needed because extensions can set privileges on
14718  * an object during the extension's script file and we record those into
14719  * pg_init_privs as that object's initial privileges.
14720  *----------
14721  */
14722 static void
14723 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
14724                 const char *type, const char *name, const char *subname,
14725                 const char *nspname, const char *owner,
14726                 const char *acls, const char *racls,
14727                 const char *initacls, const char *initracls)
14728 {
14729         DumpOptions *dopt = fout->dopt;
14730         PQExpBuffer sql;
14731
14732         /* Do nothing if ACL dump is not enabled */
14733         if (dopt->aclsSkip)
14734                 return;
14735
14736         /* --data-only skips ACLs *except* BLOB ACLs */
14737         if (dopt->dataOnly && strcmp(type, "LARGE OBJECT") != 0)
14738                 return;
14739
14740         sql = createPQExpBuffer();
14741
14742         /*
14743          * Check to see if this object has had any initial ACLs included for it.
14744          * If so, we are in binary upgrade mode and these are the ACLs to turn
14745          * into GRANT and REVOKE statements to set and record the initial
14746          * privileges for an extension object.  Let the backend know that these
14747          * are to be recorded by calling binary_upgrade_set_record_init_privs()
14748          * before and after.
14749          */
14750         if (strlen(initacls) != 0 || strlen(initracls) != 0)
14751         {
14752                 appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
14753                 if (!buildACLCommands(name, subname, nspname, type,
14754                                                           initacls, initracls, owner,
14755                                                           "", fout->remoteVersion, sql))
14756                         exit_horribly(NULL,
14757                                                   "could not parse initial GRANT ACL list (%s) or initial REVOKE ACL list (%s) for object \"%s\" (%s)\n",
14758                                                   initacls, initracls, name, type);
14759                 appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
14760         }
14761
14762         if (!buildACLCommands(name, subname, nspname, type,
14763                                                   acls, racls, owner,
14764                                                   "", fout->remoteVersion, sql))
14765                 exit_horribly(NULL,
14766                                           "could not parse GRANT ACL list (%s) or REVOKE ACL list (%s) for object \"%s\" (%s)\n",
14767                                           acls, racls, name, type);
14768
14769         if (sql->len > 0)
14770         {
14771                 PQExpBuffer tag = createPQExpBuffer();
14772
14773                 if (subname)
14774                         appendPQExpBuffer(tag, "COLUMN %s.%s", name, subname);
14775                 else
14776                         appendPQExpBuffer(tag, "%s %s", type, name);
14777
14778                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14779                                          ARCHIVE_OPTS(.tag = tag->data,
14780                                                                   .namespace = nspname,
14781                                                                   .owner = owner,
14782                                                                   .description = "ACL",
14783                                                                   .section = SECTION_NONE,
14784                                                                   .createStmt = sql->data,
14785                                                                   .deps = &objDumpId,
14786                                                                   .nDeps = 1));
14787                 destroyPQExpBuffer(tag);
14788         }
14789
14790         destroyPQExpBuffer(sql);
14791 }
14792
14793 /*
14794  * dumpSecLabel
14795  *
14796  * This routine is used to dump any security labels associated with the
14797  * object handed to this routine. The routine takes the object type
14798  * and object name (ready to print, except for schema decoration), plus
14799  * the namespace and owner of the object (for labeling the ArchiveEntry),
14800  * plus catalog ID and subid which are the lookup key for pg_seclabel,
14801  * plus the dump ID for the object (for setting a dependency).
14802  * If a matching pg_seclabel entry is found, it is dumped.
14803  *
14804  * Note: although this routine takes a dumpId for dependency purposes,
14805  * that purpose is just to mark the dependency in the emitted dump file
14806  * for possible future use by pg_restore.  We do NOT use it for determining
14807  * ordering of the label in the dump file, because this routine is called
14808  * after dependency sorting occurs.  This routine should be called just after
14809  * calling ArchiveEntry() for the specified object.
14810  */
14811 static void
14812 dumpSecLabel(Archive *fout, const char *type, const char *name,
14813                          const char *namespace, const char *owner,
14814                          CatalogId catalogId, int subid, DumpId dumpId)
14815 {
14816         DumpOptions *dopt = fout->dopt;
14817         SecLabelItem *labels;
14818         int                     nlabels;
14819         int                     i;
14820         PQExpBuffer query;
14821
14822         /* do nothing, if --no-security-labels is supplied */
14823         if (dopt->no_security_labels)
14824                 return;
14825
14826         /* Security labels are schema not data ... except blob labels are data */
14827         if (strcmp(type, "LARGE OBJECT") != 0)
14828         {
14829                 if (dopt->dataOnly)
14830                         return;
14831         }
14832         else
14833         {
14834                 /* We do dump blob security labels in binary-upgrade mode */
14835                 if (dopt->schemaOnly && !dopt->binary_upgrade)
14836                         return;
14837         }
14838
14839         /* Search for security labels associated with catalogId, using table */
14840         nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
14841
14842         query = createPQExpBuffer();
14843
14844         for (i = 0; i < nlabels; i++)
14845         {
14846                 /*
14847                  * Ignore label entries for which the subid doesn't match.
14848                  */
14849                 if (labels[i].objsubid != subid)
14850                         continue;
14851
14852                 appendPQExpBuffer(query,
14853                                                   "SECURITY LABEL FOR %s ON %s ",
14854                                                   fmtId(labels[i].provider), type);
14855                 if (namespace && *namespace)
14856                         appendPQExpBuffer(query, "%s.", fmtId(namespace));
14857                 appendPQExpBuffer(query, "%s IS ", name);
14858                 appendStringLiteralAH(query, labels[i].label, fout);
14859                 appendPQExpBufferStr(query, ";\n");
14860         }
14861
14862         if (query->len > 0)
14863         {
14864                 PQExpBuffer tag = createPQExpBuffer();
14865
14866                 appendPQExpBuffer(tag, "%s %s", type, name);
14867                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14868                                          ARCHIVE_OPTS(.tag = tag->data,
14869                                                                   .namespace = namespace,
14870                                                                   .owner = owner,
14871                                                                   .description = "SECURITY LABEL",
14872                                                                   .section = SECTION_NONE,
14873                                                                   .createStmt = query->data,
14874                                                                   .deps = &dumpId,
14875                                                                   .nDeps = 1));
14876                 destroyPQExpBuffer(tag);
14877         }
14878
14879         destroyPQExpBuffer(query);
14880 }
14881
14882 /*
14883  * dumpTableSecLabel
14884  *
14885  * As above, but dump security label for both the specified table (or view)
14886  * and its columns.
14887  */
14888 static void
14889 dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
14890 {
14891         DumpOptions *dopt = fout->dopt;
14892         SecLabelItem *labels;
14893         int                     nlabels;
14894         int                     i;
14895         PQExpBuffer query;
14896         PQExpBuffer target;
14897
14898         /* do nothing, if --no-security-labels is supplied */
14899         if (dopt->no_security_labels)
14900                 return;
14901
14902         /* SecLabel are SCHEMA not data */
14903         if (dopt->dataOnly)
14904                 return;
14905
14906         /* Search for comments associated with relation, using table */
14907         nlabels = findSecLabels(fout,
14908                                                         tbinfo->dobj.catId.tableoid,
14909                                                         tbinfo->dobj.catId.oid,
14910                                                         &labels);
14911
14912         /* If security labels exist, build SECURITY LABEL statements */
14913         if (nlabels <= 0)
14914                 return;
14915
14916         query = createPQExpBuffer();
14917         target = createPQExpBuffer();
14918
14919         for (i = 0; i < nlabels; i++)
14920         {
14921                 const char *colname;
14922                 const char *provider = labels[i].provider;
14923                 const char *label = labels[i].label;
14924                 int                     objsubid = labels[i].objsubid;
14925
14926                 resetPQExpBuffer(target);
14927                 if (objsubid == 0)
14928                 {
14929                         appendPQExpBuffer(target, "%s %s", reltypename,
14930                                                           fmtQualifiedDumpable(tbinfo));
14931                 }
14932                 else
14933                 {
14934                         colname = getAttrName(objsubid, tbinfo);
14935                         /* first fmtXXX result must be consumed before calling again */
14936                         appendPQExpBuffer(target, "COLUMN %s",
14937                                                           fmtQualifiedDumpable(tbinfo));
14938                         appendPQExpBuffer(target, ".%s", fmtId(colname));
14939                 }
14940                 appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
14941                                                   fmtId(provider), target->data);
14942                 appendStringLiteralAH(query, label, fout);
14943                 appendPQExpBufferStr(query, ";\n");
14944         }
14945         if (query->len > 0)
14946         {
14947                 resetPQExpBuffer(target);
14948                 appendPQExpBuffer(target, "%s %s", reltypename,
14949                                                   fmtId(tbinfo->dobj.name));
14950                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
14951                                          ARCHIVE_OPTS(.tag = target->data,
14952                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
14953                                                                   .owner = tbinfo->rolname,
14954                                                                   .description = "SECURITY LABEL",
14955                                                                   .section = SECTION_NONE,
14956                                                                   .createStmt = query->data,
14957                                                                   .deps = &(tbinfo->dobj.dumpId),
14958                                                                   .nDeps = 1));
14959         }
14960         destroyPQExpBuffer(query);
14961         destroyPQExpBuffer(target);
14962 }
14963
14964 /*
14965  * findSecLabels
14966  *
14967  * Find the security label(s), if any, associated with the given object.
14968  * All the objsubid values associated with the given classoid/objoid are
14969  * found with one search.
14970  */
14971 static int
14972 findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
14973 {
14974         /* static storage for table of security labels */
14975         static SecLabelItem *labels = NULL;
14976         static int      nlabels = -1;
14977
14978         SecLabelItem *middle = NULL;
14979         SecLabelItem *low;
14980         SecLabelItem *high;
14981         int                     nmatch;
14982
14983         /* Get security labels if we didn't already */
14984         if (nlabels < 0)
14985                 nlabels = collectSecLabels(fout, &labels);
14986
14987         if (nlabels <= 0)                       /* no labels, so no match is possible */
14988         {
14989                 *items = NULL;
14990                 return 0;
14991         }
14992
14993         /*
14994          * Do binary search to find some item matching the object.
14995          */
14996         low = &labels[0];
14997         high = &labels[nlabels - 1];
14998         while (low <= high)
14999         {
15000                 middle = low + (high - low) / 2;
15001
15002                 if (classoid < middle->classoid)
15003                         high = middle - 1;
15004                 else if (classoid > middle->classoid)
15005                         low = middle + 1;
15006                 else if (objoid < middle->objoid)
15007                         high = middle - 1;
15008                 else if (objoid > middle->objoid)
15009                         low = middle + 1;
15010                 else
15011                         break;                          /* found a match */
15012         }
15013
15014         if (low > high)                         /* no matches */
15015         {
15016                 *items = NULL;
15017                 return 0;
15018         }
15019
15020         /*
15021          * Now determine how many items match the object.  The search loop
15022          * invariant still holds: only items between low and high inclusive could
15023          * match.
15024          */
15025         nmatch = 1;
15026         while (middle > low)
15027         {
15028                 if (classoid != middle[-1].classoid ||
15029                         objoid != middle[-1].objoid)
15030                         break;
15031                 middle--;
15032                 nmatch++;
15033         }
15034
15035         *items = middle;
15036
15037         middle += nmatch;
15038         while (middle <= high)
15039         {
15040                 if (classoid != middle->classoid ||
15041                         objoid != middle->objoid)
15042                         break;
15043                 middle++;
15044                 nmatch++;
15045         }
15046
15047         return nmatch;
15048 }
15049
15050 /*
15051  * collectSecLabels
15052  *
15053  * Construct a table of all security labels available for database objects.
15054  * It's much faster to pull them all at once.
15055  *
15056  * The table is sorted by classoid/objid/objsubid for speed in lookup.
15057  */
15058 static int
15059 collectSecLabels(Archive *fout, SecLabelItem **items)
15060 {
15061         PGresult   *res;
15062         PQExpBuffer query;
15063         int                     i_label;
15064         int                     i_provider;
15065         int                     i_classoid;
15066         int                     i_objoid;
15067         int                     i_objsubid;
15068         int                     ntups;
15069         int                     i;
15070         SecLabelItem *labels;
15071
15072         query = createPQExpBuffer();
15073
15074         appendPQExpBufferStr(query,
15075                                                  "SELECT label, provider, classoid, objoid, objsubid "
15076                                                  "FROM pg_catalog.pg_seclabel "
15077                                                  "ORDER BY classoid, objoid, objsubid");
15078
15079         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15080
15081         /* Construct lookup table containing OIDs in numeric form */
15082         i_label = PQfnumber(res, "label");
15083         i_provider = PQfnumber(res, "provider");
15084         i_classoid = PQfnumber(res, "classoid");
15085         i_objoid = PQfnumber(res, "objoid");
15086         i_objsubid = PQfnumber(res, "objsubid");
15087
15088         ntups = PQntuples(res);
15089
15090         labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
15091
15092         for (i = 0; i < ntups; i++)
15093         {
15094                 labels[i].label = PQgetvalue(res, i, i_label);
15095                 labels[i].provider = PQgetvalue(res, i, i_provider);
15096                 labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
15097                 labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
15098                 labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
15099         }
15100
15101         /* Do NOT free the PGresult since we are keeping pointers into it */
15102         destroyPQExpBuffer(query);
15103
15104         *items = labels;
15105         return ntups;
15106 }
15107
15108 /*
15109  * dumpTable
15110  *        write out to fout the declarations (not data) of a user-defined table
15111  */
15112 static void
15113 dumpTable(Archive *fout, TableInfo *tbinfo)
15114 {
15115         DumpOptions *dopt = fout->dopt;
15116         char       *namecopy;
15117
15118         /*
15119          * noop if we are not dumping anything about this table, or if we are
15120          * doing a data-only dump
15121          */
15122         if (!tbinfo->dobj.dump || dopt->dataOnly)
15123                 return;
15124
15125         if (tbinfo->relkind == RELKIND_SEQUENCE)
15126                 dumpSequence(fout, tbinfo);
15127         else
15128                 dumpTableSchema(fout, tbinfo);
15129
15130         /* Handle the ACL here */
15131         namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
15132         if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15133         {
15134                 const char *objtype =
15135                 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
15136
15137                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
15138                                 objtype, namecopy, NULL,
15139                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15140                                 tbinfo->relacl, tbinfo->rrelacl,
15141                                 tbinfo->initrelacl, tbinfo->initrrelacl);
15142         }
15143
15144         /*
15145          * Handle column ACLs, if any.  Note: we pull these with a separate query
15146          * rather than trying to fetch them during getTableAttrs, so that we won't
15147          * miss ACLs on system columns.
15148          */
15149         if (fout->remoteVersion >= 80400 && tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15150         {
15151                 PQExpBuffer query = createPQExpBuffer();
15152                 PGresult   *res;
15153                 int                     i;
15154
15155                 if (fout->remoteVersion >= 90600)
15156                 {
15157                         PQExpBuffer acl_subquery = createPQExpBuffer();
15158                         PQExpBuffer racl_subquery = createPQExpBuffer();
15159                         PQExpBuffer initacl_subquery = createPQExpBuffer();
15160                         PQExpBuffer initracl_subquery = createPQExpBuffer();
15161
15162                         buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
15163                                                         initracl_subquery, "at.attacl", "c.relowner", "'c'",
15164                                                         dopt->binary_upgrade);
15165
15166                         appendPQExpBuffer(query,
15167                                                           "SELECT at.attname, "
15168                                                           "%s AS attacl, "
15169                                                           "%s AS rattacl, "
15170                                                           "%s AS initattacl, "
15171                                                           "%s AS initrattacl "
15172                                                           "FROM pg_catalog.pg_attribute at "
15173                                                           "JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
15174                                                           "LEFT JOIN pg_catalog.pg_init_privs pip ON "
15175                                                           "(at.attrelid = pip.objoid "
15176                                                           "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
15177                                                           "AND at.attnum = pip.objsubid) "
15178                                                           "WHERE at.attrelid = '%u'::pg_catalog.oid AND "
15179                                                           "NOT at.attisdropped "
15180                                                           "AND ("
15181                                                           "%s IS NOT NULL OR "
15182                                                           "%s IS NOT NULL OR "
15183                                                           "%s IS NOT NULL OR "
15184                                                           "%s IS NOT NULL)"
15185                                                           "ORDER BY at.attnum",
15186                                                           acl_subquery->data,
15187                                                           racl_subquery->data,
15188                                                           initacl_subquery->data,
15189                                                           initracl_subquery->data,
15190                                                           tbinfo->dobj.catId.oid,
15191                                                           acl_subquery->data,
15192                                                           racl_subquery->data,
15193                                                           initacl_subquery->data,
15194                                                           initracl_subquery->data);
15195
15196                         destroyPQExpBuffer(acl_subquery);
15197                         destroyPQExpBuffer(racl_subquery);
15198                         destroyPQExpBuffer(initacl_subquery);
15199                         destroyPQExpBuffer(initracl_subquery);
15200                 }
15201                 else
15202                 {
15203                         appendPQExpBuffer(query,
15204                                                           "SELECT attname, attacl, NULL as rattacl, "
15205                                                           "NULL AS initattacl, NULL AS initrattacl "
15206                                                           "FROM pg_catalog.pg_attribute "
15207                                                           "WHERE attrelid = '%u'::pg_catalog.oid AND NOT attisdropped "
15208                                                           "AND attacl IS NOT NULL "
15209                                                           "ORDER BY attnum",
15210                                                           tbinfo->dobj.catId.oid);
15211                 }
15212
15213                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15214
15215                 for (i = 0; i < PQntuples(res); i++)
15216                 {
15217                         char       *attname = PQgetvalue(res, i, 0);
15218                         char       *attacl = PQgetvalue(res, i, 1);
15219                         char       *rattacl = PQgetvalue(res, i, 2);
15220                         char       *initattacl = PQgetvalue(res, i, 3);
15221                         char       *initrattacl = PQgetvalue(res, i, 4);
15222                         char       *attnamecopy;
15223
15224                         attnamecopy = pg_strdup(fmtId(attname));
15225                         /* Column's GRANT type is always TABLE */
15226                         dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
15227                                         "TABLE", namecopy, attnamecopy,
15228                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15229                                         attacl, rattacl, initattacl, initrattacl);
15230                         free(attnamecopy);
15231                 }
15232                 PQclear(res);
15233                 destroyPQExpBuffer(query);
15234         }
15235
15236         free(namecopy);
15237
15238         return;
15239 }
15240
15241 /*
15242  * Create the AS clause for a view or materialized view. The semicolon is
15243  * stripped because a materialized view must add a WITH NO DATA clause.
15244  *
15245  * This returns a new buffer which must be freed by the caller.
15246  */
15247 static PQExpBuffer
15248 createViewAsClause(Archive *fout, TableInfo *tbinfo)
15249 {
15250         PQExpBuffer query = createPQExpBuffer();
15251         PQExpBuffer result = createPQExpBuffer();
15252         PGresult   *res;
15253         int                     len;
15254
15255         /* Fetch the view definition */
15256         appendPQExpBuffer(query,
15257                                           "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
15258                                           tbinfo->dobj.catId.oid);
15259
15260         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15261
15262         if (PQntuples(res) != 1)
15263         {
15264                 if (PQntuples(res) < 1)
15265                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned no data\n",
15266                                                   tbinfo->dobj.name);
15267                 else
15268                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
15269                                                   tbinfo->dobj.name);
15270         }
15271
15272         len = PQgetlength(res, 0, 0);
15273
15274         if (len == 0)
15275                 exit_horribly(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
15276                                           tbinfo->dobj.name);
15277
15278         /* Strip off the trailing semicolon so that other things may follow. */
15279         Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
15280         appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
15281
15282         PQclear(res);
15283         destroyPQExpBuffer(query);
15284
15285         return result;
15286 }
15287
15288 /*
15289  * Create a dummy AS clause for a view.  This is used when the real view
15290  * definition has to be postponed because of circular dependencies.
15291  * We must duplicate the view's external properties -- column names and types
15292  * (including collation) -- so that it works for subsequent references.
15293  *
15294  * This returns a new buffer which must be freed by the caller.
15295  */
15296 static PQExpBuffer
15297 createDummyViewAsClause(Archive *fout, TableInfo *tbinfo)
15298 {
15299         PQExpBuffer result = createPQExpBuffer();
15300         int                     j;
15301
15302         appendPQExpBufferStr(result, "SELECT");
15303
15304         for (j = 0; j < tbinfo->numatts; j++)
15305         {
15306                 if (j > 0)
15307                         appendPQExpBufferChar(result, ',');
15308                 appendPQExpBufferStr(result, "\n    ");
15309
15310                 appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
15311
15312                 /*
15313                  * Must add collation if not default for the type, because CREATE OR
15314                  * REPLACE VIEW won't change it
15315                  */
15316                 if (OidIsValid(tbinfo->attcollation[j]))
15317                 {
15318                         CollInfo   *coll;
15319
15320                         coll = findCollationByOid(tbinfo->attcollation[j]);
15321                         if (coll)
15322                                 appendPQExpBuffer(result, " COLLATE %s",
15323                                                                   fmtQualifiedDumpable(coll));
15324                 }
15325
15326                 appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
15327         }
15328
15329         return result;
15330 }
15331
15332 /*
15333  * dumpTableSchema
15334  *        write the declaration (not data) of one user-defined table or view
15335  */
15336 static void
15337 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
15338 {
15339         DumpOptions *dopt = fout->dopt;
15340         PQExpBuffer q = createPQExpBuffer();
15341         PQExpBuffer delq = createPQExpBuffer();
15342         char       *qrelname;
15343         char       *qualrelname;
15344         int                     numParents;
15345         TableInfo **parents;
15346         int                     actual_atts;    /* number of attrs in this CREATE statement */
15347         const char *reltypename;
15348         char       *storage;
15349         int                     j,
15350                                 k;
15351
15352         qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
15353         qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
15354
15355
15356         if (tbinfo->hasoids)
15357                 write_msg(NULL,
15358                                   "WARNING: WITH OIDS is not supported anymore (table \"%s\")\n",
15359                                   qrelname);
15360
15361         if (dopt->binary_upgrade)
15362                 binary_upgrade_set_type_oids_by_rel_oid(fout, q,
15363                                                                                                 tbinfo->dobj.catId.oid);
15364
15365         /* Is it a table or a view? */
15366         if (tbinfo->relkind == RELKIND_VIEW)
15367         {
15368                 PQExpBuffer result;
15369
15370                 /*
15371                  * Note: keep this code in sync with the is_view case in dumpRule()
15372                  */
15373
15374                 reltypename = "VIEW";
15375
15376                 appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
15377
15378                 if (dopt->binary_upgrade)
15379                         binary_upgrade_set_pg_class_oids(fout, q,
15380                                                                                          tbinfo->dobj.catId.oid, false);
15381
15382                 appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
15383
15384                 if (tbinfo->dummy_view)
15385                         result = createDummyViewAsClause(fout, tbinfo);
15386                 else
15387                 {
15388                         if (nonemptyReloptions(tbinfo->reloptions))
15389                         {
15390                                 appendPQExpBufferStr(q, " WITH (");
15391                                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15392                                 appendPQExpBufferChar(q, ')');
15393                         }
15394                         result = createViewAsClause(fout, tbinfo);
15395                 }
15396                 appendPQExpBuffer(q, " AS\n%s", result->data);
15397                 destroyPQExpBuffer(result);
15398
15399                 if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
15400                         appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
15401                 appendPQExpBufferStr(q, ";\n");
15402         }
15403         else
15404         {
15405                 char       *ftoptions = NULL;
15406                 char       *srvname = NULL;
15407
15408                 switch (tbinfo->relkind)
15409                 {
15410                         case RELKIND_FOREIGN_TABLE:
15411                                 {
15412                                         PQExpBuffer query = createPQExpBuffer();
15413                                         PGresult   *res;
15414                                         int                     i_srvname;
15415                                         int                     i_ftoptions;
15416
15417                                         reltypename = "FOREIGN TABLE";
15418
15419                                         /* retrieve name of foreign server and generic options */
15420                                         appendPQExpBuffer(query,
15421                                                                           "SELECT fs.srvname, "
15422                                                                           "pg_catalog.array_to_string(ARRAY("
15423                                                                           "SELECT pg_catalog.quote_ident(option_name) || "
15424                                                                           "' ' || pg_catalog.quote_literal(option_value) "
15425                                                                           "FROM pg_catalog.pg_options_to_table(ftoptions) "
15426                                                                           "ORDER BY option_name"
15427                                                                           "), E',\n    ') AS ftoptions "
15428                                                                           "FROM pg_catalog.pg_foreign_table ft "
15429                                                                           "JOIN pg_catalog.pg_foreign_server fs "
15430                                                                           "ON (fs.oid = ft.ftserver) "
15431                                                                           "WHERE ft.ftrelid = '%u'",
15432                                                                           tbinfo->dobj.catId.oid);
15433                                         res = ExecuteSqlQueryForSingleRow(fout, query->data);
15434                                         i_srvname = PQfnumber(res, "srvname");
15435                                         i_ftoptions = PQfnumber(res, "ftoptions");
15436                                         srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
15437                                         ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
15438                                         PQclear(res);
15439                                         destroyPQExpBuffer(query);
15440                                         break;
15441                                 }
15442                         case RELKIND_MATVIEW:
15443                                 reltypename = "MATERIALIZED VIEW";
15444                                 break;
15445                         default:
15446                                 reltypename = "TABLE";
15447                 }
15448
15449                 numParents = tbinfo->numParents;
15450                 parents = tbinfo->parents;
15451
15452                 appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
15453
15454                 if (dopt->binary_upgrade)
15455                         binary_upgrade_set_pg_class_oids(fout, q,
15456                                                                                          tbinfo->dobj.catId.oid, false);
15457
15458                 appendPQExpBuffer(q, "CREATE %s%s %s",
15459                                                   tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
15460                                                   "UNLOGGED " : "",
15461                                                   reltypename,
15462                                                   qualrelname);
15463
15464                 /*
15465                  * Attach to type, if reloftype; except in case of a binary upgrade,
15466                  * we dump the table normally and attach it to the type afterward.
15467                  */
15468                 if (tbinfo->reloftype && !dopt->binary_upgrade)
15469                         appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
15470
15471                 /*
15472                  * If the table is a partition, dump it as such; except in the case of
15473                  * a binary upgrade, we dump the table normally and attach it to the
15474                  * parent afterward.
15475                  */
15476                 if (tbinfo->ispartition && !dopt->binary_upgrade)
15477                 {
15478                         TableInfo  *parentRel = tbinfo->parents[0];
15479
15480                         /*
15481                          * With partitions, unlike inheritance, there can only be one
15482                          * parent.
15483                          */
15484                         if (tbinfo->numParents != 1)
15485                                 exit_horribly(NULL, "invalid number of parents %d for table \"%s\"\n",
15486                                                           tbinfo->numParents, tbinfo->dobj.name);
15487
15488                         appendPQExpBuffer(q, " PARTITION OF %s",
15489                                                           fmtQualifiedDumpable(parentRel));
15490                 }
15491
15492                 if (tbinfo->relkind != RELKIND_MATVIEW)
15493                 {
15494                         /* Dump the attributes */
15495                         actual_atts = 0;
15496                         for (j = 0; j < tbinfo->numatts; j++)
15497                         {
15498                                 /*
15499                                  * Normally, dump if it's locally defined in this table, and
15500                                  * not dropped.  But for binary upgrade, we'll dump all the
15501                                  * columns, and then fix up the dropped and nonlocal cases
15502                                  * below.
15503                                  */
15504                                 if (shouldPrintColumn(dopt, tbinfo, j))
15505                                 {
15506                                         /*
15507                                          * Default value --- suppress if to be printed separately.
15508                                          */
15509                                         bool            has_default = (tbinfo->attrdefs[j] != NULL &&
15510                                                                                            !tbinfo->attrdefs[j]->separate);
15511
15512                                         /*
15513                                          * Not Null constraint --- suppress if inherited, except
15514                                          * in binary-upgrade case where that won't work.
15515                                          */
15516                                         bool            has_notnull = (tbinfo->notnull[j] &&
15517                                                                                            (!tbinfo->inhNotNull[j] ||
15518                                                                                                 dopt->binary_upgrade));
15519
15520                                         /*
15521                                          * Skip column if fully defined by reloftype or the
15522                                          * partition parent.
15523                                          */
15524                                         if ((tbinfo->reloftype || tbinfo->ispartition) &&
15525                                                 !has_default && !has_notnull && !dopt->binary_upgrade)
15526                                                 continue;
15527
15528                                         /* Format properly if not first attr */
15529                                         if (actual_atts == 0)
15530                                                 appendPQExpBufferStr(q, " (");
15531                                         else
15532                                                 appendPQExpBufferChar(q, ',');
15533                                         appendPQExpBufferStr(q, "\n    ");
15534                                         actual_atts++;
15535
15536                                         /* Attribute name */
15537                                         appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
15538
15539                                         if (tbinfo->attisdropped[j])
15540                                         {
15541                                                 /*
15542                                                  * ALTER TABLE DROP COLUMN clears
15543                                                  * pg_attribute.atttypid, so we will not have gotten a
15544                                                  * valid type name; insert INTEGER as a stopgap. We'll
15545                                                  * clean things up later.
15546                                                  */
15547                                                 appendPQExpBufferStr(q, " INTEGER /* dummy */");
15548                                                 /* Skip all the rest, too */
15549                                                 continue;
15550                                         }
15551
15552                                         /*
15553                                          * Attribute type
15554                                          *
15555                                          * In binary-upgrade mode, we always include the type. If
15556                                          * we aren't in binary-upgrade mode, then we skip the type
15557                                          * when creating a typed table ('OF type_name') or a
15558                                          * partition ('PARTITION OF'), since the type comes from
15559                                          * the parent/partitioned table.
15560                                          */
15561                                         if (dopt->binary_upgrade || (!tbinfo->reloftype && !tbinfo->ispartition))
15562                                         {
15563                                                 appendPQExpBuffer(q, " %s",
15564                                                                                   tbinfo->atttypnames[j]);
15565                                         }
15566
15567                                         /* Add collation if not default for the type */
15568                                         if (OidIsValid(tbinfo->attcollation[j]))
15569                                         {
15570                                                 CollInfo   *coll;
15571
15572                                                 coll = findCollationByOid(tbinfo->attcollation[j]);
15573                                                 if (coll)
15574                                                         appendPQExpBuffer(q, " COLLATE %s",
15575                                                                                           fmtQualifiedDumpable(coll));
15576                                         }
15577
15578                                         if (has_default)
15579                                                 appendPQExpBuffer(q, " DEFAULT %s",
15580                                                                                   tbinfo->attrdefs[j]->adef_expr);
15581
15582                                         if (has_notnull)
15583                                                 appendPQExpBufferStr(q, " NOT NULL");
15584                                 }
15585                         }
15586
15587                         /*
15588                          * Add non-inherited CHECK constraints, if any.
15589                          */
15590                         for (j = 0; j < tbinfo->ncheck; j++)
15591                         {
15592                                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
15593
15594                                 if (constr->separate || !constr->conislocal)
15595                                         continue;
15596
15597                                 if (actual_atts == 0)
15598                                         appendPQExpBufferStr(q, " (\n    ");
15599                                 else
15600                                         appendPQExpBufferStr(q, ",\n    ");
15601
15602                                 appendPQExpBuffer(q, "CONSTRAINT %s ",
15603                                                                   fmtId(constr->dobj.name));
15604                                 appendPQExpBufferStr(q, constr->condef);
15605
15606                                 actual_atts++;
15607                         }
15608
15609                         if (actual_atts)
15610                                 appendPQExpBufferStr(q, "\n)");
15611                         else if (!((tbinfo->reloftype || tbinfo->ispartition) &&
15612                                            !dopt->binary_upgrade))
15613                         {
15614                                 /*
15615                                  * We must have a parenthesized attribute list, even though
15616                                  * empty, when not using the OF TYPE or PARTITION OF syntax.
15617                                  */
15618                                 appendPQExpBufferStr(q, " (\n)");
15619                         }
15620
15621                         if (tbinfo->ispartition && !dopt->binary_upgrade)
15622                         {
15623                                 appendPQExpBufferChar(q, '\n');
15624                                 appendPQExpBufferStr(q, tbinfo->partbound);
15625                         }
15626
15627                         /* Emit the INHERITS clause, except if this is a partition. */
15628                         if (numParents > 0 &&
15629                                 !tbinfo->ispartition &&
15630                                 !dopt->binary_upgrade)
15631                         {
15632                                 appendPQExpBufferStr(q, "\nINHERITS (");
15633                                 for (k = 0; k < numParents; k++)
15634                                 {
15635                                         TableInfo  *parentRel = parents[k];
15636
15637                                         if (k > 0)
15638                                                 appendPQExpBufferStr(q, ", ");
15639                                         appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
15640                                 }
15641                                 appendPQExpBufferChar(q, ')');
15642                         }
15643
15644                         if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15645                                 appendPQExpBuffer(q, "\nPARTITION BY %s", tbinfo->partkeydef);
15646
15647                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
15648                                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
15649                 }
15650
15651                 if (nonemptyReloptions(tbinfo->reloptions) ||
15652                         nonemptyReloptions(tbinfo->toast_reloptions))
15653                 {
15654                         bool            addcomma = false;
15655
15656                         appendPQExpBufferStr(q, "\nWITH (");
15657                         if (nonemptyReloptions(tbinfo->reloptions))
15658                         {
15659                                 addcomma = true;
15660                                 appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15661                         }
15662                         if (nonemptyReloptions(tbinfo->toast_reloptions))
15663                         {
15664                                 if (addcomma)
15665                                         appendPQExpBufferStr(q, ", ");
15666                                 appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
15667                                                                                 fout);
15668                         }
15669                         appendPQExpBufferChar(q, ')');
15670                 }
15671
15672                 /* Dump generic options if any */
15673                 if (ftoptions && ftoptions[0])
15674                         appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
15675
15676                 /*
15677                  * For materialized views, create the AS clause just like a view. At
15678                  * this point, we always mark the view as not populated.
15679                  */
15680                 if (tbinfo->relkind == RELKIND_MATVIEW)
15681                 {
15682                         PQExpBuffer result;
15683
15684                         result = createViewAsClause(fout, tbinfo);
15685                         appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
15686                                                           result->data);
15687                         destroyPQExpBuffer(result);
15688                 }
15689                 else
15690                         appendPQExpBufferStr(q, ";\n");
15691
15692                 /*
15693                  * in binary upgrade mode, update the catalog with any missing values
15694                  * that might be present.
15695                  */
15696                 if (dopt->binary_upgrade)
15697                 {
15698                         for (j = 0; j < tbinfo->numatts; j++)
15699                         {
15700                                 if (tbinfo->attmissingval[j][0] != '\0')
15701                                 {
15702                                         appendPQExpBufferStr(q, "\n-- set missing value.\n");
15703                                         appendPQExpBufferStr(q,
15704                                                                                  "SELECT pg_catalog.binary_upgrade_set_missing_value(");
15705                                         appendStringLiteralAH(q, qualrelname, fout);
15706                                         appendPQExpBufferStr(q, "::pg_catalog.regclass,");
15707                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15708                                         appendPQExpBufferStr(q, ",");
15709                                         appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
15710                                         appendPQExpBufferStr(q, ");\n\n");
15711                                 }
15712                         }
15713                 }
15714
15715                 /*
15716                  * To create binary-compatible heap files, we have to ensure the same
15717                  * physical column order, including dropped columns, as in the
15718                  * original.  Therefore, we create dropped columns above and drop them
15719                  * here, also updating their attlen/attalign values so that the
15720                  * dropped column can be skipped properly.  (We do not bother with
15721                  * restoring the original attbyval setting.)  Also, inheritance
15722                  * relationships are set up by doing ALTER TABLE INHERIT rather than
15723                  * using an INHERITS clause --- the latter would possibly mess up the
15724                  * column order.  That also means we have to take care about setting
15725                  * attislocal correctly, plus fix up any inherited CHECK constraints.
15726                  * Analogously, we set up typed tables using ALTER TABLE / OF here.
15727                  *
15728                  * We process foreign and partitioned tables here, even though they
15729                  * lack heap storage, because they can participate in inheritance
15730                  * relationships and we want this stuff to be consistent across the
15731                  * inheritance tree.  We can exclude indexes, toast tables, sequences
15732                  * and matviews, even though they have storage, because we don't
15733                  * support altering or dropping columns in them, nor can they be part
15734                  * of inheritance trees.
15735                  */
15736                 if (dopt->binary_upgrade &&
15737                         (tbinfo->relkind == RELKIND_RELATION ||
15738                          tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
15739                          tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
15740                 {
15741                         for (j = 0; j < tbinfo->numatts; j++)
15742                         {
15743                                 if (tbinfo->attisdropped[j])
15744                                 {
15745                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
15746                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
15747                                                                           "SET attlen = %d, "
15748                                                                           "attalign = '%c', attbyval = false\n"
15749                                                                           "WHERE attname = ",
15750                                                                           tbinfo->attlen[j],
15751                                                                           tbinfo->attalign[j]);
15752                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15753                                         appendPQExpBufferStr(q, "\n  AND attrelid = ");
15754                                         appendStringLiteralAH(q, qualrelname, fout);
15755                                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15756
15757                                         if (tbinfo->relkind == RELKIND_RELATION ||
15758                                                 tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15759                                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15760                                                                                   qualrelname);
15761                                         else
15762                                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE ONLY %s ",
15763                                                                                   qualrelname);
15764                                         appendPQExpBuffer(q, "DROP COLUMN %s;\n",
15765                                                                           fmtId(tbinfo->attnames[j]));
15766                                 }
15767                                 else if (!tbinfo->attislocal[j])
15768                                 {
15769                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
15770                                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
15771                                                                                  "SET attislocal = false\n"
15772                                                                                  "WHERE attname = ");
15773                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15774                                         appendPQExpBufferStr(q, "\n  AND attrelid = ");
15775                                         appendStringLiteralAH(q, qualrelname, fout);
15776                                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15777                                 }
15778                         }
15779
15780                         for (k = 0; k < tbinfo->ncheck; k++)
15781                         {
15782                                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
15783
15784                                 if (constr->separate || constr->conislocal)
15785                                         continue;
15786
15787                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
15788                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15789                                                                   qualrelname);
15790                                 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
15791                                                                   fmtId(constr->dobj.name));
15792                                 appendPQExpBuffer(q, "%s;\n", constr->condef);
15793                                 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
15794                                                                          "SET conislocal = false\n"
15795                                                                          "WHERE contype = 'c' AND conname = ");
15796                                 appendStringLiteralAH(q, constr->dobj.name, fout);
15797                                 appendPQExpBufferStr(q, "\n  AND conrelid = ");
15798                                 appendStringLiteralAH(q, qualrelname, fout);
15799                                 appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15800                         }
15801
15802                         if (numParents > 0)
15803                         {
15804                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance and partitioning this way.\n");
15805                                 for (k = 0; k < numParents; k++)
15806                                 {
15807                                         TableInfo  *parentRel = parents[k];
15808
15809                                         /* In the partitioning case, we alter the parent */
15810                                         if (tbinfo->ispartition)
15811                                                 appendPQExpBuffer(q,
15812                                                                                   "ALTER TABLE ONLY %s ATTACH PARTITION ",
15813                                                                                   fmtQualifiedDumpable(parentRel));
15814                                         else
15815                                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
15816                                                                                   qualrelname);
15817
15818                                         /* Partition needs specifying the bounds */
15819                                         if (tbinfo->ispartition)
15820                                                 appendPQExpBuffer(q, "%s %s;\n",
15821                                                                                   qualrelname,
15822                                                                                   tbinfo->partbound);
15823                                         else
15824                                                 appendPQExpBuffer(q, "%s;\n",
15825                                                                                   fmtQualifiedDumpable(parentRel));
15826                                 }
15827                         }
15828
15829                         if (tbinfo->reloftype)
15830                         {
15831                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
15832                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
15833                                                                   qualrelname,
15834                                                                   tbinfo->reloftype);
15835                         }
15836                 }
15837
15838                 /*
15839                  * In binary_upgrade mode, arrange to restore the old relfrozenxid and
15840                  * relminmxid of all vacuumable relations.  (While vacuum.c processes
15841                  * TOAST tables semi-independently, here we see them only as children
15842                  * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
15843                  * child toast table is handled below.)
15844                  */
15845                 if (dopt->binary_upgrade &&
15846                         (tbinfo->relkind == RELKIND_RELATION ||
15847                          tbinfo->relkind == RELKIND_MATVIEW))
15848                 {
15849                         appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
15850                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
15851                                                           "SET relfrozenxid = '%u', relminmxid = '%u'\n"
15852                                                           "WHERE oid = ",
15853                                                           tbinfo->frozenxid, tbinfo->minmxid);
15854                         appendStringLiteralAH(q, qualrelname, fout);
15855                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15856
15857                         if (tbinfo->toast_oid)
15858                         {
15859                                 /*
15860                                  * The toast table will have the same OID at restore, so we
15861                                  * can safely target it by OID.
15862                                  */
15863                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
15864                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
15865                                                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
15866                                                                   "WHERE oid = '%u';\n",
15867                                                                   tbinfo->toast_frozenxid,
15868                                                                   tbinfo->toast_minmxid, tbinfo->toast_oid);
15869                         }
15870                 }
15871
15872                 /*
15873                  * In binary_upgrade mode, restore matviews' populated status by
15874                  * poking pg_class directly.  This is pretty ugly, but we can't use
15875                  * REFRESH MATERIALIZED VIEW since it's possible that some underlying
15876                  * matview is not populated even though this matview is; in any case,
15877                  * we want to transfer the matview's heap storage, not run REFRESH.
15878                  */
15879                 if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
15880                         tbinfo->relispopulated)
15881                 {
15882                         appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
15883                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
15884                                                                  "SET relispopulated = 't'\n"
15885                                                                  "WHERE oid = ");
15886                         appendStringLiteralAH(q, qualrelname, fout);
15887                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15888                 }
15889
15890                 /*
15891                  * Dump additional per-column properties that we can't handle in the
15892                  * main CREATE TABLE command.
15893                  */
15894                 for (j = 0; j < tbinfo->numatts; j++)
15895                 {
15896                         /* None of this applies to dropped columns */
15897                         if (tbinfo->attisdropped[j])
15898                                 continue;
15899
15900                         /*
15901                          * If we didn't dump the column definition explicitly above, and
15902                          * it is NOT NULL and did not inherit that property from a parent,
15903                          * we have to mark it separately.
15904                          */
15905                         if (!shouldPrintColumn(dopt, tbinfo, j) &&
15906                                 tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
15907                         {
15908                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15909                                                                   qualrelname);
15910                                 appendPQExpBuffer(q, "ALTER COLUMN %s SET NOT NULL;\n",
15911                                                                   fmtId(tbinfo->attnames[j]));
15912                         }
15913
15914                         /*
15915                          * Dump per-column statistics information. We only issue an ALTER
15916                          * TABLE statement if the attstattarget entry for this column is
15917                          * non-negative (i.e. it's not the default value)
15918                          */
15919                         if (tbinfo->attstattarget[j] >= 0)
15920                         {
15921                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15922                                                                   qualrelname);
15923                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
15924                                                                   fmtId(tbinfo->attnames[j]));
15925                                 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
15926                                                                   tbinfo->attstattarget[j]);
15927                         }
15928
15929                         /*
15930                          * Dump per-column storage information.  The statement is only
15931                          * dumped if the storage has been changed from the type's default.
15932                          */
15933                         if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
15934                         {
15935                                 switch (tbinfo->attstorage[j])
15936                                 {
15937                                         case 'p':
15938                                                 storage = "PLAIN";
15939                                                 break;
15940                                         case 'e':
15941                                                 storage = "EXTERNAL";
15942                                                 break;
15943                                         case 'm':
15944                                                 storage = "MAIN";
15945                                                 break;
15946                                         case 'x':
15947                                                 storage = "EXTENDED";
15948                                                 break;
15949                                         default:
15950                                                 storage = NULL;
15951                                 }
15952
15953                                 /*
15954                                  * Only dump the statement if it's a storage type we recognize
15955                                  */
15956                                 if (storage != NULL)
15957                                 {
15958                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15959                                                                           qualrelname);
15960                                         appendPQExpBuffer(q, "ALTER COLUMN %s ",
15961                                                                           fmtId(tbinfo->attnames[j]));
15962                                         appendPQExpBuffer(q, "SET STORAGE %s;\n",
15963                                                                           storage);
15964                                 }
15965                         }
15966
15967                         /*
15968                          * Dump per-column attributes.
15969                          */
15970                         if (tbinfo->attoptions[j][0] != '\0')
15971                         {
15972                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15973                                                                   qualrelname);
15974                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
15975                                                                   fmtId(tbinfo->attnames[j]));
15976                                 appendPQExpBuffer(q, "SET (%s);\n",
15977                                                                   tbinfo->attoptions[j]);
15978                         }
15979
15980                         /*
15981                          * Dump per-column fdw options.
15982                          */
15983                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
15984                                 tbinfo->attfdwoptions[j][0] != '\0')
15985                         {
15986                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
15987                                                                   qualrelname);
15988                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
15989                                                                   fmtId(tbinfo->attnames[j]));
15990                                 appendPQExpBuffer(q, "OPTIONS (\n    %s\n);\n",
15991                                                                   tbinfo->attfdwoptions[j]);
15992                         }
15993                 }
15994
15995                 if (ftoptions)
15996                         free(ftoptions);
15997                 if (srvname)
15998                         free(srvname);
15999         }
16000
16001         /*
16002          * dump properties we only have ALTER TABLE syntax for
16003          */
16004         if ((tbinfo->relkind == RELKIND_RELATION ||
16005                  tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
16006                  tbinfo->relkind == RELKIND_MATVIEW) &&
16007                 tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
16008         {
16009                 if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
16010                 {
16011                         /* nothing to do, will be set when the index is dumped */
16012                 }
16013                 else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
16014                 {
16015                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
16016                                                           qualrelname);
16017                 }
16018                 else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
16019                 {
16020                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
16021                                                           qualrelname);
16022                 }
16023         }
16024
16025         if (tbinfo->forcerowsec)
16026                 appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
16027                                                   qualrelname);
16028
16029         if (dopt->binary_upgrade)
16030                 binary_upgrade_extension_member(q, &tbinfo->dobj,
16031                                                                                 reltypename, qrelname,
16032                                                                                 tbinfo->dobj.namespace->dobj.name);
16033
16034         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16035                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
16036                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
16037                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
16038                                                                   .tablespace = (tbinfo->relkind == RELKIND_VIEW) ?
16039                                                                   NULL : tbinfo->reltablespace,
16040                                                                   .owner = tbinfo->rolname,
16041                                                                   .description = reltypename,
16042                                                                   .section = tbinfo->postponed_def ?
16043                                                                   SECTION_POST_DATA : SECTION_PRE_DATA,
16044                                                                   .createStmt = q->data,
16045                                                                   .dropStmt = delq->data));
16046
16047
16048         /* Dump Table Comments */
16049         if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16050                 dumpTableComment(fout, tbinfo, reltypename);
16051
16052         /* Dump Table Security Labels */
16053         if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
16054                 dumpTableSecLabel(fout, tbinfo, reltypename);
16055
16056         /* Dump comments on inlined table constraints */
16057         for (j = 0; j < tbinfo->ncheck; j++)
16058         {
16059                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
16060
16061                 if (constr->separate || !constr->conislocal)
16062                         continue;
16063
16064                 if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16065                         dumpTableConstraintComment(fout, constr);
16066         }
16067
16068         destroyPQExpBuffer(q);
16069         destroyPQExpBuffer(delq);
16070         free(qrelname);
16071         free(qualrelname);
16072 }
16073
16074 /*
16075  * dumpAttrDef --- dump an attribute's default-value declaration
16076  */
16077 static void
16078 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
16079 {
16080         DumpOptions *dopt = fout->dopt;
16081         TableInfo  *tbinfo = adinfo->adtable;
16082         int                     adnum = adinfo->adnum;
16083         PQExpBuffer q;
16084         PQExpBuffer delq;
16085         char       *qualrelname;
16086         char       *tag;
16087
16088         /* Skip if table definition not to be dumped */
16089         if (!tbinfo->dobj.dump || dopt->dataOnly)
16090                 return;
16091
16092         /* Skip if not "separate"; it was dumped in the table's definition */
16093         if (!adinfo->separate)
16094                 return;
16095
16096         q = createPQExpBuffer();
16097         delq = createPQExpBuffer();
16098
16099         qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
16100
16101         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16102                                           qualrelname);
16103         appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
16104                                           fmtId(tbinfo->attnames[adnum - 1]),
16105                                           adinfo->adef_expr);
16106
16107         appendPQExpBuffer(delq, "ALTER TABLE %s ",
16108                                           qualrelname);
16109         appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
16110                                           fmtId(tbinfo->attnames[adnum - 1]));
16111
16112         tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
16113
16114         if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16115                 ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
16116                                          ARCHIVE_OPTS(.tag = tag,
16117                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
16118                                                                   .owner = tbinfo->rolname,
16119                                                                   .description = "DEFAULT",
16120                                                                   .section = SECTION_PRE_DATA,
16121                                                                   .createStmt = q->data,
16122                                                                   .dropStmt = delq->data));
16123
16124         free(tag);
16125         destroyPQExpBuffer(q);
16126         destroyPQExpBuffer(delq);
16127         free(qualrelname);
16128 }
16129
16130 /*
16131  * getAttrName: extract the correct name for an attribute
16132  *
16133  * The array tblInfo->attnames[] only provides names of user attributes;
16134  * if a system attribute number is supplied, we have to fake it.
16135  * We also do a little bit of bounds checking for safety's sake.
16136  */
16137 static const char *
16138 getAttrName(int attrnum, TableInfo *tblInfo)
16139 {
16140         if (attrnum > 0 && attrnum <= tblInfo->numatts)
16141                 return tblInfo->attnames[attrnum - 1];
16142         switch (attrnum)
16143         {
16144                 case SelfItemPointerAttributeNumber:
16145                         return "ctid";
16146                 case MinTransactionIdAttributeNumber:
16147                         return "xmin";
16148                 case MinCommandIdAttributeNumber:
16149                         return "cmin";
16150                 case MaxTransactionIdAttributeNumber:
16151                         return "xmax";
16152                 case MaxCommandIdAttributeNumber:
16153                         return "cmax";
16154                 case TableOidAttributeNumber:
16155                         return "tableoid";
16156         }
16157         exit_horribly(NULL, "invalid column number %d for table \"%s\"\n",
16158                                   attrnum, tblInfo->dobj.name);
16159         return NULL;                            /* keep compiler quiet */
16160 }
16161
16162 /*
16163  * dumpIndex
16164  *        write out to fout a user-defined index
16165  */
16166 static void
16167 dumpIndex(Archive *fout, IndxInfo *indxinfo)
16168 {
16169         DumpOptions *dopt = fout->dopt;
16170         TableInfo  *tbinfo = indxinfo->indextable;
16171         bool            is_constraint = (indxinfo->indexconstraint != 0);
16172         PQExpBuffer q;
16173         PQExpBuffer delq;
16174         char       *qindxname;
16175
16176         if (dopt->dataOnly)
16177                 return;
16178
16179         q = createPQExpBuffer();
16180         delq = createPQExpBuffer();
16181
16182         qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
16183
16184         /*
16185          * If there's an associated constraint, don't dump the index per se, but
16186          * do dump any comment for it.  (This is safe because dependency ordering
16187          * will have ensured the constraint is emitted first.)  Note that the
16188          * emitted comment has to be shown as depending on the constraint, not the
16189          * index, in such cases.
16190          */
16191         if (!is_constraint)
16192         {
16193                 char       *indstatcols = indxinfo->indstatcols;
16194                 char       *indstatvals = indxinfo->indstatvals;
16195                 char      **indstatcolsarray = NULL;
16196                 char      **indstatvalsarray = NULL;
16197                 int                     nstatcols;
16198                 int                     nstatvals;
16199
16200                 if (dopt->binary_upgrade)
16201                         binary_upgrade_set_pg_class_oids(fout, q,
16202                                                                                          indxinfo->dobj.catId.oid, true);
16203
16204                 /* Plain secondary index */
16205                 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
16206
16207                 /*
16208                  * Append ALTER TABLE commands as needed to set properties that we
16209                  * only have ALTER TABLE syntax for.  Keep this in sync with the
16210                  * similar code in dumpConstraint!
16211                  */
16212
16213                 /* If the index is clustered, we need to record that. */
16214                 if (indxinfo->indisclustered)
16215                 {
16216                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16217                                                           fmtQualifiedDumpable(tbinfo));
16218                         /* index name is not qualified in this syntax */
16219                         appendPQExpBuffer(q, " ON %s;\n",
16220                                                           qindxname);
16221                 }
16222
16223                 /*
16224                  * If the index has any statistics on some of its columns, generate
16225                  * the associated ALTER INDEX queries.
16226                  */
16227                 if (parsePGArray(indstatcols, &indstatcolsarray, &nstatcols) &&
16228                         parsePGArray(indstatvals, &indstatvalsarray, &nstatvals) &&
16229                         nstatcols == nstatvals)
16230                 {
16231                         int                     j;
16232
16233                         for (j = 0; j < nstatcols; j++)
16234                         {
16235                                 appendPQExpBuffer(q, "ALTER INDEX %s ",
16236                                                                   fmtQualifiedDumpable(indxinfo));
16237
16238                                 /*
16239                                  * Note that this is a column number, so no quotes should be
16240                                  * used.
16241                                  */
16242                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
16243                                                                   indstatcolsarray[j]);
16244                                 appendPQExpBuffer(q, "SET STATISTICS %s;\n",
16245                                                                   indstatvalsarray[j]);
16246                         }
16247                 }
16248
16249                 /* If the index defines identity, we need to record that. */
16250                 if (indxinfo->indisreplident)
16251                 {
16252                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
16253                                                           fmtQualifiedDumpable(tbinfo));
16254                         /* index name is not qualified in this syntax */
16255                         appendPQExpBuffer(q, " INDEX %s;\n",
16256                                                           qindxname);
16257                 }
16258
16259                 appendPQExpBuffer(delq, "DROP INDEX %s;\n",
16260                                                   fmtQualifiedDumpable(indxinfo));
16261
16262                 if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16263                         ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
16264                                                  ARCHIVE_OPTS(.tag = indxinfo->dobj.name,
16265                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
16266                                                                           .tablespace = indxinfo->tablespace,
16267                                                                           .owner = tbinfo->rolname,
16268                                                                           .description = "INDEX",
16269                                                                           .section = SECTION_POST_DATA,
16270                                                                           .createStmt = q->data,
16271                                                                           .dropStmt = delq->data));
16272
16273                 if (indstatcolsarray)
16274                         free(indstatcolsarray);
16275                 if (indstatvalsarray)
16276                         free(indstatvalsarray);
16277         }
16278
16279         /* Dump Index Comments */
16280         if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16281                 dumpComment(fout, "INDEX", qindxname,
16282                                         tbinfo->dobj.namespace->dobj.name,
16283                                         tbinfo->rolname,
16284                                         indxinfo->dobj.catId, 0,
16285                                         is_constraint ? indxinfo->indexconstraint :
16286                                         indxinfo->dobj.dumpId);
16287
16288         destroyPQExpBuffer(q);
16289         destroyPQExpBuffer(delq);
16290         free(qindxname);
16291 }
16292
16293 /*
16294  * dumpIndexAttach
16295  *        write out to fout a partitioned-index attachment clause
16296  */
16297 static void
16298 dumpIndexAttach(Archive *fout, IndexAttachInfo *attachinfo)
16299 {
16300         if (fout->dopt->dataOnly)
16301                 return;
16302
16303         if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
16304         {
16305                 PQExpBuffer q = createPQExpBuffer();
16306
16307                 appendPQExpBuffer(q, "ALTER INDEX %s ",
16308                                                   fmtQualifiedDumpable(attachinfo->parentIdx));
16309                 appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
16310                                                   fmtQualifiedDumpable(attachinfo->partitionIdx));
16311
16312                 ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
16313                                          ARCHIVE_OPTS(.tag = attachinfo->dobj.name,
16314                                                                   .namespace = attachinfo->dobj.namespace->dobj.name,
16315                                                                   .description = "INDEX ATTACH",
16316                                                                   .section = SECTION_POST_DATA,
16317                                                                   .createStmt = q->data));
16318
16319                 destroyPQExpBuffer(q);
16320         }
16321 }
16322
16323 /*
16324  * dumpStatisticsExt
16325  *        write out to fout an extended statistics object
16326  */
16327 static void
16328 dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo)
16329 {
16330         DumpOptions *dopt = fout->dopt;
16331         PQExpBuffer q;
16332         PQExpBuffer delq;
16333         PQExpBuffer query;
16334         char       *qstatsextname;
16335         PGresult   *res;
16336         char       *stxdef;
16337
16338         /* Skip if not to be dumped */
16339         if (!statsextinfo->dobj.dump || dopt->dataOnly)
16340                 return;
16341
16342         q = createPQExpBuffer();
16343         delq = createPQExpBuffer();
16344         query = createPQExpBuffer();
16345
16346         qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
16347
16348         appendPQExpBuffer(query, "SELECT "
16349                                           "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
16350                                           statsextinfo->dobj.catId.oid);
16351
16352         res = ExecuteSqlQueryForSingleRow(fout, query->data);
16353
16354         stxdef = PQgetvalue(res, 0, 0);
16355
16356         /* Result of pg_get_statisticsobjdef is complete except for semicolon */
16357         appendPQExpBuffer(q, "%s;\n", stxdef);
16358
16359         appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
16360                                           fmtQualifiedDumpable(statsextinfo));
16361
16362         if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16363                 ArchiveEntry(fout, statsextinfo->dobj.catId,
16364                                          statsextinfo->dobj.dumpId,
16365                                          ARCHIVE_OPTS(.tag = statsextinfo->dobj.name,
16366                                                                   .namespace = statsextinfo->dobj.namespace->dobj.name,
16367                                                                   .owner = statsextinfo->rolname,
16368                                                                   .description = "STATISTICS",
16369                                                                   .section = SECTION_POST_DATA,
16370                                                                   .createStmt = q->data,
16371                                                                   .dropStmt = delq->data));
16372
16373         /* Dump Statistics Comments */
16374         if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16375                 dumpComment(fout, "STATISTICS", qstatsextname,
16376                                         statsextinfo->dobj.namespace->dobj.name,
16377                                         statsextinfo->rolname,
16378                                         statsextinfo->dobj.catId, 0,
16379                                         statsextinfo->dobj.dumpId);
16380
16381         PQclear(res);
16382         destroyPQExpBuffer(q);
16383         destroyPQExpBuffer(delq);
16384         destroyPQExpBuffer(query);
16385         free(qstatsextname);
16386 }
16387
16388 /*
16389  * dumpConstraint
16390  *        write out to fout a user-defined constraint
16391  */
16392 static void
16393 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
16394 {
16395         DumpOptions *dopt = fout->dopt;
16396         TableInfo  *tbinfo = coninfo->contable;
16397         PQExpBuffer q;
16398         PQExpBuffer delq;
16399         char       *tag = NULL;
16400
16401         /* Skip if not to be dumped */
16402         if (!coninfo->dobj.dump || dopt->dataOnly)
16403                 return;
16404
16405         q = createPQExpBuffer();
16406         delq = createPQExpBuffer();
16407
16408         if (coninfo->contype == 'p' ||
16409                 coninfo->contype == 'u' ||
16410                 coninfo->contype == 'x')
16411         {
16412                 /* Index-related constraint */
16413                 IndxInfo   *indxinfo;
16414                 int                     k;
16415
16416                 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
16417
16418                 if (indxinfo == NULL)
16419                         exit_horribly(NULL, "missing index for constraint \"%s\"\n",
16420                                                   coninfo->dobj.name);
16421
16422                 if (dopt->binary_upgrade)
16423                         binary_upgrade_set_pg_class_oids(fout, q,
16424                                                                                          indxinfo->dobj.catId.oid, true);
16425
16426                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
16427                                                   fmtQualifiedDumpable(tbinfo));
16428                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
16429                                                   fmtId(coninfo->dobj.name));
16430
16431                 if (coninfo->condef)
16432                 {
16433                         /* pg_get_constraintdef should have provided everything */
16434                         appendPQExpBuffer(q, "%s;\n", coninfo->condef);
16435                 }
16436                 else
16437                 {
16438                         appendPQExpBuffer(q, "%s (",
16439                                                           coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
16440                         for (k = 0; k < indxinfo->indnkeyattrs; k++)
16441                         {
16442                                 int                     indkey = (int) indxinfo->indkeys[k];
16443                                 const char *attname;
16444
16445                                 if (indkey == InvalidAttrNumber)
16446                                         break;
16447                                 attname = getAttrName(indkey, tbinfo);
16448
16449                                 appendPQExpBuffer(q, "%s%s",
16450                                                                   (k == 0) ? "" : ", ",
16451                                                                   fmtId(attname));
16452                         }
16453
16454                         if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
16455                                 appendPQExpBuffer(q, ") INCLUDE (");
16456
16457                         for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
16458                         {
16459                                 int                     indkey = (int) indxinfo->indkeys[k];
16460                                 const char *attname;
16461
16462                                 if (indkey == InvalidAttrNumber)
16463                                         break;
16464                                 attname = getAttrName(indkey, tbinfo);
16465
16466                                 appendPQExpBuffer(q, "%s%s",
16467                                                                   (k == indxinfo->indnkeyattrs) ? "" : ", ",
16468                                                                   fmtId(attname));
16469                         }
16470
16471                         appendPQExpBufferChar(q, ')');
16472
16473                         if (nonemptyReloptions(indxinfo->indreloptions))
16474                         {
16475                                 appendPQExpBufferStr(q, " WITH (");
16476                                 appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
16477                                 appendPQExpBufferChar(q, ')');
16478                         }
16479
16480                         if (coninfo->condeferrable)
16481                         {
16482                                 appendPQExpBufferStr(q, " DEFERRABLE");
16483                                 if (coninfo->condeferred)
16484                                         appendPQExpBufferStr(q, " INITIALLY DEFERRED");
16485                         }
16486
16487                         appendPQExpBufferStr(q, ";\n");
16488                 }
16489
16490                 /*
16491                  * Append ALTER TABLE commands as needed to set properties that we
16492                  * only have ALTER TABLE syntax for.  Keep this in sync with the
16493                  * similar code in dumpIndex!
16494                  */
16495
16496                 /* If the index is clustered, we need to record that. */
16497                 if (indxinfo->indisclustered)
16498                 {
16499                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16500                                                           fmtQualifiedDumpable(tbinfo));
16501                         /* index name is not qualified in this syntax */
16502                         appendPQExpBuffer(q, " ON %s;\n",
16503                                                           fmtId(indxinfo->dobj.name));
16504                 }
16505
16506                 /* If the index defines identity, we need to record that. */
16507                 if (indxinfo->indisreplident)
16508                 {
16509                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
16510                                                           fmtQualifiedDumpable(tbinfo));
16511                         /* index name is not qualified in this syntax */
16512                         appendPQExpBuffer(q, " INDEX %s;\n",
16513                                                           fmtId(indxinfo->dobj.name));
16514                 }
16515
16516                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s ",
16517                                                   fmtQualifiedDumpable(tbinfo));
16518                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16519                                                   fmtId(coninfo->dobj.name));
16520
16521                 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16522
16523                 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16524                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16525                                                  ARCHIVE_OPTS(.tag = tag,
16526                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
16527                                                                           .tablespace = indxinfo->tablespace,
16528                                                                           .owner = tbinfo->rolname,
16529                                                                           .description = "CONSTRAINT",
16530                                                                           .section = SECTION_POST_DATA,
16531                                                                           .createStmt = q->data,
16532                                                                           .dropStmt = delq->data));
16533         }
16534         else if (coninfo->contype == 'f')
16535         {
16536                 char       *only;
16537
16538                 /*
16539                  * Foreign keys on partitioned tables are always declared as
16540                  * inheriting to partitions; for all other cases, emit them as
16541                  * applying ONLY directly to the named table, because that's how they
16542                  * work for regular inherited tables.
16543                  */
16544                 only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
16545
16546                 /*
16547                  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
16548                  * current table data is not processed
16549                  */
16550                 appendPQExpBuffer(q, "ALTER TABLE %s%s\n",
16551                                                   only, fmtQualifiedDumpable(tbinfo));
16552                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16553                                                   fmtId(coninfo->dobj.name),
16554                                                   coninfo->condef);
16555
16556                 appendPQExpBuffer(delq, "ALTER TABLE %s%s ",
16557                                                   only, fmtQualifiedDumpable(tbinfo));
16558                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16559                                                   fmtId(coninfo->dobj.name));
16560
16561                 tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16562
16563                 if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16564                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16565                                                  ARCHIVE_OPTS(.tag = tag,
16566                                                                           .namespace = tbinfo->dobj.namespace->dobj.name,
16567                                                                           .owner = tbinfo->rolname,
16568                                                                           .description = "FK CONSTRAINT",
16569                                                                           .section = SECTION_POST_DATA,
16570                                                                           .createStmt = q->data,
16571                                                                           .dropStmt = delq->data));
16572         }
16573         else if (coninfo->contype == 'c' && tbinfo)
16574         {
16575                 /* CHECK constraint on a table */
16576
16577                 /* Ignore if not to be dumped separately, or if it was inherited */
16578                 if (coninfo->separate && coninfo->conislocal)
16579                 {
16580                         /* not ONLY since we want it to propagate to children */
16581                         appendPQExpBuffer(q, "ALTER TABLE %s\n",
16582                                                           fmtQualifiedDumpable(tbinfo));
16583                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16584                                                           fmtId(coninfo->dobj.name),
16585                                                           coninfo->condef);
16586
16587                         appendPQExpBuffer(delq, "ALTER TABLE %s ",
16588                                                           fmtQualifiedDumpable(tbinfo));
16589                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16590                                                           fmtId(coninfo->dobj.name));
16591
16592                         tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16593
16594                         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16595                                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16596                                                          ARCHIVE_OPTS(.tag = tag,
16597                                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
16598                                                                                   .owner = tbinfo->rolname,
16599                                                                                   .description = "CHECK CONSTRAINT",
16600                                                                                   .section = SECTION_POST_DATA,
16601                                                                                   .createStmt = q->data,
16602                                                                                   .dropStmt = delq->data));
16603                 }
16604         }
16605         else if (coninfo->contype == 'c' && tbinfo == NULL)
16606         {
16607                 /* CHECK constraint on a domain */
16608                 TypeInfo   *tyinfo = coninfo->condomain;
16609
16610                 /* Ignore if not to be dumped separately */
16611                 if (coninfo->separate)
16612                 {
16613                         appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
16614                                                           fmtQualifiedDumpable(tyinfo));
16615                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16616                                                           fmtId(coninfo->dobj.name),
16617                                                           coninfo->condef);
16618
16619                         appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
16620                                                           fmtQualifiedDumpable(tyinfo));
16621                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16622                                                           fmtId(coninfo->dobj.name));
16623
16624                         tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
16625
16626                         if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16627                                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16628                                                          ARCHIVE_OPTS(.tag = tag,
16629                                                                                   .namespace = tyinfo->dobj.namespace->dobj.name,
16630                                                                                   .owner = tyinfo->rolname,
16631                                                                                   .description = "CHECK CONSTRAINT",
16632                                                                                   .section = SECTION_POST_DATA,
16633                                                                                   .createStmt = q->data,
16634                                                                                   .dropStmt = delq->data));
16635                 }
16636         }
16637         else
16638         {
16639                 exit_horribly(NULL, "unrecognized constraint type: %c\n",
16640                                           coninfo->contype);
16641         }
16642
16643         /* Dump Constraint Comments --- only works for table constraints */
16644         if (tbinfo && coninfo->separate &&
16645                 coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16646                 dumpTableConstraintComment(fout, coninfo);
16647
16648         free(tag);
16649         destroyPQExpBuffer(q);
16650         destroyPQExpBuffer(delq);
16651 }
16652
16653 /*
16654  * dumpTableConstraintComment --- dump a constraint's comment if any
16655  *
16656  * This is split out because we need the function in two different places
16657  * depending on whether the constraint is dumped as part of CREATE TABLE
16658  * or as a separate ALTER command.
16659  */
16660 static void
16661 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
16662 {
16663         TableInfo  *tbinfo = coninfo->contable;
16664         PQExpBuffer conprefix = createPQExpBuffer();
16665         char       *qtabname;
16666
16667         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
16668
16669         appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
16670                                           fmtId(coninfo->dobj.name));
16671
16672         if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16673                 dumpComment(fout, conprefix->data, qtabname,
16674                                         tbinfo->dobj.namespace->dobj.name,
16675                                         tbinfo->rolname,
16676                                         coninfo->dobj.catId, 0,
16677                                         coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
16678
16679         destroyPQExpBuffer(conprefix);
16680         free(qtabname);
16681 }
16682
16683 /*
16684  * findLastBuiltinOid_V71 -
16685  *
16686  * find the last built in oid
16687  *
16688  * For 7.1 through 8.0, we do this by retrieving datlastsysoid from the
16689  * pg_database entry for the current database.  (Note: current_database()
16690  * requires 7.3; pg_dump requires 8.0 now.)
16691  */
16692 static Oid
16693 findLastBuiltinOid_V71(Archive *fout)
16694 {
16695         PGresult   *res;
16696         Oid                     last_oid;
16697
16698         res = ExecuteSqlQueryForSingleRow(fout,
16699                                                                           "SELECT datlastsysoid FROM pg_database WHERE datname = current_database()");
16700         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
16701         PQclear(res);
16702
16703         return last_oid;
16704 }
16705
16706 /*
16707  * dumpSequence
16708  *        write the declaration (not data) of one user-defined sequence
16709  */
16710 static void
16711 dumpSequence(Archive *fout, TableInfo *tbinfo)
16712 {
16713         DumpOptions *dopt = fout->dopt;
16714         PGresult   *res;
16715         char       *startv,
16716                            *incby,
16717                            *maxv,
16718                            *minv,
16719                            *cache,
16720                            *seqtype;
16721         bool            cycled;
16722         bool            is_ascending;
16723         int64           default_minv,
16724                                 default_maxv;
16725         char            bufm[32],
16726                                 bufx[32];
16727         PQExpBuffer query = createPQExpBuffer();
16728         PQExpBuffer delqry = createPQExpBuffer();
16729         char       *qseqname;
16730
16731         qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
16732
16733         if (fout->remoteVersion >= 100000)
16734         {
16735                 appendPQExpBuffer(query,
16736                                                   "SELECT format_type(seqtypid, NULL), "
16737                                                   "seqstart, seqincrement, "
16738                                                   "seqmax, seqmin, "
16739                                                   "seqcache, seqcycle "
16740                                                   "FROM pg_catalog.pg_sequence "
16741                                                   "WHERE seqrelid = '%u'::oid",
16742                                                   tbinfo->dobj.catId.oid);
16743         }
16744         else if (fout->remoteVersion >= 80400)
16745         {
16746                 /*
16747                  * Before PostgreSQL 10, sequence metadata is in the sequence itself.
16748                  *
16749                  * Note: it might seem that 'bigint' potentially needs to be
16750                  * schema-qualified, but actually that's a keyword.
16751                  */
16752                 appendPQExpBuffer(query,
16753                                                   "SELECT 'bigint' AS sequence_type, "
16754                                                   "start_value, increment_by, max_value, min_value, "
16755                                                   "cache_value, is_cycled FROM %s",
16756                                                   fmtQualifiedDumpable(tbinfo));
16757         }
16758         else
16759         {
16760                 appendPQExpBuffer(query,
16761                                                   "SELECT 'bigint' AS sequence_type, "
16762                                                   "0 AS start_value, increment_by, max_value, min_value, "
16763                                                   "cache_value, is_cycled FROM %s",
16764                                                   fmtQualifiedDumpable(tbinfo));
16765         }
16766
16767         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16768
16769         if (PQntuples(res) != 1)
16770         {
16771                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
16772                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
16773                                                                  PQntuples(res)),
16774                                   tbinfo->dobj.name, PQntuples(res));
16775                 exit_nicely(1);
16776         }
16777
16778         seqtype = PQgetvalue(res, 0, 0);
16779         startv = PQgetvalue(res, 0, 1);
16780         incby = PQgetvalue(res, 0, 2);
16781         maxv = PQgetvalue(res, 0, 3);
16782         minv = PQgetvalue(res, 0, 4);
16783         cache = PQgetvalue(res, 0, 5);
16784         cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
16785
16786         /* Calculate default limits for a sequence of this type */
16787         is_ascending = (incby[0] != '-');
16788         if (strcmp(seqtype, "smallint") == 0)
16789         {
16790                 default_minv = is_ascending ? 1 : PG_INT16_MIN;
16791                 default_maxv = is_ascending ? PG_INT16_MAX : -1;
16792         }
16793         else if (strcmp(seqtype, "integer") == 0)
16794         {
16795                 default_minv = is_ascending ? 1 : PG_INT32_MIN;
16796                 default_maxv = is_ascending ? PG_INT32_MAX : -1;
16797         }
16798         else if (strcmp(seqtype, "bigint") == 0)
16799         {
16800                 default_minv = is_ascending ? 1 : PG_INT64_MIN;
16801                 default_maxv = is_ascending ? PG_INT64_MAX : -1;
16802         }
16803         else
16804         {
16805                 exit_horribly(NULL, "unrecognized sequence type: %s\n", seqtype);
16806                 default_minv = default_maxv = 0;        /* keep compiler quiet */
16807         }
16808
16809         /*
16810          * 64-bit strtol() isn't very portable, so convert the limits to strings
16811          * and compare that way.
16812          */
16813         snprintf(bufm, sizeof(bufm), INT64_FORMAT, default_minv);
16814         snprintf(bufx, sizeof(bufx), INT64_FORMAT, default_maxv);
16815
16816         /* Don't print minv/maxv if they match the respective default limit */
16817         if (strcmp(minv, bufm) == 0)
16818                 minv = NULL;
16819         if (strcmp(maxv, bufx) == 0)
16820                 maxv = NULL;
16821
16822         /*
16823          * Identity sequences are not to be dropped separately.
16824          */
16825         if (!tbinfo->is_identity_sequence)
16826         {
16827                 appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
16828                                                   fmtQualifiedDumpable(tbinfo));
16829         }
16830
16831         resetPQExpBuffer(query);
16832
16833         if (dopt->binary_upgrade)
16834         {
16835                 binary_upgrade_set_pg_class_oids(fout, query,
16836                                                                                  tbinfo->dobj.catId.oid, false);
16837                 binary_upgrade_set_type_oids_by_rel_oid(fout, query,
16838                                                                                                 tbinfo->dobj.catId.oid);
16839         }
16840
16841         if (tbinfo->is_identity_sequence)
16842         {
16843                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
16844
16845                 appendPQExpBuffer(query,
16846                                                   "ALTER TABLE %s ",
16847                                                   fmtQualifiedDumpable(owning_tab));
16848                 appendPQExpBuffer(query,
16849                                                   "ALTER COLUMN %s ADD GENERATED ",
16850                                                   fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
16851                 if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
16852                         appendPQExpBuffer(query, "ALWAYS");
16853                 else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
16854                         appendPQExpBuffer(query, "BY DEFAULT");
16855                 appendPQExpBuffer(query, " AS IDENTITY (\n    SEQUENCE NAME %s\n",
16856                                                   fmtQualifiedDumpable(tbinfo));
16857         }
16858         else
16859         {
16860                 appendPQExpBuffer(query,
16861                                                   "CREATE SEQUENCE %s\n",
16862                                                   fmtQualifiedDumpable(tbinfo));
16863
16864                 if (strcmp(seqtype, "bigint") != 0)
16865                         appendPQExpBuffer(query, "    AS %s\n", seqtype);
16866         }
16867
16868         if (fout->remoteVersion >= 80400)
16869                 appendPQExpBuffer(query, "    START WITH %s\n", startv);
16870
16871         appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
16872
16873         if (minv)
16874                 appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
16875         else
16876                 appendPQExpBufferStr(query, "    NO MINVALUE\n");
16877
16878         if (maxv)
16879                 appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
16880         else
16881                 appendPQExpBufferStr(query, "    NO MAXVALUE\n");
16882
16883         appendPQExpBuffer(query,
16884                                           "    CACHE %s%s",
16885                                           cache, (cycled ? "\n    CYCLE" : ""));
16886
16887         if (tbinfo->is_identity_sequence)
16888                 appendPQExpBufferStr(query, "\n);\n");
16889         else
16890                 appendPQExpBufferStr(query, ";\n");
16891
16892         /* binary_upgrade:      no need to clear TOAST table oid */
16893
16894         if (dopt->binary_upgrade)
16895                 binary_upgrade_extension_member(query, &tbinfo->dobj,
16896                                                                                 "SEQUENCE", qseqname,
16897                                                                                 tbinfo->dobj.namespace->dobj.name);
16898
16899         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16900                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
16901                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
16902                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
16903                                                                   .owner = tbinfo->rolname,
16904                                                                   .description = "SEQUENCE",
16905                                                                   .section = SECTION_PRE_DATA,
16906                                                                   .createStmt = query->data,
16907                                                                   .dropStmt = delqry->data));
16908
16909         /*
16910          * If the sequence is owned by a table column, emit the ALTER for it as a
16911          * separate TOC entry immediately following the sequence's own entry. It's
16912          * OK to do this rather than using full sorting logic, because the
16913          * dependency that tells us it's owned will have forced the table to be
16914          * created first.  We can't just include the ALTER in the TOC entry
16915          * because it will fail if we haven't reassigned the sequence owner to
16916          * match the table's owner.
16917          *
16918          * We need not schema-qualify the table reference because both sequence
16919          * and table must be in the same schema.
16920          */
16921         if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
16922         {
16923                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
16924
16925                 if (owning_tab == NULL)
16926                         exit_horribly(NULL, "failed sanity check, parent table with OID %u of sequence with OID %u not found\n",
16927                                                   tbinfo->owning_tab, tbinfo->dobj.catId.oid);
16928
16929                 if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
16930                 {
16931                         resetPQExpBuffer(query);
16932                         appendPQExpBuffer(query, "ALTER SEQUENCE %s",
16933                                                           fmtQualifiedDumpable(tbinfo));
16934                         appendPQExpBuffer(query, " OWNED BY %s",
16935                                                           fmtQualifiedDumpable(owning_tab));
16936                         appendPQExpBuffer(query, ".%s;\n",
16937                                                           fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
16938
16939                         if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16940                                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
16941                                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
16942                                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
16943                                                                                   .owner = tbinfo->rolname,
16944                                                                                   .description = "SEQUENCE OWNED BY",
16945                                                                                   .section = SECTION_PRE_DATA,
16946                                                                                   .createStmt = query->data,
16947                                                                                   .deps = &(tbinfo->dobj.dumpId),
16948                                                                                   .nDeps = 1));
16949                 }
16950         }
16951
16952         /* Dump Sequence Comments and Security Labels */
16953         if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16954                 dumpComment(fout, "SEQUENCE", qseqname,
16955                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
16956                                         tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
16957
16958         if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
16959                 dumpSecLabel(fout, "SEQUENCE", qseqname,
16960                                          tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
16961                                          tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
16962
16963         PQclear(res);
16964
16965         destroyPQExpBuffer(query);
16966         destroyPQExpBuffer(delqry);
16967         free(qseqname);
16968 }
16969
16970 /*
16971  * dumpSequenceData
16972  *        write the data of one user-defined sequence
16973  */
16974 static void
16975 dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
16976 {
16977         TableInfo  *tbinfo = tdinfo->tdtable;
16978         PGresult   *res;
16979         char       *last;
16980         bool            called;
16981         PQExpBuffer query = createPQExpBuffer();
16982
16983         appendPQExpBuffer(query,
16984                                           "SELECT last_value, is_called FROM %s",
16985                                           fmtQualifiedDumpable(tbinfo));
16986
16987         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
16988
16989         if (PQntuples(res) != 1)
16990         {
16991                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
16992                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
16993                                                                  PQntuples(res)),
16994                                   tbinfo->dobj.name, PQntuples(res));
16995                 exit_nicely(1);
16996         }
16997
16998         last = PQgetvalue(res, 0, 0);
16999         called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
17000
17001         resetPQExpBuffer(query);
17002         appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
17003         appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
17004         appendPQExpBuffer(query, ", %s, %s);\n",
17005                                           last, (called ? "true" : "false"));
17006
17007         if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
17008                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
17009                                          ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
17010                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17011                                                                   .owner = tbinfo->rolname,
17012                                                                   .description = "SEQUENCE SET",
17013                                                                   .section = SECTION_DATA,
17014                                                                   .createStmt = query->data,
17015                                                                   .deps = &(tbinfo->dobj.dumpId),
17016                                                                   .nDeps = 1));
17017
17018         PQclear(res);
17019
17020         destroyPQExpBuffer(query);
17021 }
17022
17023 /*
17024  * dumpTrigger
17025  *        write the declaration of one user-defined table trigger
17026  */
17027 static void
17028 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
17029 {
17030         DumpOptions *dopt = fout->dopt;
17031         TableInfo  *tbinfo = tginfo->tgtable;
17032         PQExpBuffer query;
17033         PQExpBuffer delqry;
17034         PQExpBuffer trigprefix;
17035         char       *qtabname;
17036         char       *tgargs;
17037         size_t          lentgargs;
17038         const char *p;
17039         int                     findx;
17040         char       *tag;
17041
17042         /*
17043          * we needn't check dobj.dump because TriggerInfo wouldn't have been
17044          * created in the first place for non-dumpable triggers
17045          */
17046         if (dopt->dataOnly)
17047                 return;
17048
17049         query = createPQExpBuffer();
17050         delqry = createPQExpBuffer();
17051         trigprefix = createPQExpBuffer();
17052
17053         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17054
17055         appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
17056                                           fmtId(tginfo->dobj.name));
17057         appendPQExpBuffer(delqry, "ON %s;\n",
17058                                           fmtQualifiedDumpable(tbinfo));
17059
17060         if (tginfo->tgdef)
17061         {
17062                 appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
17063         }
17064         else
17065         {
17066                 if (tginfo->tgisconstraint)
17067                 {
17068                         appendPQExpBufferStr(query, "CREATE CONSTRAINT TRIGGER ");
17069                         appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
17070                 }
17071                 else
17072                 {
17073                         appendPQExpBufferStr(query, "CREATE TRIGGER ");
17074                         appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
17075                 }
17076                 appendPQExpBufferStr(query, "\n    ");
17077
17078                 /* Trigger type */
17079                 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
17080                         appendPQExpBufferStr(query, "BEFORE");
17081                 else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
17082                         appendPQExpBufferStr(query, "AFTER");
17083                 else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
17084                         appendPQExpBufferStr(query, "INSTEAD OF");
17085                 else
17086                 {
17087                         write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
17088                         exit_nicely(1);
17089                 }
17090
17091                 findx = 0;
17092                 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
17093                 {
17094                         appendPQExpBufferStr(query, " INSERT");
17095                         findx++;
17096                 }
17097                 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
17098                 {
17099                         if (findx > 0)
17100                                 appendPQExpBufferStr(query, " OR DELETE");
17101                         else
17102                                 appendPQExpBufferStr(query, " DELETE");
17103                         findx++;
17104                 }
17105                 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
17106                 {
17107                         if (findx > 0)
17108                                 appendPQExpBufferStr(query, " OR UPDATE");
17109                         else
17110                                 appendPQExpBufferStr(query, " UPDATE");
17111                         findx++;
17112                 }
17113                 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
17114                 {
17115                         if (findx > 0)
17116                                 appendPQExpBufferStr(query, " OR TRUNCATE");
17117                         else
17118                                 appendPQExpBufferStr(query, " TRUNCATE");
17119                         findx++;
17120                 }
17121                 appendPQExpBuffer(query, " ON %s\n",
17122                                                   fmtQualifiedDumpable(tbinfo));
17123
17124                 if (tginfo->tgisconstraint)
17125                 {
17126                         if (OidIsValid(tginfo->tgconstrrelid))
17127                         {
17128                                 /* regclass output is already quoted */
17129                                 appendPQExpBuffer(query, "    FROM %s\n    ",
17130                                                                   tginfo->tgconstrrelname);
17131                         }
17132                         if (!tginfo->tgdeferrable)
17133                                 appendPQExpBufferStr(query, "NOT ");
17134                         appendPQExpBufferStr(query, "DEFERRABLE INITIALLY ");
17135                         if (tginfo->tginitdeferred)
17136                                 appendPQExpBufferStr(query, "DEFERRED\n");
17137                         else
17138                                 appendPQExpBufferStr(query, "IMMEDIATE\n");
17139                 }
17140
17141                 if (TRIGGER_FOR_ROW(tginfo->tgtype))
17142                         appendPQExpBufferStr(query, "    FOR EACH ROW\n    ");
17143                 else
17144                         appendPQExpBufferStr(query, "    FOR EACH STATEMENT\n    ");
17145
17146                 /* regproc output is already sufficiently quoted */
17147                 appendPQExpBuffer(query, "EXECUTE FUNCTION %s(",
17148                                                   tginfo->tgfname);
17149
17150                 tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
17151                                                                                   &lentgargs);
17152                 p = tgargs;
17153                 for (findx = 0; findx < tginfo->tgnargs; findx++)
17154                 {
17155                         /* find the embedded null that terminates this trigger argument */
17156                         size_t          tlen = strlen(p);
17157
17158                         if (p + tlen >= tgargs + lentgargs)
17159                         {
17160                                 /* hm, not found before end of bytea value... */
17161                                 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
17162                                                   tginfo->tgargs,
17163                                                   tginfo->dobj.name,
17164                                                   tbinfo->dobj.name);
17165                                 exit_nicely(1);
17166                         }
17167
17168                         if (findx > 0)
17169                                 appendPQExpBufferStr(query, ", ");
17170                         appendStringLiteralAH(query, p, fout);
17171                         p += tlen + 1;
17172                 }
17173                 free(tgargs);
17174                 appendPQExpBufferStr(query, ");\n");
17175         }
17176
17177         if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
17178         {
17179                 appendPQExpBuffer(query, "\nALTER TABLE %s ",
17180                                                   fmtQualifiedDumpable(tbinfo));
17181                 switch (tginfo->tgenabled)
17182                 {
17183                         case 'D':
17184                         case 'f':
17185                                 appendPQExpBufferStr(query, "DISABLE");
17186                                 break;
17187                         case 'A':
17188                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
17189                                 break;
17190                         case 'R':
17191                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
17192                                 break;
17193                         default:
17194                                 appendPQExpBufferStr(query, "ENABLE");
17195                                 break;
17196                 }
17197                 appendPQExpBuffer(query, " TRIGGER %s;\n",
17198                                                   fmtId(tginfo->dobj.name));
17199         }
17200
17201         appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
17202                                           fmtId(tginfo->dobj.name));
17203
17204         tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
17205
17206         if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17207                 ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
17208                                          ARCHIVE_OPTS(.tag = tag,
17209                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17210                                                                   .owner = tbinfo->rolname,
17211                                                                   .description = "TRIGGER",
17212                                                                   .section = SECTION_POST_DATA,
17213                                                                   .createStmt = query->data,
17214                                                                   .dropStmt = delqry->data));
17215
17216         if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17217                 dumpComment(fout, trigprefix->data, qtabname,
17218                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17219                                         tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
17220
17221         free(tag);
17222         destroyPQExpBuffer(query);
17223         destroyPQExpBuffer(delqry);
17224         destroyPQExpBuffer(trigprefix);
17225         free(qtabname);
17226 }
17227
17228 /*
17229  * dumpEventTrigger
17230  *        write the declaration of one user-defined event trigger
17231  */
17232 static void
17233 dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
17234 {
17235         DumpOptions *dopt = fout->dopt;
17236         PQExpBuffer query;
17237         PQExpBuffer delqry;
17238         char       *qevtname;
17239
17240         /* Skip if not to be dumped */
17241         if (!evtinfo->dobj.dump || dopt->dataOnly)
17242                 return;
17243
17244         query = createPQExpBuffer();
17245         delqry = createPQExpBuffer();
17246
17247         qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
17248
17249         appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
17250         appendPQExpBufferStr(query, qevtname);
17251         appendPQExpBufferStr(query, " ON ");
17252         appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
17253
17254         if (strcmp("", evtinfo->evttags) != 0)
17255         {
17256                 appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
17257                 appendPQExpBufferStr(query, evtinfo->evttags);
17258                 appendPQExpBufferChar(query, ')');
17259         }
17260
17261         appendPQExpBufferStr(query, "\n   EXECUTE FUNCTION ");
17262         appendPQExpBufferStr(query, evtinfo->evtfname);
17263         appendPQExpBufferStr(query, "();\n");
17264
17265         if (evtinfo->evtenabled != 'O')
17266         {
17267                 appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
17268                                                   qevtname);
17269                 switch (evtinfo->evtenabled)
17270                 {
17271                         case 'D':
17272                                 appendPQExpBufferStr(query, "DISABLE");
17273                                 break;
17274                         case 'A':
17275                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
17276                                 break;
17277                         case 'R':
17278                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
17279                                 break;
17280                         default:
17281                                 appendPQExpBufferStr(query, "ENABLE");
17282                                 break;
17283                 }
17284                 appendPQExpBufferStr(query, ";\n");
17285         }
17286
17287         appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
17288                                           qevtname);
17289
17290         if (dopt->binary_upgrade)
17291                 binary_upgrade_extension_member(query, &evtinfo->dobj,
17292                                                                                 "EVENT TRIGGER", qevtname, NULL);
17293
17294         if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17295                 ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
17296                                          ARCHIVE_OPTS(.tag = evtinfo->dobj.name,
17297                                                                   .owner = evtinfo->evtowner,
17298                                                                   .description = "EVENT TRIGGER",
17299                                                                   .section = SECTION_POST_DATA,
17300                                                                   .createStmt = query->data,
17301                                                                   .dropStmt = delqry->data));
17302
17303         if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17304                 dumpComment(fout, "EVENT TRIGGER", qevtname,
17305                                         NULL, evtinfo->evtowner,
17306                                         evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
17307
17308         destroyPQExpBuffer(query);
17309         destroyPQExpBuffer(delqry);
17310         free(qevtname);
17311 }
17312
17313 /*
17314  * dumpRule
17315  *              Dump a rule
17316  */
17317 static void
17318 dumpRule(Archive *fout, RuleInfo *rinfo)
17319 {
17320         DumpOptions *dopt = fout->dopt;
17321         TableInfo  *tbinfo = rinfo->ruletable;
17322         bool            is_view;
17323         PQExpBuffer query;
17324         PQExpBuffer cmd;
17325         PQExpBuffer delcmd;
17326         PQExpBuffer ruleprefix;
17327         char       *qtabname;
17328         PGresult   *res;
17329         char       *tag;
17330
17331         /* Skip if not to be dumped */
17332         if (!rinfo->dobj.dump || dopt->dataOnly)
17333                 return;
17334
17335         /*
17336          * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
17337          * we do not want to dump it as a separate object.
17338          */
17339         if (!rinfo->separate)
17340                 return;
17341
17342         /*
17343          * If it's an ON SELECT rule, we want to print it as a view definition,
17344          * instead of a rule.
17345          */
17346         is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
17347
17348         query = createPQExpBuffer();
17349         cmd = createPQExpBuffer();
17350         delcmd = createPQExpBuffer();
17351         ruleprefix = createPQExpBuffer();
17352
17353         qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17354
17355         if (is_view)
17356         {
17357                 PQExpBuffer result;
17358
17359                 /*
17360                  * We need OR REPLACE here because we'll be replacing a dummy view.
17361                  * Otherwise this should look largely like the regular view dump code.
17362                  */
17363                 appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
17364                                                   fmtQualifiedDumpable(tbinfo));
17365                 if (nonemptyReloptions(tbinfo->reloptions))
17366                 {
17367                         appendPQExpBufferStr(cmd, " WITH (");
17368                         appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
17369                         appendPQExpBufferChar(cmd, ')');
17370                 }
17371                 result = createViewAsClause(fout, tbinfo);
17372                 appendPQExpBuffer(cmd, " AS\n%s", result->data);
17373                 destroyPQExpBuffer(result);
17374                 if (tbinfo->checkoption != NULL)
17375                         appendPQExpBuffer(cmd, "\n  WITH %s CHECK OPTION",
17376                                                           tbinfo->checkoption);
17377                 appendPQExpBufferStr(cmd, ";\n");
17378         }
17379         else
17380         {
17381                 /* In the rule case, just print pg_get_ruledef's result verbatim */
17382                 appendPQExpBuffer(query,
17383                                                   "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
17384                                                   rinfo->dobj.catId.oid);
17385
17386                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17387
17388                 if (PQntuples(res) != 1)
17389                 {
17390                         write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
17391                                           rinfo->dobj.name, tbinfo->dobj.name);
17392                         exit_nicely(1);
17393                 }
17394
17395                 printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
17396
17397                 PQclear(res);
17398         }
17399
17400         /*
17401          * Add the command to alter the rules replication firing semantics if it
17402          * differs from the default.
17403          */
17404         if (rinfo->ev_enabled != 'O')
17405         {
17406                 appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
17407                 switch (rinfo->ev_enabled)
17408                 {
17409                         case 'A':
17410                                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
17411                                                                   fmtId(rinfo->dobj.name));
17412                                 break;
17413                         case 'R':
17414                                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
17415                                                                   fmtId(rinfo->dobj.name));
17416                                 break;
17417                         case 'D':
17418                                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
17419                                                                   fmtId(rinfo->dobj.name));
17420                                 break;
17421                 }
17422         }
17423
17424         if (is_view)
17425         {
17426                 /*
17427                  * We can't DROP a view's ON SELECT rule.  Instead, use CREATE OR
17428                  * REPLACE VIEW to replace the rule with something with minimal
17429                  * dependencies.
17430                  */
17431                 PQExpBuffer result;
17432
17433                 appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
17434                                                   fmtQualifiedDumpable(tbinfo));
17435                 result = createDummyViewAsClause(fout, tbinfo);
17436                 appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
17437                 destroyPQExpBuffer(result);
17438         }
17439         else
17440         {
17441                 appendPQExpBuffer(delcmd, "DROP RULE %s ",
17442                                                   fmtId(rinfo->dobj.name));
17443                 appendPQExpBuffer(delcmd, "ON %s;\n",
17444                                                   fmtQualifiedDumpable(tbinfo));
17445         }
17446
17447         appendPQExpBuffer(ruleprefix, "RULE %s ON",
17448                                           fmtId(rinfo->dobj.name));
17449
17450         tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
17451
17452         if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17453                 ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
17454                                          ARCHIVE_OPTS(.tag = tag,
17455                                                                   .namespace = tbinfo->dobj.namespace->dobj.name,
17456                                                                   .owner = tbinfo->rolname,
17457                                                                   .description = "RULE",
17458                                                                   .section = SECTION_POST_DATA,
17459                                                                   .createStmt = cmd->data,
17460                                                                   .dropStmt = delcmd->data));
17461
17462         /* Dump rule comments */
17463         if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17464                 dumpComment(fout, ruleprefix->data, qtabname,
17465                                         tbinfo->dobj.namespace->dobj.name,
17466                                         tbinfo->rolname,
17467                                         rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
17468
17469         free(tag);
17470         destroyPQExpBuffer(query);
17471         destroyPQExpBuffer(cmd);
17472         destroyPQExpBuffer(delcmd);
17473         destroyPQExpBuffer(ruleprefix);
17474         free(qtabname);
17475 }
17476
17477 /*
17478  * getExtensionMembership --- obtain extension membership data
17479  *
17480  * We need to identify objects that are extension members as soon as they're
17481  * loaded, so that we can correctly determine whether they need to be dumped.
17482  * Generally speaking, extension member objects will get marked as *not* to
17483  * be dumped, as they will be recreated by the single CREATE EXTENSION
17484  * command.  However, in binary upgrade mode we still need to dump the members
17485  * individually.
17486  */
17487 void
17488 getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
17489                                            int numExtensions)
17490 {
17491         PQExpBuffer query;
17492         PGresult   *res;
17493         int                     ntups,
17494                                 nextmembers,
17495                                 i;
17496         int                     i_classid,
17497                                 i_objid,
17498                                 i_refobjid;
17499         ExtensionMemberId *extmembers;
17500         ExtensionInfo *ext;
17501
17502         /* Nothing to do if no extensions */
17503         if (numExtensions == 0)
17504                 return;
17505
17506         query = createPQExpBuffer();
17507
17508         /* refclassid constraint is redundant but may speed the search */
17509         appendPQExpBufferStr(query, "SELECT "
17510                                                  "classid, objid, refobjid "
17511                                                  "FROM pg_depend "
17512                                                  "WHERE refclassid = 'pg_extension'::regclass "
17513                                                  "AND deptype = 'e' "
17514                                                  "ORDER BY 3");
17515
17516         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17517
17518         ntups = PQntuples(res);
17519
17520         i_classid = PQfnumber(res, "classid");
17521         i_objid = PQfnumber(res, "objid");
17522         i_refobjid = PQfnumber(res, "refobjid");
17523
17524         extmembers = (ExtensionMemberId *) pg_malloc(ntups * sizeof(ExtensionMemberId));
17525         nextmembers = 0;
17526
17527         /*
17528          * Accumulate data into extmembers[].
17529          *
17530          * Since we ordered the SELECT by referenced ID, we can expect that
17531          * multiple entries for the same extension will appear together; this
17532          * saves on searches.
17533          */
17534         ext = NULL;
17535
17536         for (i = 0; i < ntups; i++)
17537         {
17538                 CatalogId       objId;
17539                 Oid                     extId;
17540
17541                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17542                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
17543                 extId = atooid(PQgetvalue(res, i, i_refobjid));
17544
17545                 if (ext == NULL ||
17546                         ext->dobj.catId.oid != extId)
17547                         ext = findExtensionByOid(extId);
17548
17549                 if (ext == NULL)
17550                 {
17551                         /* shouldn't happen */
17552                         fprintf(stderr, "could not find referenced extension %u\n", extId);
17553                         continue;
17554                 }
17555
17556                 extmembers[nextmembers].catId = objId;
17557                 extmembers[nextmembers].ext = ext;
17558                 nextmembers++;
17559         }
17560
17561         PQclear(res);
17562
17563         /* Remember the data for use later */
17564         setExtensionMembership(extmembers, nextmembers);
17565
17566         destroyPQExpBuffer(query);
17567 }
17568
17569 /*
17570  * processExtensionTables --- deal with extension configuration tables
17571  *
17572  * There are two parts to this process:
17573  *
17574  * 1. Identify and create dump records for extension configuration tables.
17575  *
17576  *        Extensions can mark tables as "configuration", which means that the user
17577  *        is able and expected to modify those tables after the extension has been
17578  *        loaded.  For these tables, we dump out only the data- the structure is
17579  *        expected to be handled at CREATE EXTENSION time, including any indexes or
17580  *        foreign keys, which brings us to-
17581  *
17582  * 2. Record FK dependencies between configuration tables.
17583  *
17584  *        Due to the FKs being created at CREATE EXTENSION time and therefore before
17585  *        the data is loaded, we have to work out what the best order for reloading
17586  *        the data is, to avoid FK violations when the tables are restored.  This is
17587  *        not perfect- we can't handle circular dependencies and if any exist they
17588  *        will cause an invalid dump to be produced (though at least all of the data
17589  *        is included for a user to manually restore).  This is currently documented
17590  *        but perhaps we can provide a better solution in the future.
17591  */
17592 void
17593 processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
17594                                            int numExtensions)
17595 {
17596         DumpOptions *dopt = fout->dopt;
17597         PQExpBuffer query;
17598         PGresult   *res;
17599         int                     ntups,
17600                                 i;
17601         int                     i_conrelid,
17602                                 i_confrelid;
17603
17604         /* Nothing to do if no extensions */
17605         if (numExtensions == 0)
17606                 return;
17607
17608         /*
17609          * Identify extension configuration tables and create TableDataInfo
17610          * objects for them, ensuring their data will be dumped even though the
17611          * tables themselves won't be.
17612          *
17613          * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
17614          * user data in a configuration table is treated like schema data. This
17615          * seems appropriate since system data in a config table would get
17616          * reloaded by CREATE EXTENSION.
17617          */
17618         for (i = 0; i < numExtensions; i++)
17619         {
17620                 ExtensionInfo *curext = &(extinfo[i]);
17621                 char       *extconfig = curext->extconfig;
17622                 char       *extcondition = curext->extcondition;
17623                 char      **extconfigarray = NULL;
17624                 char      **extconditionarray = NULL;
17625                 int                     nconfigitems;
17626                 int                     nconditionitems;
17627
17628                 if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
17629                         parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
17630                         nconfigitems == nconditionitems)
17631                 {
17632                         int                     j;
17633
17634                         for (j = 0; j < nconfigitems; j++)
17635                         {
17636                                 TableInfo  *configtbl;
17637                                 Oid                     configtbloid = atooid(extconfigarray[j]);
17638                                 bool            dumpobj =
17639                                 curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
17640
17641                                 configtbl = findTableByOid(configtbloid);
17642                                 if (configtbl == NULL)
17643                                         continue;
17644
17645                                 /*
17646                                  * Tables of not-to-be-dumped extensions shouldn't be dumped
17647                                  * unless the table or its schema is explicitly included
17648                                  */
17649                                 if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
17650                                 {
17651                                         /* check table explicitly requested */
17652                                         if (table_include_oids.head != NULL &&
17653                                                 simple_oid_list_member(&table_include_oids,
17654                                                                                            configtbloid))
17655                                                 dumpobj = true;
17656
17657                                         /* check table's schema explicitly requested */
17658                                         if (configtbl->dobj.namespace->dobj.dump &
17659                                                 DUMP_COMPONENT_DATA)
17660                                                 dumpobj = true;
17661                                 }
17662
17663                                 /* check table excluded by an exclusion switch */
17664                                 if (table_exclude_oids.head != NULL &&
17665                                         simple_oid_list_member(&table_exclude_oids,
17666                                                                                    configtbloid))
17667                                         dumpobj = false;
17668
17669                                 /* check schema excluded by an exclusion switch */
17670                                 if (simple_oid_list_member(&schema_exclude_oids,
17671                                                                                    configtbl->dobj.namespace->dobj.catId.oid))
17672                                         dumpobj = false;
17673
17674                                 if (dumpobj)
17675                                 {
17676                                         makeTableDataInfo(dopt, configtbl);
17677                                         if (configtbl->dataObj != NULL)
17678                                         {
17679                                                 if (strlen(extconditionarray[j]) > 0)
17680                                                         configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
17681                                         }
17682                                 }
17683                         }
17684                 }
17685                 if (extconfigarray)
17686                         free(extconfigarray);
17687                 if (extconditionarray)
17688                         free(extconditionarray);
17689         }
17690
17691         /*
17692          * Now that all the TableInfoData objects have been created for all the
17693          * extensions, check their FK dependencies and register them to try and
17694          * dump the data out in an order that they can be restored in.
17695          *
17696          * Note that this is not a problem for user tables as their FKs are
17697          * recreated after the data has been loaded.
17698          */
17699
17700         query = createPQExpBuffer();
17701
17702         printfPQExpBuffer(query,
17703                                           "SELECT conrelid, confrelid "
17704                                           "FROM pg_constraint "
17705                                           "JOIN pg_depend ON (objid = confrelid) "
17706                                           "WHERE contype = 'f' "
17707                                           "AND refclassid = 'pg_extension'::regclass "
17708                                           "AND classid = 'pg_class'::regclass;");
17709
17710         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17711         ntups = PQntuples(res);
17712
17713         i_conrelid = PQfnumber(res, "conrelid");
17714         i_confrelid = PQfnumber(res, "confrelid");
17715
17716         /* Now get the dependencies and register them */
17717         for (i = 0; i < ntups; i++)
17718         {
17719                 Oid                     conrelid,
17720                                         confrelid;
17721                 TableInfo  *reftable,
17722                                    *contable;
17723
17724                 conrelid = atooid(PQgetvalue(res, i, i_conrelid));
17725                 confrelid = atooid(PQgetvalue(res, i, i_confrelid));
17726                 contable = findTableByOid(conrelid);
17727                 reftable = findTableByOid(confrelid);
17728
17729                 if (reftable == NULL ||
17730                         reftable->dataObj == NULL ||
17731                         contable == NULL ||
17732                         contable->dataObj == NULL)
17733                         continue;
17734
17735                 /*
17736                  * Make referencing TABLE_DATA object depend on the referenced table's
17737                  * TABLE_DATA object.
17738                  */
17739                 addObjectDependency(&contable->dataObj->dobj,
17740                                                         reftable->dataObj->dobj.dumpId);
17741         }
17742         PQclear(res);
17743         destroyPQExpBuffer(query);
17744 }
17745
17746 /*
17747  * getDependencies --- obtain available dependency data
17748  */
17749 static void
17750 getDependencies(Archive *fout)
17751 {
17752         PQExpBuffer query;
17753         PGresult   *res;
17754         int                     ntups,
17755                                 i;
17756         int                     i_classid,
17757                                 i_objid,
17758                                 i_refclassid,
17759                                 i_refobjid,
17760                                 i_deptype;
17761         DumpableObject *dobj,
17762                            *refdobj;
17763
17764         if (g_verbose)
17765                 write_msg(NULL, "reading dependency data\n");
17766
17767         query = createPQExpBuffer();
17768
17769         /*
17770          * PIN dependencies aren't interesting, and EXTENSION dependencies were
17771          * already processed by getExtensionMembership.
17772          */
17773         appendPQExpBufferStr(query, "SELECT "
17774                                                  "classid, objid, refclassid, refobjid, deptype "
17775                                                  "FROM pg_depend "
17776                                                  "WHERE deptype != 'p' AND deptype != 'e' "
17777                                                  "ORDER BY 1,2");
17778
17779         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17780
17781         ntups = PQntuples(res);
17782
17783         i_classid = PQfnumber(res, "classid");
17784         i_objid = PQfnumber(res, "objid");
17785         i_refclassid = PQfnumber(res, "refclassid");
17786         i_refobjid = PQfnumber(res, "refobjid");
17787         i_deptype = PQfnumber(res, "deptype");
17788
17789         /*
17790          * Since we ordered the SELECT by referencing ID, we can expect that
17791          * multiple entries for the same object will appear together; this saves
17792          * on searches.
17793          */
17794         dobj = NULL;
17795
17796         for (i = 0; i < ntups; i++)
17797         {
17798                 CatalogId       objId;
17799                 CatalogId       refobjId;
17800                 char            deptype;
17801
17802                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17803                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
17804                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
17805                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
17806                 deptype = *(PQgetvalue(res, i, i_deptype));
17807
17808                 if (dobj == NULL ||
17809                         dobj->catId.tableoid != objId.tableoid ||
17810                         dobj->catId.oid != objId.oid)
17811                         dobj = findObjectByCatalogId(objId);
17812
17813                 /*
17814                  * Failure to find objects mentioned in pg_depend is not unexpected,
17815                  * since for example we don't collect info about TOAST tables.
17816                  */
17817                 if (dobj == NULL)
17818                 {
17819 #ifdef NOT_USED
17820                         fprintf(stderr, "no referencing object %u %u\n",
17821                                         objId.tableoid, objId.oid);
17822 #endif
17823                         continue;
17824                 }
17825
17826                 refdobj = findObjectByCatalogId(refobjId);
17827
17828                 if (refdobj == NULL)
17829                 {
17830 #ifdef NOT_USED
17831                         fprintf(stderr, "no referenced object %u %u\n",
17832                                         refobjId.tableoid, refobjId.oid);
17833 #endif
17834                         continue;
17835                 }
17836
17837                 /*
17838                  * Ordinarily, table rowtypes have implicit dependencies on their
17839                  * tables.  However, for a composite type the implicit dependency goes
17840                  * the other way in pg_depend; which is the right thing for DROP but
17841                  * it doesn't produce the dependency ordering we need. So in that one
17842                  * case, we reverse the direction of the dependency.
17843                  */
17844                 if (deptype == 'i' &&
17845                         dobj->objType == DO_TABLE &&
17846                         refdobj->objType == DO_TYPE)
17847                         addObjectDependency(refdobj, dobj->dumpId);
17848                 else
17849                         /* normal case */
17850                         addObjectDependency(dobj, refdobj->dumpId);
17851         }
17852
17853         PQclear(res);
17854
17855         destroyPQExpBuffer(query);
17856 }
17857
17858
17859 /*
17860  * createBoundaryObjects - create dummy DumpableObjects to represent
17861  * dump section boundaries.
17862  */
17863 static DumpableObject *
17864 createBoundaryObjects(void)
17865 {
17866         DumpableObject *dobjs;
17867
17868         dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
17869
17870         dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
17871         dobjs[0].catId = nilCatalogId;
17872         AssignDumpId(dobjs + 0);
17873         dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
17874
17875         dobjs[1].objType = DO_POST_DATA_BOUNDARY;
17876         dobjs[1].catId = nilCatalogId;
17877         AssignDumpId(dobjs + 1);
17878         dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
17879
17880         return dobjs;
17881 }
17882
17883 /*
17884  * addBoundaryDependencies - add dependencies as needed to enforce the dump
17885  * section boundaries.
17886  */
17887 static void
17888 addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
17889                                                 DumpableObject *boundaryObjs)
17890 {
17891         DumpableObject *preDataBound = boundaryObjs + 0;
17892         DumpableObject *postDataBound = boundaryObjs + 1;
17893         int                     i;
17894
17895         for (i = 0; i < numObjs; i++)
17896         {
17897                 DumpableObject *dobj = dobjs[i];
17898
17899                 /*
17900                  * The classification of object types here must match the SECTION_xxx
17901                  * values assigned during subsequent ArchiveEntry calls!
17902                  */
17903                 switch (dobj->objType)
17904                 {
17905                         case DO_NAMESPACE:
17906                         case DO_EXTENSION:
17907                         case DO_TYPE:
17908                         case DO_SHELL_TYPE:
17909                         case DO_FUNC:
17910                         case DO_AGG:
17911                         case DO_OPERATOR:
17912                         case DO_ACCESS_METHOD:
17913                         case DO_OPCLASS:
17914                         case DO_OPFAMILY:
17915                         case DO_COLLATION:
17916                         case DO_CONVERSION:
17917                         case DO_TABLE:
17918                         case DO_ATTRDEF:
17919                         case DO_PROCLANG:
17920                         case DO_CAST:
17921                         case DO_DUMMY_TYPE:
17922                         case DO_TSPARSER:
17923                         case DO_TSDICT:
17924                         case DO_TSTEMPLATE:
17925                         case DO_TSCONFIG:
17926                         case DO_FDW:
17927                         case DO_FOREIGN_SERVER:
17928                         case DO_TRANSFORM:
17929                         case DO_BLOB:
17930                                 /* Pre-data objects: must come before the pre-data boundary */
17931                                 addObjectDependency(preDataBound, dobj->dumpId);
17932                                 break;
17933                         case DO_TABLE_DATA:
17934                         case DO_SEQUENCE_SET:
17935                         case DO_BLOB_DATA:
17936                                 /* Data objects: must come between the boundaries */
17937                                 addObjectDependency(dobj, preDataBound->dumpId);
17938                                 addObjectDependency(postDataBound, dobj->dumpId);
17939                                 break;
17940                         case DO_INDEX:
17941                         case DO_INDEX_ATTACH:
17942                         case DO_STATSEXT:
17943                         case DO_REFRESH_MATVIEW:
17944                         case DO_TRIGGER:
17945                         case DO_EVENT_TRIGGER:
17946                         case DO_DEFAULT_ACL:
17947                         case DO_POLICY:
17948                         case DO_PUBLICATION:
17949                         case DO_PUBLICATION_REL:
17950                         case DO_SUBSCRIPTION:
17951                                 /* Post-data objects: must come after the post-data boundary */
17952                                 addObjectDependency(dobj, postDataBound->dumpId);
17953                                 break;
17954                         case DO_RULE:
17955                                 /* Rules are post-data, but only if dumped separately */
17956                                 if (((RuleInfo *) dobj)->separate)
17957                                         addObjectDependency(dobj, postDataBound->dumpId);
17958                                 break;
17959                         case DO_CONSTRAINT:
17960                         case DO_FK_CONSTRAINT:
17961                                 /* Constraints are post-data, but only if dumped separately */
17962                                 if (((ConstraintInfo *) dobj)->separate)
17963                                         addObjectDependency(dobj, postDataBound->dumpId);
17964                                 break;
17965                         case DO_PRE_DATA_BOUNDARY:
17966                                 /* nothing to do */
17967                                 break;
17968                         case DO_POST_DATA_BOUNDARY:
17969                                 /* must come after the pre-data boundary */
17970                                 addObjectDependency(dobj, preDataBound->dumpId);
17971                                 break;
17972                 }
17973         }
17974 }
17975
17976
17977 /*
17978  * BuildArchiveDependencies - create dependency data for archive TOC entries
17979  *
17980  * The raw dependency data obtained by getDependencies() is not terribly
17981  * useful in an archive dump, because in many cases there are dependency
17982  * chains linking through objects that don't appear explicitly in the dump.
17983  * For example, a view will depend on its _RETURN rule while the _RETURN rule
17984  * will depend on other objects --- but the rule will not appear as a separate
17985  * object in the dump.  We need to adjust the view's dependencies to include
17986  * whatever the rule depends on that is included in the dump.
17987  *
17988  * Just to make things more complicated, there are also "special" dependencies
17989  * such as the dependency of a TABLE DATA item on its TABLE, which we must
17990  * not rearrange because pg_restore knows that TABLE DATA only depends on
17991  * its table.  In these cases we must leave the dependencies strictly as-is
17992  * even if they refer to not-to-be-dumped objects.
17993  *
17994  * To handle this, the convention is that "special" dependencies are created
17995  * during ArchiveEntry calls, and an archive TOC item that has any such
17996  * entries will not be touched here.  Otherwise, we recursively search the
17997  * DumpableObject data structures to build the correct dependencies for each
17998  * archive TOC item.
17999  */
18000 static void
18001 BuildArchiveDependencies(Archive *fout)
18002 {
18003         ArchiveHandle *AH = (ArchiveHandle *) fout;
18004         TocEntry   *te;
18005
18006         /* Scan all TOC entries in the archive */
18007         for (te = AH->toc->next; te != AH->toc; te = te->next)
18008         {
18009                 DumpableObject *dobj;
18010                 DumpId     *dependencies;
18011                 int                     nDeps;
18012                 int                     allocDeps;
18013
18014                 /* No need to process entries that will not be dumped */
18015                 if (te->reqs == 0)
18016                         continue;
18017                 /* Ignore entries that already have "special" dependencies */
18018                 if (te->nDeps > 0)
18019                         continue;
18020                 /* Otherwise, look up the item's original DumpableObject, if any */
18021                 dobj = findObjectByDumpId(te->dumpId);
18022                 if (dobj == NULL)
18023                         continue;
18024                 /* No work if it has no dependencies */
18025                 if (dobj->nDeps <= 0)
18026                         continue;
18027                 /* Set up work array */
18028                 allocDeps = 64;
18029                 dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
18030                 nDeps = 0;
18031                 /* Recursively find all dumpable dependencies */
18032                 findDumpableDependencies(AH, dobj,
18033                                                                  &dependencies, &nDeps, &allocDeps);
18034                 /* And save 'em ... */
18035                 if (nDeps > 0)
18036                 {
18037                         dependencies = (DumpId *) pg_realloc(dependencies,
18038                                                                                                  nDeps * sizeof(DumpId));
18039                         te->dependencies = dependencies;
18040                         te->nDeps = nDeps;
18041                 }
18042                 else
18043                         free(dependencies);
18044         }
18045 }
18046
18047 /* Recursive search subroutine for BuildArchiveDependencies */
18048 static void
18049 findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
18050                                                  DumpId **dependencies, int *nDeps, int *allocDeps)
18051 {
18052         int                     i;
18053
18054         /*
18055          * Ignore section boundary objects: if we search through them, we'll
18056          * report lots of bogus dependencies.
18057          */
18058         if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
18059                 dobj->objType == DO_POST_DATA_BOUNDARY)
18060                 return;
18061
18062         for (i = 0; i < dobj->nDeps; i++)
18063         {
18064                 DumpId          depid = dobj->dependencies[i];
18065
18066                 if (TocIDRequired(AH, depid) != 0)
18067                 {
18068                         /* Object will be dumped, so just reference it as a dependency */
18069                         if (*nDeps >= *allocDeps)
18070                         {
18071                                 *allocDeps *= 2;
18072                                 *dependencies = (DumpId *) pg_realloc(*dependencies,
18073                                                                                                           *allocDeps * sizeof(DumpId));
18074                         }
18075                         (*dependencies)[*nDeps] = depid;
18076                         (*nDeps)++;
18077                 }
18078                 else
18079                 {
18080                         /*
18081                          * Object will not be dumped, so recursively consider its deps. We
18082                          * rely on the assumption that sortDumpableObjects already broke
18083                          * any dependency loops, else we might recurse infinitely.
18084                          */
18085                         DumpableObject *otherdobj = findObjectByDumpId(depid);
18086
18087                         if (otherdobj)
18088                                 findDumpableDependencies(AH, otherdobj,
18089                                                                                  dependencies, nDeps, allocDeps);
18090                 }
18091         }
18092 }
18093
18094
18095 /*
18096  * getFormattedTypeName - retrieve a nicely-formatted type name for the
18097  * given type OID.
18098  *
18099  * This does not guarantee to schema-qualify the output, so it should not
18100  * be used to create the target object name for CREATE or ALTER commands.
18101  *
18102  * TODO: there might be some value in caching the results.
18103  */
18104 static char *
18105 getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
18106 {
18107         char       *result;
18108         PQExpBuffer query;
18109         PGresult   *res;
18110
18111         if (oid == 0)
18112         {
18113                 if ((opts & zeroAsOpaque) != 0)
18114                         return pg_strdup(g_opaque_type);
18115                 else if ((opts & zeroAsAny) != 0)
18116                         return pg_strdup("'any'");
18117                 else if ((opts & zeroAsStar) != 0)
18118                         return pg_strdup("*");
18119                 else if ((opts & zeroAsNone) != 0)
18120                         return pg_strdup("NONE");
18121         }
18122
18123         query = createPQExpBuffer();
18124         appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
18125                                           oid);
18126
18127         res = ExecuteSqlQueryForSingleRow(fout, query->data);
18128
18129         /* result of format_type is already quoted */
18130         result = pg_strdup(PQgetvalue(res, 0, 0));
18131
18132         PQclear(res);
18133         destroyPQExpBuffer(query);
18134
18135         return result;
18136 }
18137
18138 /*
18139  * Return a column list clause for the given relation.
18140  *
18141  * Special case: if there are no undropped columns in the relation, return
18142  * "", not an invalid "()" column list.
18143  */
18144 static const char *
18145 fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
18146 {
18147         int                     numatts = ti->numatts;
18148         char      **attnames = ti->attnames;
18149         bool       *attisdropped = ti->attisdropped;
18150         bool            needComma;
18151         int                     i;
18152
18153         appendPQExpBufferChar(buffer, '(');
18154         needComma = false;
18155         for (i = 0; i < numatts; i++)
18156         {
18157                 if (attisdropped[i])
18158                         continue;
18159                 if (needComma)
18160                         appendPQExpBufferStr(buffer, ", ");
18161                 appendPQExpBufferStr(buffer, fmtId(attnames[i]));
18162                 needComma = true;
18163         }
18164
18165         if (!needComma)
18166                 return "";                              /* no undropped columns */
18167
18168         appendPQExpBufferChar(buffer, ')');
18169         return buffer->data;
18170 }
18171
18172 /*
18173  * Check if a reloptions array is nonempty.
18174  */
18175 static bool
18176 nonemptyReloptions(const char *reloptions)
18177 {
18178         /* Don't want to print it if it's just "{}" */
18179         return (reloptions != NULL && strlen(reloptions) > 2);
18180 }
18181
18182 /*
18183  * Format a reloptions array and append it to the given buffer.
18184  *
18185  * "prefix" is prepended to the option names; typically it's "" or "toast.".
18186  */
18187 static void
18188 appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
18189                                                 const char *prefix, Archive *fout)
18190 {
18191         bool            res;
18192
18193         res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
18194                                                                 fout->std_strings);
18195         if (!res)
18196                 write_msg(NULL, "WARNING: could not parse reloptions array\n");
18197 }